- Pull the buffer from the rpc message into the midl stub message
[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 <stdio.h>
27 #include <string.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winerror.h"
32 #include "winreg.h"
33
34 #include "rpc.h"
35 #include "rpcdcep.h"
36
37 #include "wine/debug.h"
38
39 #include "rpc_binding.h"
40 #include "rpc_defs.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(ole);
43
44 /***********************************************************************
45  *           I_RpcGetBuffer [RPCRT4.@]
46  */
47 RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg)
48 {
49   void* buf;
50
51   TRACE("(%p)\n", pMsg);
52   /* FIXME: pfnAllocate? */
53   buf = HeapReAlloc(GetProcessHeap(), 0, pMsg->Buffer, pMsg->BufferLength);
54   if (buf) pMsg->Buffer = buf;
55   /* FIXME: which errors to return? */
56   return buf ? S_OK : E_OUTOFMEMORY;
57 }
58
59 /***********************************************************************
60  *           I_RpcFreeBuffer [RPCRT4.@]
61  */
62 RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg)
63 {
64   TRACE("(%p)\n", pMsg);
65   /* FIXME: pfnFree? */
66   HeapFree(GetProcessHeap(), 0, pMsg->Buffer);
67   pMsg->Buffer = NULL;
68   return S_OK;
69 }
70
71 /***********************************************************************
72  *           I_RpcSend [RPCRT4.@]
73  */
74 RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg)
75 {
76   RpcBinding* bind = (RpcBinding*)pMsg->Handle;
77   RPC_CLIENT_INTERFACE* cif = NULL;
78   RPC_SERVER_INTERFACE* sif = NULL;
79   RPC_STATUS status;
80   RpcPktHdr hdr;
81
82   TRACE("(%p)\n", pMsg);
83   if (!bind) return RPC_S_INVALID_BINDING;
84
85   if (bind->server) {
86     sif = pMsg->RpcInterfaceInformation;
87     if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
88   } else {
89     cif = pMsg->RpcInterfaceInformation;
90     if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
91   }
92
93   status = RPCRT4_OpenBinding(bind);
94   if (status != RPC_S_OK) return status;
95
96   /* initialize packet header */
97   memset(&hdr, 0, sizeof(hdr));
98   hdr.rpc_ver = 4;
99   hdr.ptype = PKT_REQUEST;
100   hdr.object = bind->ObjectUuid; /* FIXME: IIRC iff no object, the header structure excludes this elt */
101   hdr.if_id = (bind->server) ? sif->InterfaceId.SyntaxGUID : cif->InterfaceId.SyntaxGUID;
102   hdr.if_vers = 
103     (bind->server) ?
104     MAKELONG(sif->InterfaceId.SyntaxVersion.MinorVersion, sif->InterfaceId.SyntaxVersion.MajorVersion) :
105     MAKELONG(cif->InterfaceId.SyntaxVersion.MinorVersion, cif->InterfaceId.SyntaxVersion.MajorVersion);
106   hdr.opnum = pMsg->ProcNum;
107   /* only the low-order 3 octets of the DataRepresentation go in the header */
108   hdr.drep[0] = LOBYTE(LOWORD(pMsg->DataRepresentation));
109   hdr.drep[1] = HIBYTE(LOWORD(pMsg->DataRepresentation));
110   hdr.drep[2] = LOBYTE(HIWORD(pMsg->DataRepresentation));
111   hdr.len = pMsg->BufferLength;
112
113   /* transmit packet */
114   if (!WriteFile(bind->conn, &hdr, sizeof(hdr), NULL, NULL))
115     return GetLastError();
116   if (!WriteFile(bind->conn, pMsg->Buffer, pMsg->BufferLength, NULL, NULL))
117     return GetLastError();
118
119   /* success */
120   return RPC_S_OK;
121 }
122
123 /***********************************************************************
124  *           I_RpcReceive [RPCRT4.@]
125  */
126 RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg)
127 {
128   RpcBinding* bind = (RpcBinding*)pMsg->Handle;
129   RPC_STATUS status;
130   RpcPktHdr hdr;
131   DWORD dwRead;
132
133   TRACE("(%p)\n", pMsg);
134   if (!bind) return RPC_S_INVALID_BINDING;
135
136   status = RPCRT4_OpenBinding(bind);
137   if (status != RPC_S_OK) return status;
138
139   /* read packet header */
140 #ifdef OVERLAPPED_WORKS
141   if (!ReadFile(bind->conn, &hdr, sizeof(hdr), &dwRead, &bind->ovl)) {
142     DWORD err = GetLastError();
143     if (err != ERROR_IO_PENDING) {
144       return err;
145     }
146     if (!GetOverlappedResult(bind->conn, &bind->ovl, &dwRead, TRUE)) return GetLastError();
147   }
148 #else
149   if (!ReadFile(bind->conn, &hdr, sizeof(hdr), &dwRead, NULL))
150     return GetLastError();
151 #endif
152   if (dwRead != sizeof(hdr)) return RPC_S_PROTOCOL_ERROR;
153
154   /* read packet body */
155   pMsg->BufferLength = hdr.len;
156   status = I_RpcGetBuffer(pMsg);
157   if (status != RPC_S_OK) return status;
158 #ifdef OVERLAPPED_WORKS
159   if (!ReadFile(bind->conn, pMsg->Buffer, hdr.len, &dwRead, &bind->ovl)) {
160     DWORD err = GetLastError();
161     if (err != ERROR_IO_PENDING) {
162       return err;
163     }
164     if (!GetOverlappedResult(bind->conn, &bind->ovl, &dwRead, TRUE)) return GetLastError();
165   }
166 #else
167   if (!ReadFile(bind->conn, pMsg->Buffer, hdr.len, &dwRead, NULL))
168     return GetLastError();
169 #endif
170   if (dwRead != hdr.len) return RPC_S_PROTOCOL_ERROR;
171
172   /* success */
173   return RPC_S_OK;
174 }
175
176 /***********************************************************************
177  *           I_RpcSendReceive [RPCRT4.@]
178  */
179 RPC_STATUS WINAPI I_RpcSendReceive(PRPC_MESSAGE pMsg)
180 {
181   RPC_STATUS status;
182
183   TRACE("(%p)\n", pMsg);
184   status = I_RpcSend(pMsg);
185   if (status == RPC_S_OK)
186     status = I_RpcReceive(pMsg);
187   return status;
188 }