Module: wine Branch: master Commit: 324b4d0243c6fbcd4a8e7cd95d00a610180cb0cb URL: http://source.winehq.org/git/wine.git/?a=commit;h=324b4d0243c6fbcd4a8e7cd95d...
Author: Rob Shearman robertshearman@gmail.com Date: Wed Apr 8 12:55:38 2009 +0100
rpcrt4: Add a Win32 implementation of ncacn_ip_tcp transport.
---
dlls/rpcrt4/rpc_transport.c | 218 ++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 204 insertions(+), 14 deletions(-)
diff --git a/dlls/rpcrt4/rpc_transport.c b/dlls/rpcrt4/rpc_transport.c index 98602d2..390a7d4 100644 --- a/dlls/rpcrt4/rpc_transport.c +++ b/dlls/rpcrt4/rpc_transport.c @@ -912,7 +912,12 @@ typedef struct _RpcConnection_tcp { RpcConnection common; int sock; +#ifdef HAVE_SOCKETPAIR int cancel_fds[2]; +#else + HANDLE sock_event; + HANDLE cancel_event; +#endif } RpcConnection_tcp;
#ifdef HAVE_SOCKETPAIR @@ -978,30 +983,78 @@ static void rpcrt4_sock_wait_destroy(RpcConnection_tcp *tcpc)
static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc) { - /* FIXME */ - return FALSE; + static BOOL wsa_inited; + if (!wsa_inited) + { + WSADATA wsadata; + WSAStartup(MAKEWORD(2, 2), &wsadata); + /* Note: WSAStartup can be called more than once so we don't bother with + * making accesses to wsa_inited thread-safe */ + wsa_inited = TRUE; + } + tcpc->sock_event = CreateEventW(NULL, FALSE, FALSE, NULL); + tcpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!tcpc->sock_event || !tcpc->cancel_event) + { + ERR("event creation failed\n"); + if (tcpc->sock_event) CloseHandle(tcpc->sock_event); + return FALSE; + } + return TRUE; }
static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc) { - /* FIXME */ - return FALSE; + HANDLE wait_handles[2]; + DWORD res; + if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_READ | FD_CLOSE) == SOCKET_ERROR) + { + ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError()); + return FALSE; + } + wait_handles[0] = tcpc->sock_event; + wait_handles[1] = tcpc->cancel_event; + res = WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE); + switch (res) + { + case WAIT_OBJECT_0: + return TRUE; + case WAIT_OBJECT_0 + 1: + return FALSE; + default: + ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError()); + return FALSE; + } }
static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc) { - /* FIXME */ - return FALSE; + DWORD res; + if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_WRITE | FD_CLOSE) == SOCKET_ERROR) + { + ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError()); + return FALSE; + } + res = WaitForSingleObject(tcpc->sock_event, INFINITE); + switch (res) + { + case WAIT_OBJECT_0: + return TRUE; + default: + ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError()); + return FALSE; + } }
static void rpcrt4_sock_wait_cancel(RpcConnection_tcp *tcpc) { - /* FIXME */ + SetEvent(tcpc->cancel_event); }
static void rpcrt4_sock_wait_destroy(RpcConnection_tcp *tcpc) { - /* FIXME */ + CloseHandle(tcpc->sock_event); + CloseHandle(tcpc->cancel_event); }
#endif @@ -1105,8 +1158,6 @@ static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection) return RPC_S_SERVER_UNAVAILABLE; }
-#ifdef HAVE_SOCKETPAIR - static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, const char *endpoint) { RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT; @@ -1266,8 +1317,6 @@ static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *pr return status; }
-#endif - static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn) { int ret; @@ -1520,6 +1569,149 @@ static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq return 1; }
+#else /* HAVE_SOCKETPAIR */ + +typedef struct _RpcServerProtseq_sock +{ + RpcServerProtseq common; + HANDLE mgr_event; +} RpcServerProtseq_sock; + +static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void) +{ + RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps)); + if (ps) + { + static BOOL wsa_inited; + if (!wsa_inited) + { + WSADATA wsadata; + WSAStartup(MAKEWORD(2, 2), &wsadata); + /* Note: WSAStartup can be called more than once so we don't bother with + * making accesses to wsa_inited thread-safe */ + wsa_inited = TRUE; + } + ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL); + } + return &ps->common; +} + +static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq) +{ + RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common); + SetEvent(sockps->mgr_event); +} + +static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count) +{ + HANDLE *objs = prev_array; + RpcConnection_tcp *conn; + RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common); + + EnterCriticalSection(&protseq->cs); + + /* open and count connections */ + *count = 1; + conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common); + while (conn) + { + if (conn->sock != -1) + (*count)++; + conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common); + } + + /* make array of connections */ + if (objs) + objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE)); + else + objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE)); + if (!objs) + { + ERR("couldn't allocate objs\n"); + LeaveCriticalSection(&protseq->cs); + return NULL; + } + + objs[0] = sockps->mgr_event; + *count = 1; + conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common); + while (conn) + { + if (conn->sock != -1) + { + int res = WSAEventSelect(conn->sock, conn->sock_event, FD_ACCEPT); + if (res == SOCKET_ERROR) + ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError()); + else + { + objs[*count] = conn->sock_event; + (*count)++; + } + } + conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common); + } + LeaveCriticalSection(&protseq->cs); + return objs; +} + +static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array) +{ + HeapFree(GetProcessHeap(), 0, array); +} + +static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array) +{ + HANDLE b_handle; + HANDLE *objs = wait_array; + DWORD res; + RpcConnection *cconn; + RpcConnection_tcp *conn; + + if (!objs) + return -1; + + do + { + /* an alertable wait isn't strictly necessary, but due to our + * overlapped I/O implementation in Wine we need to free some memory + * by the file user APC being called, even if no completion routine was + * specified at the time of starting the async operation */ + res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE); + } while (res == WAIT_IO_COMPLETION); + + if (res == WAIT_OBJECT_0) + return 0; + else if (res == WAIT_FAILED) + { + ERR("wait failed with error %d\n", GetLastError()); + return -1; + } + else + { + b_handle = objs[res - WAIT_OBJECT_0]; + /* find which connection got a RPC */ + EnterCriticalSection(&protseq->cs); + conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common); + while (conn) + { + if (b_handle == conn->sock_event) break; + conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common); + } + cconn = NULL; + if (conn) + RPCRT4_SpawnConnection(&cconn, &conn->common); + else + ERR("failed to locate connection for handle %p\n", b_handle); + LeaveCriticalSection(&protseq->cs); + if (cconn) + { + RPCRT4_new_client(cconn); + return 1; + } + else return -1; + } +} + #endif /* HAVE_SOCKETPAIR */
static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data, @@ -2551,7 +2743,6 @@ static const struct protseq_ops protseq_list[] = rpcrt4_protseq_np_wait_for_new_connection, rpcrt4_protseq_ncalrpc_open_endpoint, }, -#ifdef HAVE_SOCKETPAIR { "ncacn_ip_tcp", rpcrt4_protseq_sock_alloc, @@ -2561,7 +2752,6 @@ static const struct protseq_ops protseq_list[] = rpcrt4_protseq_sock_wait_for_new_connection, rpcrt4_protseq_ncacn_ip_tcp_open_endpoint, }, -#endif };
#define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))