[RPCRT4] TCP server support (2/2) accept TCP connections
Damjan Jovanovic
damjan.jov at gmail.com
Sun Oct 8 13:20:16 CDT 2006
Adds support for RPC TCP servers using native (as opposed to winsock)
sockets. Probably closes bug 2416.
Is this any better, Robert?
Changelog:
* added support for RPC TCP servers
Damjan Jovanovic
-------------- next part --------------
--- a/AUTHORS 2006-07-10 18:01:06.000000000 +0200
+++ b/AUTHORS 2006-10-08 11:34:59.000000000 +0200
@@ -873,3 +873,4 @@
Rizsanyi Zsolt
Per ??ngstr??m
Peter ??strand
+Damjan Jovanovic
--- a/dlls/rpcrt4/rpc_transport.c 2006-10-01 09:29:06.000000000 +0200
+++ b/dlls/rpcrt4/rpc_transport.c 2006-10-08 11:01:59.000000000 +0200
@@ -441,13 +441,56 @@
{
RpcConnection common;
int sock;
+ HANDLE onEventAvailable;
+ HANDLE onEventHandled;
+ BOOL quit;
} RpcConnection_tcp;
+static DWORD WINAPI rpcrt4_tcp_poll_thread(LPVOID arg)
+{
+ RpcConnection_tcp *tcpc;
+ int ret;
+ fd_set readableSet;
+ struct timeval timeout;
+
+ tcpc = (RpcConnection_tcp*) arg;
+
+ while (!tcpc->quit)
+ {
+ FD_ZERO(&readableSet);
+ FD_SET(tcpc->sock, &readableSet);
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+ ret = select(tcpc->sock + 1, &readableSet, NULL, NULL, &timeout);
+ if (ret < 0)
+ ERR("select failed with error %d\n", ret);
+ else
+ {
+ if (FD_ISSET(tcpc->sock, &readableSet))
+ {
+ SetEvent(tcpc->onEventAvailable);
+ WaitForSingleObject(tcpc->onEventHandled, INFINITE);
+ ResetEvent(tcpc->onEventHandled);
+ }
+ }
+ }
+
+ /* This avoids the tcpc being destroyed before we are done with it */
+ SetEvent(tcpc->onEventAvailable);
+
+ return 0;
+}
+
static RpcConnection *rpcrt4_conn_tcp_alloc(void)
{
RpcConnection_tcp *tcpc;
tcpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection_tcp));
+ if (tcpc == NULL)
+ return NULL;
tcpc->sock = -1;
+ tcpc->onEventAvailable = NULL;
+ tcpc->onEventHandled = NULL;
+ tcpc->quit = FALSE;
return &tcpc->common;
}
@@ -462,12 +505,6 @@
TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
- if (Connection->server)
- {
- ERR("ncacn_ip_tcp servers not supported yet\n");
- return RPC_S_SERVER_UNAVAILABLE;
- }
-
if (tcpc->sock != -1)
return RPC_S_OK;
@@ -506,14 +543,80 @@
continue;
}
- if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
+ if (Connection->server)
{
- WARN("connect() failed\n");
- close(sock);
- continue;
+ HANDLE thread = NULL;
+ ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
+ if (ret < 0)
+ {
+ WARN("bind failed, error %d\n", ret);
+ goto done;
+ }
+ ret = listen(sock, 10);
+ if (ret < 0)
+ {
+ WARN("listen failed, error %d\n", ret);
+ goto done;
+ }
+ /* need a non-blocking socket, otherwise accept() has a potential
+ * race-condition (select() says it is readable, connection drops,
+ * and accept() blocks until the next connection comes...)
+ */
+ ret = fcntl(sock, F_GETFL, 0);
+ ret = fcntl(sock, F_SETFL, ret | O_NONBLOCK);
+ if (ret < 0)
+ {
+ WARN("couldn't make socket non-blocking, error %d\n", ret);
+ goto done;
+ }
+ tcpc->onEventAvailable = CreateEventW(NULL, TRUE, FALSE, NULL);
+ if (tcpc->onEventAvailable == NULL)
+ {
+ WARN("creating available event failed, error %lu\n", GetLastError());
+ goto done;
+ }
+ tcpc->onEventHandled = CreateEventW(NULL, TRUE, FALSE, NULL);
+ if (tcpc->onEventHandled == NULL)
+ {
+ WARN("creating handled event failed, error %lu\n", GetLastError());
+ goto done;
+ }
+ tcpc->sock = sock;
+ thread = CreateThread(NULL, 0, rpcrt4_tcp_poll_thread, tcpc, 0, NULL);
+ if (thread == NULL)
+ {
+ WARN("creating server polling thread failed, error %lu\n",
+ GetLastError());
+ tcpc->sock = -1;
+ }
+
+ done:
+ if (thread == NULL) /* ie. we failed somewhere */
+ {
+ close(sock);
+ if (tcpc->onEventAvailable != NULL)
+ {
+ CloseHandle(tcpc->onEventAvailable);
+ tcpc->onEventAvailable = NULL;
+ }
+ if (tcpc->onEventHandled != NULL)
+ {
+ CloseHandle(tcpc->onEventHandled);
+ tcpc->onEventHandled = NULL;
+ }
+ continue;
+ }
+ }
+ else /* it's a client */
+ {
+ if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
+ {
+ WARN("connect() failed\n");
+ close(sock);
+ continue;
+ }
+ tcpc->sock = sock;
}
-
- tcpc->sock = sock;
freeaddrinfo(ai);
TRACE("connected\n");
@@ -527,14 +630,30 @@
static HANDLE rpcrt4_conn_tcp_get_wait_handle(RpcConnection *Connection)
{
- assert(0);
- return 0;
+ RpcConnection_tcp *tcpc = (RpcConnection_tcp*) Connection;
+ return tcpc->onEventAvailable;
}
static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
{
- assert(0);
- return RPC_S_SERVER_UNAVAILABLE;
+ int ret;
+ struct sockaddr_in address;
+ socklen_t addrsize;
+ RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
+ RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
+
+ addrsize = sizeof(address);
+ ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
+ ResetEvent(server->onEventAvailable);
+ SetEvent(server->onEventHandled);
+ if (ret < 0)
+ {
+ ERR("Failed to accept a TCP connection: error %d\n", ret);
+ return RPC_S_SERVER_UNAVAILABLE;
+ }
+ client->sock = ret;
+ TRACE("Accepted a new TCP connection\n");
+ return RPC_S_OK;
}
static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
@@ -560,6 +679,16 @@
RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
TRACE("%d\n", tcpc->sock);
+
+ if (tcpc->onEventAvailable != NULL)
+ {
+ /* it's a server connection */
+ tcpc->quit = TRUE;
+ WaitForSingleObject(tcpc->onEventAvailable, INFINITE);
+ CloseHandle(tcpc->onEventAvailable);
+ CloseHandle(tcpc->onEventHandled);
+ }
+
if (tcpc->sock != -1)
close(tcpc->sock);
tcpc->sock = -1;
More information about the wine-patches
mailing list