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

📄 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., 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 + -