diff --git a/reactos/dll/win32/rpcrt4/ndr_marshall.c b/reactos/dll/win32/rpcrt4/ndr_marshall.c index 3d7cf4672d5..229b9d5f757 100644 --- a/reactos/dll/win32/rpcrt4/ndr_marshall.c +++ b/reactos/dll/win32/rpcrt4/ndr_marshall.c @@ -2929,7 +2929,7 @@ static unsigned char * ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg, { /* for some reason interface pointers aren't generated as * RPC_FC_POINTER, but instead as RPC_FC_EMBEDDED_COMPLEX, yet - * they still need the derefencing treatment that pointers are + * they still need the dereferencing treatment that pointers are * given */ if (*desc == RPC_FC_IP) m(pStubMsg, *(unsigned char **)pMemory, desc); @@ -3105,7 +3105,7 @@ static unsigned char * ComplexUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, { /* for some reason interface pointers aren't generated as * RPC_FC_POINTER, but instead as RPC_FC_EMBEDDED_COMPLEX, yet - * they still need the derefencing treatment that pointers are + * they still need the dereferencing treatment that pointers are * given */ if (*desc == RPC_FC_IP) m(pStubMsg, (unsigned char **)pMemory, desc, FALSE); @@ -3229,7 +3229,7 @@ static unsigned char * ComplexBufferSize(PMIDL_STUB_MESSAGE pStubMsg, { /* for some reason interface pointers aren't generated as * RPC_FC_POINTER, but instead as RPC_FC_EMBEDDED_COMPLEX, yet - * they still need the derefencing treatment that pointers are + * they still need the dereferencing treatment that pointers are * given */ if (*desc == RPC_FC_IP) m(pStubMsg, *(unsigned char **)pMemory, desc); @@ -3330,7 +3330,7 @@ static unsigned char * ComplexFree(PMIDL_STUB_MESSAGE pStubMsg, { /* for some reason interface pointers aren't generated as * RPC_FC_POINTER, but instead as RPC_FC_EMBEDDED_COMPLEX, yet - * they still need the derefencing treatment that pointers are + * they still need the dereferencing treatment that pointers are * given */ if (*desc == RPC_FC_IP) m(pStubMsg, *(unsigned char **)pMemory, desc); diff --git a/reactos/dll/win32/rpcrt4/ndr_stubless.c b/reactos/dll/win32/rpcrt4/ndr_stubless.c index 6197c9debd4..0a16cae8e24 100644 --- a/reactos/dll/win32/rpcrt4/ndr_stubless.c +++ b/reactos/dll/win32/rpcrt4/ndr_stubless.c @@ -581,8 +581,8 @@ PFORMAT_STRING convert_old_args( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFo return (PFORMAT_STRING)args; } -LONG_PTR CDECL ndr_client_call( PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat, - void **stack_top, void **fpu_stack ) +LONG_PTR CDECL DECLSPEC_HIDDEN ndr_client_call( PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat, + void **stack_top, void **fpu_stack ) { /* pointer to start of stack where arguments start */ RPC_MESSAGE rpcMsg; @@ -1511,7 +1511,8 @@ struct async_call_data ULONG_PTR NdrCorrCache[256]; }; -LONG_PTR CDECL ndr_async_client_call( PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat, void **stack_top ) +LONG_PTR CDECL DECLSPEC_HIDDEN ndr_async_client_call( PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat, + void **stack_top ) { /* pointer to start of stack where arguments start */ PRPC_MESSAGE pRpcMsg; diff --git a/reactos/dll/win32/rpcrt4/rpc_binding.c b/reactos/dll/win32/rpcrt4/rpc_binding.c index 02caa88047a..4f7b5f0044e 100644 --- a/reactos/dll/win32/rpcrt4/rpc_binding.c +++ b/reactos/dll/win32/rpcrt4/rpc_binding.c @@ -279,14 +279,13 @@ RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection) if (!Connection) return RPC_S_OK; if (Binding->server) { /* don't destroy a connection that is cached in the binding */ - if (Binding->FromConn == Connection) - return RPC_S_OK; - return RPCRT4_ReleaseConnection(Connection); + if (Binding->FromConn != Connection) + RPCRT4_ReleaseConnection(Connection); } else { RpcAssoc_ReleaseIdleConnection(Binding->Assoc, Connection); - return RPC_S_OK; } + return RPC_S_OK; } static LPSTR RPCRT4_strconcatA(LPSTR dst, LPCSTR src) diff --git a/reactos/dll/win32/rpcrt4/rpc_binding.h b/reactos/dll/win32/rpcrt4/rpc_binding.h index 1f53bac5427..991a0ff5a8f 100644 --- a/reactos/dll/win32/rpcrt4/rpc_binding.h +++ b/reactos/dll/win32/rpcrt4/rpc_binding.h @@ -59,6 +59,7 @@ typedef struct _RpcConnection { LONG ref; BOOL server; + HANDLE wait_release; LPSTR NetworkAddr; LPSTR Endpoint; LPWSTR NetworkOptions; @@ -158,7 +159,7 @@ RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPCS LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS, LPCWSTR CookieAuth) DECLSPEC_HIDDEN; RpcConnection *RPCRT4_GrabConnection( RpcConnection *conn ) DECLSPEC_HIDDEN; -RPC_STATUS RPCRT4_ReleaseConnection(RpcConnection* Connection) DECLSPEC_HIDDEN; +void RPCRT4_ReleaseConnection(RpcConnection* Connection) DECLSPEC_HIDDEN; RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection) DECLSPEC_HIDDEN; RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection) DECLSPEC_HIDDEN; RPC_STATUS RPCRT4_IsServerListening(const char *protseq, const char *endpoint) DECLSPEC_HIDDEN; @@ -172,6 +173,8 @@ RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection, const RPC_SYNTAX_IDENTIFIER *TransferSyntax, const RPC_SYNTAX_IDENTIFIER *InterfaceId) DECLSPEC_HIDDEN; RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection) DECLSPEC_HIDDEN; +void rpcrt4_conn_release_and_wait(RpcConnection *connection) DECLSPEC_HIDDEN; + static inline const char *rpcrt4_conn_get_name(const RpcConnection *Connection) { return Connection->ops->name; diff --git a/reactos/dll/win32/rpcrt4/rpc_server.c b/reactos/dll/win32/rpcrt4/rpc_server.c index 2d7c80a2242..25722691ddb 100644 --- a/reactos/dll/win32/rpcrt4/rpc_server.c +++ b/reactos/dll/win32/rpcrt4/rpc_server.c @@ -647,21 +647,44 @@ static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg) { /* cleanup */ cps->ops->free_wait_array(cps, objs); - - EnterCriticalSection(&cps->cs); - LIST_FOR_EACH_ENTRY(conn, &cps->listeners, RpcConnection, protseq_entry) - RPCRT4_CloseConnection(conn); - LIST_FOR_EACH_ENTRY(conn, &cps->connections, RpcConnection, protseq_entry) - rpcrt4_conn_close_read(conn); - LeaveCriticalSection(&cps->cs); - - if (res == 0 && !std_listen) - SetEvent(cps->server_ready_event); break; } else if (res == 0) set_ready_event = TRUE; } + + TRACE("closing connections\n"); + + EnterCriticalSection(&cps->cs); + LIST_FOR_EACH_ENTRY(conn, &cps->listeners, RpcConnection, protseq_entry) + RPCRT4_CloseConnection(conn); + LIST_FOR_EACH_ENTRY(conn, &cps->connections, RpcConnection, protseq_entry) + { + RPCRT4_GrabConnection(conn); + rpcrt4_conn_close_read(conn); + } + LeaveCriticalSection(&cps->cs); + + if (res == 0 && !std_listen) + SetEvent(cps->server_ready_event); + + TRACE("waiting for active connections to close\n"); + + EnterCriticalSection(&cps->cs); + while (!list_empty(&cps->connections)) + { + conn = LIST_ENTRY(list_head(&cps->connections), RpcConnection, protseq_entry); + LeaveCriticalSection(&cps->cs); + rpcrt4_conn_release_and_wait(conn); + EnterCriticalSection(&cps->cs); + } + LeaveCriticalSection(&cps->cs); + + EnterCriticalSection(&listen_cs); + CloseHandle(cps->server_thread); + cps->server_thread = NULL; + LeaveCriticalSection(&listen_cs); + TRACE("done\n"); return 0; } @@ -685,21 +708,15 @@ static void RPCRT4_sync_with_server_thread(RpcServerProtseq *ps) static RPC_STATUS RPCRT4_start_listen_protseq(RpcServerProtseq *ps, BOOL auto_listen) { RPC_STATUS status = RPC_S_OK; - HANDLE server_thread; EnterCriticalSection(&listen_cs); - if (ps->is_listening) goto done; + if (ps->server_thread) goto done; if (!ps->mgr_mutex) ps->mgr_mutex = CreateMutexW(NULL, FALSE, NULL); if (!ps->server_ready_event) ps->server_ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); - server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, ps, 0, NULL); - if (!server_thread) - { + ps->server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, ps, 0, NULL); + if (!ps->server_thread) status = RPC_S_OUT_OF_RESOURCES; - goto done; - } - ps->is_listening = TRUE; - CloseHandle(server_thread); done: LeaveCriticalSection(&listen_cs); @@ -767,8 +784,10 @@ static RPC_STATUS RPCRT4_stop_listen(BOOL auto_listen) if (stop_listen) { RpcServerProtseq *cps; + EnterCriticalSection(&server_cs); LIST_FOR_EACH_ENTRY(cps, &protseqs, RpcServerProtseq, entry) RPCRT4_sync_with_server_thread(cps); + LeaveCriticalSection(&server_cs); } if (!auto_listen) @@ -1503,7 +1522,8 @@ RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT */ RPC_STATUS WINAPI RpcMgmtWaitServerListen( void ) { - HANDLE event; + RpcServerProtseq *protseq; + HANDLE event, wait_thread; TRACE("()\n"); @@ -1519,6 +1539,28 @@ RPC_STATUS WINAPI RpcMgmtWaitServerListen( void ) TRACE( "done waiting\n" ); EnterCriticalSection(&listen_cs); + /* wait for server threads to finish */ + while(1) + { + if (listen_count) + break; + + wait_thread = NULL; + EnterCriticalSection(&server_cs); + LIST_FOR_EACH_ENTRY(protseq, &protseqs, RpcServerProtseq, entry) + { + if ((wait_thread = protseq->server_thread)) + break; + } + LeaveCriticalSection(&server_cs); + if (!wait_thread) + break; + + TRACE("waiting for thread %u\n", GetThreadId(wait_thread)); + LeaveCriticalSection(&listen_cs); + WaitForSingleObject(wait_thread, INFINITE); + EnterCriticalSection(&listen_cs); + } if (listen_done_event == event) { listen_done_event = NULL; diff --git a/reactos/dll/win32/rpcrt4/rpc_server.h b/reactos/dll/win32/rpcrt4/rpc_server.h index 72e73e2a89a..adaa47133e4 100644 --- a/reactos/dll/win32/rpcrt4/rpc_server.h +++ b/reactos/dll/win32/rpcrt4/rpc_server.h @@ -36,8 +36,8 @@ typedef struct _RpcServerProtseq struct list connections; /* CS cs */ CRITICAL_SECTION cs; - /* is the server currently listening? */ - BOOL is_listening; /* CS ::listen_cs */ + /* handle to listening thread */ + HANDLE server_thread; /* CS ::listen_cs */ /* mutex for ensuring only one thread can change state at a time */ HANDLE mgr_mutex; /* set when server thread has finished opening connections */ diff --git a/reactos/dll/win32/rpcrt4/rpc_transport.c b/reactos/dll/win32/rpcrt4/rpc_transport.c index ed080fb64b7..6897db62414 100644 --- a/reactos/dll/win32/rpcrt4/rpc_transport.c +++ b/reactos/dll/win32/rpcrt4/rpc_transport.c @@ -65,6 +65,7 @@ typedef struct _RpcConnection_np RpcConnection common; HANDLE pipe; HANDLE listen_event; + char *listen_pipe; IO_STATUS_BLOCK io_status; HANDLE event_cache; BOOL read_closed; @@ -89,26 +90,26 @@ static void release_np_event(RpcConnection_np *connection, HANDLE event) CloseHandle(event); } -static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *Connection, LPCSTR pname) +static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *conn) { - RpcConnection_np *npc = (RpcConnection_np *) Connection; - TRACE("listening on %s\n", pname); + RpcConnection_np *connection = (RpcConnection_np *) conn; - npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, - PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, - PIPE_UNLIMITED_INSTANCES, - RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL); - if (npc->pipe == INVALID_HANDLE_VALUE) { - WARN("CreateNamedPipe failed with error %d\n", GetLastError()); - if (GetLastError() == ERROR_FILE_EXISTS) - return RPC_S_DUPLICATE_ENDPOINT; - else - return RPC_S_CANT_CREATE_ENDPOINT; - } + TRACE("listening on %s\n", connection->listen_pipe); - /* Note: we don't call ConnectNamedPipe here because it must be done in the - * server thread as the thread must be alertable */ - return RPC_S_OK; + connection->pipe = CreateNamedPipeA(connection->listen_pipe, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, + PIPE_UNLIMITED_INSTANCES, + RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL); + if (connection->pipe == INVALID_HANDLE_VALUE) + { + WARN("CreateNamedPipe failed with error %d\n", GetLastError()); + if (GetLastError() == ERROR_FILE_EXISTS) + return RPC_S_DUPLICATE_ENDPOINT; + else + return RPC_S_CANT_CREATE_ENDPOINT; + } + + return RPC_S_OK; } static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait) @@ -201,7 +202,6 @@ static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection) static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, const char *endpoint) { RPC_STATUS r; - LPSTR pname; RpcConnection *Connection; char generated_endpoint[22]; @@ -220,9 +220,8 @@ static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq if (r != RPC_S_OK) return r; - pname = ncalrpc_pipe_name(Connection->Endpoint); - r = rpcrt4_conn_create_pipe(Connection, pname); - I_RpcFree(pname); + ((RpcConnection_np*)Connection)->listen_pipe = ncalrpc_pipe_name(Connection->Endpoint); + r = rpcrt4_conn_create_pipe(Connection); EnterCriticalSection(&protseq->cs); list_add_head(&protseq->listeners, &Connection->protseq_entry); @@ -263,7 +262,6 @@ static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection) static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, const char *endpoint) { RPC_STATUS r; - LPSTR pname; RpcConnection *Connection; char generated_endpoint[26]; @@ -282,9 +280,8 @@ static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protse if (r != RPC_S_OK) return r; - pname = ncacn_pipe_name(Connection->Endpoint); - r = rpcrt4_conn_create_pipe(Connection, pname); - I_RpcFree(pname); + ((RpcConnection_np*)Connection)->listen_pipe = ncacn_pipe_name(Connection->Endpoint); + r = rpcrt4_conn_create_pipe(Connection); EnterCriticalSection(&protseq->cs); list_add_head(&protseq->listeners, &Connection->protseq_entry); @@ -308,13 +305,9 @@ static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection { DWORD len = MAX_COMPUTERNAME_LENGTH + 1; RPC_STATUS status; - LPSTR pname; rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn); - - pname = ncacn_pipe_name(old_conn->Endpoint); - status = rpcrt4_conn_create_pipe(old_conn, pname); - I_RpcFree(pname); + status = rpcrt4_conn_create_pipe(old_conn); /* Store the local computer name as the NetworkAddr for ncacn_np as long as * we don't support named pipes over the network. */ @@ -359,15 +352,11 @@ static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection { DWORD len = MAX_COMPUTERNAME_LENGTH + 1; RPC_STATUS status; - LPSTR pname; TRACE("%s\n", old_conn->Endpoint); rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn); - - pname = ncalrpc_pipe_name(old_conn->Endpoint); - status = rpcrt4_conn_create_pipe(old_conn, pname); - I_RpcFree(pname); + status = rpcrt4_conn_create_pipe(old_conn); /* Store the local computer name as the NetworkAddr for ncalrpc. */ new_conn->NetworkAddr = HeapAlloc(GetProcessHeap(), 0, len); @@ -672,6 +661,8 @@ static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *p *count = 1; LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_np, common.protseq_entry) { + if (!conn->pipe && rpcrt4_conn_create_pipe(&conn->common) != RPC_S_OK) + continue; if (!conn->listen_event) { NTSTATUS status; @@ -3372,38 +3363,69 @@ static RpcConnection *rpcrt4_spawn_connection(RpcConnection *old_connection) return connection; } -RpcConnection *RPCRT4_GrabConnection( RpcConnection *conn ) +void rpcrt4_conn_release_and_wait(RpcConnection *connection) { - InterlockedIncrement( &conn->ref ); - return conn; + HANDLE event = NULL; + + if (connection->ref > 1) + event = connection->wait_release = CreateEventW(NULL, TRUE, FALSE, NULL); + + RPCRT4_ReleaseConnection(connection); + + if(event) + { + WaitForSingleObject(event, INFINITE); + CloseHandle(event); + } } -RPC_STATUS RPCRT4_ReleaseConnection(RpcConnection* Connection) +RpcConnection *RPCRT4_GrabConnection(RpcConnection *connection) { - if (InterlockedDecrement( &Connection->ref ) > 0) return RPC_S_OK; + LONG ref = InterlockedIncrement(&connection->ref); + TRACE("%p ref=%u\n", connection, ref); + return connection; +} - TRACE("destroying connection %p\n", Connection); +void RPCRT4_ReleaseConnection(RpcConnection *connection) +{ + LONG ref; - RPCRT4_CloseConnection(Connection); - RPCRT4_strfree(Connection->Endpoint); - RPCRT4_strfree(Connection->NetworkAddr); - HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions); - HeapFree(GetProcessHeap(), 0, Connection->CookieAuth); - if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo); - if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS); + /* protseq stores a list of active connections, but does not own references to them. + * It may need to grab a connection from the list, which could lead to a race if + * connection is being released, but not yet removed from the list. We handle that + * by synchronizing on CS here. */ + if (connection->protseq) + { + EnterCriticalSection(&connection->protseq->cs); + ref = InterlockedDecrement(&connection->ref); + if (!ref) + list_remove(&connection->protseq_entry); + LeaveCriticalSection(&connection->protseq->cs); + } + else + { + ref = InterlockedDecrement(&connection->ref); + } - /* server-only */ - if (Connection->server_binding) RPCRT4_ReleaseBinding(Connection->server_binding); + TRACE("%p ref=%u\n", connection, ref); - if (Connection->protseq) - { - EnterCriticalSection(&Connection->protseq->cs); - list_remove(&Connection->protseq_entry); - LeaveCriticalSection(&Connection->protseq->cs); - } + if (!ref) + { + RPCRT4_CloseConnection(connection); + RPCRT4_strfree(connection->Endpoint); + RPCRT4_strfree(connection->NetworkAddr); + HeapFree(GetProcessHeap(), 0, connection->NetworkOptions); + HeapFree(GetProcessHeap(), 0, connection->CookieAuth); + if (connection->AuthInfo) RpcAuthInfo_Release(connection->AuthInfo); + if (connection->QOS) RpcQualityOfService_Release(connection->QOS); - HeapFree(GetProcessHeap(), 0, Connection); - return RPC_S_OK; + /* server-only */ + if (connection->server_binding) RPCRT4_ReleaseBinding(connection->server_binding); + + if (connection->wait_release) SetEvent(connection->wait_release); + + HeapFree(GetProcessHeap(), 0, connection); + } } RPC_STATUS RPCRT4_IsServerListening(const char *protseq, const char *endpoint) diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index f768530c518..7d49850e640 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -160,7 +160,7 @@ reactos/dll/win32/rasapi32 # Synced to WineStaging-2.9 reactos/dll/win32/resutils # Synced to WineStaging-2.9 reactos/dll/win32/riched20 # Synced to WineStaging-2.16 reactos/dll/win32/riched32 # Synced to WineStaging-2.9 -reactos/dll/win32/rpcrt4 # Synced to WineStaging-2.9 +reactos/dll/win32/rpcrt4 # Synced to WineStaging-2.16 reactos/dll/win32/rsabase # Synced to WineStaging-2.9 reactos/dll/win32/rsaenh # Synced to WineStaging-2.9 reactos/dll/win32/sccbase # Synced to WineStaging-2.9