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

📄 rpc.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 *	RPC Manager
 *
 * Copyright 2001  Ove K鍁en, TransGaming Technologies
 * Copyright 2002  Marcus Meissner
 * Copyright 2005  Mike Hearn, Rob Shearman for CodeWeavers
 *
 * 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
 */

#include "config.h"
#include "wine/port.h"

#include <stdarg.h>
#include <string.h>

#define COBJMACROS
#define NONAMELESSUNION
#define NONAMELESSSTRUCT

#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "winsvc.h"
#include "objbase.h"
#include "ole2.h"
#include "rpc.h"
#include "winerror.h"
#include "winreg.h"
#include "wine/unicode.h"

#include "compobj_private.h"

#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(ole);

static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg);

/* we only use one function to dispatch calls for all methods - we use the
 * RPC_IF_OLE flag to tell the RPC runtime that this is the case */
static RPC_DISPATCH_FUNCTION rpc_dispatch_table[1] = { dispatch_rpc }; /* (RO) */
static RPC_DISPATCH_TABLE rpc_dispatch = { 1, rpc_dispatch_table }; /* (RO) */

static struct list registered_interfaces = LIST_INIT(registered_interfaces); /* (CS csRegIf) */
static CRITICAL_SECTION csRegIf;
static CRITICAL_SECTION_DEBUG csRegIf_debug =
{
    0, 0, &csRegIf,
    { &csRegIf_debug.ProcessLocksList, &csRegIf_debug.ProcessLocksList },
      0, 0, { (DWORD_PTR)(__FILE__ ": dcom registered server interfaces") }
};
static CRITICAL_SECTION csRegIf = { &csRegIf_debug, -1, 0, 0, 0, 0 };

static struct list channel_hooks = LIST_INIT(channel_hooks); /* (CS csChannelHook) */
static CRITICAL_SECTION csChannelHook;
static CRITICAL_SECTION_DEBUG csChannelHook_debug =
{
    0, 0, &csChannelHook,
    { &csChannelHook_debug.ProcessLocksList, &csChannelHook_debug.ProcessLocksList },
      0, 0, { (DWORD_PTR)(__FILE__ ": channel hooks") }
};
static CRITICAL_SECTION csChannelHook = { &csChannelHook_debug, -1, 0, 0, 0, 0 };

static WCHAR wszRpcTransport[] = {'n','c','a','l','r','p','c',0};


struct registered_if
{
    struct list entry;
    DWORD refs; /* ref count */
    RPC_SERVER_INTERFACE If; /* interface registered with the RPC runtime */
};

/* get the pipe endpoint specified of the specified apartment */
static inline void get_rpc_endpoint(LPWSTR endpoint, const OXID *oxid)
{
    /* FIXME: should get endpoint from rpcss */
    static const WCHAR wszEndpointFormat[] = {'\\','p','i','p','e','\\','O','L','E','_','%','0','8','l','x','%','0','8','l','x',0};
    wsprintfW(endpoint, wszEndpointFormat, (DWORD)(*oxid >> 32),(DWORD)*oxid);
}

typedef struct
{
    const IRpcChannelBufferVtbl *lpVtbl;
    LONG                  refs;
} RpcChannelBuffer;

typedef struct
{
    RpcChannelBuffer       super; /* superclass */

    RPC_BINDING_HANDLE     bind; /* handle to the remote server */
    OXID                   oxid; /* apartment in which the channel is valid */
    DWORD                  server_pid; /* id of server process */
    DWORD                  dest_context; /* returned from GetDestCtx */
    LPVOID                 dest_context_data; /* returned from GetDestCtx */
    HANDLE                 event; /* cached event handle */
} ClientRpcChannelBuffer;

