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
);
92 RpcRaiseException(ERROR_INVALID_HANDLE
);
96 void WINAPI
NDRCContextMarshall(NDR_CCONTEXT CContext
, void *pBuff
)
98 struct context_handle_entry
*che
;
100 TRACE("%p %p\n", CContext
, pBuff
);
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
);
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
;
133 list_remove(&che
->entry
);
136 LeaveCriticalSection(&ndr_context_cs
);
140 RpcBindingFree(&che
->handle
);
141 HeapFree(GetProcessHeap(), 0, che
);
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
))
168 che
= get_context_entry(*CContext
);
170 return ERROR_INVALID_HANDLE
;
171 list_remove(&che
->entry
);
172 RpcBindingFree(&che
->handle
);
173 HeapFree(GetProcessHeap(), 0, che
);
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
);
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
);
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
)
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
);
210 RpcRaiseException(r
);
213 /***********************************************************************
214 * NDRSContextMarshall [RPCRT4.@]
216 void WINAPI
NDRSContextMarshall(NDR_SCONTEXT SContext
,
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
,
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
,
242 NDR_RUNDOWN userRunDownIn
,
243 void *CtxGuard
, ULONG Flags
)
245 RpcBinding
*binding
= hBinding
;
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
);
261 RpcContextHandle_GetUuid(SContext
, &ndr
->uuid
);
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
,
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
,
304 ULONG DataRepresentation
,
305 void *CtxGuard
, ULONG Flags
)
307 RpcBinding
*binding
= hBinding
;
308 NDR_SCONTEXT SContext
;
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
);
318 status
= RpcServerAssoc_AllocateContextHandle(binding
->Assoc
, CtxGuard
,
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
;
329 status
= RpcServerAssoc_FindContextHandle(binding
->Assoc
,
335 if (status
!= RPC_S_OK
)
336 RpcRaiseException(status
);