[RPCRT4] Sync with Wine Staging 1.7.55. CORE-10536
[reactos.git] / reactos / 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 "precomp.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(ole);
25
26 #define NDR_CONTEXT_HANDLE_MAGIC 0x4352444e
27
28 typedef struct ndr_context_handle
29 {
30 ULONG attributes;
31 GUID uuid;
32 } ndr_context_handle;
33
34 struct context_handle_entry
35 {
36 struct list entry;
37 DWORD magic;
38 RPC_BINDING_HANDLE handle;
39 ndr_context_handle wire_data;
40 };
41
42 static struct list context_handle_list = LIST_INIT(context_handle_list);
43
44 static CRITICAL_SECTION ndr_context_cs;
45 static CRITICAL_SECTION_DEBUG ndr_context_debug =
46 {
47 0, 0, &ndr_context_cs,
48 { &ndr_context_debug.ProcessLocksList, &ndr_context_debug.ProcessLocksList },
49 0, 0, { (DWORD_PTR)(__FILE__ ": ndr_context") }
50 };
51 static CRITICAL_SECTION ndr_context_cs = { &ndr_context_debug, -1, 0, 0, 0, 0 };
52
53 static struct context_handle_entry *get_context_entry(NDR_CCONTEXT CContext)
54 {
55 struct context_handle_entry *che = CContext;
56
57 if (che->magic != NDR_CONTEXT_HANDLE_MAGIC)
58 return NULL;
59 return che;
60 }
61
62 static struct context_handle_entry *context_entry_from_guid(LPCGUID uuid)
63 {
64 struct context_handle_entry *che;
65 LIST_FOR_EACH_ENTRY(che, &context_handle_list, struct context_handle_entry, entry)
66 if (IsEqualGUID(&che->wire_data.uuid, uuid))
67 return che;
68 return NULL;
69 }
70
71 RPC_BINDING_HANDLE WINAPI NDRCContextBinding(NDR_CCONTEXT CContext)
72 {
73 struct context_handle_entry *che;
74 RPC_BINDING_HANDLE handle = NULL;
75
76 TRACE("%p\n", CContext);
77
78 EnterCriticalSection(&ndr_context_cs);
79 che = get_context_entry(CContext);
80 if (che)
81 handle = che->handle;
82 LeaveCriticalSection(&ndr_context_cs);
83
84 if (!handle)
85 {
86 ERR("invalid handle %p\n", CContext);
87 RpcRaiseException(RPC_X_SS_CONTEXT_MISMATCH);
88 }
89 return handle;
90 }
91
92 void WINAPI NDRCContextMarshall(NDR_CCONTEXT CContext, void *pBuff)
93 {
94 struct context_handle_entry *che;
95
96 TRACE("%p %p\n", CContext, pBuff);
97
98 if (CContext)
99 {
100 EnterCriticalSection(&ndr_context_cs);
101 che = get_context_entry(CContext);
102 memcpy(pBuff, &che->wire_data, sizeof (ndr_context_handle));
103 LeaveCriticalSection(&ndr_context_cs);
104 }
105 else
106 {
107 ndr_context_handle *wire_data = pBuff;
108 wire_data->attributes = 0;
109 wire_data->uuid = GUID_NULL;
110 }
111 }
112
113 /***********************************************************************
114 * RpcSmDestroyClientContext [RPCRT4.@]
115 */
116 RPC_STATUS WINAPI RpcSmDestroyClientContext(void **ContextHandle)
117 {
118 RPC_STATUS status = RPC_X_SS_CONTEXT_MISMATCH;
119 struct context_handle_entry *che = NULL;
120
121 TRACE("(%p)\n", ContextHandle);
122
123 EnterCriticalSection(&ndr_context_cs);
124 che = get_context_entry(*ContextHandle);
125 *ContextHandle = NULL;
126 if (che)
127 {
128 status = RPC_S_OK;
129 list_remove(&che->entry);
130 }
131
132 LeaveCriticalSection(&ndr_context_cs);
133
134 if (che)
135 {
136 RpcBindingFree(&che->handle);
137 HeapFree(GetProcessHeap(), 0, che);
138 }
139
140 return status;
141 }
142
143 /***********************************************************************
144 * RpcSsDestroyClientContext [RPCRT4.@]
145 */
146 void WINAPI RpcSsDestroyClientContext(void **ContextHandle)
147 {
148 RPC_STATUS status = RpcSmDestroyClientContext(ContextHandle);
149 if (status != RPC_S_OK)
150 RpcRaiseException(status);
151 }
152
153 /***********************************************************************
154 * RpcSsDontSerializeContext [RPCRT4.@]
155 */
156 void WINAPI RpcSsDontSerializeContext(void)
157 {
158 FIXME("stub\n");
159 }
160
161 static RPC_STATUS ndr_update_context_handle(NDR_CCONTEXT *CContext,
162 RPC_BINDING_HANDLE hBinding,
163 const ndr_context_handle *chi)
164 {
165 struct context_handle_entry *che = NULL;
166
167 /* a null UUID means we should free the context handle */
168 if (IsEqualGUID(&chi->uuid, &GUID_NULL))
169 {
170 if (*CContext)
171 {
172 che = get_context_entry(*CContext);
173 if (!che)
174 return RPC_X_SS_CONTEXT_MISMATCH;
175 list_remove(&che->entry);
176 RpcBindingFree(&che->handle);
177 HeapFree(GetProcessHeap(), 0, che);
178 che = NULL;
179 }
180 }
181 /* if there's no existing entry matching the GUID, allocate one */
182 else if (!(che = context_entry_from_guid(&chi->uuid)))
183 {
184 che = HeapAlloc(GetProcessHeap(), 0, sizeof *che);
185 if (!che)
186 return RPC_X_NO_MEMORY;
187 che->magic = NDR_CONTEXT_HANDLE_MAGIC;
188 RpcBindingCopy(hBinding, &che->handle);
189 list_add_tail(&context_handle_list, &che->entry);
190 che->wire_data = *chi;
191 }
192
193 *CContext = che;
194
195 return RPC_S_OK;
196 }
197
198 /***********************************************************************
199 * NDRCContextUnmarshall [RPCRT4.@]
200 */
201 void WINAPI NDRCContextUnmarshall(NDR_CCONTEXT *CContext,
202 RPC_BINDING_HANDLE hBinding,
203 void *pBuff, ULONG DataRepresentation)
204 {
205 RPC_STATUS status;
206
207 TRACE("*%p=(%p) %p %p %08x\n",
208 CContext, *CContext, hBinding, pBuff, DataRepresentation);
209
210 EnterCriticalSection(&ndr_context_cs);
211 status = ndr_update_context_handle(CContext, hBinding, pBuff);
212 LeaveCriticalSection(&ndr_context_cs);
213 if (status)
214 RpcRaiseException(status);
215 }
216
217 /***********************************************************************
218 * NDRSContextMarshall [RPCRT4.@]
219 */
220 void WINAPI NDRSContextMarshall(NDR_SCONTEXT SContext,
221 void *pBuff,
222 NDR_RUNDOWN userRunDownIn)
223 {
224 TRACE("(%p %p %p)\n", SContext, pBuff, userRunDownIn);
225 NDRSContextMarshall2(I_RpcGetCurrentCallHandle(), SContext, pBuff,
226 userRunDownIn, NULL, RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
227 }
228
229 /***********************************************************************
230 * NDRSContextMarshallEx [RPCRT4.@]
231 */
232 void WINAPI NDRSContextMarshallEx(RPC_BINDING_HANDLE hBinding,
233 NDR_SCONTEXT SContext,
234 void *pBuff,
235 NDR_RUNDOWN userRunDownIn)
236 {
237 TRACE("(%p %p %p %p)\n", hBinding, SContext, pBuff, userRunDownIn);
238 NDRSContextMarshall2(hBinding, SContext, pBuff, userRunDownIn, NULL,
239 RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
240 }
241
242 /***********************************************************************
243 * NDRSContextMarshall2 [RPCRT4.@]
244 */
245 void WINAPI NDRSContextMarshall2(RPC_BINDING_HANDLE hBinding,
246 NDR_SCONTEXT SContext,
247 void *pBuff,
248 NDR_RUNDOWN userRunDownIn,
249 void *CtxGuard, ULONG Flags)
250 {
251 RpcBinding *binding = hBinding;
252 RPC_STATUS status;
253 ndr_context_handle *ndr = pBuff;
254
255 TRACE("(%p %p %p %p %p %u)\n",
256 hBinding, SContext, pBuff, userRunDownIn, CtxGuard, Flags);
257
258 if (!binding->server || !binding->Assoc)
259 RpcRaiseException(RPC_S_INVALID_BINDING);
260
261 if (Flags & RPC_CONTEXT_HANDLE_FLAGS)
262 FIXME("unimplemented flags: 0x%x\n", Flags & RPC_CONTEXT_HANDLE_FLAGS);
263
264 if (SContext->userContext)
265 {
266 status = RpcServerAssoc_UpdateContextHandle(binding->Assoc, SContext, CtxGuard, userRunDownIn);
267 if (status != RPC_S_OK)
268 RpcRaiseException(status);
269 ndr->attributes = 0;
270 RpcContextHandle_GetUuid(SContext, &ndr->uuid);
271
272 RPCRT4_RemoveThreadContextHandle(SContext);
273 RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, TRUE);
274 }
275 else
276 {
277 if (!RpcContextHandle_IsGuardCorrect(SContext, CtxGuard))
278 RpcRaiseException(RPC_X_SS_CONTEXT_MISMATCH);
279 memset(ndr, 0, sizeof(*ndr));
280
281 RPCRT4_RemoveThreadContextHandle(SContext);
282 /* Note: release the context handle twice in this case to release
283 * one ref being kept around for the data and one ref for the
284 * unmarshall/marshall sequence */
285 if (!RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, TRUE))
286 return; /* this is to cope with the case of the data not being valid
287 * before and so not having a further reference */
288 RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, FALSE);
289 }
290 }
291
292 /***********************************************************************
293 * NDRSContextUnmarshall [RPCRT4.@]
294 */
295 NDR_SCONTEXT WINAPI NDRSContextUnmarshall(void *pBuff,
296 ULONG DataRepresentation)
297 {
298 TRACE("(%p %08x)\n", pBuff, DataRepresentation);
299 return NDRSContextUnmarshall2(I_RpcGetCurrentCallHandle(), pBuff,
300 DataRepresentation, NULL,
301 RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
302 }
303
304 /***********************************************************************
305 * NDRSContextUnmarshallEx [RPCRT4.@]
306 */
307 NDR_SCONTEXT WINAPI NDRSContextUnmarshallEx(RPC_BINDING_HANDLE hBinding,
308 void *pBuff,
309 ULONG DataRepresentation)
310 {
311 TRACE("(%p %p %08x)\n", hBinding, pBuff, DataRepresentation);
312 return NDRSContextUnmarshall2(hBinding, pBuff, DataRepresentation, NULL,
313 RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
314 }
315
316 /***********************************************************************
317 * NDRSContextUnmarshall2 [RPCRT4.@]
318 */
319 NDR_SCONTEXT WINAPI NDRSContextUnmarshall2(RPC_BINDING_HANDLE hBinding,
320 void *pBuff,
321 ULONG DataRepresentation,
322 void *CtxGuard, ULONG Flags)
323 {
324 RpcBinding *binding = hBinding;
325 NDR_SCONTEXT SContext;
326 RPC_STATUS status;
327 const ndr_context_handle *context_ndr = pBuff;
328
329 TRACE("(%p %p %08x %p %u)\n",
330 hBinding, pBuff, DataRepresentation, CtxGuard, Flags);
331
332 if (!binding->server || !binding->Assoc)
333 RpcRaiseException(RPC_S_INVALID_BINDING);
334
335 if (Flags & RPC_CONTEXT_HANDLE_FLAGS)
336 FIXME("unimplemented flags: 0x%x\n", Flags & RPC_CONTEXT_HANDLE_FLAGS);
337
338 if (!pBuff || (!context_ndr->attributes &&
339 UuidIsNil((UUID *)&context_ndr->uuid, &status)))
340 status = RpcServerAssoc_AllocateContextHandle(binding->Assoc, CtxGuard,
341 &SContext);
342 else
343 {
344 if (context_ndr->attributes)
345 {
346 ERR("non-null attributes 0x%x\n", context_ndr->attributes);
347 status = RPC_X_SS_CONTEXT_MISMATCH;
348 }
349 else
350 status = RpcServerAssoc_FindContextHandle(binding->Assoc,
351 &context_ndr->uuid,
352 CtxGuard, Flags,
353 &SContext);
354 }
355
356 if (status != RPC_S_OK)
357 RpcRaiseException(status);
358
359 RPCRT4_PushThreadContextHandle(SContext);
360 return SContext;
361 }