Jacek Caban : rpcrt4: Use non-blocking listening on named pipes.
Alexandre Julliard
julliard at winehq.org
Mon May 22 15:54:04 CDT 2017
Module: wine
Branch: master
Commit: 6e7a2978e7e1be40dc0e05f307dbefac3bbfaf24
URL: http://source.winehq.org/git/wine.git/?a=commit;h=6e7a2978e7e1be40dc0e05f307dbefac3bbfaf24
Author: Jacek Caban <jacek at codeweavers.com>
Date: Mon May 22 16:04:31 2017 +0200
rpcrt4: Use non-blocking listening on named pipes.
Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/rpcrt4/rpc_transport.c | 139 ++++++++++++++++++++------------------------
1 file changed, 62 insertions(+), 77 deletions(-)
diff --git a/dlls/rpcrt4/rpc_transport.c b/dlls/rpcrt4/rpc_transport.c
index 98fa597..afcb0e7 100644
--- a/dlls/rpcrt4/rpc_transport.c
+++ b/dlls/rpcrt4/rpc_transport.c
@@ -38,6 +38,7 @@
#include "winerror.h"
#include "wininet.h"
#include "winternl.h"
+#include "winioctl.h"
#include "wine/unicode.h"
#include "rpc.h"
@@ -63,10 +64,10 @@ static RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnecti
typedef struct _RpcConnection_np
{
- RpcConnection common;
- HANDLE pipe;
- HANDLE listen_thread;
- BOOL listening;
+ RpcConnection common;
+ HANDLE pipe;
+ HANDLE listen_event;
+ IO_STATUS_BLOCK io_status;
} RpcConnection_np;
static RpcConnection *rpcrt4_conn_np_alloc(void)
@@ -85,49 +86,6 @@ static void release_np_event(HANDLE event)
CloseHandle(event);
}
-static DWORD CALLBACK listen_thread(void *arg)
-{
- RpcConnection_np *npc = arg;
- for (;;)
- {
- if (ConnectNamedPipe(npc->pipe, NULL))
- return RPC_S_OK;
-
- switch(GetLastError())
- {
- case ERROR_PIPE_CONNECTED:
- return RPC_S_OK;
- case ERROR_HANDLES_CLOSED:
- /* connection closed during listen */
- return RPC_S_NO_CONTEXT_AVAILABLE;
- case ERROR_NO_DATA_DETECTED:
- /* client has disconnected, retry */
- DisconnectNamedPipe( npc->pipe );
- break;
- default:
- npc->listening = FALSE;
- WARN("Couldn't ConnectNamedPipe (error was %d)\n", GetLastError());
- return RPC_S_OUT_OF_RESOURCES;
- }
- }
-}
-
-static RPC_STATUS rpcrt4_conn_listen_pipe(RpcConnection_np *npc)
-{
- if (npc->listening)
- return RPC_S_OK;
-
- npc->listening = TRUE;
- npc->listen_thread = CreateThread(NULL, 0, listen_thread, npc, 0, NULL);
- if (!npc->listen_thread)
- {
- npc->listening = FALSE;
- ERR("Couldn't create listen thread (error was %d)\n", GetLastError());
- return RPC_S_OUT_OF_RESOURCES;
- }
- return RPC_S_OK;
-}
-
static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *Connection, LPCSTR pname)
{
RpcConnection_np *npc = (RpcConnection_np *) Connection;
@@ -333,14 +291,12 @@ static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protse
static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc)
{
- /* because of the way named pipes work, we'll transfer the connected pipe
- * to the child, then reopen the server binding to continue listening */
+ /* because of the way named pipes work, we'll transfer the connected pipe
+ * to the child, then reopen the server binding to continue listening */
- new_npc->pipe = old_npc->pipe;
- new_npc->listen_thread = old_npc->listen_thread;
- old_npc->pipe = 0;
- old_npc->listen_thread = 0;
- old_npc->listening = FALSE;
+ new_npc->pipe = old_npc->pipe;
+ old_npc->pipe = 0;
+ assert(!old_npc->listen_event);
}
static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
@@ -465,19 +421,21 @@ static int rpcrt4_conn_np_write(RpcConnection *conn, const void *buffer, unsigne
return count;
}
-static int rpcrt4_conn_np_close(RpcConnection *Connection)
+static int rpcrt4_conn_np_close(RpcConnection *conn)
{
- RpcConnection_np *npc = (RpcConnection_np *) Connection;
- if (npc->pipe) {
- FlushFileBuffers(npc->pipe);
- CloseHandle(npc->pipe);
- npc->pipe = 0;
- }
- if (npc->listen_thread) {
- CloseHandle(npc->listen_thread);
- npc->listen_thread = 0;
- }
- return 0;
+ RpcConnection_np *connection = (RpcConnection_np *) conn;
+ if (connection->pipe)
+ {
+ FlushFileBuffers(connection->pipe);
+ CloseHandle(connection->pipe);
+ connection->pipe = 0;
+ }
+ if (connection->listen_event)
+ {
+ CloseHandle(connection->listen_event);
+ connection->listen_event = 0;
+ }
+ return 0;
}
static void rpcrt4_conn_np_cancel_call(RpcConnection *Connection)
@@ -677,9 +635,33 @@ static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *p
/* open and count connections */
*count = 1;
LIST_FOR_EACH_ENTRY(conn, &protseq->connections, RpcConnection_np, common.protseq_entry) {
- rpcrt4_conn_listen_pipe(conn);
- if (conn->listen_thread)
- (*count)++;
+ if (!conn->listen_event)
+ {
+ NTSTATUS status;
+ HANDLE event;
+
+ event = get_np_event();
+ if (!event)
+ continue;
+
+ status = NtFsControlFile(conn->pipe, event, NULL, NULL, &conn->io_status, FSCTL_PIPE_LISTEN, NULL, 0, NULL, 0);
+ switch (status)
+ {
+ case STATUS_SUCCESS:
+ case STATUS_PIPE_CONNECTED:
+ conn->io_status.Status = status;
+ SetEvent(event);
+ break;
+ case STATUS_PENDING:
+ break;
+ default:
+ ERR("pipe listen error %x\n", status);
+ continue;
+ }
+
+ conn->listen_event = event;
+ }
+ (*count)++;
}
/* make array of connections */
@@ -697,8 +679,8 @@ static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *p
objs[0] = npps->mgr_event;
*count = 1;
LIST_FOR_EACH_ENTRY(conn, &protseq->connections, RpcConnection_np, common.protseq_entry) {
- if ((objs[*count] = conn->listen_thread))
- (*count)++;
+ if (conn->listen_event)
+ objs[(*count)++] = conn->listen_event;
}
LeaveCriticalSection(&protseq->cs);
return objs;
@@ -741,13 +723,16 @@ static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq,
b_handle = objs[res - WAIT_OBJECT_0];
/* find which connection got a RPC */
EnterCriticalSection(&protseq->cs);
- LIST_FOR_EACH_ENTRY(conn, &protseq->connections, RpcConnection_np, common.protseq_entry) {
- if (b_handle == conn->listen_thread) {
- DWORD exit_code;
- if (GetExitCodeThread(conn->listen_thread, &exit_code) && exit_code == RPC_S_OK)
+ LIST_FOR_EACH_ENTRY(conn, &protseq->connections, RpcConnection_np, common.protseq_entry)
+ {
+ if (b_handle == conn->listen_event)
+ {
+ release_np_event(conn->listen_event);
+ conn->listen_event = NULL;
+ if (conn->io_status.Status == STATUS_SUCCESS || conn->io_status.Status == STATUS_PIPE_CONNECTED)
RPCRT4_SpawnConnection(&cconn, &conn->common);
- CloseHandle(conn->listen_thread);
- conn->listen_thread = 0;
+ else
+ ERR("listen failed %x\n", conn->io_status.Status);
break;
}
}
More information about the wine-cvs
mailing list