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
25 #include "rpc_assoc.h"
29 #include "wine/debug.h"
30 #include "wine/list.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
34 #define NDR_CONTEXT_HANDLE_MAGIC 0x4352444e
36 typedef struct ndr_context_handle
42 struct context_handle_entry
46 RPC_BINDING_HANDLE handle
;
47 ndr_context_handle wire_data
;
50 static struct list context_handle_list
= LIST_INIT(context_handle_list
);
52 static CRITICAL_SECTION ndr_context_cs
;
53 static CRITICAL_SECTION_DEBUG ndr_context_debug
=
55 0, 0, &ndr_context_cs
,
56 { &ndr_context_debug
.ProcessLocksList
, &ndr_context_debug
.ProcessLocksList
},
57 0, 0, { (DWORD_PTR
)(__FILE__
": ndr_context") }
59 static CRITICAL_SECTION ndr_context_cs
= { &ndr_context_debug
, -1, 0, 0, 0, 0 };
61 static struct context_handle_entry
*get_context_entry(NDR_CCONTEXT CContext
)
63 struct context_handle_entry
*che
= CContext
;
65 if (che
->magic
!= NDR_CONTEXT_HANDLE_MAGIC
)
70 static struct context_handle_entry
*context_entry_from_guid(LPCGUID uuid
)
72 struct context_handle_entry
*che
;
73 LIST_FOR_EACH_ENTRY(che
, &context_handle_list
, struct context_handle_entry
, entry
)
74 if (IsEqualGUID(&che
->wire_data
.uuid
, uuid
))
79 RPC_BINDING_HANDLE WINAPI
NDRCContextBinding(NDR_CCONTEXT CContext
)
81 struct context_handle_entry
*che
;
82 RPC_BINDING_HANDLE handle
= NULL
;
84 TRACE("%p\n", CContext
);
86 EnterCriticalSection(&ndr_context_cs
);
87 che
= get_context_entry(CContext
);
90 LeaveCriticalSection(&ndr_context_cs
);
94 ERR("invalid handle %p\n", CContext
);
95 RpcRaiseException(RPC_X_SS_CONTEXT_MISMATCH
);
100 void WINAPI
NDRCContextMarshall(NDR_CCONTEXT CContext
, void *pBuff
)
102 struct context_handle_entry
*che
;
104 TRACE("%p %p\n", CContext
, pBuff
);
108 EnterCriticalSection(&ndr_context_cs
);
109 che
= get_context_entry(CContext
);
110 memcpy(pBuff
, &che
->wire_data
, sizeof (ndr_context_handle
));
111 LeaveCriticalSection(&ndr_context_cs
);
115 ndr_context_handle
*wire_data
= pBuff
;
116 wire_data
->attributes
= 0;
117 wire_data
->uuid
= GUID_NULL
;
121 /***********************************************************************
122 * RpcSmDestroyClientContext [RPCRT4.@]
124 RPC_STATUS WINAPI
RpcSmDestroyClientContext(void **ContextHandle
)
126 RPC_STATUS status
= RPC_X_SS_CONTEXT_MISMATCH
;
127 struct context_handle_entry
*che
= NULL
;
129 TRACE("(%p)\n", ContextHandle
);
131 EnterCriticalSection(&ndr_context_cs
);
132 che
= get_context_entry(*ContextHandle
);
133 *ContextHandle
= NULL
;
137 list_remove(&che
->entry
);
140 LeaveCriticalSection(&ndr_context_cs
);
144 RpcBindingFree(&che
->handle
);
151 /***********************************************************************
152 * RpcSsDestroyClientContext [RPCRT4.@]
154 void WINAPI
RpcSsDestroyClientContext(void **ContextHandle
)
156 RPC_STATUS status
= RpcSmDestroyClientContext(ContextHandle
);
157 if (status
!= RPC_S_OK
)
158 RpcRaiseException(status
);
161 /***********************************************************************
162 * RpcSsDontSerializeContext [RPCRT4.@]
164 void WINAPI
RpcSsDontSerializeContext(void)
169 static RPC_STATUS
ndr_update_context_handle(NDR_CCONTEXT
*CContext
,
170 RPC_BINDING_HANDLE hBinding
,
171 const ndr_context_handle
*chi
)
173 struct context_handle_entry
*che
= NULL
;
175 /* a null UUID means we should free the context handle */
176 if (IsEqualGUID(&chi
->uuid
, &GUID_NULL
))
180 che
= get_context_entry(*CContext
);
182 return RPC_X_SS_CONTEXT_MISMATCH
;
183 list_remove(&che
->entry
);
184 RpcBindingFree(&che
->handle
);
189 /* if there's no existing entry matching the GUID, allocate one */
190 else if (!(che
= context_entry_from_guid(&chi
->uuid
)))
192 che
= malloc(sizeof *che
);
194 return RPC_X_NO_MEMORY
;
195 che
->magic
= NDR_CONTEXT_HANDLE_MAGIC
;
196 RpcBindingCopy(hBinding
, &che
->handle
);
197 list_add_tail(&context_handle_list
, &che
->entry
);
198 che
->wire_data
= *chi
;
206 /***********************************************************************
207 * NDRCContextUnmarshall [RPCRT4.@]
209 void WINAPI
NDRCContextUnmarshall(NDR_CCONTEXT
*CContext
,
210 RPC_BINDING_HANDLE hBinding
,
211 void *pBuff
, ULONG DataRepresentation
)
215 TRACE("*%p=(%p) %p %p %08lx\n",
216 CContext
, *CContext
, hBinding
, pBuff
, DataRepresentation
);
218 EnterCriticalSection(&ndr_context_cs
);
219 status
= ndr_update_context_handle(CContext
, hBinding
, pBuff
);
220 LeaveCriticalSection(&ndr_context_cs
);
222 RpcRaiseException(status
);
225 /***********************************************************************
226 * NDRSContextMarshall [RPCRT4.@]
228 void WINAPI
NDRSContextMarshall(NDR_SCONTEXT SContext
,
230 NDR_RUNDOWN userRunDownIn
)
232 TRACE("(%p %p %p)\n", SContext
, pBuff
, userRunDownIn
);
233 NDRSContextMarshall2(I_RpcGetCurrentCallHandle(), SContext
, pBuff
,
234 userRunDownIn
, NULL
, RPC_CONTEXT_HANDLE_DEFAULT_FLAGS
);
237 /***********************************************************************
238 * NDRSContextMarshallEx [RPCRT4.@]
240 void WINAPI
NDRSContextMarshallEx(RPC_BINDING_HANDLE hBinding
,
241 NDR_SCONTEXT SContext
,
243 NDR_RUNDOWN userRunDownIn
)
245 TRACE("(%p %p %p %p)\n", hBinding
, SContext
, pBuff
, userRunDownIn
);
246 NDRSContextMarshall2(hBinding
, SContext
, pBuff
, userRunDownIn
, NULL
,
247 RPC_CONTEXT_HANDLE_DEFAULT_FLAGS
);
250 /***********************************************************************
251 * NDRSContextMarshall2 [RPCRT4.@]
253 void WINAPI
NDRSContextMarshall2(RPC_BINDING_HANDLE hBinding
,
254 NDR_SCONTEXT SContext
,
256 NDR_RUNDOWN userRunDownIn
,
257 void *CtxGuard
, ULONG Flags
)
259 RpcBinding
*binding
= hBinding
;
261 ndr_context_handle
*ndr
= pBuff
;
263 TRACE("(%p %p %p %p %p %lu)\n",
264 hBinding
, SContext
, pBuff
, userRunDownIn
, CtxGuard
, Flags
);
266 if (!binding
->server
|| !binding
->Assoc
)
267 RpcRaiseException(RPC_S_INVALID_BINDING
);
269 if (SContext
->userContext
)
271 status
= RpcServerAssoc_UpdateContextHandle(binding
->Assoc
, SContext
, CtxGuard
, userRunDownIn
);
272 if (status
!= RPC_S_OK
)
273 RpcRaiseException(status
);
275 RpcContextHandle_GetUuid(SContext
, &ndr
->uuid
);
277 RPCRT4_RemoveThreadContextHandle(SContext
);
278 RpcServerAssoc_ReleaseContextHandle(binding
->Assoc
, SContext
, TRUE
);
282 if (!RpcContextHandle_IsGuardCorrect(SContext
, CtxGuard
))
283 RpcRaiseException(RPC_X_SS_CONTEXT_MISMATCH
);
284 memset(ndr
, 0, sizeof(*ndr
));
286 RPCRT4_RemoveThreadContextHandle(SContext
);
287 /* Note: release the context handle twice in this case to release
288 * one ref being kept around for the data and one ref for the
289 * unmarshall/marshall sequence */
290 if (!RpcServerAssoc_ReleaseContextHandle(binding
->Assoc
, SContext
, TRUE
))
291 return; /* this is to cope with the case of the data not being valid
292 * before and so not having a further reference */
293 RpcServerAssoc_ReleaseContextHandle(binding
->Assoc
, SContext
, FALSE
);
297 /***********************************************************************
298 * NDRSContextUnmarshall [RPCRT4.@]
300 NDR_SCONTEXT WINAPI
NDRSContextUnmarshall(void *pBuff
,
301 ULONG DataRepresentation
)
303 TRACE("(%p %08lx)\n", pBuff
, DataRepresentation
);
304 return NDRSContextUnmarshall2(I_RpcGetCurrentCallHandle(), pBuff
,
305 DataRepresentation
, NULL
,
306 RPC_CONTEXT_HANDLE_DEFAULT_FLAGS
);
309 /***********************************************************************
310 * NDRSContextUnmarshallEx [RPCRT4.@]
312 NDR_SCONTEXT WINAPI
NDRSContextUnmarshallEx(RPC_BINDING_HANDLE hBinding
,
314 ULONG DataRepresentation
)
316 TRACE("(%p %p %08lx)\n", hBinding
, pBuff
, DataRepresentation
);
317 return NDRSContextUnmarshall2(hBinding
, pBuff
, DataRepresentation
, NULL
,
318 RPC_CONTEXT_HANDLE_DEFAULT_FLAGS
);
321 /***********************************************************************
322 * NDRSContextUnmarshall2 [RPCRT4.@]
324 NDR_SCONTEXT WINAPI
NDRSContextUnmarshall2(RPC_BINDING_HANDLE hBinding
,
326 ULONG DataRepresentation
,
327 void *CtxGuard
, ULONG Flags
)
329 RpcBinding
*binding
= hBinding
;
330 NDR_SCONTEXT SContext
;
332 const ndr_context_handle
*context_ndr
= pBuff
;
334 TRACE("(%p %p %08lx %p %lu)\n",
335 hBinding
, pBuff
, DataRepresentation
, CtxGuard
, Flags
);
337 if (!binding
->server
|| !binding
->Assoc
)
338 RpcRaiseException(RPC_S_INVALID_BINDING
);
340 if (!pBuff
|| (!context_ndr
->attributes
&&
341 UuidIsNil((UUID
*)&context_ndr
->uuid
, &status
)))
342 status
= RpcServerAssoc_AllocateContextHandle(binding
->Assoc
, CtxGuard
,
346 if (context_ndr
->attributes
)
348 ERR("non-null attributes 0x%lx\n", context_ndr
->attributes
);
349 status
= RPC_X_SS_CONTEXT_MISMATCH
;
352 status
= RpcServerAssoc_FindContextHandle(binding
->Assoc
,
358 if (status
!= RPC_S_OK
)
359 RpcRaiseException(status
);
361 RPCRT4_PushThreadContextHandle(SContext
);