d3d11/tests: Add some tests for Map() on deferred contexts.
[wine.git] / dlls / rpcrt4 / ndr_contexthandle.c
blob36deb41d81298e0dcc80fd7ed4ae979d1df24283
1 /*
2 * NDR data marshalling
4 * Copyright 2006 Mike McCormack (for CodeWeavers)
5 * Copyright 2006-2007 Robert Shearman (for CodeWeavers)
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.
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.
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
22 #include "ndr_misc.h"
23 #include "rpc_assoc.h"
24 #include "rpcndr.h"
25 #include "cguid.h"
27 #include "wine/debug.h"
28 #include "wine/list.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(ole);
32 #define NDR_CONTEXT_HANDLE_MAGIC 0x4352444e
34 typedef struct ndr_context_handle
36 ULONG attributes;
37 GUID uuid;
38 } ndr_context_handle;
40 struct context_handle_entry
42 struct list entry;
43 DWORD magic;
44 RPC_BINDING_HANDLE handle;
45 ndr_context_handle wire_data;
48 static struct list context_handle_list = LIST_INIT(context_handle_list);
50 static CRITICAL_SECTION ndr_context_cs;
51 static CRITICAL_SECTION_DEBUG ndr_context_debug =
53 0, 0, &ndr_context_cs,
54 { &ndr_context_debug.ProcessLocksList, &ndr_context_debug.ProcessLocksList },
55 0, 0, { (DWORD_PTR)(__FILE__ ": ndr_context") }
57 static CRITICAL_SECTION ndr_context_cs = { &ndr_context_debug, -1, 0, 0, 0, 0 };
59 static struct context_handle_entry *get_context_entry(NDR_CCONTEXT CContext)
61 struct context_handle_entry *che = CContext;
63 if (che->magic != NDR_CONTEXT_HANDLE_MAGIC)
64 return NULL;
65 return che;
68 static struct context_handle_entry *context_entry_from_guid(LPCGUID uuid)
70 struct context_handle_entry *che;
71 LIST_FOR_EACH_ENTRY(che, &context_handle_list, struct context_handle_entry, entry)
72 if (IsEqualGUID(&che->wire_data.uuid, uuid))
73 return che;
74 return NULL;
77 RPC_BINDING_HANDLE WINAPI NDRCContextBinding(NDR_CCONTEXT CContext)
79 struct context_handle_entry *che;
80 RPC_BINDING_HANDLE handle = NULL;
82 TRACE("%p\n", CContext);
84 EnterCriticalSection(&ndr_context_cs);
85 che = get_context_entry(CContext);
86 if (che)
87 handle = che->handle;
88 LeaveCriticalSection(&ndr_context_cs);
90 if (!handle)
92 ERR("invalid handle %p\n", CContext);
93 RpcRaiseException(RPC_X_SS_CONTEXT_MISMATCH);
95 return handle;
98 void WINAPI NDRCContextMarshall(NDR_CCONTEXT CContext, void *pBuff)
100 struct context_handle_entry *che;
102 TRACE("%p %p\n", CContext, pBuff);
104 if (CContext)
106 EnterCriticalSection(&ndr_context_cs);
107 che = get_context_entry(CContext);
108 memcpy(pBuff, &che->wire_data, sizeof (ndr_context_handle));
109 LeaveCriticalSection(&ndr_context_cs);
111 else
113 ndr_context_handle *wire_data = pBuff;
114 wire_data->attributes = 0;
115 wire_data->uuid = GUID_NULL;
119 /***********************************************************************
120 * RpcSmDestroyClientContext [RPCRT4.@]
122 RPC_STATUS WINAPI RpcSmDestroyClientContext(void **ContextHandle)
124 RPC_STATUS status = RPC_X_SS_CONTEXT_MISMATCH;
125 struct context_handle_entry *che = NULL;
127 TRACE("(%p)\n", ContextHandle);
129 EnterCriticalSection(&ndr_context_cs);
130 che = get_context_entry(*ContextHandle);
131 *ContextHandle = NULL;
132 if (che)
134 status = RPC_S_OK;
135 list_remove(&che->entry);
138 LeaveCriticalSection(&ndr_context_cs);
140 if (che)
142 RpcBindingFree(&che->handle);
143 HeapFree(GetProcessHeap(), 0, che);
146 return status;
149 /***********************************************************************
150 * RpcSsDestroyClientContext [RPCRT4.@]
152 void WINAPI RpcSsDestroyClientContext(void **ContextHandle)
154 RPC_STATUS status = RpcSmDestroyClientContext(ContextHandle);
155 if (status != RPC_S_OK)
156 RpcRaiseException(status);
159 /***********************************************************************
160 * RpcSsDontSerializeContext [RPCRT4.@]
162 void WINAPI RpcSsDontSerializeContext(void)
164 FIXME("stub\n");
167 static RPC_STATUS ndr_update_context_handle(NDR_CCONTEXT *CContext,
168 RPC_BINDING_HANDLE hBinding,
169 const ndr_context_handle *chi)
171 struct context_handle_entry *che = NULL;
173 /* a null UUID means we should free the context handle */
174 if (IsEqualGUID(&chi->uuid, &GUID_NULL))
176 if (*CContext)
178 che = get_context_entry(*CContext);
179 if (!che)
180 return RPC_X_SS_CONTEXT_MISMATCH;
181 list_remove(&che->entry);
182 RpcBindingFree(&che->handle);
183 HeapFree(GetProcessHeap(), 0, che);
184 che = NULL;
187 /* if there's no existing entry matching the GUID, allocate one */
188 else if (!(che = context_entry_from_guid(&chi->uuid)))
190 che = HeapAlloc(GetProcessHeap(), 0, sizeof *che);
191 if (!che)
192 return RPC_X_NO_MEMORY;
193 che->magic = NDR_CONTEXT_HANDLE_MAGIC;
194 RpcBindingCopy(hBinding, &che->handle);
195 list_add_tail(&context_handle_list, &che->entry);
196 che->wire_data = *chi;
199 *CContext = che;
201 return RPC_S_OK;
204 /***********************************************************************
205 * NDRCContextUnmarshall [RPCRT4.@]
207 void WINAPI NDRCContextUnmarshall(NDR_CCONTEXT *CContext,
208 RPC_BINDING_HANDLE hBinding,
209 void *pBuff, ULONG DataRepresentation)
211 RPC_STATUS status;
213 TRACE("*%p=(%p) %p %p %08x\n",
214 CContext, *CContext, hBinding, pBuff, DataRepresentation);
216 EnterCriticalSection(&ndr_context_cs);
217 status = ndr_update_context_handle(CContext, hBinding, pBuff);
218 LeaveCriticalSection(&ndr_context_cs);
219 if (status)
220 RpcRaiseException(status);
223 /***********************************************************************
224 * NDRSContextMarshall [RPCRT4.@]
226 void WINAPI NDRSContextMarshall(NDR_SCONTEXT SContext,
227 void *pBuff,
228 NDR_RUNDOWN userRunDownIn)
230 TRACE("(%p %p %p)\n", SContext, pBuff, userRunDownIn);
231 NDRSContextMarshall2(I_RpcGetCurrentCallHandle(), SContext, pBuff,
232 userRunDownIn, NULL, RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
235 /***********************************************************************
236 * NDRSContextMarshallEx [RPCRT4.@]
238 void WINAPI NDRSContextMarshallEx(RPC_BINDING_HANDLE hBinding,
239 NDR_SCONTEXT SContext,
240 void *pBuff,
241 NDR_RUNDOWN userRunDownIn)
243 TRACE("(%p %p %p %p)\n", hBinding, SContext, pBuff, userRunDownIn);
244 NDRSContextMarshall2(hBinding, SContext, pBuff, userRunDownIn, NULL,
245 RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
248 /***********************************************************************
249 * NDRSContextMarshall2 [RPCRT4.@]
251 void WINAPI NDRSContextMarshall2(RPC_BINDING_HANDLE hBinding,
252 NDR_SCONTEXT SContext,
253 void *pBuff,
254 NDR_RUNDOWN userRunDownIn,
255 void *CtxGuard, ULONG Flags)
257 RpcBinding *binding = hBinding;
258 RPC_STATUS status;
259 ndr_context_handle *ndr = pBuff;
261 TRACE("(%p %p %p %p %p %u)\n",
262 hBinding, SContext, pBuff, userRunDownIn, CtxGuard, Flags);
264 if (!binding->server || !binding->Assoc)
265 RpcRaiseException(RPC_S_INVALID_BINDING);
267 if (SContext->userContext)
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);
275 RPCRT4_RemoveThreadContextHandle(SContext);
276 RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, TRUE);
278 else
280 if (!RpcContextHandle_IsGuardCorrect(SContext, CtxGuard))
281 RpcRaiseException(RPC_X_SS_CONTEXT_MISMATCH);
282 memset(ndr, 0, sizeof(*ndr));
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);
295 /***********************************************************************
296 * NDRSContextUnmarshall [RPCRT4.@]
298 NDR_SCONTEXT WINAPI NDRSContextUnmarshall(void *pBuff,
299 ULONG DataRepresentation)
301 TRACE("(%p %08x)\n", pBuff, DataRepresentation);
302 return NDRSContextUnmarshall2(I_RpcGetCurrentCallHandle(), pBuff,
303 DataRepresentation, NULL,
304 RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
307 /***********************************************************************
308 * NDRSContextUnmarshallEx [RPCRT4.@]
310 NDR_SCONTEXT WINAPI NDRSContextUnmarshallEx(RPC_BINDING_HANDLE hBinding,
311 void *pBuff,
312 ULONG DataRepresentation)
314 TRACE("(%p %p %08x)\n", hBinding, pBuff, DataRepresentation);
315 return NDRSContextUnmarshall2(hBinding, pBuff, DataRepresentation, NULL,
316 RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
319 /***********************************************************************
320 * NDRSContextUnmarshall2 [RPCRT4.@]
322 NDR_SCONTEXT WINAPI NDRSContextUnmarshall2(RPC_BINDING_HANDLE hBinding,
323 void *pBuff,
324 ULONG DataRepresentation,
325 void *CtxGuard, ULONG Flags)
327 RpcBinding *binding = hBinding;
328 NDR_SCONTEXT SContext;
329 RPC_STATUS status;
330 const ndr_context_handle *context_ndr = pBuff;
332 TRACE("(%p %p %08x %p %u)\n",
333 hBinding, pBuff, DataRepresentation, CtxGuard, Flags);
335 if (!binding->server || !binding->Assoc)
336 RpcRaiseException(RPC_S_INVALID_BINDING);
338 if (!pBuff || (!context_ndr->attributes &&
339 UuidIsNil((UUID *)&context_ndr->uuid, &status)))
340 status = RpcServerAssoc_AllocateContextHandle(binding->Assoc, CtxGuard,
341 &SContext);
342 else
344 if (context_ndr->attributes)
346 ERR("non-null attributes 0x%x\n", context_ndr->attributes);
347 status = RPC_X_SS_CONTEXT_MISMATCH;
349 else
350 status = RpcServerAssoc_FindContextHandle(binding->Assoc,
351 &context_ndr->uuid,
352 CtxGuard, Flags,
353 &SContext);
356 if (status != RPC_S_OK)
357 RpcRaiseException(status);
359 RPCRT4_PushThreadContextHandle(SContext);
360 return SContext;