push f98ef5dce4886db1f9801e7c454145e1b633b4ff
[wine/hacks.git] / dlls / rpcrt4 / ndr_contexthandle.c
blob0b3eeb1fcd40f22d78609912591cdaccb7439534
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"
26 #include "wine/rpcfc.h"
28 #include "wine/debug.h"
29 #include "wine/list.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(ole);
33 #define NDR_CONTEXT_HANDLE_MAGIC 0x4352444e
35 typedef struct ndr_context_handle
37 ULONG attributes;
38 GUID uuid;
39 } ndr_context_handle;
41 struct context_handle_entry
43 struct list entry;
44 DWORD magic;
45 RPC_BINDING_HANDLE handle;
46 ndr_context_handle wire_data;
49 static struct list context_handle_list = LIST_INIT(context_handle_list);
51 static CRITICAL_SECTION ndr_context_cs;
52 static CRITICAL_SECTION_DEBUG ndr_context_debug =
54 0, 0, &ndr_context_cs,
55 { &ndr_context_debug.ProcessLocksList, &ndr_context_debug.ProcessLocksList },
56 0, 0, { (DWORD_PTR)(__FILE__ ": ndr_context") }
58 static CRITICAL_SECTION ndr_context_cs = { &ndr_context_debug, -1, 0, 0, 0, 0 };
60 static struct context_handle_entry *get_context_entry(NDR_CCONTEXT CContext)
62 struct context_handle_entry *che = (struct context_handle_entry*) CContext;
64 if (che->magic != NDR_CONTEXT_HANDLE_MAGIC)
65 return NULL;
66 return che;
69 static struct context_handle_entry *context_entry_from_guid(LPCGUID uuid)
71 struct context_handle_entry *che;
72 LIST_FOR_EACH_ENTRY(che, &context_handle_list, struct context_handle_entry, entry)
73 if (IsEqualGUID(&che->wire_data.uuid, uuid))
74 return che;
75 return NULL;
78 RPC_BINDING_HANDLE WINAPI NDRCContextBinding(NDR_CCONTEXT CContext)
80 struct context_handle_entry *che;
81 RPC_BINDING_HANDLE handle = NULL;
83 TRACE("%p\n", CContext);
85 EnterCriticalSection(&ndr_context_cs);
86 che = get_context_entry(CContext);
87 if (che)
88 handle = che->handle;
89 LeaveCriticalSection(&ndr_context_cs);
91 if (!handle)
92 RpcRaiseException(ERROR_INVALID_HANDLE);
93 return handle;
96 void WINAPI NDRCContextMarshall(NDR_CCONTEXT CContext, void *pBuff)
98 struct context_handle_entry *che;
100 TRACE("%p %p\n", CContext, pBuff);
102 if (CContext)
104 EnterCriticalSection(&ndr_context_cs);
105 che = get_context_entry(CContext);
106 memcpy(pBuff, &che->wire_data, sizeof (ndr_context_handle));
107 LeaveCriticalSection(&ndr_context_cs);
109 else
111 ndr_context_handle *wire_data = (ndr_context_handle *)pBuff;
112 wire_data->attributes = 0;
113 wire_data->uuid = GUID_NULL;
117 /***********************************************************************
118 * RpcSmDestroyClientContext [RPCRT4.@]
120 RPC_STATUS WINAPI RpcSmDestroyClientContext(void **ContextHandle)
122 RPC_STATUS status = RPC_X_SS_CONTEXT_MISMATCH;
123 struct context_handle_entry *che = NULL;
125 TRACE("(%p)\n", ContextHandle);
127 EnterCriticalSection(&ndr_context_cs);
128 che = get_context_entry(*ContextHandle);
129 *ContextHandle = NULL;
130 if (che)
132 status = RPC_S_OK;
133 list_remove(&che->entry);
136 LeaveCriticalSection(&ndr_context_cs);
138 if (che)
140 RpcBindingFree(&che->handle);
141 HeapFree(GetProcessHeap(), 0, che);
144 return status;
147 /***********************************************************************
148 * RpcSsDestroyClientContext [RPCRT4.@]
150 void WINAPI RpcSsDestroyClientContext(void **ContextHandle)
152 RPC_STATUS status = RpcSmDestroyClientContext(ContextHandle);
153 if (status != RPC_S_OK)
154 RpcRaiseException(status);
157 static UINT ndr_update_context_handle(NDR_CCONTEXT *CContext,
158 RPC_BINDING_HANDLE hBinding,
159 const ndr_context_handle *chi)
161 struct context_handle_entry *che = NULL;
163 /* a null UUID means we should free the context handle */
164 if (IsEqualGUID(&chi->uuid, &GUID_NULL))
166 if (*CContext)
168 che = get_context_entry(*CContext);
169 if (!che)
170 return ERROR_INVALID_HANDLE;
171 list_remove(&che->entry);
172 RpcBindingFree(&che->handle);
173 HeapFree(GetProcessHeap(), 0, che);
174 che = NULL;
177 /* if there's no existing entry matching the GUID, allocate one */
178 else if (!(che = context_entry_from_guid(&chi->uuid)))
180 che = HeapAlloc(GetProcessHeap(), 0, sizeof *che);
181 if (!che)
182 return ERROR_NOT_ENOUGH_MEMORY;
183 che->magic = NDR_CONTEXT_HANDLE_MAGIC;
184 RpcBindingCopy(hBinding, &che->handle);
185 list_add_tail(&context_handle_list, &che->entry);
186 memcpy(&che->wire_data, chi, sizeof *chi);
189 *CContext = che;
191 return ERROR_SUCCESS;
194 /***********************************************************************
195 * NDRCContextUnmarshall [RPCRT4.@]
197 void WINAPI NDRCContextUnmarshall(NDR_CCONTEXT *CContext,
198 RPC_BINDING_HANDLE hBinding,
199 void *pBuff, ULONG DataRepresentation)
201 UINT r;
203 TRACE("*%p=(%p) %p %p %08x\n",
204 CContext, *CContext, hBinding, pBuff, DataRepresentation);
206 EnterCriticalSection(&ndr_context_cs);
207 r = ndr_update_context_handle(CContext, hBinding, pBuff);
208 LeaveCriticalSection(&ndr_context_cs);
209 if (r)
210 RpcRaiseException(r);
213 /***********************************************************************
214 * NDRSContextMarshall [RPCRT4.@]
216 void WINAPI NDRSContextMarshall(NDR_SCONTEXT SContext,
217 void *pBuff,
218 NDR_RUNDOWN userRunDownIn)
220 TRACE("(%p %p %p)\n", SContext, pBuff, userRunDownIn);
221 NDRSContextMarshall2(I_RpcGetCurrentCallHandle(), SContext, pBuff, userRunDownIn, NULL, 0);
224 /***********************************************************************
225 * NDRSContextMarshallEx [RPCRT4.@]
227 void WINAPI NDRSContextMarshallEx(RPC_BINDING_HANDLE hBinding,
228 NDR_SCONTEXT SContext,
229 void *pBuff,
230 NDR_RUNDOWN userRunDownIn)
232 TRACE("(%p %p %p %p)\n", hBinding, SContext, pBuff, userRunDownIn);
233 NDRSContextMarshall2(hBinding, SContext, pBuff, userRunDownIn, NULL, 0);
236 /***********************************************************************
237 * NDRSContextMarshall2 [RPCRT4.@]
239 void WINAPI NDRSContextMarshall2(RPC_BINDING_HANDLE hBinding,
240 NDR_SCONTEXT SContext,
241 void *pBuff,
242 NDR_RUNDOWN userRunDownIn,
243 void *CtxGuard, ULONG Flags)
245 RpcBinding *binding = hBinding;
246 RPC_STATUS status;
247 ndr_context_handle *ndr = pBuff;
249 TRACE("(%p %p %p %p %p %u)\n",
250 hBinding, SContext, pBuff, userRunDownIn, CtxGuard, Flags);
252 if (!binding->server || !binding->Assoc)
253 RpcRaiseException(ERROR_INVALID_HANDLE);
255 if (SContext->userContext)
257 status = RpcServerAssoc_UpdateContextHandle(binding->Assoc, SContext, CtxGuard, userRunDownIn);
258 if (status != RPC_S_OK)
259 RpcRaiseException(status);
260 ndr->attributes = 0;
261 RpcContextHandle_GetUuid(SContext, &ndr->uuid);
263 else
265 if (!RpcContextHandle_IsGuardCorrect(SContext, CtxGuard))
266 RpcRaiseException(ERROR_INVALID_HANDLE);
267 memset(ndr, 0, sizeof(*ndr));
268 /* Note: release the context handle twice in this case to release
269 * one ref being kept around for the data and one ref for the
270 * unmarshall/marshall sequence */
271 if (!RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, FALSE))
272 return; /* this is to cope with the case of the data not being valid
273 * before and so not having a further reference */
275 RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, TRUE);
278 /***********************************************************************
279 * NDRSContextUnmarshall [RPCRT4.@]
281 NDR_SCONTEXT WINAPI NDRSContextUnmarshall(void *pBuff,
282 ULONG DataRepresentation)
284 TRACE("(%p %08x)\n", pBuff, DataRepresentation);
285 return NDRSContextUnmarshall2(I_RpcGetCurrentCallHandle(), pBuff, DataRepresentation, NULL, 0);
288 /***********************************************************************
289 * NDRSContextUnmarshallEx [RPCRT4.@]
291 NDR_SCONTEXT WINAPI NDRSContextUnmarshallEx(RPC_BINDING_HANDLE hBinding,
292 void *pBuff,
293 ULONG DataRepresentation)
295 TRACE("(%p %p %08x)\n", hBinding, pBuff, DataRepresentation);
296 return NDRSContextUnmarshall2(hBinding, pBuff, DataRepresentation, NULL, 0);
299 /***********************************************************************
300 * NDRSContextUnmarshall2 [RPCRT4.@]
302 NDR_SCONTEXT WINAPI NDRSContextUnmarshall2(RPC_BINDING_HANDLE hBinding,
303 void *pBuff,
304 ULONG DataRepresentation,
305 void *CtxGuard, ULONG Flags)
307 RpcBinding *binding = hBinding;
308 NDR_SCONTEXT SContext;
309 RPC_STATUS status;
311 TRACE("(%p %p %08x %p %u)\n",
312 hBinding, pBuff, DataRepresentation, CtxGuard, Flags);
314 if (!binding->server || !binding->Assoc)
315 RpcRaiseException(ERROR_INVALID_HANDLE);
317 if (!pBuff)
318 status = RpcServerAssoc_AllocateContextHandle(binding->Assoc, CtxGuard,
319 &SContext);
320 else
322 const ndr_context_handle *context_ndr = pBuff;
323 if (context_ndr->attributes)
325 ERR("non-null attributes 0x%x\n", context_ndr->attributes);
326 status = ERROR_INVALID_HANDLE;
328 else
329 status = RpcServerAssoc_FindContextHandle(binding->Assoc,
330 &context_ndr->uuid,
331 CtxGuard, Flags,
332 &SContext);
335 if (status != RPC_S_OK)
336 RpcRaiseException(status);
338 return SContext;