struct dispatch_params
{
    RPCOLEMESSAGE     *msg; /* message */
    IRpcStubBuffer    *stub; /* stub buffer, if applicable */
    IRpcChannelBuffer *chan; /* server channel buffer, if applicable */
    IID                iid; /* ID of interface being called */
    IUnknown          *iface; /* interface being called */
    HANDLE             handle; /* handle that will become signaled when call finishes */
    RPC_STATUS         status; /* status (out) */
    HRESULT            hr; /* hresult (out) */
};

struct message_state
{
    RPC_BINDING_HANDLE binding_handle;
    ULONG prefix_data_len;
    SChannelHookCallInfo channel_hook_info;
};

typedef struct
{
    ULONG conformance; /* NDR */
    GUID id;
    ULONG size;
    /* [size_is((size+7)&~7)] */ unsigned char data[1];
} WIRE_ORPC_EXTENT;

struct channel_hook_entry
{
    struct list entry;
    GUID id;
    IChannelHook *hook;
};

struct channel_hook_buffer_data
{
    GUID id;
    ULONG extension_size;
};


static HRESULT unmarshal_ORPCTHAT(RPC_MESSAGE *msg, ORPCTHAT *orpcthat,
                                  ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent);

/* Channel Hook Functions */

static ULONG ChannelHooks_ClientGetSize(SChannelHookCallInfo *info,
    struct channel_hook_buffer_data **data, unsigned int *hook_count,
    ULONG *extension_count)
{
    struct channel_hook_entry *entry;
    ULONG total_size = 0;
    unsigned int hook_index = 0;

    *hook_count = 0;
    *extension_count = 0;

    EnterCriticalSection(&csChannelHook);

    LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
        (*hook_count)++;

    if (*hook_count)
        *data = HeapAlloc(GetProcessHeap(), 0, *hook_count * sizeof(struct channel_hook_buffer_data));
    else
        *data = NULL;

    LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
    {
        ULONG extension_size = 0;

        IChannelHook_ClientGetSize(entry->hook, &entry->id, &info->iid, &extension_size);

        TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size);

        extension_size = (extension_size+7)&~7;
        (*data)[hook_index].id = entry->id;
        (*data)[hook_index].extension_size = extension_size;

        /* an extension is only put onto the wire if it has data to write */
        if (extension_size)
        {
            total_size += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[extension_size]);
            (*extension_count)++;
        }

        hook_index++;
    }

    LeaveCriticalSection(&csChannelHook);

    return total_size;
}

static unsigned char * ChannelHooks_ClientFillBuffer(SChannelHookCallInfo *info,
    unsigned char *buffer, struct channel_hook_buffer_data *data,
    unsigned int hook_count)
{
    struct channel_hook_entry *entry;

    EnterCriticalSection(&csChannelHook);

    LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
    {
        unsigned int i;
        ULONG extension_size = 0;
        WIRE_ORPC_EXTENT *wire_orpc_extent = (WIRE_ORPC_EXTENT *)buffer;

        for (i = 0; i < hook_count; i++)
            if (IsEqualGUID(&entry->id, &data[i].id))
                extension_size = data[i].extension_size;

        /* an extension is only put onto the wire if it has data to write */
        if (!extension_size)
            continue;

        IChannelHook_ClientFillBuffer(entry->hook, &entry->id, &info->iid,
            &extension_size, buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]));

        TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size);

        /* FIXME: set unused portion of wire_orpc_extent->data to 0? */

        wire_orpc_extent->conformance = (extension_size+7)&~7;
        wire_orpc_extent->size = extension_size;
        memcpy(&wire_orpc_extent->id, &entry->id, sizeof(wire_orpc_extent->id));
        buffer += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[wire_orpc_extent->conformance]);
    }

    LeaveCriticalSection(&csChannelHook);

    HeapFree(GetProcessHeap(), 0, data);

    return buffer;
}

