⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rpc_server.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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 + -