For better concurrency, separate the connections from the bindings.
This commit is contained in:
parent
586808fdf2
commit
def211c4c9
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ typedef struct _RpcServerProtseq
|
|||
LPSTR Protseq;
|
||||
LPSTR Endpoint;
|
||||
UINT MaxCalls;
|
||||
RpcBinding* bind;
|
||||
RpcConnection* conn;
|
||||
} RpcServerProtseq;
|
||||
|
||||
typedef struct _RpcServerInterface
|
||||
|
|
Loading…
Reference in New Issue