1 /*
2 * Associations
3 *
4 * Copyright 2007 Robert Shearman (for CodeWeavers)
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 *
20 */
21
22 #include <stdarg.h>
23 #include <assert.h>
24
25 #include "rpc.h"
26 #include "rpcndr.h"
27 #include "wine/winternl.h"
28
29 #include "wine/debug.h"
30
31 #include "rpc_binding.h"
32 #include "rpc_assoc.h"
33 #include "rpc_message.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
36
37 static CRITICAL_SECTION assoc_list_cs;
38 static CRITICAL_SECTION_DEBUG assoc_list_cs_debug =
39 {
40 0, 0, &assoc_list_cs,
41 { &assoc_list_cs_debug.ProcessLocksList, &assoc_list_cs_debug.ProcessLocksList },
42 0, 0, { (DWORD_PTR)(__FILE__ ": assoc_list_cs") }
43 };
44 static CRITICAL_SECTION assoc_list_cs = { &assoc_list_cs_debug, -1, 0, 0, 0, 0 };
45
46 static struct list client_assoc_list = LIST_INIT(client_assoc_list);
47 static struct list server_assoc_list = LIST_INIT(server_assoc_list);
48
49 static LONG last_assoc_group_id;
50
51 typedef struct _RpcContextHandle
52 {
53 struct list entry;
54 void *user_context;
55 NDR_RUNDOWN rundown_routine;
56 void *ctx_guard;
57 UUID uuid;
58 RTL_RWLOCK rw_lock;
59 unsigned int refs;
60 } RpcContextHandle;
61
62 static void RpcContextHandle_Destroy(RpcContextHandle *context_handle);
63
RpcAssoc_Alloc(LPCSTR Protseq,LPCSTR NetworkAddr,LPCSTR Endpoint,LPCWSTR NetworkOptions,RpcAssoc ** assoc_out)64 static RPC_STATUS RpcAssoc_Alloc(LPCSTR Protseq, LPCSTR NetworkAddr,
65 LPCSTR Endpoint, LPCWSTR NetworkOptions,
66 RpcAssoc **assoc_out)
67 {
68 RpcAssoc *assoc;
69 assoc = HeapAlloc(GetProcessHeap(), 0, sizeof(*assoc));
70 if (!assoc)
71 return RPC_S_OUT_OF_RESOURCES;
72 assoc->refs = 1;
73 list_init(&assoc->free_connection_pool);
74 list_init(&assoc->context_handle_list);
75 InitializeCriticalSection(&assoc->cs);
76 assoc->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RpcAssoc.cs");
77 assoc->Protseq = RPCRT4_strdupA(Protseq);
78 assoc->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
79 assoc->Endpoint = RPCRT4_strdupA(Endpoint);
80 assoc->NetworkOptions = NetworkOptions ? RPCRT4_strdupW(NetworkOptions) : NULL;
81 assoc->assoc_group_id = 0;
82 assoc->connection_cnt = 0;
83 UuidCreate(&assoc->http_uuid);
84 list_init(&assoc->entry);
85 *assoc_out = assoc;
86 return RPC_S_OK;
87 }
88
compare_networkoptions(LPCWSTR opts1,LPCWSTR opts2)89 static BOOL compare_networkoptions(LPCWSTR opts1, LPCWSTR opts2)
90 {
91 if ((opts1 == NULL) && (opts2 == NULL))
92 return TRUE;
93 if ((opts1 == NULL) || (opts2 == NULL))
94 return FALSE;
95 return !wcscmp(opts1, opts2);
96 }
97
RPCRT4_GetAssociation(LPCSTR Protseq,LPCSTR NetworkAddr,LPCSTR Endpoint,LPCWSTR NetworkOptions,RpcAssoc ** assoc_out)98 RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr,
99 LPCSTR Endpoint, LPCWSTR NetworkOptions,
100 RpcAssoc **assoc_out)
101 {
102 RpcAssoc *assoc;
103 RPC_STATUS status;
104
105 EnterCriticalSection(&assoc_list_cs);
106 LIST_FOR_EACH_ENTRY(assoc, &client_assoc_list, RpcAssoc, entry)
107 {
108 if (!strcmp(Protseq, assoc->Protseq) &&
109 !strcmp(NetworkAddr, assoc->NetworkAddr) &&
110 !strcmp(Endpoint, assoc->Endpoint) &&
111 compare_networkoptions(NetworkOptions, assoc->NetworkOptions))
112 {
113 assoc->refs++;
114 *assoc_out = assoc;
115 LeaveCriticalSection(&assoc_list_cs);
116 TRACE("using existing assoc %p\n", assoc);
117 return RPC_S_OK;
118 }
119 }
120
121 status = RpcAssoc_Alloc(Protseq, NetworkAddr, Endpoint, NetworkOptions, &assoc);
122 if (status != RPC_S_OK)
123 {
124 LeaveCriticalSection(&assoc_list_cs);
125 return status;
126 }
127 list_add_head(&client_assoc_list, &assoc->entry);
128 *assoc_out = assoc;
129
130 LeaveCriticalSection(&assoc_list_cs);
131
132 TRACE("new assoc %p\n", assoc);
133
134 return RPC_S_OK;
135 }
136
RpcServerAssoc_GetAssociation(LPCSTR Protseq,LPCSTR NetworkAddr,LPCSTR Endpoint,LPCWSTR NetworkOptions,ULONG assoc_gid,RpcAssoc ** assoc_out)137 RPC_STATUS RpcServerAssoc_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr,
138 LPCSTR Endpoint, LPCWSTR NetworkOptions,
139 ULONG assoc_gid,
140 RpcAssoc **assoc_out)
141 {
142 RpcAssoc *assoc;
143 RPC_STATUS status;
144
145 EnterCriticalSection(&assoc_list_cs);
146 if (assoc_gid)
147 {
148 LIST_FOR_EACH_ENTRY(assoc, &server_assoc_list, RpcAssoc, entry)
149 {
150 /* FIXME: NetworkAddr shouldn't be NULL */
151 if (assoc->assoc_group_id == assoc_gid &&
152 !strcmp(Protseq, assoc->Protseq) &&
153 (!NetworkAddr || !assoc->NetworkAddr || !strcmp(NetworkAddr, assoc->NetworkAddr)) &&
154 !strcmp(Endpoint, assoc->Endpoint) &&
155 ((!assoc->NetworkOptions == !NetworkOptions) &&
156 (!NetworkOptions || !wcscmp(NetworkOptions, assoc->NetworkOptions))))
157 {
158 assoc->refs++;
159 *assoc_out = assoc;
160 LeaveCriticalSection(&assoc_list_cs);
161 TRACE("using existing assoc %p\n", assoc);
162 return RPC_S_OK;
163 }
164 }
165 *assoc_out = NULL;
166 LeaveCriticalSection(&assoc_list_cs);
167 return RPC_S_NO_CONTEXT_AVAILABLE;
168 }
169
170 status = RpcAssoc_Alloc(Protseq, NetworkAddr, Endpoint, NetworkOptions, &assoc);
171 if (status != RPC_S_OK)
172 {
173 LeaveCriticalSection(&assoc_list_cs);
174 return status;
175 }
176 assoc->assoc_group_id = InterlockedIncrement(&last_assoc_group_id);
177 list_add_head(&server_assoc_list, &assoc->entry);
178 *assoc_out = assoc;
179
180 LeaveCriticalSection(&assoc_list_cs);
181
182 TRACE("new assoc %p\n", assoc);
183
184 return RPC_S_OK;
185 }
186
RpcAssoc_Release(RpcAssoc * assoc)187 ULONG RpcAssoc_Release(RpcAssoc *assoc)
188 {
189 ULONG refs;
190
191 EnterCriticalSection(&assoc_list_cs);
192 refs = --assoc->refs;
193 if (!refs)
194 list_remove(&assoc->entry);
195 LeaveCriticalSection(&assoc_list_cs);
196
197 if (!refs)
198 {
199 RpcConnection *Connection, *cursor2;
200 RpcContextHandle *context_handle, *context_handle_cursor;
201
202 TRACE("destroying assoc %p\n", assoc);
203
204 LIST_FOR_EACH_ENTRY_SAFE(Connection, cursor2, &assoc->free_connection_pool, RpcConnection, conn_pool_entry)
205 {
206 list_remove(&Connection->conn_pool_entry);
207 RPCRT4_ReleaseConnection(Connection);
208 }
209
210 LIST_FOR_EACH_ENTRY_SAFE(context_handle, context_handle_cursor, &assoc->context_handle_list, RpcContextHandle, entry)
211 RpcContextHandle_Destroy(context_handle);
212
213 HeapFree(GetProcessHeap(), 0, assoc->NetworkOptions);
214 HeapFree(GetProcessHeap(), 0, assoc->Endpoint);
215 HeapFree(GetProcessHeap(), 0, assoc->NetworkAddr);
216 HeapFree(GetProcessHeap(), 0, assoc->Protseq);
217
218 assoc->cs.DebugInfo->Spare[0] = 0;
219 DeleteCriticalSection(&assoc->cs);
220
221 HeapFree(GetProcessHeap(), 0, assoc);
222 }
223
224 return refs;
225 }
226
227 #define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1))
228
RpcAssoc_BindConnection(const RpcAssoc * assoc,RpcConnection * conn,const RPC_SYNTAX_IDENTIFIER * InterfaceId,const RPC_SYNTAX_IDENTIFIER * TransferSyntax)229 static RPC_STATUS RpcAssoc_BindConnection(const RpcAssoc *assoc, RpcConnection *conn,
230 const RPC_SYNTAX_IDENTIFIER *InterfaceId,
231 const RPC_SYNTAX_IDENTIFIER *TransferSyntax)
232 {
233 RpcPktHdr *hdr;
234 RpcPktHdr *response_hdr;
235 RPC_MESSAGE msg;
236 RPC_STATUS status;
237 unsigned char *auth_data = NULL;
238 ULONG auth_length;
239
240 TRACE("sending bind request to server\n");
241
242 hdr = RPCRT4_BuildBindHeader(NDR_LOCAL_DATA_REPRESENTATION,
243 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE,
244 assoc->assoc_group_id,
245 InterfaceId, TransferSyntax);
246
247 status = RPCRT4_Send(conn, hdr, NULL, 0);
248 RPCRT4_FreeHeader(hdr);
249 if (status != RPC_S_OK)
250 return status;
251
252 status = RPCRT4_ReceiveWithAuth(conn, &response_hdr, &msg, &auth_data, &auth_length);
253 if (status != RPC_S_OK)
254 {
255 ERR("receive failed with error %d\n", status);
256 return status;
257 }
258
259 switch (response_hdr->common.ptype)
260 {
261 case PKT_BIND_ACK:
262 {
263 RpcAddressString *server_address = msg.Buffer;
264 if ((msg.BufferLength >= FIELD_OFFSET(RpcAddressString, string[0])) ||
265 (msg.BufferLength >= ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4)))
266 {
267 unsigned short remaining = msg.BufferLength -
268 ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4);
269 RpcResultList *results = (RpcResultList*)((ULONG_PTR)server_address +
270 ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4));
271 if ((results->num_results == 1) &&
272 (remaining >= FIELD_OFFSET(RpcResultList, results[results->num_results])))
273 {
274 switch (results->results[0].result)
275 {
276 case RESULT_ACCEPT:
277 /* respond to authorization request */
278 if (auth_length > sizeof(RpcAuthVerifier))
279 status = RPCRT4_ClientConnectionAuth(conn,
280 auth_data + sizeof(RpcAuthVerifier),
281 auth_length);
282 if (status == RPC_S_OK)
283 {
284 conn->assoc_group_id = response_hdr->bind_ack.assoc_gid;
285 conn->MaxTransmissionSize = response_hdr->bind_ack.max_tsize;
286 conn->ActiveInterface = *InterfaceId;
287 }
288 break;
289 case RESULT_PROVIDER_REJECTION:
290 switch (results->results[0].reason)
291 {
292 case REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
293 ERR("syntax %s, %d.%d not supported\n",
294 debugstr_guid(&InterfaceId->SyntaxGUID),
295 InterfaceId->SyntaxVersion.MajorVersion,
296 InterfaceId->SyntaxVersion.MinorVersion);
297 status = RPC_S_UNKNOWN_IF;
298 break;
299 case REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
300 ERR("transfer syntax not supported\n");
301 status = RPC_S_SERVER_UNAVAILABLE;
302 break;
303 case REASON_NONE:
304 default:
305 status = RPC_S_CALL_FAILED_DNE;
306 }
307 break;
308 case RESULT_USER_REJECTION:
309 default:
310 ERR("rejection result %d\n", results->results[0].result);
311 status = RPC_S_CALL_FAILED_DNE;
312 }
313 }
314 else
315 {
316 ERR("incorrect results size\n");
317 status = RPC_S_CALL_FAILED_DNE;
318 }
319 }
320 else
321 {
322 ERR("bind ack packet too small (%d)\n", msg.BufferLength);
323 status = RPC_S_PROTOCOL_ERROR;
324 }
325 break;
326 }
327 case PKT_BIND_NACK:
328 switch (response_hdr->bind_nack.reject_reason)
329 {
330 case REJECT_LOCAL_LIMIT_EXCEEDED:
331 case REJECT_TEMPORARY_CONGESTION:
332 ERR("server too busy\n");
333 status = RPC_S_SERVER_TOO_BUSY;
334 break;
335 case REJECT_PROTOCOL_VERSION_NOT_SUPPORTED:
336 ERR("protocol version not supported\n");
337 status = RPC_S_PROTOCOL_ERROR;
338 break;
339 case REJECT_UNKNOWN_AUTHN_SERVICE:
340 ERR("unknown authentication service\n");
341 status = RPC_S_UNKNOWN_AUTHN_SERVICE;
342 break;
343 case REJECT_INVALID_CHECKSUM:
344 ERR("invalid checksum\n");
345 status = RPC_S_ACCESS_DENIED;
346 break;
347 default:
348 ERR("rejected bind for reason %d\n", response_hdr->bind_nack.reject_reason);
349 status = RPC_S_CALL_FAILED_DNE;
350 }
351 break;
352 default:
353 ERR("wrong packet type received %d\n", response_hdr->common.ptype);
354 status = RPC_S_PROTOCOL_ERROR;
355 break;
356 }
357
358 I_RpcFree(msg.Buffer);
359 RPCRT4_FreeHeader(response_hdr);
360 HeapFree(GetProcessHeap(), 0, auth_data);
361 return status;
362 }
363
RpcAssoc_GetIdleConnection(RpcAssoc * assoc,const RPC_SYNTAX_IDENTIFIER * InterfaceId,const RPC_SYNTAX_IDENTIFIER * TransferSyntax,const RpcAuthInfo * AuthInfo,const RpcQualityOfService * QOS)364 static RpcConnection *RpcAssoc_GetIdleConnection(RpcAssoc *assoc,
365 const RPC_SYNTAX_IDENTIFIER *InterfaceId,
366 const RPC_SYNTAX_IDENTIFIER *TransferSyntax, const RpcAuthInfo *AuthInfo,
367 const RpcQualityOfService *QOS)
368 {
369 RpcConnection *Connection;
370 EnterCriticalSection(&assoc->cs);
371 /* try to find a compatible connection from the connection pool */
372 LIST_FOR_EACH_ENTRY(Connection, &assoc->free_connection_pool, RpcConnection, conn_pool_entry)
373 {
374 if (!memcmp(&Connection->ActiveInterface, InterfaceId,
375 sizeof(RPC_SYNTAX_IDENTIFIER)) &&
376 RpcAuthInfo_IsEqual(Connection->AuthInfo, AuthInfo) &&
377 RpcQualityOfService_IsEqual(Connection->QOS, QOS))
378 {
379 list_remove(&Connection->conn_pool_entry);
380 LeaveCriticalSection(&assoc->cs);
381 TRACE("got connection from pool %p\n", Connection);
382 return Connection;
383 }
384 }
385
386 LeaveCriticalSection(&assoc->cs);
387 return NULL;
388 }
389
RpcAssoc_GetClientConnection(RpcAssoc * assoc,const RPC_SYNTAX_IDENTIFIER * InterfaceId,const RPC_SYNTAX_IDENTIFIER * TransferSyntax,RpcAuthInfo * AuthInfo,RpcQualityOfService * QOS,LPCWSTR CookieAuth,RpcConnection ** Connection,BOOL * from_cache)390 RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc,
391 const RPC_SYNTAX_IDENTIFIER *InterfaceId,
392 const RPC_SYNTAX_IDENTIFIER *TransferSyntax, RpcAuthInfo *AuthInfo,
393 RpcQualityOfService *QOS, LPCWSTR CookieAuth,
394 RpcConnection **Connection, BOOL *from_cache)
395 {
396 RpcConnection *NewConnection;
397 RPC_STATUS status;
398
399 *Connection = RpcAssoc_GetIdleConnection(assoc, InterfaceId, TransferSyntax, AuthInfo, QOS);
400 if (*Connection) {
401 TRACE("return idle connection %p for association %p\n", *Connection, assoc);
402 if (from_cache) *from_cache = TRUE;
403 return RPC_S_OK;
404 }
405
406 /* create a new connection */
407 status = RPCRT4_CreateConnection(&NewConnection, FALSE /* is this a server connection? */,
408 assoc->Protseq, assoc->NetworkAddr,
409 assoc->Endpoint, assoc->NetworkOptions,
410 AuthInfo, QOS, CookieAuth);
411 if (status != RPC_S_OK)
412 return status;
413
414 NewConnection->assoc = assoc;
415 status = RPCRT4_OpenClientConnection(NewConnection);
416 if (status != RPC_S_OK)
417 {
418 RPCRT4_ReleaseConnection(NewConnection);
419 return status;
420 }
421
422 status = RpcAssoc_BindConnection(assoc, NewConnection, InterfaceId, TransferSyntax);
423 if (status != RPC_S_OK)
424 {
425 RPCRT4_ReleaseConnection(NewConnection);
426 return status;
427 }
428
429 InterlockedIncrement(&assoc->connection_cnt);
430
431 TRACE("return new connection %p for association %p\n", *Connection, assoc);
432 *Connection = NewConnection;
433 if (from_cache) *from_cache = FALSE;
434 return RPC_S_OK;
435 }
436
RpcAssoc_ReleaseIdleConnection(RpcAssoc * assoc,RpcConnection * Connection)437 void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection)
438 {
439 assert(!Connection->server);
440 Connection->async_state = NULL;
441 EnterCriticalSection(&assoc->cs);
442 if (!assoc->assoc_group_id) assoc->assoc_group_id = Connection->assoc_group_id;
443 list_add_head(&assoc->free_connection_pool, &Connection->conn_pool_entry);
444 LeaveCriticalSection(&assoc->cs);
445 }
446
RpcAssoc_ConnectionReleased(RpcAssoc * assoc)447 void RpcAssoc_ConnectionReleased(RpcAssoc *assoc)
448 {
449 if (InterlockedDecrement(&assoc->connection_cnt))
450 return;
451
452 TRACE("Last %p connection released\n", assoc);
453 assoc->assoc_group_id = 0;
454 }
455
RpcServerAssoc_AllocateContextHandle(RpcAssoc * assoc,void * CtxGuard,NDR_SCONTEXT * SContext)456 RPC_STATUS RpcServerAssoc_AllocateContextHandle(RpcAssoc *assoc, void *CtxGuard,
457 NDR_SCONTEXT *SContext)
458 {
459 RpcContextHandle *context_handle;
460
461 context_handle = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*context_handle));
462 if (!context_handle)
463 return RPC_S_OUT_OF_MEMORY;
464
465 context_handle->ctx_guard = CtxGuard;
466 RtlInitializeResource(&context_handle->rw_lock);
467 context_handle->refs = 1;
468
469 /* lock here to mirror unmarshall, so we don't need to special-case the
470 * freeing of a non-marshalled context handle */
471 RtlAcquireResourceExclusive(&context_handle->rw_lock, TRUE);
472
473 EnterCriticalSection(&assoc->cs);
474 list_add_tail(&assoc->context_handle_list, &context_handle->entry);
475 LeaveCriticalSection(&assoc->cs);
476
477 *SContext = (NDR_SCONTEXT)context_handle;
478 return RPC_S_OK;
479 }
480
RpcContextHandle_IsGuardCorrect(NDR_SCONTEXT SContext,void * CtxGuard)481 BOOL RpcContextHandle_IsGuardCorrect(NDR_SCONTEXT SContext, void *CtxGuard)
482 {
483 RpcContextHandle *context_handle = (RpcContextHandle *)SContext;
484 return context_handle->ctx_guard == CtxGuard;
485 }
486
RpcServerAssoc_FindContextHandle(RpcAssoc * assoc,const UUID * uuid,void * CtxGuard,ULONG Flags,NDR_SCONTEXT * SContext)487 RPC_STATUS RpcServerAssoc_FindContextHandle(RpcAssoc *assoc, const UUID *uuid,
488 void *CtxGuard, ULONG Flags, NDR_SCONTEXT *SContext)
489 {
490 RpcContextHandle *context_handle;
491
492 EnterCriticalSection(&assoc->cs);
493 LIST_FOR_EACH_ENTRY(context_handle, &assoc->context_handle_list, RpcContextHandle, entry)
494 {
495 if (RpcContextHandle_IsGuardCorrect((NDR_SCONTEXT)context_handle, CtxGuard) &&
496 !memcmp(&context_handle->uuid, uuid, sizeof(*uuid)))
497 {
498 *SContext = (NDR_SCONTEXT)context_handle;
499 if (context_handle->refs++)
500 {
501 LeaveCriticalSection(&assoc->cs);
502 TRACE("found %p\n", context_handle);
503 RtlAcquireResourceExclusive(&context_handle->rw_lock, TRUE);
504 return RPC_S_OK;
505 }
506 }
507 }
508 LeaveCriticalSection(&assoc->cs);
509
510 ERR("no context handle found for uuid %s, guard %p\n",
511 debugstr_guid(uuid), CtxGuard);
512 return ERROR_INVALID_HANDLE;
513 }
514
RpcServerAssoc_UpdateContextHandle(RpcAssoc * assoc,NDR_SCONTEXT SContext,void * CtxGuard,NDR_RUNDOWN rundown_routine)515 RPC_STATUS RpcServerAssoc_UpdateContextHandle(RpcAssoc *assoc,
516 NDR_SCONTEXT SContext,
517 void *CtxGuard,
518 NDR_RUNDOWN rundown_routine)
519 {
520 RpcContextHandle *context_handle = (RpcContextHandle *)SContext;
521 RPC_STATUS status;
522
523 if (!RpcContextHandle_IsGuardCorrect((NDR_SCONTEXT)context_handle, CtxGuard))
524 return ERROR_INVALID_HANDLE;
525
526 EnterCriticalSection(&assoc->cs);
527 if (UuidIsNil(&context_handle->uuid, &status))
528 {
529 /* add a ref for the data being valid */
530 context_handle->refs++;
531 UuidCreate(&context_handle->uuid);
532 context_handle->rundown_routine = rundown_routine;
533 TRACE("allocated uuid %s for context handle %p\n",
534 debugstr_guid(&context_handle->uuid), context_handle);
535 }
536 LeaveCriticalSection(&assoc->cs);
537
538 return RPC_S_OK;
539 }
540
RpcContextHandle_GetUuid(NDR_SCONTEXT SContext,UUID * uuid)541 void RpcContextHandle_GetUuid(NDR_SCONTEXT SContext, UUID *uuid)
542 {
543 RpcContextHandle *context_handle = (RpcContextHandle *)SContext;
544 *uuid = context_handle->uuid;
545 }
546
RpcContextHandle_Destroy(RpcContextHandle * context_handle)547 static void RpcContextHandle_Destroy(RpcContextHandle *context_handle)
548 {
549 TRACE("freeing %p\n", context_handle);
550
551 if (context_handle->user_context && context_handle->rundown_routine)
552 {
553 TRACE("calling rundown routine %p with user context %p\n",
554 context_handle->rundown_routine, context_handle->user_context);
555 context_handle->rundown_routine(context_handle->user_context);
556 }
557
558 RtlDeleteResource(&context_handle->rw_lock);
559
560 HeapFree(GetProcessHeap(), 0, context_handle);
561 }
562
RpcServerAssoc_ReleaseContextHandle(RpcAssoc * assoc,NDR_SCONTEXT SContext,BOOL release_lock)563 unsigned int RpcServerAssoc_ReleaseContextHandle(RpcAssoc *assoc, NDR_SCONTEXT SContext, BOOL release_lock)
564 {
565 RpcContextHandle *context_handle = (RpcContextHandle *)SContext;
566 unsigned int refs;
567
568 if (release_lock)
569 RtlReleaseResource(&context_handle->rw_lock);
570
571 EnterCriticalSection(&assoc->cs);
572 refs = --context_handle->refs;
573 if (!refs)
574 list_remove(&context_handle->entry);
575 LeaveCriticalSection(&assoc->cs);
576
577 if (!refs)
578 RpcContextHandle_Destroy(context_handle);
579
580 return refs;
581 }
582