Damjan Jovanovic : rpcrt4: Added support for RPC TCP servers.
Alexandre Julliard
julliard at wine.codeweavers.com
Fri Oct 20 08:00:39 CDT 2006
Module: wine
Branch: master
Commit: 48ca62185b6606401a427db3a0ab4e718582dc76
URL: http://source.winehq.org/git/wine.git/?a=commit;h=48ca62185b6606401a427db3a0ab4e718582dc76
Author: Damjan Jovanovic <damjan.jov at gmail.com>
Date: Wed Oct 18 18:14:11 2006 +0200
rpcrt4: Added support for RPC TCP servers.
---
dlls/rpcrt4/rpc_transport.c | 164 ++++++++++++++++++++++++++++++++++++++-----
1 files changed, 146 insertions(+), 18 deletions(-)
diff --git a/dlls/rpcrt4/rpc_transport.c b/dlls/rpcrt4/rpc_transport.c
index 0f11bfa..f9bd4b4 100644
--- a/dlls/rpcrt4/rpc_transport.c
+++ b/dlls/rpcrt4/rpc_transport.c
@@ -5,6 +5,7 @@
* Copyright 2003 Mike Hearn
* Copyright 2004 Filip Navara
* Copyright 2006 Mike McCormack
+ * Copyright 2006 Damjan Jovanovic
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -48,6 +49,9 @@ #endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
#include "windef.h"
#include "winbase.h"
@@ -448,14 +452,52 @@ typedef struct _RpcConnection_tcp
{
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;
+ struct pollfd pollInfo;
+
+ tcpc = (RpcConnection_tcp*) arg;
+ pollInfo.fd = tcpc->sock;
+ pollInfo.events = POLLIN;
+
+ while (!tcpc->quit)
+ {
+ ret = poll(&pollInfo, 1, 1000);
+ if (ret < 0)
+ ERR("poll failed with error %d\n", ret);
+ else
+ {
+ if (pollInfo.revents & POLLIN)
+ {
+ SignalObjectAndWait(tcpc->onEventAvailable,
+ tcpc->onEventHandled, INFINITE, FALSE);
+ }
+ }
+ }
+
+ /* 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(), 0, sizeof(RpcConnection_tcp));
- if (tcpc)
- tcpc->sock = -1;
+ if (tcpc == NULL)
+ return NULL;
+ tcpc->sock = -1;
+ tcpc->onEventAvailable = NULL;
+ tcpc->onEventHandled = NULL;
+ tcpc->quit = FALSE;
return &tcpc->common;
}
@@ -470,12 +512,6 @@ static RPC_STATUS rpcrt4_ncacn_ip_tcp_op
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;
@@ -514,14 +550,81 @@ static RPC_STATUS rpcrt4_ncacn_ip_tcp_op
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 (poll() says it is readable, connection drops,
+ * and accept() blocks until the next connection comes...)
+ */
+ ret = fcntl(sock, F_SETFL, O_NONBLOCK);
+ if (ret < 0)
+ {
+ WARN("couldn't make socket non-blocking, error %d\n", ret);
+ goto done;
+ }
+ tcpc->onEventAvailable = CreateEventW(NULL, FALSE, FALSE, NULL);
+ if (tcpc->onEventAvailable == NULL)
+ {
+ WARN("creating available event failed, error %lu\n", GetLastError());
+ goto done;
+ }
+ tcpc->onEventHandled = CreateEventW(NULL, FALSE, 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;
+ goto done;
+ }
+ CloseHandle(thread);
+
+ 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");
@@ -535,14 +638,29 @@ static RPC_STATUS rpcrt4_ncacn_ip_tcp_op
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);
+ 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,
@@ -568,6 +686,16 @@ static int rpcrt4_conn_tcp_close(RpcConn
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-cvs
mailing list