📄 rpc_server.c
字号:
/*
* RPC server API
*
* Copyright 2001 Ove K鍁en, TransGaming Technologies
* Copyright 2004 Filip Navara
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* TODO:
* - a whole lot
*/
#include "config.h"
#include "wine/port.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "winreg.h"
#include "rpc.h"
#include "rpcndr.h"
#include "excpt.h"
#include "wine/debug.h"
#include "wine/exception.h"
#include "rpc_server.h"
#include "rpc_misc.h"
#include "rpc_message.h"
#include "rpc_defs.h"
#define MAX_THREADS 128
WINE_DEFAULT_DEBUG_CHANNEL(rpc);
typedef struct _RpcPacket
{
struct _RpcPacket* next;
struct _RpcConnection* conn;
RpcPktHdr* hdr;
RPC_MESSAGE* msg;
} RpcPacket;
typedef struct _RpcObjTypeMap
{
/* FIXME: a hash table would be better. */
struct _RpcObjTypeMap *next;
UUID Object;
UUID Type;
} RpcObjTypeMap;
static RpcObjTypeMap *RpcObjTypeMaps;
static RpcServerProtseq* protseqs;
static RpcServerInterface* ifs;
static CRITICAL_SECTION server_cs;
static CRITICAL_SECTION_DEBUG server_cs_debug =
{
0, 0, &server_cs,
{ &server_cs_debug.ProcessLocksList, &server_cs_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": server_cs") }
};
static CRITICAL_SECTION server_cs = { &server_cs_debug, -1, 0, 0, 0, 0 };
static CRITICAL_SECTION listen_cs;
static CRITICAL_SECTION_DEBUG listen_cs_debug =
{
0, 0, &listen_cs,
{ &listen_cs_debug.ProcessLocksList, &listen_cs_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": listen_cs") }
};
static CRITICAL_SECTION listen_cs = { &listen_cs_debug, -1, 0, 0, 0, 0 };
/* whether the server is currently listening */
static BOOL std_listen;
/* number of manual listeners (calls to RpcServerListen) */
static LONG manual_listen_count;
/* total listeners including auto listeners */
static LONG listen_count;
/* set on change of configuration (e.g. listening on new protseq) */
static HANDLE mgr_event;
/* mutex for ensuring only one thread can change state at a time */
static HANDLE mgr_mutex;
/* set when server thread has finished opening connections */
static HANDLE server_ready_event;
static CRITICAL_SECTION spacket_cs;
static CRITICAL_SECTION_DEBUG spacket_cs_debug =
{
0, 0, &spacket_cs,
{ &spacket_cs_debug.ProcessLocksList, &spacket_cs_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": spacket_cs") }
};
static CRITICAL_SECTION spacket_cs = { &spacket_cs_debug, -1, 0, 0, 0, 0 };
static RpcPacket* spacket_head;
static RpcPacket* spacket_tail;
static HANDLE server_sem;
static LONG worker_count, worker_free, worker_tls;
static UUID uuid_nil;
inline static RpcObjTypeMap *LookupObjTypeMap(UUID *ObjUuid)
{
RpcObjTypeMap *rslt = RpcObjTypeMaps;
RPC_STATUS dummy;
while (rslt) {
if (! UuidCompare(ObjUuid, &rslt->Object, &dummy)) break;
rslt = rslt->next;
}
return rslt;
}
inline static UUID *LookupObjType(UUID *ObjUuid)
{
RpcObjTypeMap *map = LookupObjTypeMap(ObjUuid);
if (map)
return &map->Type;
else
return &uuid_nil;
}
static RpcServerInterface* RPCRT4_find_interface(UUID* object,
RPC_SYNTAX_IDENTIFIER* if_id,
BOOL check_object)
{
UUID* MgrType = NULL;
RpcServerInterface* cif = NULL;
RPC_STATUS status;
if (check_object)
MgrType = LookupObjType(object);
EnterCriticalSection(&server_cs);
cif = ifs;
while (cif) {
if (!memcmp(if_id, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER)) &&
(check_object == FALSE || UuidEqual(MgrType, &cif->MgrTypeUuid, &status)) &&
std_listen) break;
cif = cif->Next;
}
LeaveCriticalSection(&server_cs);
TRACE("returning %p for %s\n", cif, debugstr_guid(object));
return cif;
}
static void RPCRT4_push_packet(RpcPacket* packet)
{
packet->next = NULL;
EnterCriticalSection(&spacket_cs);
if (spacket_tail) {
spacket_tail->next = packet;
spacket_tail = 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;
}
#ifndef __REACTOS__
typedef struct {
PRPC_MESSAGE msg;
void* buf;
} packet_state;
static WINE_EXCEPTION_FILTER(rpc_filter)
{
packet_state* state;
PRPC_MESSAGE msg;
state = TlsGetValue(worker_tls);
msg = state->msg;
if (msg->Buffer != state->buf) I_RpcFreeBuffer(msg);
msg->RpcFlags |= WINE_RPCFLAG_EXCEPTION;
msg->BufferLength = sizeof(DWORD);
I_RpcGetBuffer(msg);
*(DWORD*)msg->Buffer = GetExceptionCode();
WARN("exception caught with code 0x%08lx = %ld\n", *(DWORD*)msg->Buffer, *(DWORD*)msg->Buffer);
TRACE("returning failure packet\n");
return EXCEPTION_EXECUTE_HANDLER;
}
#endif
static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSAGE* msg)
{
RpcServerInterface* sif;
RPC_DISPATCH_FUNCTION func;
#ifndef __REACTOS__
packet_state state;
#endif
UUID *object_uuid;
RpcPktHdr *response;
void *buf = msg->Buffer;
RPC_STATUS status;
#ifndef __REACTOS__
state.msg = msg;
state.buf = buf;
TlsSetValue(worker_tls, &state);
#endif
switch (hdr->common.ptype) {
case PKT_BIND:
TRACE("got bind packet\n");
/* FIXME: do more checks! */
if (hdr->bind.max_tsize < RPC_MIN_PACKET_SIZE ||
!UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) {
TRACE("packet size less than min size, or active interface syntax guid non-null\n");
sif = NULL;
} else {
sif = RPCRT4_find_interface(NULL, &hdr->bind.abstract, FALSE);
}
if (sif == NULL) {
TRACE("rejecting bind request on connection %p\n", conn);
/* Report failure to client. */
response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION,
RPC_VER_MAJOR, RPC_VER_MINOR);
} else {
TRACE("accepting bind request on connection %p\n", conn);
/* accept. */
response = RPCRT4_BuildBindAckHeader(NDR_LOCAL_DATA_REPRESENTATION,
RPC_MAX_PACKET_SIZE,
RPC_MAX_PACKET_SIZE,
conn->Endpoint,
RESULT_ACCEPT, NO_REASON,
&sif->If->TransferSyntax);
/* save the interface for later use */
conn->ActiveInterface = hdr->bind.abstract;
conn->MaxTransmissionSize = hdr->bind.max_tsize;
}
if (RPCRT4_Send(conn, response, NULL, 0) != RPC_S_OK)
goto fail;
break;
case PKT_REQUEST:
TRACE("got request packet\n");
/* fail if the connection isn't bound with an interface */
if (UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) {
response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION,
status);
RPCRT4_Send(conn, response, NULL, 0);
break;
}
if (hdr->common.flags & RPC_FLG_OBJECT_UUID) {
object_uuid = (UUID*)(&hdr->request + 1);
} else {
object_uuid = NULL;
}
sif = RPCRT4_find_interface(object_uuid, &conn->ActiveInterface, TRUE);
msg->RpcInterfaceInformation = sif->If;
/* copy the endpoint vector from sif to msg so that midl-generated code will use it */
msg->ManagerEpv = sif->MgrEpv;
if (object_uuid != NULL) {
RPCRT4_SetBindingObject(msg->Handle, object_uuid);
}
/* find dispatch function */
msg->ProcNum = hdr->request.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->common.drep[0], hdr->common.drep[1]),
MAKEWORD(hdr->common.drep[2], hdr->common.drep[3]));
/* dispatch */
#ifndef __REACTOS__
__TRY {
if (func) func(msg);
} __EXCEPT(rpc_filter) {
/* failure packet was created in rpc_filter */
} __ENDTRY
#else
if (func) func(msg);
#endif
/* send response packet */
I_RpcSend(msg);
msg->RpcInterfaceInformation = NULL;
break;
default:
FIXME("unhandled packet type\n");
break;
}
fail:
/* clean up */
if (msg->Buffer == buf) msg->Buffer = NULL;
TRACE("freeing Buffer=%p\n", buf);
HeapFree(GetProcessHeap(), 0, buf);
RPCRT4_DestroyBinding(msg->Handle);
msg->Handle = 0;
I_RpcFreeBuffer(msg);
msg->Buffer = NULL;
RPCRT4_FreeHeader(hdr);
#ifndef __REACTOS__
TlsSetValue(worker_tls, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -