For better concurrency, separate the connections from the bindings.

This commit is contained in:
Ove Kaaven 2003-02-19 03:44:35 +00:00 committed by Alexandre Julliard
parent 586808fdf2
commit def211c4c9
5 changed files with 581 additions and 330 deletions

View File

@ -93,13 +93,209 @@ void RPCRT4_strfree(LPSTR src)
if (src) HeapFree(GetProcessHeap(), 0, src);
}
RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPSTR Protseq)
RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions)
{
RpcConnection* NewConnection;
NewConnection = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection));
NewConnection->server = server;
NewConnection->Protseq = RPCRT4_strdupA(Protseq);
NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
TRACE("connection: %p\n", NewConnection);
*Connection = NewConnection;
return RPC_S_OK;
}
RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
{
TRACE("connection: %p\n", Connection);
if (Connection->Used) ERR("connection is still in use\n");
RPCRT4_CloseConnection(Connection);
RPCRT4_strfree(Connection->Endpoint);
RPCRT4_strfree(Connection->NetworkAddr);
RPCRT4_strfree(Connection->Protseq);
HeapFree(GetProcessHeap(), 0, Connection);
return RPC_S_OK;
}
RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection)
{
TRACE("(Connection == ^%p)\n", Connection);
if (!Connection->conn) {
if (Connection->server) { /* server */
/* protseq=ncalrpc: supposed to use NT LPC ports,
* but we'll implement it with named pipes for now */
if (strcmp(Connection->Protseq, "ncalrpc") == 0) {
static LPSTR prefix = "\\\\.\\pipe\\lrpc\\";
LPSTR pname;
pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
strcat(strcpy(pname, prefix), Connection->Endpoint);
TRACE("listening on %s\n", pname);
Connection->conn = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
0, PIPE_UNLIMITED_INSTANCES, 0, 0, 5000, NULL);
HeapFree(GetProcessHeap(), 0, pname);
memset(&Connection->ovl, 0, sizeof(Connection->ovl));
Connection->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
if (!ConnectNamedPipe(Connection->conn, &Connection->ovl)) {
DWORD err = GetLastError();
if (err == ERROR_PIPE_CONNECTED) {
SetEvent(Connection->ovl.hEvent);
return RPC_S_OK;
}
return err;
}
}
/* protseq=ncacn_np: named pipes */
else if (strcmp(Connection->Protseq, "ncacn_np") == 0) {
static LPSTR prefix = "\\\\.";
LPSTR pname;
pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
strcat(strcpy(pname, prefix), Connection->Endpoint);
TRACE("listening on %s\n", pname);
Connection->conn = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
0, PIPE_UNLIMITED_INSTANCES, 0, 0, 5000, NULL);
HeapFree(GetProcessHeap(), 0, pname);
memset(&Connection->ovl, 0, sizeof(Connection->ovl));
Connection->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
if (!ConnectNamedPipe(Connection->conn, &Connection->ovl)) {
DWORD err = GetLastError();
if (err == ERROR_PIPE_CONNECTED) {
SetEvent(Connection->ovl.hEvent);
return RPC_S_OK;
}
return err;
}
}
else {
ERR("protseq %s not supported\n", Connection->Protseq);
return RPC_S_PROTSEQ_NOT_SUPPORTED;
}
}
else { /* client */
/* protseq=ncalrpc: supposed to use NT LPC ports,
* but we'll implement it with named pipes for now */
if (strcmp(Connection->Protseq, "ncalrpc") == 0) {
static LPSTR prefix = "\\\\.\\pipe\\lrpc\\";
LPSTR pname;
HANDLE conn;
DWORD err;
pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
strcat(strcpy(pname, prefix), Connection->Endpoint);
TRACE("connecting to %s\n", pname);
while (TRUE) {
if (WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (conn != INVALID_HANDLE_VALUE) break;
err = GetLastError();
if (err == ERROR_PIPE_BUSY) continue;
TRACE("connection failed, error=%lx\n", err);
HeapFree(GetProcessHeap(), 0, pname);
return err;
} else {
err = GetLastError();
TRACE("connection failed, error=%lx\n", err);
HeapFree(GetProcessHeap(), 0, pname);
return err;
}
}
/* success */
HeapFree(GetProcessHeap(), 0, pname);
memset(&Connection->ovl, 0, sizeof(Connection->ovl));
Connection->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
Connection->conn = conn;
}
/* protseq=ncacn_np: named pipes */
else if (strcmp(Connection->Protseq, "ncacn_np") == 0) {
static LPSTR prefix = "\\\\.";
LPSTR pname;
HANDLE conn;
DWORD err;
pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
strcat(strcpy(pname, prefix), Connection->Endpoint);
TRACE("connecting to %s\n", pname);
conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (conn == INVALID_HANDLE_VALUE) {
err = GetLastError();
/* we don't need to handle ERROR_PIPE_BUSY here,
* the doc says that it is returned to the app */
TRACE("connection failed, error=%lx\n", err);
HeapFree(GetProcessHeap(), 0, pname);
return err;
}
/* success */
HeapFree(GetProcessHeap(), 0, pname);
memset(&Connection->ovl, 0, sizeof(Connection->ovl));
Connection->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
Connection->conn = conn;
} else {
ERR("protseq %s not supported\n", Connection->Protseq);
return RPC_S_PROTSEQ_NOT_SUPPORTED;
}
}
}
return RPC_S_OK;
}
RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
{
TRACE("(Connection == ^%p)\n", Connection);
if (Connection->conn) {
CancelIo(Connection->conn);
CloseHandle(Connection->conn);
Connection->conn = 0;
}
if (Connection->ovl.hEvent) {
CloseHandle(Connection->ovl.hEvent);
Connection->ovl.hEvent = 0;
}
return RPC_S_OK;
}
RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
{
RpcConnection* NewConnection;
RPC_STATUS err = RPCRT4_CreateConnection(&NewConnection, OldConnection->server, OldConnection->Protseq,
OldConnection->NetworkAddr, OldConnection->Endpoint, NULL);
if (err == RPC_S_OK) {
/* because of the way named pipes work, we'll transfer the connected pipe
* to the child, then reopen the server binding to continue listening */
NewConnection->conn = OldConnection->conn;
NewConnection->ovl = OldConnection->ovl;
OldConnection->conn = 0;
memset(&OldConnection->ovl, 0, sizeof(OldConnection->ovl));
*Connection = NewConnection;
RPCRT4_OpenConnection(OldConnection);
}
return err;
}
RPC_STATUS RPCRT4_AllocBinding(RpcBinding** Binding, BOOL server)
{
RpcBinding* NewBinding;
NewBinding = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcBinding));
NewBinding->refs = 1;
NewBinding->server = server;
*Binding = NewBinding;
return RPC_S_OK;
}
RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPSTR Protseq)
{
RpcBinding* NewBinding;
RPCRT4_AllocBinding(&NewBinding, server);
NewBinding->Protseq = RPCRT4_strdupA(Protseq);
TRACE("binding: %p\n", NewBinding);
@ -111,16 +307,8 @@ RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPSTR Protse
RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPWSTR Protseq)
{
RpcBinding* NewBinding;
if (Binding)
TRACE("(*Binding == ^%p, server == %s, Protseq == \"%s\")\n", *Binding, server ? "Yes" : "No", debugstr_w(Protseq));
else {
ERR("!RpcBinding?\n");
assert(FALSE); /* we will crash below anyhow... */
}
NewBinding = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcBinding));
NewBinding->refs = 1;
NewBinding->server = server;
RPCRT4_AllocBinding(&NewBinding, server);
NewBinding->Protseq = RPCRT4_strdupWtoA(Protseq);
TRACE("binding: %p\n", NewBinding);
@ -131,8 +319,8 @@ RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPWSTR Prots
RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions)
{
TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding, NetworkAddr, Endpoint, NetworkOptions);
TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding,
debugstr_a(NetworkAddr), debugstr_a(Endpoint), debugstr_a(NetworkOptions));
RPCRT4_strfree(Binding->NetworkAddr);
Binding->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
@ -183,31 +371,19 @@ RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, UUID* ObjectUuid)
return RPC_S_OK;
}
RPC_STATUS RPCRT4_SpawnBinding(RpcBinding** Binding, RpcBinding* OldBinding)
RPC_STATUS RPCRT4_MakeBinding(RpcBinding** Binding, RpcConnection* Connection)
{
RpcBinding* NewBinding;
if (Binding)
TRACE("(*RpcBinding == ^%p, OldBinding == ^%p)\n", *Binding, OldBinding);
else {
ERR("!RpcBinding?");
/* we will crash below anyhow... */
*((char *)0) = 0;
}
TRACE("(*RpcBinding == ^%p, Connection == ^%p)\n", *Binding, Connection);
NewBinding = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcBinding));
NewBinding->refs = 1;
NewBinding->server = OldBinding->server;
NewBinding->Protseq = RPCRT4_strdupA(OldBinding->Protseq);
NewBinding->NetworkAddr = RPCRT4_strdupA(OldBinding->NetworkAddr);
NewBinding->Endpoint = RPCRT4_strdupA(OldBinding->Endpoint);
/* because of the way named pipes work, we'll transfer the connected pipe
* to the child, then reopen the server binding to continue listening */
NewBinding->conn = OldBinding->conn;
NewBinding->ovl = OldBinding->ovl;
OldBinding->conn = 0;
memset(&OldBinding->ovl, 0, sizeof(OldBinding->ovl));
RPCRT4_AllocBinding(&NewBinding, Connection->server);
NewBinding->Protseq = RPCRT4_strdupA(Connection->Protseq);
NewBinding->NetworkAddr = RPCRT4_strdupA(Connection->NetworkAddr);
NewBinding->Endpoint = RPCRT4_strdupA(Connection->Endpoint);
NewBinding->FromConn = Connection;
TRACE("binding: %p\n", NewBinding);
*Binding = NewBinding;
RPCRT4_OpenBinding(OldBinding);
return RPC_S_OK;
}
@ -225,7 +401,7 @@ RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding)
return RPC_S_OK;
TRACE("binding: %p\n", Binding);
RPCRT4_CloseBinding(Binding);
/* FIXME: release connections */
RPCRT4_strfree(Binding->Endpoint);
RPCRT4_strfree(Binding->NetworkAddr);
RPCRT4_strfree(Binding->Protseq);
@ -233,143 +409,29 @@ RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding)
return RPC_S_OK;
}
RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding)
RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection)
{
RpcConnection* NewConnection;
TRACE("(Binding == ^%p)\n", Binding);
if (!Binding->conn) {
if (Binding->server) { /* server */
/* protseq=ncalrpc: supposed to use NT LPC ports,
* but we'll implement it with named pipes for now */
if (strcmp(Binding->Protseq, "ncalrpc") == 0) {
static LPSTR prefix = "\\\\.\\pipe\\lrpc\\";
LPSTR pname;
pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Binding->Endpoint) + 1);
strcat(strcpy(pname, prefix), Binding->Endpoint);
TRACE("listening on %s\n", pname);
Binding->conn = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
0, PIPE_UNLIMITED_INSTANCES, 0, 0, 5000, NULL);
HeapFree(GetProcessHeap(), 0, pname);
memset(&Binding->ovl, 0, sizeof(Binding->ovl));
Binding->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
if (!ConnectNamedPipe(Binding->conn, &Binding->ovl)) {
DWORD err = GetLastError();
if (err == ERROR_PIPE_CONNECTED) {
SetEvent(Binding->ovl.hEvent);
return RPC_S_OK;
}
return err;
}
}
/* protseq=ncacn_np: named pipes */
else if (strcmp(Binding->Protseq, "ncacn_np") == 0) {
static LPSTR prefix = "\\\\.";
LPSTR pname;
pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Binding->Endpoint) + 1);
strcat(strcpy(pname, prefix), Binding->Endpoint);
TRACE("listening on %s\n", pname);
Binding->conn = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
0, PIPE_UNLIMITED_INSTANCES, 0, 0, 5000, NULL);
HeapFree(GetProcessHeap(), 0, pname);
memset(&Binding->ovl, 0, sizeof(Binding->ovl));
Binding->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
if (!ConnectNamedPipe(Binding->conn, &Binding->ovl)) {
DWORD err = GetLastError();
if (err == ERROR_PIPE_CONNECTED) {
SetEvent(Binding->ovl.hEvent);
return RPC_S_OK;
}
return err;
}
}
else {
ERR("protseq %s not supported\n", Binding->Protseq);
return RPC_S_PROTSEQ_NOT_SUPPORTED;
}
}
else { /* client */
/* protseq=ncalrpc: supposed to use NT LPC ports,
* but we'll implement it with named pipes for now */
if (strcmp(Binding->Protseq, "ncalrpc") == 0) {
static LPSTR prefix = "\\\\.\\pipe\\lrpc\\";
LPSTR pname;
HANDLE conn;
DWORD err;
pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Binding->Endpoint) + 1);
strcat(strcpy(pname, prefix), Binding->Endpoint);
TRACE("connecting to %s\n", pname);
while (TRUE) {
if (WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (conn != INVALID_HANDLE_VALUE) break;
err = GetLastError();
if (err == ERROR_PIPE_BUSY) continue;
TRACE("connection failed, error=%lx\n", err);
HeapFree(GetProcessHeap(), 0, pname);
return err;
} else {
err = GetLastError();
TRACE("connection failed, error=%lx\n", err);
HeapFree(GetProcessHeap(), 0, pname);
return err;
}
}
/* success */
HeapFree(GetProcessHeap(), 0, pname);
memset(&Binding->ovl, 0, sizeof(Binding->ovl));
Binding->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
Binding->conn = conn;
}
/* protseq=ncacn_np: named pipes */
else if (strcmp(Binding->Protseq, "ncacn_np") == 0) {
static LPSTR prefix = "\\\\.";
LPSTR pname;
HANDLE conn;
DWORD err;
pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Binding->Endpoint) + 1);
strcat(strcpy(pname, prefix), Binding->Endpoint);
TRACE("connecting to %s\n", pname);
conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (conn == INVALID_HANDLE_VALUE) {
err = GetLastError();
/* we don't need to handle ERROR_PIPE_BUSY here,
* the doc says that it is returned to the app */
TRACE("connection failed, error=%lx\n", err);
HeapFree(GetProcessHeap(), 0, pname);
return err;
}
/* success */
HeapFree(GetProcessHeap(), 0, pname);
memset(&Binding->ovl, 0, sizeof(Binding->ovl));
Binding->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
Binding->conn = conn;
} else {
ERR("protseq %s not supported\n", Binding->Protseq);
return RPC_S_PROTSEQ_NOT_SUPPORTED;
}
}
if (Binding->FromConn) {
*Connection = Binding->FromConn;
return RPC_S_OK;
}
return RPC_S_OK;
/* FIXME: cache connections */
RPCRT4_CreateConnection(&NewConnection, Binding->server, Binding->Protseq, Binding->NetworkAddr, Binding->Endpoint, NULL);
NewConnection->Used = Binding;
*Connection = NewConnection;
return RPCRT4_OpenConnection(NewConnection);
}
RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding)
RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection)
{
TRACE("(Binding == ^%p)\n", Binding);
if (Binding->conn) {
CancelIo(Binding->conn);
CloseHandle(Binding->conn);
Binding->conn = 0;
}
if (Binding->ovl.hEvent) {
CloseHandle(Binding->ovl.hEvent);
Binding->ovl.hEvent = 0;
}
return RPC_S_OK;
if (!Connection) return RPC_S_OK;
if (Binding->FromConn == Connection) return RPC_S_OK;
Connection->Used = NULL;
return RPCRT4_DestroyConnection(Connection);
}
/* utility functions for string composing and parsing */

