Rob Shearman : rpcrt4: Implement asynchronous RPC support.
Alexandre Julliard
julliard at winehq.org
Mon Jan 21 05:59:05 CST 2008
Module: wine
Branch: master
Commit: 5f077bab07ba5cd7eebe7aeba48c6a570f39da4a
URL: http://source.winehq.org/git/wine.git/?a=commit;h=5f077bab07ba5cd7eebe7aeba48c6a570f39da4a
Author: Rob Shearman <rob at codeweavers.com>
Date: Mon Jan 21 10:31:40 2008 +0000
rpcrt4: Implement asynchronous RPC support.
---
dlls/rpcrt4/Makefile.in | 2 +-
dlls/rpcrt4/rpc_binding.h | 2 +
dlls/rpcrt4/rpc_message.c | 63 +++++++++++++++++++++++++++++++++++++++++-
dlls/rpcrt4/rpc_transport.c | 36 ++++++++++++++++++++++++
4 files changed, 100 insertions(+), 3 deletions(-)
diff --git a/dlls/rpcrt4/Makefile.in b/dlls/rpcrt4/Makefile.in
index 5cb090b..9fe0026 100644
--- a/dlls/rpcrt4/Makefile.in
+++ b/dlls/rpcrt4/Makefile.in
@@ -6,7 +6,7 @@ VPATH = @srcdir@
MODULE = rpcrt4.dll
IMPORTLIB = librpcrt4.$(IMPLIBEXT)
IMPORTS = iphlpapi advapi32 kernel32 ntdll
-DELAYIMPORTS = secur32
+DELAYIMPORTS = secur32 user32
EXTRALIBS = -luuid
C_SRCS = \
diff --git a/dlls/rpcrt4/rpc_binding.h b/dlls/rpcrt4/rpc_binding.h
index ed8d4ea..e3a3c95 100644
--- a/dlls/rpcrt4/rpc_binding.h
+++ b/dlls/rpcrt4/rpc_binding.h
@@ -73,6 +73,7 @@ typedef struct _RpcConnection
/* client-only */
struct list conn_pool_entry;
ULONG assoc_group_id; /* association group returned during binding */
+ RPC_ASYNC_STATE *async_state;
/* server-only */
/* The active interface bound to server. */
@@ -92,6 +93,7 @@ struct connection_ops {
int (*write)(RpcConnection *conn, const void *buffer, unsigned int len);
int (*close)(RpcConnection *conn);
void (*cancel_call)(RpcConnection *conn);
+ int (*wait_for_incoming_data)(RpcConnection *conn);
size_t (*get_top_of_tower)(unsigned char *tower_data, const char *networkaddr, const char *endpoint);
RPC_STATUS (*parse_top_of_tower)(const unsigned char *tower_data, size_t tower_size, char **networkaddr, char **endpoint);
};
diff --git a/dlls/rpcrt4/rpc_message.c b/dlls/rpcrt4/rpc_message.c
index 07af1fc..ff1a808 100644
--- a/dlls/rpcrt4/rpc_message.c
+++ b/dlls/rpcrt4/rpc_message.c
@@ -27,6 +27,7 @@
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
+#include "winuser.h"
#include "rpc.h"
#include "rpcndr.h"
@@ -1039,6 +1040,49 @@ RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg)
return RPC_S_OK;
}
+static void CALLBACK async_apc_notifier_proc(ULONG_PTR ulParam)
+{
+ RPC_ASYNC_STATE *state = (RPC_ASYNC_STATE *)ulParam;
+ state->u.APC.NotificationRoutine(state, NULL, state->Event);
+}
+
+static DWORD WINAPI async_notifier_proc(LPVOID p)
+{
+ RpcConnection *conn = p;
+ RPC_ASYNC_STATE *state = conn->async_state;
+
+ if (state && !conn->ops->wait_for_incoming_data(conn))
+ {
+ state->Event = RpcCallComplete;
+ switch (state->NotificationType)
+ {
+ case RpcNotificationTypeEvent:
+ SetEvent(state->u.hEvent);
+ break;
+ case RpcNotificationTypeApc:
+ QueueUserAPC(async_apc_notifier_proc, state->u.APC.hThread, (ULONG_PTR)state);
+ break;
+ case RpcNotificationTypeIoc:
+ PostQueuedCompletionStatus(state->u.IOC.hIOPort,
+ state->u.IOC.dwNumberOfBytesTransferred,
+ state->u.IOC.dwCompletionKey,
+ state->u.IOC.lpOverlapped);
+ break;
+ case RpcNotificationTypeHwnd:
+ PostMessageW(state->u.HWND.hWnd, state->u.HWND.Msg, 0, 0);
+ break;
+ case RpcNotificationTypeCallback:
+ state->u.NotificationRoutine(state, NULL, state->Event);
+ break;
+ case RpcNotificationTypeNone:
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
/***********************************************************************
* I_RpcSend [RPCRT4.@]
*
@@ -1080,6 +1124,12 @@ RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg)
RPCRT4_FreeHeader(hdr);
+ if (status == RPC_S_OK && pMsg->RpcFlags & RPC_BUFFER_ASYNC)
+ {
+ if (!QueueUserWorkItem(async_notifier_proc, conn, WT_EXECUTEDEFAULT | WT_EXECUTELONGFUNCTION))
+ status = RPC_S_OUT_OF_RESOURCES;
+ }
+
return status;
}
@@ -1198,8 +1248,17 @@ RPC_STATUS WINAPI I_RpcSendReceive(PRPC_MESSAGE pMsg)
*/
RPC_STATUS WINAPI I_RpcAsyncSetHandle(PRPC_MESSAGE pMsg, PRPC_ASYNC_STATE pAsync)
{
- FIXME("(%p, %p): stub\n", pMsg, pAsync);
- return RPC_S_INVALID_BINDING;
+ RpcBinding* bind = (RpcBinding*)pMsg->Handle;
+ RpcConnection *conn;
+
+ TRACE("(%p, %p)\n", pMsg, pAsync);
+
+ if (!bind || bind->server || !pMsg->ReservedForRuntime) return RPC_S_INVALID_BINDING;
+
+ conn = pMsg->ReservedForRuntime;
+ conn->async_state = pAsync;
+
+ return RPC_S_OK;
}
/***********************************************************************
diff --git a/dlls/rpcrt4/rpc_transport.c b/dlls/rpcrt4/rpc_transport.c
index eb6bd8d..e3fd8c1 100644
--- a/dlls/rpcrt4/rpc_transport.c
+++ b/dlls/rpcrt4/rpc_transport.c
@@ -410,6 +410,12 @@ static void rpcrt4_conn_np_cancel_call(RpcConnection *Connection)
/* FIXME: implement when named pipe writes use overlapped I/O */
}
+static int rpcrt4_conn_np_wait_for_incoming_data(RpcConnection *Connection)
+{
+ /* FIXME: implement when named pipe writes use overlapped I/O */
+ return -1;
+}
+
static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
const char *networkaddr,
const char *endpoint)
@@ -1047,6 +1053,32 @@ static void rpcrt4_conn_tcp_cancel_call(RpcConnection *Connection)
write(tcpc->cancel_fds[1], &dummy, 1);
}
+static int rpcrt4_conn_tcp_wait_for_incoming_data(RpcConnection *Connection)
+{
+ RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
+ struct pollfd pfds[2];
+
+ TRACE("%p\n", Connection);
+
+ pfds[0].fd = tcpc->sock;
+ pfds[0].events = POLLIN;
+ pfds[1].fd = tcpc->cancel_fds[0];
+ pfds[1].events = POLLIN;
+ if (poll(pfds, 2, -1 /* infinite */) == -1 && errno != EINTR)
+ {
+ ERR("poll() failed: %s\n", strerror(errno));
+ return -1;
+ }
+ if (pfds[1].revents & POLLIN) /* canceled */
+ {
+ char dummy;
+ read(pfds[1].fd, &dummy, sizeof(dummy));
+ return -1;
+ }
+
+ return 0;
+}
+
static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
const char *networkaddr,
const char *endpoint)
@@ -1330,6 +1362,7 @@ static const struct connection_ops conn_protseq_list[] = {
rpcrt4_conn_np_write,
rpcrt4_conn_np_close,
rpcrt4_conn_np_cancel_call,
+ rpcrt4_conn_np_wait_for_incoming_data,
rpcrt4_ncacn_np_get_top_of_tower,
rpcrt4_ncacn_np_parse_top_of_tower,
},
@@ -1342,6 +1375,7 @@ static const struct connection_ops conn_protseq_list[] = {
rpcrt4_conn_np_write,
rpcrt4_conn_np_close,
rpcrt4_conn_np_cancel_call,
+ rpcrt4_conn_np_wait_for_incoming_data,
rpcrt4_ncalrpc_get_top_of_tower,
rpcrt4_ncalrpc_parse_top_of_tower,
},
@@ -1354,6 +1388,7 @@ static const struct connection_ops conn_protseq_list[] = {
rpcrt4_conn_tcp_write,
rpcrt4_conn_tcp_close,
rpcrt4_conn_tcp_cancel_call,
+ rpcrt4_conn_tcp_wait_for_incoming_data,
rpcrt4_ncacn_ip_tcp_get_top_of_tower,
rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
}
@@ -1470,6 +1505,7 @@ RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
NewConnection->QOS = QOS;
list_init(&NewConnection->conn_pool_entry);
+ NewConnection->async_state = NULL;
TRACE("connection: %p\n", NewConnection);
*Connection = NewConnection;
More information about the wine-cvs
mailing list