static void ChannelHooks_ServerNotify(SChannelHookCallInfo *info,
    DWORD lDataRep, WIRE_ORPC_EXTENT *first_wire_orpc_extent,
    ULONG extension_count)
{
    struct channel_hook_entry *entry;
    ULONG i;

    EnterCriticalSection(&csChannelHook);

    LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
    {
        WIRE_ORPC_EXTENT *wire_orpc_extent;
        for (i = 0, wire_orpc_extent = first_wire_orpc_extent;
             i < extension_count;
             i++, wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance])
        {
            if (IsEqualGUID(&entry->id, &wire_orpc_extent->id))
                break;
        }
        if (i == extension_count) wire_orpc_extent = NULL;

        IChannelHook_ServerNotify(entry->hook, &entry->id, &info->iid,
            wire_orpc_extent ? wire_orpc_extent->size : 0,
            wire_orpc_extent ? wire_orpc_extent->data : NULL,
            lDataRep);
    }

    LeaveCriticalSection(&csChannelHook);
}

static ULONG ChannelHooks_ServerGetSize(SChannelHookCallInfo *info,
                                        struct channel_hook_buffer_data **data, unsigned int *hook_count,
                                        ULONG *extension_count)
{
    struct channel_hook_entry *entry;
    ULONG total_size = 0;
    unsigned int hook_index = 0;

    *hook_count = 0;
    *extension_count = 0;

    EnterCriticalSection(&csChannelHook);

    LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
        (*hook_count)++;

    if (*hook_count)
        *data = HeapAlloc(GetProcessHeap(), 0, *hook_count * sizeof(struct channel_hook_buffer_data));
    else
        *data = NULL;

    LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
    {
        ULONG extension_size = 0;

        IChannelHook_ServerGetSize(entry->hook, &entry->id, &info->iid, S_OK,
                                   &extension_size);

        TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size);

        extension_size = (extension_size+7)&~7;
        (*data)[hook_index].id = entry->id;
        (*data)[hook_index].extension_size = extension_size;

        /* an extension is only put onto the wire if it has data to write */
        if (extension_size)
        {
            total_size += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[extension_size]);
            (*extension_count)++;
        }

        hook_index++;
    }

    LeaveCriticalSection(&csChannelHook);

    return total_size;
}

static unsigned char * ChannelHooks_ServerFillBuffer(SChannelHookCallInfo *info,
                                                     unsigned char *buffer, struct channel_hook_buffer_data *data,
                                                     unsigned int hook_count)
{
    struct channel_hook_entry *entry;

    EnterCriticalSection(&csChannelHook);

    LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
    {
        unsigned int i;
        ULONG extension_size = 0;
        WIRE_ORPC_EXTENT *wire_orpc_extent = (WIRE_ORPC_EXTENT *)buffer;

        for (i = 0; i < hook_count; i++)
            if (IsEqualGUID(&entry->id, &data[i].id))
                extension_size = data[i].extension_size;

        /* an extension is only put onto the wire if it has data to write */
        if (!extension_size)
            continue;

        IChannelHook_ServerFillBuffer(entry->hook, &entry->id, &info->iid,
                                      &extension_size, buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]),
                                      S_OK);

        TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size);

        /* FIXME: set unused portion of wire_orpc_extent->data to 0? */

        wire_orpc_extent->conformance = (extension_size+7)&~7;
        wire_orpc_extent->size = extension_size;
        memcpy(&wire_orpc_extent->id, &entry->id, sizeof(wire_orpc_extent->id));
        buffer += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[wire_orpc_extent->conformance]);
    }

    LeaveCriticalSection(&csChannelHook);

    HeapFree(GetProcessHeap(), 0, data);

    return buffer;
}

static void ChannelHooks_ClientNotify(SChannelHookCallInfo *info,
                                      DWORD lDataRep, WIRE_ORPC_EXTENT *first_wire_orpc_extent,
                                      ULONG extension_count, HRESULT hrFault)
{
    struct channel_hook_entry *entry;
    ULONG i;

    EnterCriticalSection(&csChannelHook);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -