📄 rpc_binding.c
字号:
/*
* RPC binding API
*
* Copyright 2001 Ove K鍁en, TransGaming Technologies
* Copyright 2003 Mike Hearn
* 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 <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "winerror.h"
#include "winreg.h"
#include "winternl.h"
#include "wine/unicode.h"
#include "rpc.h"
#include "rpcndr.h"
#include "wine/debug.h"
#include "rpc_binding.h"
#include "rpc_message.h"
WINE_DEFAULT_DEBUG_CHANNEL(rpc);
LPSTR RPCRT4_strndupA(LPCSTR src, INT slen)
{
DWORD len;
LPSTR s;
if (!src) return NULL;
if (slen == -1) slen = strlen(src);
len = slen;
s = HeapAlloc(GetProcessHeap(), 0, len+1);
memcpy(s, src, len);
s[len] = 0;
return s;
}
LPSTR RPCRT4_strdupWtoA(LPWSTR src)
{
DWORD len;
LPSTR s;
if (!src) return NULL;
len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
s = HeapAlloc(GetProcessHeap(), 0, len);
WideCharToMultiByte(CP_ACP, 0, src, -1, s, len, NULL, NULL);
return s;
}
LPWSTR RPCRT4_strdupAtoW(LPSTR src)
{
DWORD len;
LPWSTR s;
if (!src) return NULL;
len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
s = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, src, -1, s, len);
return s;
}
LPWSTR RPCRT4_strndupW(LPWSTR src, INT slen)
{
DWORD len;
LPWSTR s;
if (!src) return NULL;
if (slen == -1) slen = strlenW(src);
len = slen;
s = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
memcpy(s, src, len*sizeof(WCHAR));
s[len] = 0;
return s;
}
void RPCRT4_strfree(LPSTR src)
{
HeapFree(GetProcessHeap(), 0, src);
}
RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions, RpcBinding* Binding)
{
RpcConnection* NewConnection;
NewConnection = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection));
NewConnection->server = server;
NewConnection->Protseq = RPCRT4_strdupA(Protseq);
NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
NewConnection->Used = Binding;
NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
TRACE("connection: %p\n", NewConnection);
*Connection = NewConnection;
return RPC_S_OK;
}
RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
{
TRACE("connection: %p\n", Connection);
RPCRT4_CloseConnection(Connection);
RPCRT4_strfree(Connection->Endpoint);
RPCRT4_strfree(Connection->NetworkAddr);
RPCRT4_strfree(Connection->Protseq);
HeapFree(GetProcessHeap(), 0, Connection);
return RPC_S_OK;
}
RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection)
{
TRACE("(Connection == ^%p)\n", Connection);
if (!Connection->conn) {
if (Connection->server) { /* server */
/* protseq=ncalrpc: supposed to use NT LPC ports,
* but we'll implement it with named pipes for now */
if (strcmp(Connection->Protseq, "ncalrpc") == 0) {
static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\";
LPSTR pname;
pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
strcat(strcpy(pname, prefix), Connection->Endpoint);
TRACE("listening on %s\n", pname);
Connection->conn = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES,
RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
HeapFree(GetProcessHeap(), 0, pname);
memset(&Connection->ovl, 0, sizeof(Connection->ovl));
Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
if (!ConnectNamedPipe(Connection->conn, &Connection->ovl[0])) {
WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
if (GetLastError() == ERROR_PIPE_CONNECTED) {
SetEvent(Connection->ovl[0].hEvent);
return RPC_S_OK;
} else if (GetLastError() == ERROR_IO_PENDING) {
return RPC_S_OK;
}
return RPC_S_SERVER_UNAVAILABLE;
}
}
/* protseq=ncacn_np: named pipes */
else if (strcmp(Connection->Protseq, "ncacn_np") == 0) {
static LPCSTR prefix = "\\\\.";
LPSTR pname;
pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
strcat(strcpy(pname, prefix), Connection->Endpoint);
TRACE("listening on %s\n", pname);
Connection->conn = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
HeapFree(GetProcessHeap(), 0, pname);
memset(&Connection->ovl, 0, sizeof(Connection->ovl));
Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
if (!ConnectNamedPipe(Connection->conn, &Connection->ovl[0])) {
if (GetLastError() == ERROR_PIPE_CONNECTED) {
SetEvent(Connection->ovl[0].hEvent);
return RPC_S_OK;
} else if (GetLastError() == ERROR_IO_PENDING) {
return RPC_S_OK;
}
WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
return RPC_S_SERVER_UNAVAILABLE;
}
}
else {
ERR("protseq %s not supported\n", Connection->Protseq);
return RPC_S_PROTSEQ_NOT_SUPPORTED;
}
}
else { /* client */
/* protseq=ncalrpc: supposed to use NT LPC ports,
* but we'll implement it with named pipes for now */
if (strcmp(Connection->Protseq, "ncalrpc") == 0) {
static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\";
LPSTR pname;
HANDLE conn;
DWORD err;
DWORD dwMode;
pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
strcat(strcpy(pname, prefix), Connection->Endpoint);
TRACE("connecting to %s\n", pname);
while (TRUE) {
if (WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, 0, 0);
if (conn != INVALID_HANDLE_VALUE) break;
err = GetLastError();
if (err == ERROR_PIPE_BUSY) continue;
TRACE("connection failed, error=%lx\n", err);
HeapFree(GetProcessHeap(), 0, pname);
return RPC_S_SERVER_TOO_BUSY;
} else {
err = GetLastError();
WARN("connection failed, error=%lx\n", err);
HeapFree(GetProcessHeap(), 0, pname);
return RPC_S_SERVER_UNAVAILABLE;
}
}
/* success */
HeapFree(GetProcessHeap(), 0, pname);
memset(&Connection->ovl, 0, sizeof(Connection->ovl));
/* pipe is connected; change to message-read mode. */
dwMode = PIPE_READMODE_MESSAGE;
SetNamedPipeHandleState(conn, &dwMode, NULL, NULL);
Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
Connection->conn = conn;
}
/* protseq=ncacn_np: named pipes */
else if (strcmp(Connection->Protseq, "ncacn_np") == 0) {
static LPCSTR prefix = "\\\\.";
LPSTR pname;
HANDLE conn;
DWORD err;
DWORD dwMode;
pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
strcat(strcpy(pname, prefix), Connection->Endpoint);
TRACE("connecting to %s\n", pname);
conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, 0, 0);
if (conn == INVALID_HANDLE_VALUE) {
err = GetLastError();
/* we don't need to handle ERROR_PIPE_BUSY here,
* the doc says that it is returned to the app */
WARN("connection failed, error=%lx\n", err);
HeapFree(GetProcessHeap(), 0, pname);
if (err == ERROR_PIPE_BUSY)
return RPC_S_SERVER_TOO_BUSY;
else
return RPC_S_SERVER_UNAVAILABLE;
}
/* success */
HeapFree(GetProcessHeap(), 0, pname);
memset(&Connection->ovl, 0, sizeof(Connection->ovl));
/* pipe is connected; change to message-read mode. */
dwMode = PIPE_READMODE_MESSAGE;
SetNamedPipeHandleState(conn, &dwMode, NULL, NULL);
Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
Connection->conn = conn;
} else {
ERR("protseq %s not supported\n", Connection->Protseq);
return RPC_S_PROTSEQ_NOT_SUPPORTED;
}
}
}
return RPC_S_OK;
}
RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
{
TRACE("(Connection == ^%p)\n", Connection);
if (Connection->conn) {
FlushFileBuffers(Connection->conn);
CloseHandle(Connection->conn);
Connection->conn = 0;
}
if (Connection->ovl[0].hEvent) {
CloseHandle(Connection->ovl[0].hEvent);
Connection->ovl[0].hEvent = 0;
}
if (Connection->ovl[1].hEvent) {
CloseHandle(Connection->ovl[1].hEvent);
Connection->ovl[1].hEvent = 0;
}
return RPC_S_OK;
}
RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
{
RpcConnection* NewConnection;
RPC_STATUS err = RPCRT4_CreateConnection(&NewConnection, OldConnection->server, OldConnection->Protseq,
OldConnection->NetworkAddr, OldConnection->Endpoint, NULL, NULL);
if (err == RPC_S_OK) {
/* because of the way named pipes work, we'll transfer the connected pipe
* to the child, then reopen the server binding to continue listening */
NewConnection->conn = OldConnection->conn;
NewConnection->ovl[0] = OldConnection->ovl[0];
NewConnection->ovl[1] = OldConnection->ovl[1];
OldConnection->conn = 0;
memset(&OldConnection->ovl, 0, sizeof(OldConnection->ovl));
*Connection = NewConnection;
RPCRT4_OpenConnection(OldConnection);
}
return err;
}
static RPC_STATUS RPCRT4_AllocBinding(RpcBinding** Binding, BOOL server)
{
RpcBinding* NewBinding;
NewBinding = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcBinding));
NewBinding->refs = 1;
NewBinding->server = server;
*Binding = NewBinding;
return RPC_S_OK;
}
RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPSTR Protseq)
{
RpcBinding* NewBinding;
RPCRT4_AllocBinding(&NewBinding, server);
NewBinding->Protseq = RPCRT4_strdupA(Protseq);
TRACE("binding: %p\n", NewBinding);
*Binding = NewBinding;
return RPC_S_OK;
}
RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPWSTR Protseq)
{
RpcBinding* NewBinding;
RPCRT4_AllocBinding(&NewBinding, server);
NewBinding->Protseq = RPCRT4_strdupWtoA(Protseq);
TRACE("binding: %p\n", NewBinding);
*Binding = NewBinding;
return RPC_S_OK;
}
RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions)
{
TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding,
debugstr_a(NetworkAddr), debugstr_a(Endpoint), debugstr_a(NetworkOptions));
RPCRT4_strfree(Binding->NetworkAddr);
Binding->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
RPCRT4_strfree(Binding->Endpoint);
if (Endpoint) {
Binding->Endpoint = RPCRT4_strdupA(Endpoint);
} else {
Binding->Endpoint = RPCRT4_strdupA("");
}
if (!Binding->Endpoint) ERR("out of memory?\n");
return RPC_S_OK;
}
RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPWSTR NetworkAddr, LPWSTR Endpoint, LPWSTR NetworkOptions)
{
TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding,
debugstr_w(NetworkAddr), debugstr_w(Endpoint), debugstr_w(NetworkOptions));
RPCRT4_strfree(Binding->NetworkAddr);
Binding->NetworkAddr = RPCRT4_strdupWtoA(NetworkAddr);
RPCRT4_strfree(Binding->Endpoint);
if (Endpoint) {
Binding->Endpoint = RPCRT4_strdupWtoA(Endpoint);
} else {
Binding->Endpoint = RPCRT4_strdupA("");
}
if (!Binding->Endpoint) ERR("out of memory?\n");
return RPC_S_OK;
}
RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPSTR Endpoint)
{
TRACE("(RpcBinding == ^%p, EndPoint == \"%s\"\n", Binding, Endpoint);
RPCRT4_strfree(Binding->Endpoint);
Binding->Endpoint = RPCRT4_strdupA(Endpoint);
return RPC_S_OK;
}
RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, UUID* ObjectUuid)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -