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
23 #include "rpc_assoc.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
41 struct context_handle_entry
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)
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))
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);
89 LeaveCriticalSection(&ndr_context_cs);
93 ERR("invalid handle %p\n", CContext);
94 RpcRaiseException(ERROR_INVALID_HANDLE);
99 void WINAPI NDRCContextMarshall(NDR_CCONTEXT CContext, void *pBuff)
101 struct context_handle_entry *che;
103 TRACE("%p %p\n", CContext, pBuff);
107 EnterCriticalSection(&ndr_context_cs);
108 che = get_context_entry(CContext);
109 memcpy(pBuff, &che->wire_data, sizeof (ndr_context_handle));
110 LeaveCriticalSection(&ndr_context_cs);
114 ndr_context_handle *wire_data = (ndr_context_handle *)pBuff;
115 wire_data->attributes = 0;
116 wire_data->uuid = GUID_NULL;
120 /***********************************************************************
121 * RpcSmDestroyClientContext [RPCRT4.@]
123 RPC_STATUS WINAPI RpcSmDestroyClientContext(void **ContextHandle)
125 RPC_STATUS status = RPC_X_SS_CONTEXT_MISMATCH;
126 struct context_handle_entry *che = NULL;
128 TRACE("(%p)\n", ContextHandle);
130 EnterCriticalSection(&ndr_context_cs);
131 che = get_context_entry(*ContextHandle);
132 *ContextHandle = NULL;
136 list_remove(&che->entry);
139 LeaveCriticalSection(&ndr_context_cs);
143 RpcBindingFree(&che->handle);
144 HeapFree(GetProcessHeap(), 0, che);
150 /***********************************************************************
151 * RpcSsDestroyClientContext [RPCRT4.@]
153 void WINAPI RpcSsDestroyClientContext(void **ContextHandle)
155 RPC_STATUS status = RpcSmDestroyClientContext(ContextHandle);
156 if (status != RPC_S_OK)
157 RpcRaiseException(status);
160 static UINT ndr_update_context_handle(NDR_CCONTEXT *CContext,
161 RPC_BINDING_HANDLE hBinding,
162 const ndr_context_handle *chi)
164 struct context_handle_entry *che = NULL;
166 /* a null UUID means we should free the context handle */
167 if (IsEqualGUID(&chi->uuid, &GUID_NULL))
171 che = get_context_entry(*CContext);
173 return ERROR_INVALID_HANDLE;
174 list_remove(&che->entry);
175 RpcBindingFree(&che->handle);
176 HeapFree(GetProcessHeap(), 0, che);
180 /* if there's no existing entry matching the GUID, allocate one */
181 else if (!(che = context_entry_from_guid(&chi->uuid)))
183 che = HeapAlloc(GetProcessHeap(), 0, sizeof *che);
185 return ERROR_NOT_ENOUGH_MEMORY;
186 che->magic = NDR_CONTEXT_HANDLE_MAGIC;
187 RpcBindingCopy(hBinding, &che->handle);
188 list_add_tail(&context_handle_list, &che->entry);
189 che->wire_data = *chi;
194 return ERROR_SUCCESS;
197 /***********************************************************************
198 * NDRCContextUnmarshall [RPCRT4.@]
200 void WINAPI NDRCContextUnmarshall(NDR_CCONTEXT *CContext,
201 RPC_BINDING_HANDLE hBinding,
202 void *pBuff, ULONG DataRepresentation)
206 TRACE("*%p=(%p) %p %p %08x\n",
207 CContext, *CContext, hBinding, pBuff, DataRepresentation);
209 EnterCriticalSection(&ndr_context_cs);
210 r = ndr_update_context_handle(CContext, hBinding, pBuff);
211 LeaveCriticalSection(&ndr_context_cs);
213 RpcRaiseException(r);
216 /***********************************************************************
217 * NDRSContextMarshall [RPCRT4.@]
219 void WINAPI NDRSContextMarshall(NDR_SCONTEXT SContext,
221 NDR_RUNDOWN userRunDownIn)
223 TRACE("(%p %p %p)\n", SContext, pBuff, userRunDownIn);
224 NDRSContextMarshall2(I_RpcGetCurrentCallHandle(), SContext, pBuff,
225 userRunDownIn, NULL, RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
228 /***********************************************************************
229 * NDRSContextMarshallEx [RPCRT4.@]
231 void WINAPI NDRSContextMarshallEx(RPC_BINDING_HANDLE hBinding,
232 NDR_SCONTEXT SContext,
234 NDR_RUNDOWN userRunDownIn)
236 TRACE("(%p %p %p %p)\n", hBinding, SContext, pBuff, userRunDownIn);
237 NDRSContextMarshall2(hBinding, SContext, pBuff, userRunDownIn, NULL,
238 RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
241 /***********************************************************************
242 * NDRSContextMarshall2 [RPCRT4.@]
244 void WINAPI NDRSContextMarshall2(RPC_BINDING_HANDLE hBinding,
245 NDR_SCONTEXT SContext,
247 NDR_RUNDOWN userRunDownIn,
248 void *CtxGuard, ULONG Flags)
250 RpcBinding *binding = hBinding;
252 ndr_context_handle *ndr = pBuff;
254 TRACE("(%p %p %p %p %p %u)\n",
255 hBinding, SContext, pBuff, userRunDownIn, CtxGuard, Flags);
257 if (!binding->server || !binding->Assoc)
258 RpcRaiseException(ERROR_INVALID_HANDLE);
260 if (Flags & RPC_CONTEXT_HANDLE_FLAGS)
261 FIXME("unimplemented flags: 0x%x\n", Flags & RPC_CONTEXT_HANDLE_FLAGS);
263 if (SContext->userContext)
265 status = RpcServerAssoc_UpdateContextHandle(binding->Assoc, SContext, CtxGuard, userRunDownIn);
266 if (status != RPC_S_OK)
267 RpcRaiseException(status);
269 RpcContextHandle_GetUuid(SContext, &ndr->uuid);
271 RPCRT4_RemoveThreadContextHandle(SContext);
272 RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, TRUE);
276 if (!RpcContextHandle_IsGuardCorrect(SContext, CtxGuard))
277 RpcRaiseException(ERROR_INVALID_HANDLE);
278 memset(ndr, 0, sizeof(*ndr));
280 RPCRT4_RemoveThreadContextHandle(SContext);
281 /* Note: release the context handle twice in this case to release
282 * one ref being kept around for the data and one ref for the
283 * unmarshall/marshall sequence */
284 if (!RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, TRUE))
285 return; /* this is to cope with the case of the data not being valid
286 * before and so not having a further reference */
287 RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, FALSE);
291 /***********************************************************************
292 * NDRSContextUnmarshall [RPCRT4.@]
294 NDR_SCONTEXT WINAPI NDRSContextUnmarshall(void *pBuff,
295 ULONG DataRepresentation)
297 TRACE("(%p %08x)\n", pBuff, DataRepresentation);
298 return NDRSContextUnmarshall2(I_RpcGetCurrentCallHandle(), pBuff,
299 DataRepresentation, NULL,
300 RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
303 /***********************************************************************
304 * NDRSContextUnmarshallEx [RPCRT4.@]
306 NDR_SCONTEXT WINAPI NDRSContextUnmarshallEx(RPC_BINDING_HANDLE hBinding,
308 ULONG DataRepresentation)
310 TRACE("(%p %p %08x)\n", hBinding, pBuff, DataRepresentation);
311 return NDRSContextUnmarshall2(hBinding, pBuff, DataRepresentation, NULL,
312 RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
315 /***********************************************************************
316 * NDRSContextUnmarshall2 [RPCRT4.@]
318 NDR_SCONTEXT WINAPI NDRSContextUnmarshall2(RPC_BINDING_HANDLE hBinding,
320 ULONG DataRepresentation,
321 void *CtxGuard, ULONG Flags)
323 RpcBinding *binding = hBinding;
324 NDR_SCONTEXT SContext;
326 const ndr_context_handle *context_ndr = pBuff;
328 TRACE("(%p %p %08x %p %u)\n",
329 hBinding, pBuff, DataRepresentation, CtxGuard, Flags);
331 if (!binding->server || !binding->Assoc)
332 RpcRaiseException(ERROR_INVALID_HANDLE);
334 if (Flags & RPC_CONTEXT_HANDLE_FLAGS)
335 FIXME("unimplemented flags: 0x%x\n", Flags & RPC_CONTEXT_HANDLE_FLAGS);
337 if (!pBuff || (!context_ndr->attributes &&
338 UuidIsNil((UUID *)&context_ndr->uuid, &status)))
339 status = RpcServerAssoc_AllocateContextHandle(binding->Assoc, CtxGuard,
343 if (context_ndr->attributes)
345 ERR("non-null attributes 0x%x\n", context_ndr->attributes);
346 status = ERROR_INVALID_HANDLE;
349 status = RpcServerAssoc_FindContextHandle(binding->Assoc,
355 if (status != RPC_S_OK)
356 RpcRaiseException(status);
358 RPCRT4_PushThreadContextHandle(SContext);