- Convert ordinals to their real names.
[wine] / dlls / rpcrt4 / rpc_message.c
1 /*
2  * RPC messages
3  *
4  * Copyright 2001-2002 Ove Kåven, TransGaming Technologies
5  *
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.
10  *
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.
15  *
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
19  *
20  * TODO:
21  *  - figure out whether we *really* got this right
22  *  - check for errors and throw exceptions
23  *  - decide if OVERLAPPED_WORKS
24  */
25
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winerror.h"
33 #include "winreg.h"
34
35 #include "rpc.h"
36 #include "rpcdcep.h"
37
38 #include "wine/debug.h"
39
40 #include "rpc_binding.h"
41 #include "rpc_misc.h"
42 #include "rpc_defs.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(ole);
45
46 /***********************************************************************
47  *           I_RpcGetBuffer [RPCRT4.@]
48  */
49 RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg)
50 {
51   RpcBinding* bind = (RpcBinding*)pMsg->Handle;
52   void* buf;
53
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);
63   }
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;
68 }
69
70 /***********************************************************************
71  *           I_RpcFreeBuffer [RPCRT4.@]
72  */
73 RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg)
74 {
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;
80 }
81
82 /***********************************************************************
83  *           I_RpcSend [RPCRT4.@]
84  */
85 RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg)
86 {
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;
95
96   TRACE("(%p)\n", pMsg);
97   if (!bind) return RPC_S_INVALID_BINDING;
98
99   status = RPCRT4_OpenBinding(bind, &conn);
100   if (status != RPC_S_OK) return status;
101
102   obj = &bind->ObjectUuid;
103   act = &bind->ActiveUuid;
104
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; /* ? */
111   }
112
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;
132
133   /* transmit packet */
134   if (!WriteFile(conn->conn, &hdr, sizeof(hdr), NULL, NULL)) {
135     status = GetLastError();
136     goto fail;
137   }
138   if (pMsg->BufferLength && !WriteFile(conn->conn, pMsg->Buffer, pMsg->BufferLength, NULL, NULL)) {
139     status = GetLastError();
140     goto fail;
141   }
142
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;
148   }
149   RPCRT4_CloseBinding(bind, conn);
150   status = RPC_S_OK;
151 fail:
152
153   return status;
154 }
155
156 /***********************************************************************
157  *           I_RpcReceive [RPCRT4.@]
158  */
159 RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg)
160 {
161   RpcBinding* bind = (RpcBinding*)pMsg->Handle;
162   RpcConnection* conn;
163   UUID* act;
164   RPC_STATUS status;
165   RpcPktHdr hdr;
166   DWORD dwRead;
167
168   TRACE("(%p)\n", pMsg);
169   if (!bind) return RPC_S_INVALID_BINDING;
170
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;
177   }
178
179   act = &bind->ActiveUuid;
180
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;
189       }
190       if (!GetOverlappedResult(conn->conn, &conn->ovl, &dwRead, TRUE)) {
191         status = GetLastError();
192         goto fail;
193       }
194     }
195 #else
196     if (!ReadFile(conn->conn, &hdr, sizeof(hdr), &dwRead, NULL)) {
197       status = GetLastError();
198       goto fail;
199     }
200 #endif
201     if (dwRead != sizeof(hdr)) {
202       status = RPC_S_PROTOCOL_ERROR;
203       goto fail;
204     }
205
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;
217       }
218       if (!GetOverlappedResult(conn->conn, &conn->ovl, &dwRead, TRUE)) {
219         status = GetLastError();
220         goto fail;
221       }
222     }
223 #else
224     if (!ReadFile(conn->conn, pMsg->Buffer, hdr.len, &dwRead, NULL)) {
225       status = GetLastError();
226       goto fail;
227     }
228 #endif
229     if (dwRead != hdr.len) {
230       status = RPC_S_PROTOCOL_ERROR;
231       goto fail;
232     }
233
234     status = RPC_S_PROTOCOL_ERROR;
235
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;
249     }
250
251     /* success */
252     status = RPC_S_OK;
253
254     /* FIXME: check destination, etc? */
255     break;
256   }
257 fail:
258   RPCRT4_CloseBinding(bind, conn);
259   return status;
260 }
261
262 /***********************************************************************
263  *           I_RpcSendReceive [RPCRT4.@]
264  */
265 RPC_STATUS WINAPI I_RpcSendReceive(PRPC_MESSAGE pMsg)
266 {
267   RPC_STATUS status;
268
269   TRACE("(%p)\n", pMsg);
270   status = I_RpcSend(pMsg);
271   if (status == RPC_S_OK)
272     status = I_RpcReceive(pMsg);
273   return status;
274 }