[LT2013]
[reactos.git] / dll / win32 / rpcrt4 / ndr_contexthandle.c
1 /*
2 * NDR data marshalling
3 *
4 * Copyright 2006 Mike McCormack (for CodeWeavers)
5 * Copyright 2006-2007 Robert Shearman (for CodeWeavers)
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "ndr_misc.h"
23 #include "rpc_assoc.h"
24 //#include "rpcndr.h"
25
26 //#include "wine/rpcfc.h"
27
28 #include <wine/debug.h>
29 //#include "wine/list.h"
30
31 #ifdef __REACTOS__
32 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
33 #endif
34
35 WINE_DEFAULT_DEBUG_CHANNEL(ole);
36
37 #define NDR_CONTEXT_HANDLE_MAGIC 0x4352444e
38
39 typedef struct ndr_context_handle
40 {
41 ULONG attributes;
42 GUID uuid;
43 } ndr_context_handle;
44
45 struct context_handle_entry
46 {
47 struct list entry;
48 DWORD magic;
49 RPC_BINDING_HANDLE handle;
50 ndr_context_handle wire_data;
51 };
52
53 static struct list context_handle_list = LIST_INIT(context_handle_list);
54
55 static CRITICAL_SECTION ndr_context_cs;
56 static CRITICAL_SECTION_DEBUG ndr_context_debug =
57 {
58 0, 0, &ndr_context_cs,
59 { &ndr_context_debug.ProcessLocksList, &ndr_context_debug.ProcessLocksList },
60 0, 0, { (DWORD_PTR)(__FILE__ ": ndr_context") }
61 };
62 static CRITICAL_SECTION ndr_context_cs = { &ndr_context_debug, -1, 0, 0, 0, 0 };
63
64 static struct context_handle_entry *get_context_entry(NDR_CCONTEXT CContext)
65 {
66 struct context_handle_entry *che = CContext;
67
68 if (che->magic != NDR_CONTEXT_HANDLE_MAGIC)
69 return NULL;
70 return che;
71 }
72
73 static struct context_handle_entry *context_entry_from_guid(LPCGUID uuid)
74 {
75 struct context_handle_entry *che;
76 LIST_FOR_EACH_ENTRY(che, &context_handle_list, struct context_handle_entry, entry)
77 if (IsEqualGUID(&che->wire_data.uuid, uuid))
78 return che;
79 return NULL;
80 }
81
82 RPC_BINDING_HANDLE WINAPI NDRCContextBinding(NDR_CCONTEXT CContext)
83 {
84 struct context_handle_entry *che;
85 RPC_BINDING_HANDLE handle = NULL;
86
87 TRACE("%p\n", CContext);
88
89 EnterCriticalSection(&ndr_context_cs);
90 che = get_context_entry(CContext);
91 if (che)
92 handle = che->handle;
93 LeaveCriticalSection(&ndr_context_cs);
94
95 if (!handle)
96 {
97 ERR("invalid handle %p\n", CContext);
98 RpcRaiseException(ERROR_INVALID_HANDLE);
99 }
100 return handle;
101 }
102
103 void WINAPI NDRCContextMarshall(NDR_CCONTEXT CContext, void *pBuff)
104 {
105 struct context_handle_entry *che;
106
107 TRACE("%p %p\n", CContext, pBuff);
108
109 if (CContext)
110 {
111 EnterCriticalSection(&ndr_context_cs);
112 che = get_context_entry(CContext);
113 memcpy(pBuff, &che->wire_data, sizeof (ndr_context_handle));
114 LeaveCriticalSection(&ndr_context_cs);
115 }
116 else
117 {
118 ndr_context_handle *wire_data = pBuff;
119 wire_data->attributes = 0;
120 wire_data->uuid = GUID_NULL;
121 }
122 }
123
124 /***********************************************************************
125 * RpcSmDestroyClientContext [RPCRT4.@]
126 */
127 RPC_STATUS WINAPI RpcSmDestroyClientContext(void **ContextHandle)
128 {
129 RPC_STATUS status = RPC_X_SS_CONTEXT_MISMATCH;
130 struct context_handle_entry *che = NULL;
131
132 TRACE("(%p)\n", ContextHandle);
133
134 EnterCriticalSection(&ndr_context_cs);
135 che = get_context_entry(*ContextHandle);
136 *ContextHandle = NULL;
137 if (che)
138 {
139 status = RPC_S_OK;
140 list_remove(&che->entry);
141 }
142
143 LeaveCriticalSection(&ndr_context_cs);
144
145 if (che)
146 {
147 RpcBindingFree(&che->handle);
148 HeapFree(GetProcessHeap(), 0, che);
149 }
150
151 return status;
152 }
153
154 /***********************************************************************
155 * RpcSsDestroyClientContext [RPCRT4.@]
156 */
157 void WINAPI RpcSsDestroyClientContext(void **ContextHandle)
158 {
159 RPC_STATUS status = RpcSmDestroyClientContext(ContextHandle);
160 if (status != RPC_S_OK)
161 RpcRaiseException(status);
162 }
163
164 static UINT ndr_update_context_handle(NDR_CCONTEXT *CContext,
165 RPC_BINDING_HANDLE hBinding,
166 const ndr_context_handle *chi)
167 {
168 struct context_handle_entry *che = NULL;
169
170 /* a null UUID means we should free the context handle */
171 if (IsEqualGUID(&chi->uuid, &GUID_NULL))
172 {
173 if (*CContext)
174 {
175 che = get_context_entry(*CContext);
176 if (!che)
177 return ERROR_INVALID_HANDLE;
178 list_remove(&che->entry);
179 RpcBindingFree(&che->handle);
180 HeapFree(GetProcessHeap(), 0, che);
181 che = NULL;
182 }
183 }
184 /* if there's no existing entry matching the GUID, allocate one */
185 else if (!(che = context_entry_from_guid(&chi->uuid)))
186 {
187 che = HeapAlloc(GetProcessHeap(), 0, sizeof *che);
188 if (!che)
189 return ERROR_NOT_ENOUGH_MEMORY;
190 che->magic = NDR_CONTEXT_HANDLE_MAGIC;
191 RpcBindingCopy(hBinding, &che->handle);
192 list_add_tail(&context_handle_list, &che->entry);
193 che->wire_data = *chi;
194 }
195
196 *CContext = che;
197
198 return ERROR_SUCCESS;
199 }
200
201 /***********************************************************************
202 * NDRCContextUnmarshall [RPCRT4.@]
203 */
204 void WINAPI NDRCContextUnmarshall(NDR_CCONTEXT *CContext,
205 RPC_BINDING_HANDLE hBinding,
206 void *pBuff, ULONG DataRepresentation)
207 {
208 UINT r;
209
210 TRACE("*%p=(%p) %p %p %08x\n",
211 CContext, *CContext, hBinding, pBuff, DataRepresentation);
212
213 EnterCriticalSection(&ndr_context_cs);
214 r = ndr_update_context_handle(CContext, hBinding, pBuff);
215 LeaveCriticalSection(&ndr_context_cs);
216 if (r)
217 RpcRaiseException(r);
218 }
219
220 /***********************************************************************
221 * NDRSContextMarshall [RPCRT4.@]
222 */
223 void WINAPI NDRSContextMarshall(NDR_SCONTEXT SContext,
224 void *pBuff,
225 NDR_RUNDOWN userRunDownIn)
226 {
227 TRACE("(%p %p %p)\n", SContext, pBuff, userRunDownIn);
228 NDRSContextMarshall2(I_RpcGetCurrentCallHandle(), SContext, pBuff,
229 userRunDownIn, NULL, RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
230 }
231
232 /***********************************************************************
233 * NDRSContextMarshallEx [RPCRT4.@]
234 */
235 void WINAPI NDRSContextMarshallEx(RPC_BINDING_HANDLE hBinding,
236 NDR_SCONTEXT SContext,
237 void *pBuff,
238 NDR_RUNDOWN userRunDownIn)
239 {
240 TRACE("(%p %p %p %p)\n", hBinding, SContext, pBuff, userRunDownIn);
241 NDRSContextMarshall2(hBinding, SContext, pBuff, userRunDownIn, NULL,
242 RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
243 }
244
245 /***********************************************************************
246 * NDRSContextMarshall2 [RPCRT4.@]
247 */
248 void WINAPI NDRSContextMarshall2(RPC_BINDING_HANDLE hBinding,
249 NDR_SCONTEXT SContext,
250 void *pBuff,
251 NDR_RUNDOWN userRunDownIn,
252 void *CtxGuard, ULONG Flags)
253 {
254 RpcBinding *binding = hBinding;
255 RPC_STATUS status;
256 ndr_context_handle *ndr = pBuff;
257
258 TRACE("(%p %p %p %p %p %u)\n",
259 hBinding, SContext, pBuff, userRunDownIn, CtxGuard, Flags);
260
261 if (!binding->server || !binding->Assoc)
262 RpcRaiseException(ERROR_INVALID_HANDLE);
263
264 if (Flags & RPC_CONTEXT_HANDLE_FLAGS)
265 FIXME("unimplemented flags: 0x%x\n", Flags & RPC_CONTEXT_HANDLE_FLAGS);
266
267 if (SContext->userContext)
268 {
269 status = RpcServerAssoc_UpdateContextHandle(binding->Assoc, SContext, CtxGuard, userRunDownIn);
270 if (status != RPC_S_OK)
271 RpcRaiseException(status);
272 ndr->attributes = 0;
273 RpcContextHandle_GetUuid(SContext, &ndr->uuid);
274
275 RPCRT4_RemoveThreadContextHandle(SContext);
276 RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, TRUE);
277 }
278 else
279 {
280 if (!RpcContextHandle_IsGuardCorrect(SContext, CtxGuard))
281 RpcRaiseException(ERROR_INVALID_HANDLE);
282 memset(ndr, 0, sizeof(*ndr));
283
284 RPCRT4_RemoveThreadContextHandle(SContext);
285 /* Note: release the context handle twice in this case to release
286 * one ref being kept around for the data and one ref for the
287 * unmarshall/marshall sequence */
288 if (!RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, TRUE))
289 return; /* this is to cope with the case of the data not being valid
290 * before and so not having a further reference */
291 RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, FALSE);
292 }
293 }
294
295 /***********************************************************************
296 * NDRSContextUnmarshall [RPCRT4.@]
297 */
298 NDR_SCONTEXT WINAPI NDRSContextUnmarshall(void *pBuff,
299 ULONG DataRepresentation)
300 {
301 TRACE("(%p %08x)\n", pBuff, DataRepresentation);
302 return NDRSContextUnmarshall2(I_RpcGetCurrentCallHandle(), pBuff,
303 DataRepresentation, NULL,
304 RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
305 }
306
307 /***********************************************************************
308 * NDRSContextUnmarshallEx [RPCRT4.@]
309 */
310 NDR_SCONTEXT WINAPI NDRSContextUnmarshallEx(RPC_BINDING_HANDLE hBinding,
311 void *pBuff,
312 ULONG DataRepresentation)
313 {
314 TRACE("(%p %p %08x)\n", hBinding, pBuff, DataRepresentation);
315 return NDRSContextUnmarshall2(hBinding, pBuff, DataRepresentation, NULL,
316 RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
317 }
318
319 /***********************************************************************
320 * NDRSContextUnmarshall2 [RPCRT4.@]
321 */
322 NDR_SCONTEXT WINAPI NDRSContextUnmarshall2(RPC_BINDING_HANDLE hBinding,
323 void *pBuff,
324 ULONG DataRepresentation,
325 void *CtxGuard, ULONG Flags)
326 {
327 RpcBinding *binding = hBinding;
328 NDR_SCONTEXT SContext;
329 RPC_STATUS status;
330 const ndr_context_handle *context_ndr = pBuff;
331
332 TRACE("(%p %p %08x %p %u)\n",
333 hBinding, pBuff, DataRepresentation, CtxGuard, Flags);
334
335 if (!binding->server || !binding->Assoc)
336 RpcRaiseException(ERROR_INVALID_HANDLE);
337
338 if (Flags & RPC_CONTEXT_HANDLE_FLAGS)
339 FIXME("unimplemented flags: 0x%x\n", Flags & RPC_CONTEXT_HANDLE_FLAGS);
340
341 if (!pBuff || (!context_ndr->attributes &&
342 UuidIsNil((UUID *)&context_ndr->uuid, &status)))
343 status = RpcServerAssoc_AllocateContextHandle(binding->Assoc, CtxGuard,
344 &SContext);
345 else
346 {
347 if (context_ndr->attributes)
348 {
349 ERR("non-null attributes 0x%x\n", context_ndr->attributes);
350 status = ERROR_INVALID_HANDLE;
351 }
352 else
353 status = RpcServerAssoc_FindContextHandle(binding->Assoc,
354 &context_ndr->uuid,
355 CtxGuard, Flags,
356 &SContext);
357 }
358
359 if (status != RPC_S_OK)
360 RpcRaiseException(status);
361
362 RPCRT4_PushThreadContextHandle(SContext);
363 return SContext;
364 }