[RPCRT4] Sync with Wine Staging 2.16. CORE-13762

2d9e894 rpcrt4: Always protect ref access for connections associated with protseq in RPCRT4_ReleaseConnection.
aea6d23 rpcrt4: Mark function that are only called from assembly as hidden.
bea5c0c rpcrt4: Spelling fixes in comments.
2cb32b2 rpcrt4: Change RPCRT4_ReleaseConnection return type to void.
e889b02 rpcrt4: Fix a race when server grabs a connection from the list of active connections.
09e98be rpcrt4: Wait for server threads to finish in RpcMgmtWaitServerListen.
e98c7a5 rpcrt4: Wait for all active connections to be released before quiting server thread.
10a6b33 rpcrt4: Recreate listening pipe in rpcrt4_protseq_np_get_wait_array if needed.
5c2083f rpcrt4: Store listening pipe name in RpcConnection_np.
5c81f82 rpcrt4: Store server thread handle in RpcServerProtseq.

svn path=/trunk/; revision=75898
This commit is contained in:
Amine Khaldi 2017-09-17 22:57:32 +00:00
parent c615faa665
commit 0ee2ebaf78
8 changed files with 160 additions and 93 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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)

View file

@ -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;

View file

@ -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;

View file

@ -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 */

View file

@ -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)

View file

@ -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