rpcrt4: Add a Win32 implementation of ncacn_ip_tcp transport.

This commit is contained in:
Rob Shearman 2009-04-08 12:55:38 +01:00 committed by Alexandre Julliard
parent 06c2982a39
commit 324b4d0243
1 changed files with 204 additions and 14 deletions

View File

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