Add a couple of missing spec files.
[wine.git] / dlls / rpcrt4 / rpc_message.c
blobac232a52fd506fc719c95688e77b2fbdcf35fcf4
1 /*
2 * RPC messages
4 * Copyright 2001-2002 Ove Kåven, TransGaming Technologies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * TODO:
21 * - figure out whether we *really* got this right
22 * - check for errors and throw exceptions
23 * - decide if OVERLAPPED_WORKS
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winerror.h"
33 #include "winreg.h"
35 #include "rpc.h"
36 #include "rpcdcep.h"
38 #include "wine/debug.h"
40 #include "rpc_binding.h"
41 #include "rpc_misc.h"
42 #include "rpc_defs.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(ole);
46 /***********************************************************************
47 * I_RpcGetBuffer [RPCRT4.@]
49 RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg)
51 RpcBinding* bind = (RpcBinding*)pMsg->Handle;
52 void* buf;
54 TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength);
55 /* FIXME: pfnAllocate? */
56 if (bind->server) {
57 /* it turns out that the original buffer data must still be available
58 * while the RPC server is marshalling a reply, so we should not deallocate
59 * it, we'll leave deallocating the original buffer to the RPC server */
60 buf = HeapAlloc(GetProcessHeap(), 0, pMsg->BufferLength);
61 } else {
62 buf = HeapReAlloc(GetProcessHeap(), 0, pMsg->Buffer, pMsg->BufferLength);
64 TRACE("Buffer=%p\n", buf);
65 if (buf) pMsg->Buffer = buf;
66 /* FIXME: which errors to return? */
67 return buf ? S_OK : E_OUTOFMEMORY;
70 /***********************************************************************
71 * I_RpcFreeBuffer [RPCRT4.@]
73 RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg)
75 TRACE("(%p) Buffer=%p\n", pMsg, pMsg->Buffer);
76 /* FIXME: pfnFree? */
77 HeapFree(GetProcessHeap(), 0, pMsg->Buffer);
78 pMsg->Buffer = NULL;
79 return S_OK;
82 /***********************************************************************
83 * I_RpcSend [RPCRT4.@]
85 RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg)
87 RpcBinding* bind = (RpcBinding*)pMsg->Handle;
88 RpcConnection* conn;
89 RPC_CLIENT_INTERFACE* cif = NULL;
90 RPC_SERVER_INTERFACE* sif = NULL;
91 UUID* obj;
92 UUID* act;
93 RPC_STATUS status;
94 RpcPktHdr hdr;
96 TRACE("(%p)\n", pMsg);
97 if (!bind) return RPC_S_INVALID_BINDING;
99 status = RPCRT4_OpenBinding(bind, &conn);
100 if (status != RPC_S_OK) return status;
102 obj = &bind->ObjectUuid;
103 act = &bind->ActiveUuid;
105 if (bind->server) {
106 sif = pMsg->RpcInterfaceInformation;
107 if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
108 } else {
109 cif = pMsg->RpcInterfaceInformation;
110 if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
113 /* initialize packet header */
114 memset(&hdr, 0, sizeof(hdr));
115 hdr.rpc_ver = 4;
116 hdr.ptype = bind->server
117 ? ((pMsg->RpcFlags & WINE_RPCFLAG_EXCEPTION) ? PKT_FAULT : PKT_RESPONSE)
118 : PKT_REQUEST;
119 hdr.object = *obj; /* FIXME: IIRC iff no object, the header structure excludes this elt */
120 hdr.if_id = (bind->server) ? sif->InterfaceId.SyntaxGUID : cif->InterfaceId.SyntaxGUID;
121 hdr.if_vers =
122 (bind->server) ?
123 MAKELONG(sif->InterfaceId.SyntaxVersion.MinorVersion, sif->InterfaceId.SyntaxVersion.MajorVersion) :
124 MAKELONG(cif->InterfaceId.SyntaxVersion.MinorVersion, cif->InterfaceId.SyntaxVersion.MajorVersion);
125 hdr.act_id = *act;
126 hdr.opnum = pMsg->ProcNum;
127 /* only the low-order 3 octets of the DataRepresentation go in the header */
128 hdr.drep[0] = LOBYTE(LOWORD(pMsg->DataRepresentation));
129 hdr.drep[1] = HIBYTE(LOWORD(pMsg->DataRepresentation));
130 hdr.drep[2] = LOBYTE(HIWORD(pMsg->DataRepresentation));
131 hdr.len = pMsg->BufferLength;
133 /* transmit packet */
134 if (!WriteFile(conn->conn, &hdr, sizeof(hdr), NULL, NULL)) {
135 status = GetLastError();
136 goto fail;
138 if (pMsg->BufferLength && !WriteFile(conn->conn, pMsg->Buffer, pMsg->BufferLength, NULL, NULL)) {
139 status = GetLastError();
140 goto fail;
143 /* success */
144 if (!bind->server) {
145 /* save the connection, so the response can be read from it */
146 pMsg->ReservedForRuntime = conn;
147 return RPC_S_OK;
149 RPCRT4_CloseBinding(bind, conn);
150 status = RPC_S_OK;
151 fail:
153 return status;
156 /***********************************************************************
157 * I_RpcReceive [RPCRT4.@]
159 RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg)
161 RpcBinding* bind = (RpcBinding*)pMsg->Handle;
162 RpcConnection* conn;
163 UUID* act;
164 RPC_STATUS status;
165 RpcPktHdr hdr;
166 DWORD dwRead;
168 TRACE("(%p)\n", pMsg);
169 if (!bind) return RPC_S_INVALID_BINDING;
171 if (pMsg->ReservedForRuntime) {
172 conn = pMsg->ReservedForRuntime;
173 pMsg->ReservedForRuntime = NULL;
174 } else {
175 status = RPCRT4_OpenBinding(bind, &conn);
176 if (status != RPC_S_OK) return status;
179 act = &bind->ActiveUuid;
181 for (;;) {
182 /* read packet header */
183 #ifdef OVERLAPPED_WORKS
184 if (!ReadFile(conn->conn, &hdr, sizeof(hdr), &dwRead, &conn->ovl)) {
185 DWORD err = GetLastError();
186 if (err != ERROR_IO_PENDING) {
187 status = err;
188 goto fail;
190 if (!GetOverlappedResult(conn->conn, &conn->ovl, &dwRead, TRUE)) {
191 status = GetLastError();
192 goto fail;
195 #else
196 if (!ReadFile(conn->conn, &hdr, sizeof(hdr), &dwRead, NULL)) {
197 status = GetLastError();
198 goto fail;
200 #endif
201 if (dwRead != sizeof(hdr)) {
202 status = RPC_S_PROTOCOL_ERROR;
203 goto fail;
206 /* read packet body */
207 pMsg->BufferLength = hdr.len;
208 status = I_RpcGetBuffer(pMsg);
209 if (status != RPC_S_OK) goto fail;
210 if (!pMsg->BufferLength) dwRead = 0; else
211 #ifdef OVERLAPPED_WORKS
212 if (!ReadFile(conn->conn, pMsg->Buffer, hdr.len, &dwRead, &conn->ovl)) {
213 DWORD err = GetLastError();
214 if (err != ERROR_IO_PENDING) {
215 status = err;
216 goto fail;
218 if (!GetOverlappedResult(conn->conn, &conn->ovl, &dwRead, TRUE)) {
219 status = GetLastError();
220 goto fail;
223 #else
224 if (!ReadFile(conn->conn, pMsg->Buffer, hdr.len, &dwRead, NULL)) {
225 status = GetLastError();
226 goto fail;
228 #endif
229 if (dwRead != hdr.len) {
230 status = RPC_S_PROTOCOL_ERROR;
231 goto fail;
234 status = RPC_S_PROTOCOL_ERROR;
236 switch (hdr.ptype) {
237 case PKT_RESPONSE:
238 if (bind->server) goto fail;
239 break;
240 case PKT_REQUEST:
241 if (!bind->server) goto fail;
242 break;
243 case PKT_FAULT:
244 pMsg->RpcFlags |= WINE_RPCFLAG_EXCEPTION;
245 status = RPC_S_CALL_FAILED; /* ? */
246 goto fail;
247 default:
248 goto fail;
251 /* success */
252 status = RPC_S_OK;
254 /* FIXME: check destination, etc? */
255 break;
257 fail:
258 RPCRT4_CloseBinding(bind, conn);
259 return status;
262 /***********************************************************************
263 * I_RpcSendReceive [RPCRT4.@]
265 RPC_STATUS WINAPI I_RpcSendReceive(PRPC_MESSAGE pMsg)
267 RPC_STATUS status;
269 TRACE("(%p)\n", pMsg);
270 status = I_RpcSend(pMsg);
271 if (status == RPC_S_OK)
272 status = I_RpcReceive(pMsg);
273 return status;