-/*\r
- * RPC messages\r
- *\r
- * Copyright 2001-2002 Ove Kåven, TransGaming Technologies\r
- * Copyright 2004 Filip Navara\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
- *\r
- * TODO:\r
- * - figure out whether we *really* got this right\r
- * - check for errors and throw exceptions\r
- */\r
-\r
-#include <stdarg.h>\r
-#include <stdio.h>\r
-#include <string.h>\r
-\r
-#include "windef.h"\r
-#include "winbase.h"\r
-#include "winerror.h"\r
-#include "winreg.h"\r
-\r
-#include "rpc.h"\r
-#include "rpcndr.h"\r
-#include "rpcdcep.h"\r
-\r
-#include "wine/debug.h"\r
-\r
-#include "rpc_binding.h"\r
-#include "rpc_misc.h"\r
-#include "rpc_defs.h"\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(ole);\r
-\r
-DWORD RPCRT4_GetHeaderSize(RpcPktHdr *Header)\r
-{\r
- static const DWORD header_sizes[] = {\r
- sizeof(Header->request), 0, sizeof(Header->response),\r
- sizeof(Header->fault), 0, 0, 0, 0, 0, 0, 0, sizeof(Header->bind),\r
- sizeof(Header->bind_ack), sizeof(Header->bind_nack),\r
- 0, 0, 0, 0, 0\r
- };\r
- ULONG ret = 0;\r
- \r
- if (Header->common.ptype < sizeof(header_sizes) / sizeof(header_sizes[0])) {\r
- ret = header_sizes[Header->common.ptype];\r
- if (ret == 0)\r
- FIXME("unhandled packet type\n");\r
- if (Header->common.flags & RPC_FLG_OBJECT_UUID)\r
- ret += sizeof(UUID);\r
- } else {\r
- TRACE("invalid packet type\n");\r
- }\r
-\r
- return ret;\r
-}\r
-\r
-VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType,\r
- unsigned long DataRepresentation)\r
-{\r
- Header->common.rpc_ver = RPC_VER_MAJOR;\r
- Header->common.rpc_ver_minor = RPC_VER_MINOR;\r
- Header->common.ptype = PacketType;\r
- Header->common.drep[0] = LOBYTE(LOWORD(DataRepresentation));\r
- Header->common.drep[1] = HIBYTE(LOWORD(DataRepresentation));\r
- Header->common.drep[2] = LOBYTE(HIWORD(DataRepresentation));\r
- Header->common.drep[3] = HIBYTE(HIWORD(DataRepresentation));\r
- Header->common.auth_len = 0;\r
- Header->common.call_id = 1;\r
- Header->common.flags = 0;\r
- /* Flags and fragment length are computed in RPCRT4_Send. */\r
-} \r
-\r
-RpcPktHdr *RPCRT4_BuildRequestHeader(unsigned long DataRepresentation,\r
- unsigned long BufferLength,\r
- unsigned short ProcNum,\r
- UUID *ObjectUuid)\r
-{\r
- RpcPktHdr *header;\r
- BOOL has_object;\r
- RPC_STATUS status;\r
-\r
- has_object = (ObjectUuid != NULL && !UuidIsNil(ObjectUuid, &status));\r
- header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,\r
- sizeof(header->request) + (has_object ? sizeof(UUID) : 0));\r
- if (header == NULL) {\r
- return NULL;\r
- }\r
-\r
- RPCRT4_BuildCommonHeader(header, PKT_REQUEST, DataRepresentation);\r
- header->common.frag_len = sizeof(header->request);\r
- header->request.alloc_hint = BufferLength;\r
- header->request.context_id = 0;\r
- header->request.opnum = ProcNum;\r
- if (has_object) {\r
- header->common.flags |= RPC_FLG_OBJECT_UUID;\r
- header->common.frag_len += sizeof(UUID);\r
- memcpy(&header->request + 1, ObjectUuid, sizeof(UUID));\r
- }\r
-\r
- return header;\r
-}\r
-\r
-RpcPktHdr *RPCRT4_BuildResponseHeader(unsigned long DataRepresentation,\r
- unsigned long BufferLength)\r
-{\r
- RpcPktHdr *header;\r
-\r
- header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->response));\r
- if (header == NULL) {\r
- return NULL;\r
- }\r
-\r
- RPCRT4_BuildCommonHeader(header, PKT_RESPONSE, DataRepresentation);\r
- header->common.frag_len = sizeof(header->response);\r
- header->response.alloc_hint = BufferLength;\r
-\r
- return header;\r
-}\r
-\r
-RpcPktHdr *RPCRT4_BuildFaultHeader(unsigned long DataRepresentation,\r
- RPC_STATUS Status)\r
-{\r
- RpcPktHdr *header;\r
-\r
- header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->fault));\r
- if (header == NULL) {\r
- return NULL;\r
- }\r
-\r
- RPCRT4_BuildCommonHeader(header, PKT_FAULT, DataRepresentation);\r
- header->common.frag_len = sizeof(header->fault);\r
- header->fault.status = Status;\r
-\r
- return header;\r
-}\r
-\r
-RpcPktHdr *RPCRT4_BuildBindHeader(unsigned long DataRepresentation,\r
- unsigned short MaxTransmissionSize,\r
- unsigned short MaxReceiveSize,\r
- RPC_SYNTAX_IDENTIFIER *AbstractId,\r
- RPC_SYNTAX_IDENTIFIER *TransferId)\r
-{\r
- RpcPktHdr *header;\r
-\r
- header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->bind));\r
- if (header == NULL) {\r
- return NULL;\r
- }\r
-\r
- RPCRT4_BuildCommonHeader(header, PKT_BIND, DataRepresentation);\r
- header->common.frag_len = sizeof(header->bind);\r
- header->bind.max_tsize = MaxTransmissionSize;\r
- header->bind.max_rsize = MaxReceiveSize;\r
- header->bind.num_elements = 1;\r
- header->bind.num_syntaxes = 1;\r
- memcpy(&header->bind.abstract, AbstractId, sizeof(RPC_SYNTAX_IDENTIFIER));\r
- memcpy(&header->bind.transfer, TransferId, sizeof(RPC_SYNTAX_IDENTIFIER));\r
-\r
- return header;\r
-}\r
-\r
-RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation,\r
- unsigned char RpcVersion,\r
- unsigned char RpcVersionMinor)\r
-{\r
- RpcPktHdr *header;\r
-\r
- header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->bind_nack));\r
- if (header == NULL) {\r
- return NULL;\r
- }\r
-\r
- RPCRT4_BuildCommonHeader(header, PKT_BIND_NACK, DataRepresentation);\r
- header->common.frag_len = sizeof(header->bind_nack);\r
- header->bind_nack.protocols_count = 1;\r
- header->bind_nack.protocols[0].rpc_ver = RpcVersion;\r
- header->bind_nack.protocols[0].rpc_ver_minor = RpcVersionMinor;\r
-\r
- return header;\r
-}\r
-\r
-RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation,\r
- unsigned short MaxTransmissionSize,\r
- unsigned short MaxReceiveSize,\r
- LPSTR ServerAddress,\r
- unsigned long Result,\r
- unsigned long Reason,\r
- RPC_SYNTAX_IDENTIFIER *TransferId)\r
-{\r
- RpcPktHdr *header;\r
- unsigned long header_size;\r
- RpcAddressString *server_address;\r
- RpcResults *results;\r
- RPC_SYNTAX_IDENTIFIER *transfer_id;\r
-\r
- header_size = sizeof(header->bind_ack) + sizeof(RpcResults) +\r
- sizeof(RPC_SYNTAX_IDENTIFIER) + sizeof(RpcAddressString) +\r
- strlen(ServerAddress);\r
-\r
- header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, header_size);\r
- if (header == NULL) {\r
- return NULL;\r
- }\r
-\r
- RPCRT4_BuildCommonHeader(header, PKT_BIND_ACK, DataRepresentation);\r
- header->common.frag_len = header_size;\r
- header->bind_ack.max_tsize = MaxTransmissionSize;\r
- header->bind_ack.max_rsize = MaxReceiveSize;\r
- server_address = (RpcAddressString*)(&header->bind_ack + 1);\r
- server_address->length = strlen(ServerAddress) + 1;\r
- strcpy(server_address->string, ServerAddress);\r
- results = (RpcResults*)((ULONG_PTR)server_address + sizeof(RpcAddressString) + server_address->length - 1);\r
- results->num_results = 1;\r
- results->results[0].result = Result;\r
- results->results[0].reason = Reason;\r
- transfer_id = (RPC_SYNTAX_IDENTIFIER*)(results + 1);\r
- memcpy(transfer_id, TransferId, sizeof(RPC_SYNTAX_IDENTIFIER));\r
-\r
- return header;\r
-}\r
-\r
-VOID RPCRT4_FreeHeader(RpcPktHdr *Header)\r
-{\r
- HeapFree(GetProcessHeap(), 0, Header);\r
-}\r
-\r
-/***********************************************************************\r
- * RPCRT4_Send (internal)\r
- * \r
- * Transmit a packet over connection in acceptable fragments.\r
- */\r
-RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header,\r
- void *Buffer, unsigned int BufferLength)\r
-{\r
- PUCHAR buffer_pos;\r
- DWORD hdr_size, count;\r
-\r
- buffer_pos = Buffer;\r
- /* The packet building functions save the packet header size, so we can use it. */\r
- hdr_size = Header->common.frag_len;\r
- Header->common.flags |= RPC_FLG_FIRST;\r
- Header->common.flags &= ~RPC_FLG_LAST;\r
- while (!(Header->common.flags & RPC_FLG_LAST)) { \r
- /* decide if we need to split the packet into fragments */\r
- if ((BufferLength + hdr_size) <= Connection->MaxTransmissionSize) {\r
- Header->common.flags |= RPC_FLG_LAST;\r
- Header->common.frag_len = BufferLength + hdr_size;\r
- } else {\r
- Header->common.frag_len = Connection->MaxTransmissionSize;\r
- buffer_pos += Header->common.frag_len - hdr_size;\r
- BufferLength -= Header->common.frag_len - hdr_size;\r
- }\r
-\r
- /* transmit packet header */\r
- if (!WriteFile(Connection->conn, Header, hdr_size, &count, &Connection->ovl)) {\r
- WARN("WriteFile failed with error %ld\n", GetLastError());\r
- return GetLastError();\r
- }\r
- if (!GetOverlappedResult(Connection->conn, &Connection->ovl, &count, TRUE)) {\r
- WARN("GetOverlappedResult failed with error %ld\n", GetLastError());\r
- return GetLastError();\r
- }\r
-\r
- /* fragment consisted of header only and is the last one */\r
- if (hdr_size == Header->common.frag_len &&\r
- Header->common.flags & RPC_FLG_LAST) {\r
- return RPC_S_OK;\r
- }\r
-\r
- /* send the fragment data */\r
- if (!WriteFile(Connection->conn, buffer_pos, Header->common.frag_len - hdr_size, &count, &Connection->ovl)) {\r
- WARN("WriteFile failed with error %ld\n", GetLastError());\r
- return GetLastError();\r
- }\r
- if (!GetOverlappedResult(Connection->conn, &Connection->ovl, &count, TRUE)) {\r
- WARN("GetOverlappedResult failed with error %ld\n", GetLastError());\r
- return GetLastError();\r
- }\r
-\r
- Header->common.flags &= ~RPC_FLG_FIRST;\r
- }\r
-\r
- return RPC_S_OK;\r
-}\r
-\r
-/***********************************************************************\r
- * RPCRT4_Receive (internal)\r
- * \r
- * Receive a packet from connection and merge the fragments.\r
- */\r
-RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header,\r
- PRPC_MESSAGE pMsg)\r
-{\r
- RPC_STATUS status;\r
- DWORD dwRead, hdr_length;\r
- unsigned short first_flag;\r
- unsigned long data_length;\r
- unsigned long buffer_length;\r
- unsigned char *buffer_ptr;\r
- RpcPktCommonHdr common_hdr;\r
-\r
- *Header = NULL;\r
-\r
- TRACE("(%p, %p, %p)\n", Connection, Header, pMsg);\r
-\r
- /* read packet common header */\r
- if (!ReadFile(Connection->conn, &common_hdr, sizeof(common_hdr), &dwRead, &Connection->ovl)) {\r
- WARN("ReadFile failed with error %ld\n", GetLastError());\r
- status = RPC_S_PROTOCOL_ERROR;\r
- goto fail;\r
- }\r
- if (!GetOverlappedResult(Connection->conn, &Connection->ovl, &dwRead, TRUE)) {\r
- if (GetLastError() != ERROR_MORE_DATA) {\r
- WARN("GetOverlappedResult failed with error %ld\n", GetLastError());\r
- status = RPC_S_PROTOCOL_ERROR;\r
- goto fail;\r
- }\r
- }\r
- if (dwRead != sizeof(common_hdr)) {\r
- WARN("Short read of header, %ld/%d bytes\n", dwRead, sizeof(common_hdr));\r
- status = RPC_S_PROTOCOL_ERROR;\r
- goto fail;\r
- }\r
-\r
- /* verify if the header really makes sense */\r
- if (common_hdr.rpc_ver != RPC_VER_MAJOR ||\r
- common_hdr.rpc_ver_minor != RPC_VER_MINOR) {\r
- WARN("unhandled packet version\n");\r
- status = RPC_S_PROTOCOL_ERROR;\r
- goto fail;\r
- }\r
-\r
- hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr);\r
- if (hdr_length == 0) {\r
- WARN("header length == 0\n");\r
- status = RPC_S_PROTOCOL_ERROR;\r
- goto fail;\r
- }\r
-\r
- *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length);\r
- memcpy(*Header, &common_hdr, sizeof(common_hdr));\r
-\r
- /* read the rest of packet header */\r
- if (!ReadFile(Connection->conn, &(*Header)->common + 1,\r
- hdr_length - sizeof(common_hdr), &dwRead, &Connection->ovl)) {\r
- WARN("ReadFile failed with error %ld\n", GetLastError());\r
- status = RPC_S_PROTOCOL_ERROR;\r
- goto fail;\r
- }\r
- if (!GetOverlappedResult(Connection->conn, &Connection->ovl, &dwRead, TRUE)) {\r
- if (GetLastError() != ERROR_MORE_DATA) {\r
- WARN("GetOverlappedResult failed with error %ld\n", GetLastError());\r
- status = RPC_S_PROTOCOL_ERROR;\r
- goto fail;\r
- }\r
- }\r
- if (dwRead != hdr_length - sizeof(common_hdr)) {\r
- WARN("bad header length, %ld/%ld bytes\n", dwRead, hdr_length - sizeof(common_hdr));\r
- status = RPC_S_PROTOCOL_ERROR;\r
- goto fail;\r
- }\r
-\r
-\r
- /* read packet body */\r
- switch (common_hdr.ptype) {\r
- case PKT_RESPONSE:\r
- pMsg->BufferLength = (*Header)->response.alloc_hint;\r
- break;\r
- case PKT_REQUEST:\r
- pMsg->BufferLength = (*Header)->request.alloc_hint;\r
- break;\r
- default:\r
- pMsg->BufferLength = common_hdr.frag_len - hdr_length;\r
- }\r
-\r
- TRACE("buffer length = %u\n", pMsg->BufferLength);\r
-\r
- status = I_RpcGetBuffer(pMsg);\r
- if (status != RPC_S_OK) goto fail;\r
-\r
- first_flag = RPC_FLG_FIRST;\r
- buffer_length = 0;\r
- buffer_ptr = pMsg->Buffer;\r
- while (buffer_length < pMsg->BufferLength)\r
- {\r
- data_length = (*Header)->common.frag_len - hdr_length;\r
- if (((*Header)->common.flags & RPC_FLG_FIRST) != first_flag ||\r
- data_length + buffer_length > pMsg->BufferLength) {\r
- TRACE("invalid packet flags or buffer length\n");\r
- status = RPC_S_PROTOCOL_ERROR;\r
- goto fail;\r
- }\r
-\r
- if (data_length == 0) dwRead = 0; else {\r
- if (!ReadFile(Connection->conn, buffer_ptr, data_length, &dwRead, &Connection->ovl)) {\r
- WARN("ReadFile failed with error %ld\n", GetLastError());\r
- status = RPC_S_PROTOCOL_ERROR;\r
- goto fail;\r
- }\r
- if (!GetOverlappedResult(Connection->conn, &Connection->ovl, &dwRead, TRUE)) {\r
- if (GetLastError() != ERROR_MORE_DATA) {\r
- WARN("GetOverlappedResult failed with error %ld\n", GetLastError());\r
- status = RPC_S_PROTOCOL_ERROR;\r
- goto fail;\r
- }\r
- }\r
- }\r
- if (dwRead != data_length) {\r
- WARN("bad data length, %ld/%ld\n", dwRead, data_length);\r
- status = RPC_S_PROTOCOL_ERROR;\r
- goto fail;\r
- }\r
-\r
- /* when there is no more data left, it should be the last packet */\r
- if (buffer_length == pMsg->BufferLength &&\r
- ((*Header)->common.flags & RPC_FLG_LAST) == 0) {\r
- WARN("no more data left, but not last packet\n");\r
- status = RPC_S_PROTOCOL_ERROR;\r
- goto fail;\r
- }\r
-\r
- buffer_length += data_length;\r
- if (buffer_length < pMsg->BufferLength) {\r
- TRACE("next header\n");\r
-\r
- /* read the header of next packet */\r
- if (!ReadFile(Connection->conn, *Header, hdr_length, &dwRead, &Connection->ovl)) {\r
- WARN("ReadFile failed with error %ld\n", GetLastError());\r
- status = GetLastError();\r
- goto fail;\r
- }\r
- if (!GetOverlappedResult(Connection->conn, &Connection->ovl, &dwRead, TRUE)) {\r
- if (GetLastError() != ERROR_MORE_DATA) {\r
- WARN("GetOverlappedResult failed with error %ld\n", GetLastError());\r
- status = RPC_S_PROTOCOL_ERROR;\r
- goto fail;\r
- }\r
- }\r
- if (dwRead != hdr_length) {\r
- WARN("invalid packet header size (%ld)\n", dwRead);\r
- status = RPC_S_PROTOCOL_ERROR;\r
- goto fail;\r
- }\r
-\r
- buffer_ptr += data_length;\r
- first_flag = 0;\r
- }\r
- }\r
-\r
- /* success */\r
- status = RPC_S_OK;\r
-\r
-fail:\r
- if (status != RPC_S_OK && *Header) {\r
- RPCRT4_FreeHeader(*Header);\r
- *Header = NULL;\r
- }\r
- return status;\r
-}\r
-\r
-/***********************************************************************\r
- * I_RpcGetBuffer [RPCRT4.@]\r
- */\r
-RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg)\r
-{\r
- RpcBinding* bind = (RpcBinding*)pMsg->Handle;\r
-\r
- TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength);\r
- /* FIXME: pfnAllocate? */\r
- if (bind->server) {\r
- /* it turns out that the original buffer data must still be available\r
- * while the RPC server is marshalling a reply, so we should not deallocate\r
- * it, we'll leave deallocating the original buffer to the RPC server */\r
- pMsg->Buffer = HeapAlloc(GetProcessHeap(), 0, pMsg->BufferLength);\r
- } else {\r
- HeapFree(GetProcessHeap(), 0, pMsg->Buffer);\r
- pMsg->Buffer = HeapAlloc(GetProcessHeap(), 0, pMsg->BufferLength);\r
- }\r
- TRACE("Buffer=%p\n", pMsg->Buffer);\r
- /* FIXME: which errors to return? */\r
- return pMsg->Buffer ? S_OK : E_OUTOFMEMORY;\r
-}\r
-\r
-/***********************************************************************\r
- * I_RpcFreeBuffer [RPCRT4.@]\r
- */\r
-RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg)\r
-{\r
- TRACE("(%p) Buffer=%p\n", pMsg, pMsg->Buffer);\r
- /* FIXME: pfnFree? */\r
- HeapFree(GetProcessHeap(), 0, pMsg->Buffer);\r
- pMsg->Buffer = NULL;\r
- return S_OK;\r
-}\r
-\r
-/***********************************************************************\r
- * I_RpcSend [RPCRT4.@]\r
- */\r
-RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg)\r
-{\r
- RpcBinding* bind = (RpcBinding*)pMsg->Handle;\r
- RpcConnection* conn;\r
- RPC_CLIENT_INTERFACE* cif = NULL;\r
- RPC_SERVER_INTERFACE* sif = NULL;\r
- RPC_STATUS status;\r
- RpcPktHdr *hdr;\r
-\r
- TRACE("(%p)\n", pMsg);\r
- if (!bind) return RPC_S_INVALID_BINDING;\r
-\r
- if (bind->server) {\r
- sif = pMsg->RpcInterfaceInformation;\r
- if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */\r
- status = RPCRT4_OpenBinding(bind, &conn, &sif->TransferSyntax,\r
- &sif->InterfaceId);\r
- } else {\r
- cif = pMsg->RpcInterfaceInformation;\r
- if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */\r
- status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax,\r
- &cif->InterfaceId);\r
- }\r
-\r
- if (status != RPC_S_OK) return status;\r
-\r
- if (bind->server) {\r
- if (pMsg->RpcFlags & WINE_RPCFLAG_EXCEPTION) {\r
- hdr = RPCRT4_BuildFaultHeader(pMsg->DataRepresentation,\r
- RPC_S_CALL_FAILED);\r
- } else {\r
- hdr = RPCRT4_BuildResponseHeader(pMsg->DataRepresentation,\r
- pMsg->BufferLength);\r
- }\r
- } else {\r
- hdr = RPCRT4_BuildRequestHeader(pMsg->DataRepresentation,\r
- pMsg->BufferLength, pMsg->ProcNum,\r
- &bind->ObjectUuid);\r
- }\r
-\r
- status = RPCRT4_Send(conn, hdr, pMsg->Buffer, pMsg->BufferLength);\r
-\r
- RPCRT4_FreeHeader(hdr);\r
-\r
- /* success */\r
- if (!bind->server) {\r
- /* save the connection, so the response can be read from it */\r
- pMsg->ReservedForRuntime = conn;\r
- return RPC_S_OK;\r
- }\r
- RPCRT4_CloseBinding(bind, conn);\r
- status = RPC_S_OK;\r
-\r
- return status;\r
-}\r
-\r
-/***********************************************************************\r
- * I_RpcReceive [RPCRT4.@]\r
- */\r
-RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg)\r
-{\r
- RpcBinding* bind = (RpcBinding*)pMsg->Handle;\r
- RpcConnection* conn;\r
- RPC_CLIENT_INTERFACE* cif = NULL;\r
- RPC_SERVER_INTERFACE* sif = NULL;\r
- RPC_STATUS status;\r
- RpcPktHdr *hdr = NULL;\r
-\r
- TRACE("(%p)\n", pMsg);\r
- if (!bind) return RPC_S_INVALID_BINDING;\r
-\r
- if (pMsg->ReservedForRuntime) {\r
- conn = pMsg->ReservedForRuntime;\r
- pMsg->ReservedForRuntime = NULL;\r
- } else {\r
- if (bind->server) {\r
- sif = pMsg->RpcInterfaceInformation;\r
- if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */\r
- status = RPCRT4_OpenBinding(bind, &conn, &sif->TransferSyntax,\r
- &sif->InterfaceId);\r
- } else {\r
- cif = pMsg->RpcInterfaceInformation;\r
- if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */\r
- status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax,\r
- &cif->InterfaceId);\r
- }\r
- if (status != RPC_S_OK) return status;\r
- }\r
-\r
- status = RPCRT4_Receive(conn, &hdr, pMsg);\r
- if (status != RPC_S_OK) {\r
- WARN("receive failed with error %lx\n", status);\r
- goto fail;\r
- }\r
-\r
- status = RPC_S_PROTOCOL_ERROR;\r
-\r
- switch (hdr->common.ptype) {\r
- case PKT_RESPONSE:\r
- if (bind->server) goto fail;\r
- break;\r
- case PKT_REQUEST:\r
- if (!bind->server) goto fail;\r
- break;\r
- case PKT_FAULT:\r
- pMsg->RpcFlags |= WINE_RPCFLAG_EXCEPTION;\r
- ERR ("we got fault packet with status %lx\n", hdr->fault.status);\r
- status = RPC_S_CALL_FAILED; /* ? */\r
- goto fail;\r
- default:\r
- WARN("bad packet type %d\n", hdr->common.ptype);\r
- goto fail;\r
- }\r
-\r
- /* success */\r
- status = RPC_S_OK;\r
-\r
-fail:\r
- if (hdr) {\r
- RPCRT4_FreeHeader(hdr);\r
- }\r
- RPCRT4_CloseBinding(bind, conn);\r
- return status;\r
-}\r
-\r
-/***********************************************************************\r
- * I_RpcSendReceive [RPCRT4.@]\r
- */\r
-RPC_STATUS WINAPI I_RpcSendReceive(PRPC_MESSAGE pMsg)\r
-{\r
- RPC_STATUS status;\r
-\r
- TRACE("(%p)\n", pMsg);\r
- status = I_RpcSend(pMsg);\r
- if (status == RPC_S_OK)\r
- status = I_RpcReceive(pMsg);\r
- return status;\r
-}\r
+/*
+ * RPC messages
+ *
+ * Copyright 2001-2002 Ove Kåven, 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:
+ * - figure out whether we *really* got this right
+ * - check for errors and throw exceptions
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "winreg.h"
+
+#include "rpc.h"
+#include "rpcndr.h"
+#include "rpcdcep.h"
+
+#include "wine/debug.h"
+
+#include "rpc_binding.h"
+#include "rpc_misc.h"
+#include "rpc_defs.h"
+#include "rpc_message.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(rpc);
+
+static DWORD RPCRT4_GetHeaderSize(RpcPktHdr *Header)
+{
+ static const DWORD header_sizes[] = {
+ sizeof(Header->request), 0, sizeof(Header->response),
+ sizeof(Header->fault), 0, 0, 0, 0, 0, 0, 0, sizeof(Header->bind),
+ sizeof(Header->bind_ack), sizeof(Header->bind_nack),
+ 0, 0, 0, 0, 0
+ };
+ ULONG ret = 0;
+
+ if (Header->common.ptype < sizeof(header_sizes) / sizeof(header_sizes[0])) {
+ ret = header_sizes[Header->common.ptype];
+ if (ret == 0)
+ FIXME("unhandled packet type\n");
+ if (Header->common.flags & RPC_FLG_OBJECT_UUID)
+ ret += sizeof(UUID);
+ } else {
+ TRACE("invalid packet type\n");
+ }
+
+ return ret;
+}
+
+static VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType,
+ unsigned long DataRepresentation)
+{
+ Header->common.rpc_ver = RPC_VER_MAJOR;
+ Header->common.rpc_ver_minor = RPC_VER_MINOR;
+ Header->common.ptype = PacketType;
+ Header->common.drep[0] = LOBYTE(LOWORD(DataRepresentation));
+ Header->common.drep[1] = HIBYTE(LOWORD(DataRepresentation));
+ Header->common.drep[2] = LOBYTE(HIWORD(DataRepresentation));
+ Header->common.drep[3] = HIBYTE(HIWORD(DataRepresentation));
+ Header->common.auth_len = 0;
+ Header->common.call_id = 1;
+ Header->common.flags = 0;
+ /* Flags and fragment length are computed in RPCRT4_Send. */
+}
+
+static RpcPktHdr *RPCRT4_BuildRequestHeader(unsigned long DataRepresentation,
+ unsigned long BufferLength,
+ unsigned short ProcNum,
+ UUID *ObjectUuid)
+{
+ RpcPktHdr *header;
+ BOOL has_object;
+ RPC_STATUS status;
+
+ has_object = (ObjectUuid != NULL && !UuidIsNil(ObjectUuid, &status));
+ header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ sizeof(header->request) + (has_object ? sizeof(UUID) : 0));
+ if (header == NULL) {
+ return NULL;
+ }
+
+ RPCRT4_BuildCommonHeader(header, PKT_REQUEST, DataRepresentation);
+ header->common.frag_len = sizeof(header->request);
+ header->request.alloc_hint = BufferLength;
+ header->request.context_id = 0;
+ header->request.opnum = ProcNum;
+ if (has_object) {
+ header->common.flags |= RPC_FLG_OBJECT_UUID;
+ header->common.frag_len += sizeof(UUID);
+ memcpy(&header->request + 1, ObjectUuid, sizeof(UUID));
+ }
+
+ return header;
+}
+
+static RpcPktHdr *RPCRT4_BuildResponseHeader(unsigned long DataRepresentation,
+ unsigned long BufferLength)
+{
+ RpcPktHdr *header;
+
+ header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->response));
+ if (header == NULL) {
+ return NULL;
+ }
+
+ RPCRT4_BuildCommonHeader(header, PKT_RESPONSE, DataRepresentation);
+ header->common.frag_len = sizeof(header->response);
+ header->response.alloc_hint = BufferLength;
+
+ return header;
+}
+
+RpcPktHdr *RPCRT4_BuildFaultHeader(unsigned long DataRepresentation,
+ RPC_STATUS Status)
+{
+ RpcPktHdr *header;
+
+ header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->fault));
+ if (header == NULL) {
+ return NULL;
+ }
+
+ RPCRT4_BuildCommonHeader(header, PKT_FAULT, DataRepresentation);
+ header->common.frag_len = sizeof(header->fault);
+ header->fault.status = Status;
+
+ return header;
+}
+
+RpcPktHdr *RPCRT4_BuildBindHeader(unsigned long DataRepresentation,
+ unsigned short MaxTransmissionSize,
+ unsigned short MaxReceiveSize,
+ RPC_SYNTAX_IDENTIFIER *AbstractId,
+ RPC_SYNTAX_IDENTIFIER *TransferId)
+{
+ RpcPktHdr *header;
+
+ header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->bind));
+ if (header == NULL) {
+ return NULL;
+ }
+
+ RPCRT4_BuildCommonHeader(header, PKT_BIND, DataRepresentation);
+ header->common.frag_len = sizeof(header->bind);
+ header->bind.max_tsize = MaxTransmissionSize;
+ header->bind.max_rsize = MaxReceiveSize;
+ header->bind.num_elements = 1;
+ header->bind.num_syntaxes = 1;
+ memcpy(&header->bind.abstract, AbstractId, sizeof(RPC_SYNTAX_IDENTIFIER));
+ memcpy(&header->bind.transfer, TransferId, sizeof(RPC_SYNTAX_IDENTIFIER));
+
+ return header;
+}
+
+RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation,
+ unsigned char RpcVersion,
+ unsigned char RpcVersionMinor)
+{
+ RpcPktHdr *header;
+
+ header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->bind_nack));
+ if (header == NULL) {
+ return NULL;
+ }
+
+ RPCRT4_BuildCommonHeader(header, PKT_BIND_NACK, DataRepresentation);
+ header->common.frag_len = sizeof(header->bind_nack);
+ header->bind_nack.protocols_count = 1;
+ header->bind_nack.protocols[0].rpc_ver = RpcVersion;
+ header->bind_nack.protocols[0].rpc_ver_minor = RpcVersionMinor;
+
+ return header;
+}
+
+RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation,
+ unsigned short MaxTransmissionSize,
+ unsigned short MaxReceiveSize,
+ LPSTR ServerAddress,
+ unsigned long Result,
+ unsigned long Reason,
+ RPC_SYNTAX_IDENTIFIER *TransferId)
+{
+ RpcPktHdr *header;
+ unsigned long header_size;
+ RpcAddressString *server_address;
+ RpcResults *results;
+ RPC_SYNTAX_IDENTIFIER *transfer_id;
+
+ header_size = sizeof(header->bind_ack) + sizeof(RpcResults) +
+ sizeof(RPC_SYNTAX_IDENTIFIER) + sizeof(RpcAddressString) +
+ strlen(ServerAddress);
+
+ header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, header_size);
+ if (header == NULL) {
+ return NULL;
+ }
+
+ RPCRT4_BuildCommonHeader(header, PKT_BIND_ACK, DataRepresentation);
+ header->common.frag_len = header_size;
+ header->bind_ack.max_tsize = MaxTransmissionSize;
+ header->bind_ack.max_rsize = MaxReceiveSize;
+ server_address = (RpcAddressString*)(&header->bind_ack + 1);
+ server_address->length = strlen(ServerAddress) + 1;
+ strcpy(server_address->string, ServerAddress);
+ results = (RpcResults*)((ULONG_PTR)server_address + sizeof(RpcAddressString) + server_address->length - 1);
+ results->num_results = 1;
+ results->results[0].result = Result;
+ results->results[0].reason = Reason;
+ transfer_id = (RPC_SYNTAX_IDENTIFIER*)(results + 1);
+ memcpy(transfer_id, TransferId, sizeof(RPC_SYNTAX_IDENTIFIER));
+
+ return header;
+}
+
+VOID RPCRT4_FreeHeader(RpcPktHdr *Header)
+{
+ HeapFree(GetProcessHeap(), 0, Header);
+}
+
+/***********************************************************************
+ * RPCRT4_Send (internal)
+ *
+ * Transmit a packet over connection in acceptable fragments.
+ */
+RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header,
+ void *Buffer, unsigned int BufferLength)
+{
+ PUCHAR buffer_pos;
+ DWORD hdr_size, count;
+
+ buffer_pos = Buffer;
+ /* The packet building functions save the packet header size, so we can use it. */
+ hdr_size = Header->common.frag_len;
+ Header->common.flags |= RPC_FLG_FIRST;
+ Header->common.flags &= ~RPC_FLG_LAST;
+ while (!(Header->common.flags & RPC_FLG_LAST)) {
+ /* decide if we need to split the packet into fragments */
+ if ((BufferLength + hdr_size) <= Connection->MaxTransmissionSize) {
+ Header->common.flags |= RPC_FLG_LAST;
+ Header->common.frag_len = BufferLength + hdr_size;
+ } else {
+ Header->common.frag_len = Connection->MaxTransmissionSize;
+ buffer_pos += Header->common.frag_len - hdr_size;
+ BufferLength -= Header->common.frag_len - hdr_size;
+ }
+
+ /* transmit packet header */
+ if (!WriteFile(Connection->conn, Header, hdr_size, &count, &Connection->ovl[1]) &&
+ ERROR_IO_PENDING != GetLastError()) {
+ WARN("WriteFile failed with error %ld\n", GetLastError());
+ return GetLastError();
+ }
+ if (!GetOverlappedResult(Connection->conn, &Connection->ovl[1], &count, TRUE)) {
+ WARN("GetOverlappedResult failed with error %ld\n", GetLastError());
+ return GetLastError();
+ }
+
+ /* fragment consisted of header only and is the last one */
+ if (hdr_size == Header->common.frag_len &&
+ Header->common.flags & RPC_FLG_LAST) {
+ return RPC_S_OK;
+ }
+
+ /* send the fragment data */
+ if (!WriteFile(Connection->conn, buffer_pos, Header->common.frag_len - hdr_size, &count, &Connection->ovl[1]) &&
+ ERROR_IO_PENDING != GetLastError()) {
+ WARN("WriteFile failed with error %ld\n", GetLastError());
+ return GetLastError();
+ }
+ if (!GetOverlappedResult(Connection->conn, &Connection->ovl[1], &count, TRUE)) {
+ WARN("GetOverlappedResult failed with error %ld\n", GetLastError());
+ return GetLastError();
+ }
+
+ Header->common.flags &= ~RPC_FLG_FIRST;
+ }
+
+ return RPC_S_OK;
+}
+
+/***********************************************************************
+ * RPCRT4_Receive (internal)
+ *
+ * Receive a packet from connection and merge the fragments.
+ */
+RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header,
+ PRPC_MESSAGE pMsg)
+{
+ RPC_STATUS status;
+ DWORD dwRead, hdr_length;
+ unsigned short first_flag;
+ unsigned long data_length;
+ unsigned long buffer_length;
+ unsigned char *buffer_ptr;
+ RpcPktCommonHdr common_hdr;
+
+ *Header = NULL;
+
+ TRACE("(%p, %p, %p)\n", Connection, Header, pMsg);
+
+ /* read packet common header */
+ if (!ReadFile(Connection->conn, &common_hdr, sizeof(common_hdr), &dwRead, &Connection->ovl[0]) &&
+ ERROR_IO_PENDING != GetLastError()) {
+ WARN("ReadFile failed with error %ld\n", GetLastError());
+ status = RPC_S_PROTOCOL_ERROR;
+ goto fail;
+ }
+ if (!GetOverlappedResult(Connection->conn, &Connection->ovl[0], &dwRead, TRUE)) {
+ if (GetLastError() != ERROR_MORE_DATA) {
+ WARN("GetOverlappedResult failed with error %ld\n", GetLastError());
+ status = RPC_S_PROTOCOL_ERROR;
+ goto fail;
+ }
+ }
+ if (dwRead != sizeof(common_hdr)) {
+ WARN("Short read of header, %ld/%d bytes\n", dwRead, sizeof(common_hdr));
+ status = RPC_S_PROTOCOL_ERROR;
+ goto fail;
+ }
+
+ /* verify if the header really makes sense */
+ if (common_hdr.rpc_ver != RPC_VER_MAJOR ||
+ common_hdr.rpc_ver_minor != RPC_VER_MINOR) {
+ WARN("unhandled packet version\n");
+ status = RPC_S_PROTOCOL_ERROR;
+ goto fail;
+ }
+
+ hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr);
+ if (hdr_length == 0) {
+ WARN("header length == 0\n");
+ status = RPC_S_PROTOCOL_ERROR;
+ goto fail;
+ }
+
+ *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length);
+ memcpy(*Header, &common_hdr, sizeof(common_hdr));
+
+ /* read the rest of packet header */
+ if (!ReadFile(Connection->conn, &(*Header)->common + 1,
+ hdr_length - sizeof(common_hdr), &dwRead, &Connection->ovl[0]) &&
+ ERROR_IO_PENDING != GetLastError()) {
+ WARN("ReadFile failed with error %ld\n", GetLastError());
+ status = RPC_S_PROTOCOL_ERROR;
+ goto fail;
+ }
+ if (!GetOverlappedResult(Connection->conn, &Connection->ovl[0], &dwRead, TRUE)) {
+ if (GetLastError() != ERROR_MORE_DATA) {
+ WARN("GetOverlappedResult failed with error %ld\n", GetLastError());
+ status = RPC_S_PROTOCOL_ERROR;
+ goto fail;
+ }
+ }
+ if (dwRead != hdr_length - sizeof(common_hdr)) {
+ WARN("bad header length, %ld/%ld bytes\n", dwRead, hdr_length - sizeof(common_hdr));
+ status = RPC_S_PROTOCOL_ERROR;
+ goto fail;
+ }
+
+
+ /* read packet body */
+ switch (common_hdr.ptype) {
+ case PKT_RESPONSE:
+ pMsg->BufferLength = (*Header)->response.alloc_hint;
+ break;
+ case PKT_REQUEST:
+ pMsg->BufferLength = (*Header)->request.alloc_hint;
+ break;
+ default:
+ pMsg->BufferLength = common_hdr.frag_len - hdr_length;
+ }
+
+ TRACE("buffer length = %u\n", pMsg->BufferLength);
+
+ status = I_RpcGetBuffer(pMsg);
+ if (status != RPC_S_OK) goto fail;
+
+ first_flag = RPC_FLG_FIRST;
+ buffer_length = 0;
+ buffer_ptr = pMsg->Buffer;
+ while (buffer_length < pMsg->BufferLength)
+ {
+ data_length = (*Header)->common.frag_len - hdr_length;
+ if (((*Header)->common.flags & RPC_FLG_FIRST) != first_flag ||
+ data_length + buffer_length > pMsg->BufferLength) {
+ TRACE("invalid packet flags or buffer length\n");
+ status = RPC_S_PROTOCOL_ERROR;
+ goto fail;
+ }
+
+ if (data_length == 0) dwRead = 0; else {
+ if (!ReadFile(Connection->conn, buffer_ptr, data_length, &dwRead, &Connection->ovl[0]) &&
+ ERROR_IO_PENDING != GetLastError()) {
+ WARN("ReadFile failed with error %ld\n", GetLastError());
+ status = RPC_S_PROTOCOL_ERROR;
+ goto fail;
+ }
+ if (!GetOverlappedResult(Connection->conn, &Connection->ovl[0], &dwRead, TRUE)) {
+ if (GetLastError() != ERROR_MORE_DATA) {
+ WARN("GetOverlappedResult failed with error %ld\n", GetLastError());
+ status = RPC_S_PROTOCOL_ERROR;
+ goto fail;
+ }
+ }
+ }
+ if (dwRead != data_length) {
+ WARN("bad data length, %ld/%ld\n", dwRead, data_length);
+ status = RPC_S_PROTOCOL_ERROR;
+ goto fail;
+ }
+
+ /* when there is no more data left, it should be the last packet */
+ if (buffer_length == pMsg->BufferLength &&
+ ((*Header)->common.flags & RPC_FLG_LAST) == 0) {
+ WARN("no more data left, but not last packet\n");
+ status = RPC_S_PROTOCOL_ERROR;
+ goto fail;
+ }
+
+ buffer_length += data_length;
+ if (buffer_length < pMsg->BufferLength) {
+ TRACE("next header\n");
+
+ /* read the header of next packet */
+ if (!ReadFile(Connection->conn, *Header, hdr_length, &dwRead, &Connection->ovl[0]) &&
+ ERROR_IO_PENDING != GetLastError()) {
+ WARN("ReadFile failed with error %ld\n", GetLastError());
+ status = GetLastError();
+ goto fail;
+ }
+ if (!GetOverlappedResult(Connection->conn, &Connection->ovl[0], &dwRead, TRUE)) {
+ if (GetLastError() != ERROR_MORE_DATA) {
+ WARN("GetOverlappedResult failed with error %ld\n", GetLastError());
+ status = RPC_S_PROTOCOL_ERROR;
+ goto fail;
+ }
+ }
+ if (dwRead != hdr_length) {
+ WARN("invalid packet header size (%ld)\n", dwRead);
+ status = RPC_S_PROTOCOL_ERROR;
+ goto fail;
+ }
+
+ buffer_ptr += data_length;
+ first_flag = 0;
+ }
+ }
+
+ /* success */
+ status = RPC_S_OK;
+
+fail:
+ if (status != RPC_S_OK && *Header) {
+ RPCRT4_FreeHeader(*Header);
+ *Header = NULL;
+ }
+ return status;
+}
+
+/***********************************************************************
+ * I_RpcGetBuffer [RPCRT4.@]
+ */
+RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg)
+{
+ TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength);
+ /* FIXME: pfnAllocate? */
+ pMsg->Buffer = HeapAlloc(GetProcessHeap(), 0, pMsg->BufferLength);
+
+ TRACE("Buffer=%p\n", pMsg->Buffer);
+ /* FIXME: which errors to return? */
+ return pMsg->Buffer ? S_OK : E_OUTOFMEMORY;
+}
+
+/***********************************************************************
+ * I_RpcFreeBuffer [RPCRT4.@]
+ */
+RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg)
+{
+ TRACE("(%p) Buffer=%p\n", pMsg, pMsg->Buffer);
+ /* FIXME: pfnFree? */
+ HeapFree(GetProcessHeap(), 0, pMsg->Buffer);
+ pMsg->Buffer = NULL;
+ return S_OK;
+}
+
+/***********************************************************************
+ * I_RpcSend [RPCRT4.@]
+ */
+RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg)
+{
+ RpcBinding* bind = (RpcBinding*)pMsg->Handle;
+ RpcConnection* conn;
+ RPC_CLIENT_INTERFACE* cif = NULL;
+ RPC_SERVER_INTERFACE* sif = NULL;
+ RPC_STATUS status;
+ RpcPktHdr *hdr;
+
+ TRACE("(%p)\n", pMsg);
+ if (!bind) return RPC_S_INVALID_BINDING;
+
+ if (bind->server) {
+ sif = pMsg->RpcInterfaceInformation;
+ if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
+ status = RPCRT4_OpenBinding(bind, &conn, &sif->TransferSyntax,
+ &sif->InterfaceId);
+ } else {
+ cif = pMsg->RpcInterfaceInformation;
+ if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
+ status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax,
+ &cif->InterfaceId);
+ }
+
+ if (status != RPC_S_OK) return status;
+
+ if (bind->server) {
+ if (pMsg->RpcFlags & WINE_RPCFLAG_EXCEPTION) {
+ hdr = RPCRT4_BuildFaultHeader(pMsg->DataRepresentation,
+ RPC_S_CALL_FAILED);
+ } else {
+ hdr = RPCRT4_BuildResponseHeader(pMsg->DataRepresentation,
+ pMsg->BufferLength);
+ }
+ } else {
+ hdr = RPCRT4_BuildRequestHeader(pMsg->DataRepresentation,
+ pMsg->BufferLength, pMsg->ProcNum,
+ &bind->ObjectUuid);
+ }
+
+ status = RPCRT4_Send(conn, hdr, pMsg->Buffer, pMsg->BufferLength);
+
+ RPCRT4_FreeHeader(hdr);
+
+ /* success */
+ if (!bind->server) {
+ /* save the connection, so the response can be read from it */
+ pMsg->ReservedForRuntime = conn;
+ return RPC_S_OK;
+ }
+ RPCRT4_CloseBinding(bind, conn);
+ status = RPC_S_OK;
+
+ return status;
+}
+
+/***********************************************************************
+ * I_RpcReceive [RPCRT4.@]
+ */
+RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg)
+{
+ RpcBinding* bind = (RpcBinding*)pMsg->Handle;
+ RpcConnection* conn;
+ RPC_CLIENT_INTERFACE* cif = NULL;
+ RPC_SERVER_INTERFACE* sif = NULL;
+ RPC_STATUS status;
+ RpcPktHdr *hdr = NULL;
+
+ TRACE("(%p)\n", pMsg);
+ if (!bind) return RPC_S_INVALID_BINDING;
+
+ if (pMsg->ReservedForRuntime) {
+ conn = pMsg->ReservedForRuntime;
+ pMsg->ReservedForRuntime = NULL;
+ } else {
+ if (bind->server) {
+ sif = pMsg->RpcInterfaceInformation;
+ if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
+ status = RPCRT4_OpenBinding(bind, &conn, &sif->TransferSyntax,
+ &sif->InterfaceId);
+ } else {
+ cif = pMsg->RpcInterfaceInformation;
+ if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
+ status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax,
+ &cif->InterfaceId);
+ }
+ if (status != RPC_S_OK) return status;
+ }
+
+ status = RPCRT4_Receive(conn, &hdr, pMsg);
+ if (status != RPC_S_OK) {
+ WARN("receive failed with error %lx\n", status);
+ goto fail;
+ }
+
+ status = RPC_S_PROTOCOL_ERROR;
+
+ switch (hdr->common.ptype) {
+ case PKT_RESPONSE:
+ if (bind->server) goto fail;
+ break;
+ case PKT_REQUEST:
+ if (!bind->server) goto fail;
+ break;
+ case PKT_FAULT:
+ pMsg->RpcFlags |= WINE_RPCFLAG_EXCEPTION;
+ ERR ("we got fault packet with status %lx\n", hdr->fault.status);
+ status = RPC_S_CALL_FAILED; /* ? */
+ goto fail;
+ default:
+ WARN("bad packet type %d\n", hdr->common.ptype);
+ goto fail;
+ }
+
+ /* success */
+ status = RPC_S_OK;
+
+fail:
+ if (hdr) {
+ RPCRT4_FreeHeader(hdr);
+ }
+ RPCRT4_CloseBinding(bind, conn);
+ return status;
+}
+
+/***********************************************************************
+ * I_RpcSendReceive [RPCRT4.@]
+ */
+RPC_STATUS WINAPI I_RpcSendReceive(PRPC_MESSAGE pMsg)
+{
+ RPC_STATUS status;
+
+ TRACE("(%p)\n", pMsg);
+ status = I_RpcSend(pMsg);
+ if (status == RPC_S_OK)
+ status = I_RpcReceive(pMsg);
+ return status;
+}