View File

@ -23,20 +23,32 @@
#include "wine/rpcss_shared.h"
typedef struct _RpcConnection
{
struct _RpcConnection* Next;
struct _RpcBinding* Used;
BOOL server;
LPSTR Protseq;
LPSTR NetworkAddr;
LPSTR Endpoint;
HANDLE conn, thread;
OVERLAPPED ovl;
} RpcConnection;
/* don't know what MS's structure looks like */
typedef struct _RpcBinding
{
DWORD refs;
struct _RpcBinding* Next; /* for rpc server */
struct _RpcBinding* Next;
BOOL server;
UUID ObjectUuid;
UUID ActiveUuid;
LPSTR Protseq;
LPSTR NetworkAddr;
LPSTR Endpoint;
RPC_BLOCKING_FN BlockingFn;
ULONG ServerTid;
HANDLE conn, thread;
OVERLAPPED ovl;
RpcConnection* FromConn;
} RpcBinding;
LPSTR RPCRT4_strndupA(LPSTR src, INT len);
@ -48,17 +60,23 @@ void RPCRT4_strfree(LPSTR src);
#define RPCRT4_strdupA(x) RPCRT4_strndupA((x),-1)
#define RPCRT4_strdupW(x) RPCRT4_strndupW((x),-1)
RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions);
RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection);
RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection);
RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection);
RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection);
RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPSTR Protseq);
RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPWSTR Protseq);
RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions);
RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPWSTR NetworkAddr, LPWSTR Endpoint, LPWSTR NetworkOptions);
RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPSTR Endpoint);
RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, UUID* ObjectUuid);
RPC_STATUS RPCRT4_SpawnBinding(RpcBinding** Binding, RpcBinding* OldBinding);
RPC_STATUS RPCRT4_MakeBinding(RpcBinding** Binding, RpcConnection* Connection);
RPC_STATUS RPCRT4_ExportBinding(RpcBinding** Binding, RpcBinding* OldBinding);
RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding);
RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding);
RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding);
RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection);
RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection);
BOOL RPCRT4_RPCSSOnDemandCall(PRPCSS_NP_MESSAGE msg, char *vardata_payload, PRPCSS_NP_REPLY reply);
HANDLE RPCRT4_GetMasterMutex(void);
HANDLE RPCRT4_RpcssNPConnect(void);

View File

@ -48,9 +48,10 @@ RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg)
{
void* buf;
TRACE("(%p)\n", pMsg);
TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength);
/* FIXME: pfnAllocate? */
buf = HeapReAlloc(GetProcessHeap(), 0, pMsg->Buffer, pMsg->BufferLength);
TRACE("Buffer=%p\n", buf);
if (buf) pMsg->Buffer = buf;
/* FIXME: which errors to return? */
return buf ? S_OK : E_OUTOFMEMORY;
@ -74,14 +75,23 @@ RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg)
RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg)
{
RpcBinding* bind = (RpcBinding*)pMsg->Handle;
RpcConnection* conn;
RPC_CLIENT_INTERFACE* cif = NULL;
RPC_SERVER_INTERFACE* sif = NULL;
UUID* obj;
UUID* act;
RPC_STATUS status;
RpcPktHdr hdr;
TRACE("(%p)\n", pMsg);
if (!bind) return RPC_S_INVALID_BINDING;
status = RPCRT4_OpenBinding(bind, &conn);
if (status != RPC_S_OK) return status;
obj = &bind->ObjectUuid;
act = &bind->ActiveUuid;
if (bind->server) {
sif = pMsg->RpcInterfaceInformation;
if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
@ -90,19 +100,17 @@ RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg)
if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
}
status = RPCRT4_OpenBinding(bind);
if (status != RPC_S_OK) return status;
/* initialize packet header */
memset(&hdr, 0, sizeof(hdr));
hdr.rpc_ver = 4;
hdr.ptype = PKT_REQUEST;
hdr.object = bind->ObjectUuid; /* FIXME: IIRC iff no object, the header structure excludes this elt */
hdr.ptype = bind->server ? PKT_RESPONSE : PKT_REQUEST;
hdr.object = *obj; /* FIXME: IIRC iff no object, the header structure excludes this elt */
hdr.if_id = (bind->server) ? sif->InterfaceId.SyntaxGUID : cif->InterfaceId.SyntaxGUID;
hdr.if_vers =
(bind->server) ?
MAKELONG(sif->InterfaceId.SyntaxVersion.MinorVersion, sif->InterfaceId.SyntaxVersion.MajorVersion) :
MAKELONG(cif->InterfaceId.SyntaxVersion.MinorVersion, cif->InterfaceId.SyntaxVersion.MajorVersion);
hdr.act_id = *act;
hdr.opnum = pMsg->ProcNum;
/* only the low-order 3 octets of the DataRepresentation go in the header */
hdr.drep[0] = LOBYTE(LOWORD(pMsg->DataRepresentation));
@ -111,13 +119,26 @@ RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg)
hdr.len = pMsg->BufferLength;
/* transmit packet */
if (!WriteFile(bind->conn, &hdr, sizeof(hdr), NULL, NULL))
return GetLastError();
if (!WriteFile(bind->conn, pMsg->Buffer, pMsg->BufferLength, NULL, NULL))
return GetLastError();
if (!WriteFile(conn->conn, &hdr, sizeof(hdr), NULL, NULL)) {
status = GetLastError();
goto fail;
}
if (pMsg->BufferLength && !WriteFile(conn->conn, pMsg->Buffer, pMsg->BufferLength, NULL, NULL)) {
status = GetLastError();
goto fail;
}
/* success */
return RPC_S_OK;
if (!bind->server) {
/* save the connection, so the response can be read from it */
pMsg->ReservedForRuntime = conn;
return RPC_S_OK;
}
RPCRT4_CloseBinding(bind, conn);
status = RPC_S_OK;
fail:
return status;
}
/***********************************************************************
@ -126,6 +147,8 @@ RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg)
RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg)
{
RpcBinding* bind = (RpcBinding*)pMsg->Handle;
RpcConnection* conn;
UUID* act;
RPC_STATUS status;
RpcPktHdr hdr;
DWORD dwRead;
@ -133,44 +156,78 @@ RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg)
TRACE("(%p)\n", pMsg);
if (!bind) return RPC_S_INVALID_BINDING;
status = RPCRT4_OpenBinding(bind);
if (status != RPC_S_OK) return status;
/* read packet header */
#ifdef OVERLAPPED_WORKS
if (!ReadFile(bind->conn, &hdr, sizeof(hdr), &dwRead, &bind->ovl)) {
DWORD err = GetLastError();
if (err != ERROR_IO_PENDING) {
return err;
}
if (!GetOverlappedResult(bind->conn, &bind->ovl, &dwRead, TRUE)) return GetLastError();
if (pMsg->ReservedForRuntime) {
conn = pMsg->ReservedForRuntime;
pMsg->ReservedForRuntime = NULL;
} else {
status = RPCRT4_OpenBinding(bind, &conn);
if (status != RPC_S_OK) return status;
}
#else
if (!ReadFile(bind->conn, &hdr, sizeof(hdr), &dwRead, NULL))
return GetLastError();
#endif
if (dwRead != sizeof(hdr)) return RPC_S_PROTOCOL_ERROR;
/* read packet body */
pMsg->BufferLength = hdr.len;
status = I_RpcGetBuffer(pMsg);
if (status != RPC_S_OK) return status;
act = &bind->ActiveUuid;
for (;;) {
/* read packet header */
#ifdef OVERLAPPED_WORKS
if (!ReadFile(bind->conn, pMsg->Buffer, hdr.len, &dwRead, &bind->ovl)) {
DWORD err = GetLastError();
if (err != ERROR_IO_PENDING) {
return err;
if (!ReadFile(conn->conn, &hdr, sizeof(hdr), &dwRead, &conn->ovl)) {
DWORD err = GetLastError();
if (err != ERROR_IO_PENDING) {
status = err;
goto fail;
}
if (!GetOverlappedResult(conn->conn, &conn->ovl, &dwRead, TRUE)) {
status = GetLastError();
goto fail;
}
}
if (!GetOverlappedResult(bind->conn, &bind->ovl, &dwRead, TRUE)) return GetLastError();
}
#else
if (!ReadFile(bind->conn, pMsg->Buffer, hdr.len, &dwRead, NULL))
return GetLastError();
if (!ReadFile(conn->conn, &hdr, sizeof(hdr), &dwRead, NULL)) {
status = GetLastError();
goto fail;
}
#endif
if (dwRead != hdr.len) return RPC_S_PROTOCOL_ERROR;
if (dwRead != sizeof(hdr)) {
status = RPC_S_PROTOCOL_ERROR;
goto fail;
}
/* success */
return RPC_S_OK;
/* read packet body */
pMsg->BufferLength = hdr.len;
status = I_RpcGetBuffer(pMsg);
if (status != RPC_S_OK) goto fail;
if (!pMsg->BufferLength) dwRead = 0; else
#ifdef OVERLAPPED_WORKS
if (!ReadFile(conn->conn, pMsg->Buffer, hdr.len, &dwRead, &conn->ovl)) {
DWORD err = GetLastError();
if (err != ERROR_IO_PENDING) {
status = err;
goto fail;
}
if (!GetOverlappedResult(conn->conn, &conn->ovl, &dwRead, TRUE)) {
status = GetLastError();
goto fail;
}
}
#else
if (!ReadFile(conn->conn, pMsg->Buffer, hdr.len, &dwRead, NULL)) {
status = GetLastError();
goto fail;
}
#endif
if (dwRead != hdr.len) {
status = RPC_S_PROTOCOL_ERROR;
goto fail;
}
/* success */
status = RPC_S_OK;
/* FIXME: check packet type, destination, etc? */
break;
}
fail:
RPCRT4_CloseBinding(bind, conn);
return status;
}
/***********************************************************************

View File

@ -37,8 +37,18 @@
#include "rpc_server.h"
#include "rpc_defs.h"
#define MAX_THREADS 128
WINE_DEFAULT_DEBUG_CHANNEL(ole);
typedef struct _RpcPacket
{
struct _RpcPacket* next;
struct _RpcConnection* conn;
RpcPktHdr hdr;
void* buf;
} RpcPacket;
static RpcServerProtseq* protseqs;
static RpcServerInterface* ifs;
@ -48,6 +58,13 @@ static BOOL std_listen;
static LONG listen_count = -1;
static HANDLE mgr_event, server_thread;
static CRITICAL_SECTION spacket_cs = CRITICAL_SECTION_INIT("RpcServerPacket");
static RpcPacket* spacket_head;
static RpcPacket* spacket_tail;
static HANDLE server_sem;
static DWORD worker_count, worker_free;
static RpcServerInterface* RPCRT4_find_interface(UUID* object, UUID* if_id)
{
UUID* MgrType = NULL;
@ -67,31 +84,168 @@ static RpcServerInterface* RPCRT4_find_interface(UUID* object, UUID* if_id)
return cif;
}
static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg)
static void RPCRT4_push_packet(RpcPacket* packet)
{
RpcBinding* bind = (RpcBinding*)the_arg;
RpcPktHdr hdr;
DWORD dwRead;
packet->next = NULL;
EnterCriticalSection(&spacket_cs);
if (spacket_tail) spacket_tail->next = packet;
else {
spacket_head = packet;
spacket_tail = packet;
}
LeaveCriticalSection(&spacket_cs);
}
static RpcPacket* RPCRT4_pop_packet(void)
{
RpcPacket* packet;
EnterCriticalSection(&spacket_cs);
packet = spacket_head;
if (packet) {
spacket_head = packet->next;
if (!spacket_head) spacket_tail = NULL;
}
LeaveCriticalSection(&spacket_cs);
if (packet) packet->next = NULL;
return packet;
}
static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, void* buf)
{
RpcBinding* pbind;
RPC_MESSAGE msg;
RpcServerInterface* sif;
RPC_DISPATCH_FUNCTION func;
memset(&msg, 0, sizeof(msg));
msg.Handle = (RPC_BINDING_HANDLE)bind;
msg.BufferLength = hdr->len;
msg.Buffer = buf;
sif = RPCRT4_find_interface(&hdr->object, &hdr->if_id);
if (sif) {
TRACE("packet received for interface %s\n", debugstr_guid(&hdr->if_id));
msg.RpcInterfaceInformation = sif->If;
/* create temporary binding for dispatch */
RPCRT4_MakeBinding(&pbind, conn);
RPCRT4_SetBindingObject(pbind, &hdr->object);
msg.Handle = (RPC_BINDING_HANDLE)pbind;
/* process packet */
switch (hdr->ptype) {
case PKT_REQUEST:
/* find dispatch function */
msg.ProcNum = hdr->opnum;
if (sif->Flags & RPC_IF_OLE) {
/* native ole32 always gives us a dispatch table with a single entry
* (I assume that's a wrapper for IRpcStubBuffer::Invoke) */
func = *sif->If->DispatchTable->DispatchTable;
} else {
if (msg.ProcNum >= sif->If->DispatchTable->DispatchTableCount) {
ERR("invalid procnum\n");
func = NULL;
}
func = sif->If->DispatchTable->DispatchTable[msg.ProcNum];
}
/* put in the drep. FIXME: is this more universally applicable?
perhaps we should move this outward... */
msg.DataRepresentation =
MAKELONG( MAKEWORD(hdr->drep[0], hdr->drep[1]),
MAKEWORD(hdr->drep[2], 0));
/* dispatch */
if (func) func(&msg);
/* send response packet */
I_RpcSend(&msg);
break;
default:
ERR("unknown packet type\n");
break;
}
RPCRT4_DestroyBinding(pbind);
msg.Handle = 0;
msg.RpcInterfaceInformation = NULL;
}
else {
ERR("got RPC packet to unregistered interface %s\n", debugstr_guid(&hdr->if_id));
}
/* clean up */
HeapFree(GetProcessHeap(), 0, msg.Buffer);
msg.Buffer = NULL;
}
static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg)
{
DWORD obj;
RpcPacket* pkt;
for (;;) {
/* idle timeout after 5s */
obj = WaitForSingleObject(server_sem, 5000);
if (obj == WAIT_TIMEOUT) {
/* if another idle thread exist, self-destruct */
if (worker_free > 1) break;
continue;
}
pkt = RPCRT4_pop_packet();
if (!pkt) continue;
InterlockedDecrement(&worker_free);
for (;;) {
RPCRT4_process_packet(pkt->conn, &pkt->hdr, pkt->buf);
HeapFree(GetProcessHeap(), 0, pkt);
/* try to grab another packet here without waiting
* on the semaphore, in case it hits max */
pkt = RPCRT4_pop_packet();
if (!pkt) break;
/* decrement semaphore */
WaitForSingleObject(server_sem, 0);
}
InterlockedIncrement(&worker_free);
}
InterlockedDecrement(&worker_free);
InterlockedDecrement(&worker_count);
return 0;
}
static void RPCRT4_create_worker_if_needed(void)
{
if (!worker_free && worker_count < MAX_THREADS) {
HANDLE thread;
InterlockedIncrement(&worker_count);
InterlockedIncrement(&worker_free);
thread = CreateThread(NULL, 0, RPCRT4_worker_thread, NULL, 0, NULL);
if (thread) CloseHandle(thread);
else {
InterlockedDecrement(&worker_free);
InterlockedDecrement(&worker_count);
}
}
}
static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg)
{
RpcConnection* conn = (RpcConnection*)the_arg;
RpcPktHdr hdr;
DWORD dwRead;
void* buf = NULL;
RpcPacket* packet;
TRACE("(%p)\n", conn);
for (;;) {
/* read packet header */
#ifdef OVERLAPPED_WORKS
if (!ReadFile(bind->conn, &hdr, sizeof(hdr), &dwRead, &bind->ovl)) {
if (!ReadFile(conn->conn, &hdr, sizeof(hdr), &dwRead, &conn->ovl)) {
DWORD err = GetLastError();
if (err != ERROR_IO_PENDING) {
TRACE("connection lost, error=%08lx\n", err);
break;
}
if (!GetOverlappedResult(bind->conn, &bind->ovl, &dwRead, TRUE)) break;
if (!GetOverlappedResult(conn->conn, &conn->ovl, &dwRead, TRUE)) break;
}
#else
if (!ReadFile(bind->conn, &hdr, sizeof(hdr), &dwRead, NULL)) {
if (!ReadFile(conn->conn, &hdr, sizeof(hdr), &dwRead, NULL)) {
TRACE("connection lost, error=%08lx\n", GetLastError());
break;
}
@ -102,19 +256,20 @@ static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg)
}
/* read packet body */
msg.BufferLength = hdr.len;
msg.Buffer = HeapAlloc(GetProcessHeap(), 0, msg.BufferLength);
buf = HeapAlloc(GetProcessHeap(), 0, hdr.len);
TRACE("receiving payload=%d\n", hdr.len);
if (!hdr.len) dwRead = 0; else
#ifdef OVERLAPPED_WORKS
if (!ReadFile(bind->conn, msg.Buffer, msg.BufferLength, &dwRead, &bind->ovl)) {
if (!ReadFile(conn->conn, buf, hdr.len, &dwRead, &conn->ovl)) {
DWORD err = GetLastError();
if (err != ERROR_IO_PENDING) {
TRACE("connection lost, error=%08lx\n", err);
break;
}
if (!GetOverlappedResult(bind->conn, &bind->ovl, &dwRead, TRUE)) break;
if (!GetOverlappedResult(conn->conn, &conn->ovl, &dwRead, TRUE)) break;
}
#else
if (!ReadFile(bind->conn, msg.Buffer, msg.BufferLength, &dwRead, NULL)) {
if (!ReadFile(conn->conn, buf, hdr.len, &dwRead, NULL)) {
TRACE("connection lost, error=%08lx\n", GetLastError());
break;
}
@ -124,72 +279,31 @@ static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg)
break;
}
sif = RPCRT4_find_interface(&hdr.object, &hdr.if_id);
if (sif) {
msg.RpcInterfaceInformation = sif->If;
/* associate object with binding (this is a bit of a hack...
* a new binding should probably be created for each object) */
RPCRT4_SetBindingObject(bind, &hdr.object);
/* process packet*/
switch (hdr.ptype) {
case PKT_REQUEST:
/* find dispatch function */
msg.ProcNum = hdr.opnum;
if (sif->Flags & RPC_IF_OLE) {
/* native ole32 always gives us a dispatch table with a single entry
* (I assume that's a wrapper for IRpcStubBuffer::Invoke) */
func = *sif->If->DispatchTable->DispatchTable;
} else {
if (msg.ProcNum >= sif->If->DispatchTable->DispatchTableCount) {
ERR("invalid procnum\n");
func = NULL;
}
func = sif->If->DispatchTable->DispatchTable[msg.ProcNum];
}
/* put in the drep. FIXME: is this more universally applicable?
perhaps we should move this outward... */
msg.DataRepresentation =
MAKELONG( MAKEWORD(hdr.drep[0], hdr.drep[1]),
MAKEWORD(hdr.drep[2], 0));
/* dispatch */
if (func) func(&msg);
/* prepare response packet */
hdr.ptype = PKT_RESPONSE;
break;
default:
ERR("unknown packet type\n");
goto no_reply;
}
/* write reply packet */
hdr.len = msg.BufferLength;
WriteFile(bind->conn, &hdr, sizeof(hdr), NULL, NULL);
WriteFile(bind->conn, msg.Buffer, msg.BufferLength, NULL, NULL);
no_reply:
/* un-associate object */
RPCRT4_SetBindingObject(bind, NULL);
msg.RpcInterfaceInformation = NULL;
}
else {
ERR("got RPC packet to unregistered interface %s\n", debugstr_guid(&hdr.if_id));
}
/* clean up */
HeapFree(GetProcessHeap(), 0, msg.Buffer);
msg.Buffer = NULL;
#if 0
RPCRT4_process_packet(conn, &hdr, buf);
#else
packet = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcPacket));
packet->conn = conn;
packet->hdr = hdr;
packet->buf = buf;
RPCRT4_create_worker_if_needed();
RPCRT4_push_packet(packet);
ReleaseSemaphore(server_sem, 1, NULL);
#endif
buf = NULL;
}
if (msg.Buffer) HeapFree(GetProcessHeap(), 0, msg.Buffer);
RPCRT4_DestroyBinding(bind);
if (buf) HeapFree(GetProcessHeap(), 0, buf);
RPCRT4_DestroyConnection(conn);
return 0;
}
static void RPCRT4_new_client(RpcBinding* bind)
static void RPCRT4_new_client(RpcConnection* conn)
{
bind->thread = CreateThread(NULL, 0, RPCRT4_io_thread, bind, 0, NULL);
conn->thread = CreateThread(NULL, 0, RPCRT4_io_thread, conn, 0, NULL);
if (!conn->thread) {
DWORD err = GetLastError();
ERR("failed to create thread, error=%08lx\n", err);
}
}
static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg)
@ -198,33 +312,33 @@ static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg)
HANDLE *objs = NULL;
DWORD count, res;
RpcServerProtseq* cps;
RpcBinding* bind;
RpcBinding* cbind;
RpcConnection* conn;
RpcConnection* cconn;
for (;;) {
EnterCriticalSection(&server_cs);
/* open and count bindings */
/* open and count connections */
count = 1;
cps = protseqs;
while (cps) {
bind = cps->bind;
while (bind) {
RPCRT4_OpenBinding(bind);
if (bind->ovl.hEvent) count++;
bind = bind->Next;
conn = cps->conn;
while (conn) {
RPCRT4_OpenConnection(conn);
if (conn->ovl.hEvent) count++;
conn = conn->Next;
}
cps = cps->Next;
}
/* make array of bindings */
/* make array of connings */
objs = HeapReAlloc(GetProcessHeap(), 0, objs, count*sizeof(HANDLE));
objs[0] = m_event;
count = 1;
cps = protseqs;
while (cps) {
bind = cps->bind;
while (bind) {
if (bind->ovl.hEvent) objs[count++] = bind->ovl.hEvent;
bind = bind->Next;
conn = cps->conn;
while (conn) {
if (conn->ovl.hEvent) objs[count++] = conn->ovl.hEvent;
conn = conn->Next;
}
cps = cps->Next;
}
@ -241,37 +355,37 @@ static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg)
}
else {
b_handle = objs[res - WAIT_OBJECT_0];
/* find which binding got a RPC */
/* find which connection got a RPC */
EnterCriticalSection(&server_cs);
bind = NULL;
conn = NULL;
cps = protseqs;
while (cps) {
bind = cps->bind;
while (bind) {
if (bind->ovl.hEvent == b_handle) break;
bind = bind->Next;
conn = cps->conn;
while (conn) {
if (conn->ovl.hEvent == b_handle) break;
conn = conn->Next;
}
if (bind) break;
if (conn) break;
cps = cps->Next;
}
cbind = NULL;
if (bind) RPCRT4_SpawnBinding(&cbind, bind);
cconn = NULL;
if (conn) RPCRT4_SpawnConnection(&cconn, conn);
LeaveCriticalSection(&server_cs);
if (!bind) {
ERR("failed to locate binding for handle %p\n", b_handle);
if (!conn) {
ERR("failed to locate connection for handle %p\n", b_handle);
}
if (cbind) RPCRT4_new_client(cbind);
if (cconn) RPCRT4_new_client(cconn);
}
}
HeapFree(GetProcessHeap(), 0, objs);
EnterCriticalSection(&server_cs);
/* close bindings */
/* close connections */
cps = protseqs;
while (cps) {
bind = cps->bind;
while (bind) {
RPCRT4_CloseBinding(bind);
bind = bind->Next;
conn = cps->conn;
while (conn) {
RPCRT4_CloseConnection(conn);
conn = conn->Next;
}
cps = cps->Next;
}
@ -286,6 +400,7 @@ static void RPCRT4_start_listen(void)
EnterCriticalSection(&listen_cs);
if (! ++listen_count) {
if (!mgr_event) mgr_event = CreateEventA(NULL, TRUE, FALSE, NULL);
if (!server_sem) server_sem = CreateSemaphoreA(NULL, 0, MAX_THREADS, NULL);
std_listen = TRUE;
server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, NULL, 0, NULL);
LeaveCriticalSection(&listen_cs);
@ -311,8 +426,7 @@ static void RPCRT4_stop_listen(void)
static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps)
{
RPCRT4_CreateBindingA(&ps->bind, TRUE, ps->Protseq);
RPCRT4_CompleteBindingA(ps->bind, NULL, ps->Endpoint, NULL);
RPCRT4_CreateConnection(&ps->conn, TRUE, ps->Protseq, NULL, ps->Endpoint, NULL);
EnterCriticalSection(&server_cs);
ps->Next = protseqs;
@ -332,7 +446,7 @@ RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector )
RPC_STATUS status;
DWORD count;
RpcServerProtseq* ps;
RpcBinding* bind;
RpcConnection* conn;
if (BindingVector)
TRACE("(*BindingVector == ^%p)\n", *BindingVector);
@ -340,14 +454,14 @@ RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector )
ERR("(BindingVector == ^null!!?)\n");
EnterCriticalSection(&server_cs);
/* count bindings */
/* count connections */
count = 0;
ps = protseqs;
while (ps) {
bind = ps->bind;
while (bind) {
conn = ps->conn;
while (conn) {
count++;
bind = bind->Next;
conn = conn->Next;
}
ps = ps->Next;
}
@ -360,12 +474,12 @@ RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector )
count = 0;
ps = protseqs;
while (ps) {
bind = ps->bind;
while (bind) {
RPCRT4_ExportBinding((RpcBinding**)&(*BindingVector)->BindingH[count],
bind);
conn = ps->conn;
while (conn) {
RPCRT4_MakeBinding((RpcBinding**)&(*BindingVector)->BindingH[count],
conn);
count++;
bind = bind->Next;
conn = conn->Next;
}
ps = ps->Next;
}

View File

@ -29,7 +29,7 @@ typedef struct _RpcServerProtseq
LPSTR Protseq;
LPSTR Endpoint;
UINT MaxCalls;
RpcBinding* bind;
RpcConnection* conn;
} RpcServerProtseq;
typedef struct _RpcServerInterface