📄 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "rpc.h"#include "rpcndr.h"#include "excpt.h"#include "wine/debug.h"#include "wine/exception.h"#include "rpc_server.h"#include "rpc_message.h"#include "rpc_defs.h"#include "ncastatus.h"WINE_DEFAULT_DEBUG_CHANNEL(rpc);typedef struct _RpcPacket{ 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;/* list of type RpcServerProtseq */static struct list protseqs = LIST_INIT(protseqs);static struct list server_interfaces = LIST_INIT(server_interfaces);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;static UUID uuid_nil;static inline RpcObjTypeMap *LookupObjTypeMap(UUID *ObjUuid){ RpcObjTypeMap *rslt = RpcObjTypeMaps; RPC_STATUS dummy; while (rslt) { if (! UuidCompare(ObjUuid, &rslt->Object, &dummy)) break; rslt = rslt->next; } return rslt;}static inline 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; RPC_STATUS status; if (check_object) MgrType = LookupObjType(object); EnterCriticalSection(&server_cs); LIST_FOR_EACH_ENTRY(cif, &server_interfaces, RpcServerInterface, entry) { if (!memcmp(if_id, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER)) && (check_object == FALSE || UuidEqual(MgrType, &cif->MgrTypeUuid, &status)) && std_listen) { InterlockedIncrement(&cif->CurrentCalls); break; } } LeaveCriticalSection(&server_cs); if (&cif->entry == &server_interfaces) cif = NULL; TRACE("returning %p for %s\n", cif, debugstr_guid(object)); return cif;}static void RPCRT4_release_server_interface(RpcServerInterface *sif){ if (!InterlockedDecrement(&sif->CurrentCalls) && sif->CallsCompletedEvent) { /* sif must have been removed from server_interfaces before * CallsCompletedEvent is set */ SetEvent(sif->CallsCompletedEvent); HeapFree(GetProcessHeap(), 0, sif); }}static WINE_EXCEPTION_FILTER(rpc_filter){ WARN("exception caught with code 0x%08x = %d\n", GetExceptionCode(), GetExceptionCode()); TRACE("returning failure packet\n"); /* catch every exception */ return EXCEPTION_EXECUTE_HANDLER;}static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSAGE* msg){ RpcServerInterface* sif; RPC_DISPATCH_FUNCTION func; UUID *object_uuid; RpcPktHdr *response; void *buf = msg->Buffer; RPC_STATUS status; BOOL exception; 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 for %s\n", conn, debugstr_guid(&hdr->bind.abstract.SyntaxGUID)); /* 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; RPCRT4_release_server_interface(sif); } status = RPCRT4_Send(conn, response, NULL, 0); RPCRT4_FreeHeader(response); if (status != 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)) { /* FIXME: should send BindNack instead */ response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION, status); RPCRT4_Send(conn, response, NULL, 0); RPCRT4_FreeHeader(response); 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); if (!sif) { WARN("interface %s no longer registered, returning fault packet\n", debugstr_guid(&conn->ActiveInterface.SyntaxGUID)); response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION, NCA_S_UNK_IF); RPCRT4_Send(conn, response, NULL, 0); RPCRT4_FreeHeader(response); break; } 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) { WARN("invalid procnum (%d/%d)\n", msg->ProcNum, sif->If->DispatchTable->DispatchTableCount); response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION, NCA_S_OP_RNG_ERROR); RPCRT4_Send(conn, response, NULL, 0); RPCRT4_FreeHeader(response); } 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])); exception = FALSE; /* dispatch */ __TRY { if (func) func(msg); } __EXCEPT(rpc_filter) { exception = TRUE; if (GetExceptionCode() == STATUS_ACCESS_VIOLATION) status = ERROR_NOACCESS; else status = GetExceptionCode(); response = RPCRT4_BuildFaultHeader(msg->DataRepresentation, RPC2NCA_STATUS(status)); } __ENDTRY if (!exception) response = RPCRT4_BuildResponseHeader(msg->DataRepresentation, msg->BufferLength); /* send response packet */ if (response) { status = RPCRT4_Send(conn, response, exception ? NULL : msg->Buffer, exception ? 0 : msg->BufferLength); RPCRT4_FreeHeader(response); } else ERR("out of memory\n"); msg->RpcInterfaceInformation = NULL; RPCRT4_release_server_interface(sif); break; default: FIXME("unhandled packet type %u\n", hdr->common.ptype); 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); HeapFree(GetProcessHeap(), 0, msg);}static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg){ RpcPacket *pkt = the_arg; RPCRT4_process_packet(pkt->conn, pkt->hdr, pkt->msg); HeapFree(GetProcessHeap(), 0, pkt); return 0;}static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg){ RpcConnection* conn = (RpcConnection*)the_arg; RpcPktHdr *hdr; RpcBinding *pbind; RPC_MESSAGE *msg; RPC_STATUS status; RpcPacket *packet; TRACE("(%p)\n", conn); for (;;) { msg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_MESSAGE)); /* create temporary binding for dispatch, it will be freed in * RPCRT4_process_packet */ RPCRT4_MakeBinding(&pbind, conn); msg->Handle = (RPC_BINDING_HANDLE)pbind; status = RPCRT4_Receive(conn, &hdr, msg); if (status != RPC_S_OK) { WARN("receive failed with error %lx\n", status); HeapFree(GetProcessHeap(), 0, msg); break; }#if 0 RPCRT4_process_packet(conn, hdr, msg);#else packet = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcPacket)); packet->conn = conn; packet->hdr = hdr; packet->msg = msg; QueueUserWorkItem(RPCRT4_worker_thread, packet, WT_EXECUTELONGFUNCTION);#endif msg = NULL; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -