📄 rpc.c
字号:
/*
* 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 + -