ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

rpc_assoc.c
Go to the documentation of this file.
00001 /*
00002  * Associations
00003  *
00004  * Copyright 2007 Robert Shearman (for CodeWeavers)
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00019  *
00020  */
00021 
00022 #include <stdarg.h>
00023 #include <assert.h>
00024 
00025 #include "rpc.h"
00026 #include "rpcndr.h"
00027 #include "winternl.h"
00028 
00029 #include "wine/unicode.h"
00030 #include "wine/debug.h"
00031 
00032 #include "rpc_binding.h"
00033 #include "rpc_assoc.h"
00034 #include "rpc_message.h"
00035 
00036 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
00037 
00038 static CRITICAL_SECTION assoc_list_cs;
00039 static CRITICAL_SECTION_DEBUG assoc_list_cs_debug =
00040 {
00041     0, 0, &assoc_list_cs,
00042     { &assoc_list_cs_debug.ProcessLocksList, &assoc_list_cs_debug.ProcessLocksList },
00043       0, 0, { (DWORD_PTR)(__FILE__ ": assoc_list_cs") }
00044 };
00045 static CRITICAL_SECTION assoc_list_cs = { &assoc_list_cs_debug, -1, 0, 0, 0, 0 };
00046 
00047 static struct list client_assoc_list = LIST_INIT(client_assoc_list);
00048 static struct list server_assoc_list = LIST_INIT(server_assoc_list);
00049 
00050 static LONG last_assoc_group_id;
00051 
00052 typedef struct _RpcContextHandle
00053 {
00054     struct list entry;
00055     void *user_context;
00056     NDR_RUNDOWN rundown_routine;
00057     void *ctx_guard;
00058     UUID uuid;
00059     RTL_RWLOCK rw_lock;
00060     unsigned int refs;
00061 } RpcContextHandle;
00062 
00063 static void RpcContextHandle_Destroy(RpcContextHandle *context_handle);
00064 
00065 static RPC_STATUS RpcAssoc_Alloc(LPCSTR Protseq, LPCSTR NetworkAddr,
00066                                  LPCSTR Endpoint, LPCWSTR NetworkOptions,
00067                                  RpcAssoc **assoc_out)
00068 {
00069     RpcAssoc *assoc;
00070     assoc = HeapAlloc(GetProcessHeap(), 0, sizeof(*assoc));
00071     if (!assoc)
00072         return RPC_S_OUT_OF_RESOURCES;
00073     assoc->refs = 1;
00074     list_init(&assoc->free_connection_pool);
00075     list_init(&assoc->context_handle_list);
00076     InitializeCriticalSection(&assoc->cs);
00077     assoc->Protseq = RPCRT4_strdupA(Protseq);
00078     assoc->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
00079     assoc->Endpoint = RPCRT4_strdupA(Endpoint);
00080     assoc->NetworkOptions = NetworkOptions ? RPCRT4_strdupW(NetworkOptions) : NULL;
00081     assoc->assoc_group_id = 0;
00082     list_init(&assoc->entry);
00083     *assoc_out = assoc;
00084     return RPC_S_OK;
00085 }
00086 
00087 static BOOL compare_networkoptions(LPCWSTR opts1, LPCWSTR opts2)
00088 {
00089     if ((opts1 == NULL) && (opts2 == NULL))
00090         return TRUE;
00091     if ((opts1 == NULL) || (opts2 == NULL))
00092         return FALSE;
00093     return !strcmpW(opts1, opts2);
00094 }
00095 
00096 RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr,
00097                                  LPCSTR Endpoint, LPCWSTR NetworkOptions,
00098                                  RpcAssoc **assoc_out)
00099 {
00100     RpcAssoc *assoc;
00101     RPC_STATUS status;
00102 
00103     EnterCriticalSection(&assoc_list_cs);
00104     LIST_FOR_EACH_ENTRY(assoc, &client_assoc_list, RpcAssoc, entry)
00105     {
00106         if (!strcmp(Protseq, assoc->Protseq) &&
00107             !strcmp(NetworkAddr, assoc->NetworkAddr) &&
00108             !strcmp(Endpoint, assoc->Endpoint) &&
00109             compare_networkoptions(NetworkOptions, assoc->NetworkOptions))
00110         {
00111             assoc->refs++;
00112             *assoc_out = assoc;
00113             LeaveCriticalSection(&assoc_list_cs);
00114             TRACE("using existing assoc %p\n", assoc);
00115             return RPC_S_OK;
00116         }
00117     }
00118 
00119     status = RpcAssoc_Alloc(Protseq, NetworkAddr, Endpoint, NetworkOptions, &assoc);
00120     if (status != RPC_S_OK)
00121     {
00122         LeaveCriticalSection(&assoc_list_cs);
00123         return status;
00124     }
00125     list_add_head(&client_assoc_list, &assoc->entry);
00126     *assoc_out = assoc;
00127 
00128     LeaveCriticalSection(&assoc_list_cs);
00129 
00130     TRACE("new assoc %p\n", assoc);
00131 
00132     return RPC_S_OK;
00133 }
00134 
00135 RPC_STATUS RpcServerAssoc_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr,
00136                                          LPCSTR Endpoint, LPCWSTR NetworkOptions,
00137                                          ULONG assoc_gid,
00138                                          RpcAssoc **assoc_out)
00139 {
00140     RpcAssoc *assoc;
00141     RPC_STATUS status;
00142 
00143     EnterCriticalSection(&assoc_list_cs);
00144     if (assoc_gid)
00145     {
00146         LIST_FOR_EACH_ENTRY(assoc, &server_assoc_list, RpcAssoc, entry)
00147         {
00148             /* FIXME: NetworkAddr shouldn't be NULL */
00149             if (assoc->assoc_group_id == assoc_gid &&
00150                 !strcmp(Protseq, assoc->Protseq) &&
00151                 (!NetworkAddr || !assoc->NetworkAddr || !strcmp(NetworkAddr, assoc->NetworkAddr)) &&
00152                 !strcmp(Endpoint, assoc->Endpoint) &&
00153                 ((!assoc->NetworkOptions == !NetworkOptions) &&
00154                  (!NetworkOptions || !strcmpW(NetworkOptions, assoc->NetworkOptions))))
00155             {
00156                 assoc->refs++;
00157                 *assoc_out = assoc;
00158                 LeaveCriticalSection(&assoc_list_cs);
00159                 TRACE("using existing assoc %p\n", assoc);
00160                 return RPC_S_OK;
00161             }
00162         }
00163         *assoc_out = NULL;
00164         LeaveCriticalSection(&assoc_list_cs);
00165         return RPC_S_NO_CONTEXT_AVAILABLE;
00166     }
00167 
00168     status = RpcAssoc_Alloc(Protseq, NetworkAddr, Endpoint, NetworkOptions, &assoc);
00169     if (status != RPC_S_OK)
00170     {
00171         LeaveCriticalSection(&assoc_list_cs);
00172         return status;
00173     }
00174     assoc->assoc_group_id = InterlockedIncrement(&last_assoc_group_id);
00175     list_add_head(&server_assoc_list, &assoc->entry);
00176     *assoc_out = assoc;
00177 
00178     LeaveCriticalSection(&assoc_list_cs);
00179 
00180     TRACE("new assoc %p\n", assoc);
00181 
00182     return RPC_S_OK;
00183 }
00184 
00185 ULONG RpcAssoc_Release(RpcAssoc *assoc)
00186 {
00187     ULONG refs;
00188 
00189     EnterCriticalSection(&assoc_list_cs);
00190     refs = --assoc->refs;
00191     if (!refs)
00192         list_remove(&assoc->entry);
00193     LeaveCriticalSection(&assoc_list_cs);
00194 
00195     if (!refs)
00196     {
00197         RpcConnection *Connection, *cursor2;
00198         RpcContextHandle *context_handle, *context_handle_cursor;
00199 
00200         TRACE("destroying assoc %p\n", assoc);
00201 
00202         LIST_FOR_EACH_ENTRY_SAFE(Connection, cursor2, &assoc->free_connection_pool, RpcConnection, conn_pool_entry)
00203         {
00204             list_remove(&Connection->conn_pool_entry);
00205             RPCRT4_DestroyConnection(Connection);
00206         }
00207 
00208         LIST_FOR_EACH_ENTRY_SAFE(context_handle, context_handle_cursor, &assoc->context_handle_list, RpcContextHandle, entry)
00209             RpcContextHandle_Destroy(context_handle);
00210 
00211         HeapFree(GetProcessHeap(), 0, assoc->NetworkOptions);
00212         HeapFree(GetProcessHeap(), 0, assoc->Endpoint);
00213         HeapFree(GetProcessHeap(), 0, assoc->NetworkAddr);
00214         HeapFree(GetProcessHeap(), 0, assoc->Protseq);
00215 
00216         DeleteCriticalSection(&assoc->cs);
00217 
00218         HeapFree(GetProcessHeap(), 0, assoc);
00219     }
00220 
00221     return refs;
00222 }
00223 
00224 #define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1))
00225 
00226 static RPC_STATUS RpcAssoc_BindConnection(const RpcAssoc *assoc, RpcConnection *conn,
00227                                           const RPC_SYNTAX_IDENTIFIER *InterfaceId,
00228                                           const RPC_SYNTAX_IDENTIFIER *TransferSyntax)
00229 {
00230     RpcPktHdr *hdr;
00231     RpcPktHdr *response_hdr;
00232     RPC_MESSAGE msg;
00233     RPC_STATUS status;
00234     unsigned char *auth_data = NULL;
00235     ULONG auth_length;
00236 
00237     TRACE("sending bind request to server\n");
00238 
00239     hdr = RPCRT4_BuildBindHeader(NDR_LOCAL_DATA_REPRESENTATION,
00240                                  RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE,
00241                                  assoc->assoc_group_id,
00242                                  InterfaceId, TransferSyntax);
00243 
00244     status = RPCRT4_Send(conn, hdr, NULL, 0);
00245     RPCRT4_FreeHeader(hdr);
00246     if (status != RPC_S_OK)
00247         return status;
00248 
00249     status = RPCRT4_ReceiveWithAuth(conn, &response_hdr, &msg, &auth_data, &auth_length);
00250     if (status != RPC_S_OK)
00251     {
00252         ERR("receive failed with error %d\n", status);
00253         return status;
00254     }
00255 
00256     switch (response_hdr->common.ptype)
00257     {
00258     case PKT_BIND_ACK:
00259     {
00260         RpcAddressString *server_address = msg.Buffer;
00261         if ((msg.BufferLength >= FIELD_OFFSET(RpcAddressString, string[0])) ||
00262             (msg.BufferLength >= ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4)))
00263         {
00264             unsigned short remaining = msg.BufferLength -
00265             ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4);
00266             RpcResultList *results = (RpcResultList*)((ULONG_PTR)server_address +
00267                 ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4));
00268             if ((results->num_results == 1) &&
00269                 (remaining >= FIELD_OFFSET(RpcResultList, results[results->num_results])))
00270             {
00271                 switch (results->results[0].result)
00272                 {
00273                 case RESULT_ACCEPT:
00274                     /* respond to authorization request */
00275                     if (auth_length > sizeof(RpcAuthVerifier))
00276                         status = RPCRT4_ClientConnectionAuth(conn,
00277                                                              auth_data + sizeof(RpcAuthVerifier),
00278                                                              auth_length);
00279                     if (status == RPC_S_OK)
00280                     {
00281                         conn->assoc_group_id = response_hdr->bind_ack.assoc_gid;
00282                         conn->MaxTransmissionSize = response_hdr->bind_ack.max_tsize;
00283                         conn->ActiveInterface = *InterfaceId;
00284                     }
00285                     break;
00286                 case RESULT_PROVIDER_REJECTION:
00287                     switch (results->results[0].reason)
00288                     {
00289                     case REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
00290                         ERR("syntax %s, %d.%d not supported\n",
00291                             debugstr_guid(&InterfaceId->SyntaxGUID),
00292                             InterfaceId->SyntaxVersion.MajorVersion,
00293                             InterfaceId->SyntaxVersion.MinorVersion);
00294                         status = RPC_S_UNKNOWN_IF;
00295                         break;
00296                     case REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
00297                         ERR("transfer syntax not supported\n");
00298                         status = RPC_S_SERVER_UNAVAILABLE;
00299                         break;
00300                     case REASON_NONE:
00301                     default:
00302                         status = RPC_S_CALL_FAILED_DNE;
00303                     }
00304                     break;
00305                 case RESULT_USER_REJECTION:
00306                 default:
00307                     ERR("rejection result %d\n", results->results[0].result);
00308                     status = RPC_S_CALL_FAILED_DNE;
00309                 }
00310             }
00311             else
00312             {
00313                 ERR("incorrect results size\n");
00314                 status = RPC_S_CALL_FAILED_DNE;
00315             }
00316         }
00317         else
00318         {
00319             ERR("bind ack packet too small (%d)\n", msg.BufferLength);
00320             status = RPC_S_PROTOCOL_ERROR;
00321         }
00322         break;
00323     }
00324     case PKT_BIND_NACK:
00325         switch (response_hdr->bind_nack.reject_reason)
00326         {
00327         case REJECT_LOCAL_LIMIT_EXCEEDED:
00328         case REJECT_TEMPORARY_CONGESTION:
00329             ERR("server too busy\n");
00330             status = RPC_S_SERVER_TOO_BUSY;
00331             break;
00332         case REJECT_PROTOCOL_VERSION_NOT_SUPPORTED:
00333             ERR("protocol version not supported\n");
00334             status = RPC_S_PROTOCOL_ERROR;
00335             break;
00336         case REJECT_UNKNOWN_AUTHN_SERVICE:
00337             ERR("unknown authentication service\n");
00338             status = RPC_S_UNKNOWN_AUTHN_SERVICE;
00339             break;
00340         case REJECT_INVALID_CHECKSUM:
00341             ERR("invalid checksum\n");
00342             status = ERROR_ACCESS_DENIED;
00343             break;
00344         default:
00345             ERR("rejected bind for reason %d\n", response_hdr->bind_nack.reject_reason);
00346             status = RPC_S_CALL_FAILED_DNE;
00347         }
00348         break;
00349     default:
00350         ERR("wrong packet type received %d\n", response_hdr->common.ptype);
00351         status = RPC_S_PROTOCOL_ERROR;
00352         break;
00353     }
00354 
00355     I_RpcFree(msg.Buffer);
00356     RPCRT4_FreeHeader(response_hdr);
00357     HeapFree(GetProcessHeap(), 0, auth_data);
00358     return status;
00359 }
00360 
00361 static RpcConnection *RpcAssoc_GetIdleConnection(RpcAssoc *assoc,
00362                                                  const RPC_SYNTAX_IDENTIFIER *InterfaceId,
00363                                                  const RPC_SYNTAX_IDENTIFIER *TransferSyntax, const RpcAuthInfo *AuthInfo,
00364                                                  const RpcQualityOfService *QOS)
00365 {
00366     RpcConnection *Connection;
00367     EnterCriticalSection(&assoc->cs);
00368     /* try to find a compatible connection from the connection pool */
00369     LIST_FOR_EACH_ENTRY(Connection, &assoc->free_connection_pool, RpcConnection, conn_pool_entry)
00370     {
00371         if (!memcmp(&Connection->ActiveInterface, InterfaceId,
00372                     sizeof(RPC_SYNTAX_IDENTIFIER)) &&
00373             RpcAuthInfo_IsEqual(Connection->AuthInfo, AuthInfo) &&
00374             RpcQualityOfService_IsEqual(Connection->QOS, QOS))
00375         {
00376             list_remove(&Connection->conn_pool_entry);
00377             LeaveCriticalSection(&assoc->cs);
00378             TRACE("got connection from pool %p\n", Connection);
00379             return Connection;
00380         }
00381     }
00382 
00383     LeaveCriticalSection(&assoc->cs);
00384     return NULL;
00385 }
00386 
00387 RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc,
00388                                         const RPC_SYNTAX_IDENTIFIER *InterfaceId,
00389                                         const RPC_SYNTAX_IDENTIFIER *TransferSyntax, RpcAuthInfo *AuthInfo,
00390                                         RpcQualityOfService *QOS, RpcConnection **Connection)
00391 {
00392     RpcConnection *NewConnection;
00393     RPC_STATUS status;
00394 
00395     *Connection = RpcAssoc_GetIdleConnection(assoc, InterfaceId, TransferSyntax, AuthInfo, QOS);
00396     if (*Connection)
00397         return RPC_S_OK;
00398 
00399     /* create a new connection */
00400     status = RPCRT4_CreateConnection(&NewConnection, FALSE /* is this a server connection? */,
00401         assoc->Protseq, assoc->NetworkAddr,
00402         assoc->Endpoint, assoc->NetworkOptions,
00403         AuthInfo, QOS);
00404     if (status != RPC_S_OK)
00405         return status;
00406 
00407     NewConnection->assoc = assoc;
00408     status = RPCRT4_OpenClientConnection(NewConnection);
00409     if (status != RPC_S_OK)
00410     {
00411         RPCRT4_DestroyConnection(NewConnection);
00412         return status;
00413     }
00414 
00415     status = RpcAssoc_BindConnection(assoc, NewConnection, InterfaceId, TransferSyntax);
00416     if (status != RPC_S_OK)
00417     {
00418         RPCRT4_DestroyConnection(NewConnection);
00419         return status;
00420     }
00421 
00422     *Connection = NewConnection;
00423 
00424     return RPC_S_OK;
00425 }
00426 
00427 void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection)
00428 {
00429     assert(!Connection->server);
00430     Connection->async_state = NULL;
00431     EnterCriticalSection(&assoc->cs);
00432     if (!assoc->assoc_group_id) assoc->assoc_group_id = Connection->assoc_group_id;
00433     list_add_head(&assoc->free_connection_pool, &Connection->conn_pool_entry);
00434     LeaveCriticalSection(&assoc->cs);
00435 }
00436 
00437 RPC_STATUS RpcServerAssoc_AllocateContextHandle(RpcAssoc *assoc, void *CtxGuard,
00438                                                 NDR_SCONTEXT *SContext)
00439 {
00440     RpcContextHandle *context_handle;
00441 
00442     context_handle = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*context_handle));
00443     if (!context_handle)
00444         return ERROR_OUTOFMEMORY;
00445 
00446     context_handle->ctx_guard = CtxGuard;
00447     RtlInitializeResource(&context_handle->rw_lock);
00448     context_handle->refs = 1;
00449 
00450     /* lock here to mirror unmarshall, so we don't need to special-case the
00451      * freeing of a non-marshalled context handle */
00452     RtlAcquireResourceExclusive(&context_handle->rw_lock, TRUE);
00453 
00454     EnterCriticalSection(&assoc->cs);
00455     list_add_tail(&assoc->context_handle_list, &context_handle->entry);
00456     LeaveCriticalSection(&assoc->cs);
00457 
00458     *SContext = (NDR_SCONTEXT)context_handle;
00459     return RPC_S_OK;
00460 }
00461 
00462 BOOL RpcContextHandle_IsGuardCorrect(NDR_SCONTEXT SContext, void *CtxGuard)
00463 {
00464     RpcContextHandle *context_handle = (RpcContextHandle *)SContext;
00465     return context_handle->ctx_guard == CtxGuard;
00466 }
00467 
00468 RPC_STATUS RpcServerAssoc_FindContextHandle(RpcAssoc *assoc, const UUID *uuid,
00469                                             void *CtxGuard, ULONG Flags, NDR_SCONTEXT *SContext)
00470 {
00471     RpcContextHandle *context_handle;
00472 
00473     EnterCriticalSection(&assoc->cs);
00474     LIST_FOR_EACH_ENTRY(context_handle, &assoc->context_handle_list, RpcContextHandle, entry)
00475     {
00476         if (RpcContextHandle_IsGuardCorrect((NDR_SCONTEXT)context_handle, CtxGuard) &&
00477             !memcmp(&context_handle->uuid, uuid, sizeof(*uuid)))
00478         {
00479             *SContext = (NDR_SCONTEXT)context_handle;
00480             if (context_handle->refs++)
00481             {
00482                 LeaveCriticalSection(&assoc->cs);
00483                 TRACE("found %p\n", context_handle);
00484                 RtlAcquireResourceExclusive(&context_handle->rw_lock, TRUE);
00485                 return RPC_S_OK;
00486             }
00487         }
00488     }
00489     LeaveCriticalSection(&assoc->cs);
00490 
00491     ERR("no context handle found for uuid %s, guard %p\n",
00492         debugstr_guid(uuid), CtxGuard);
00493     return ERROR_INVALID_HANDLE;
00494 }
00495 
00496 RPC_STATUS RpcServerAssoc_UpdateContextHandle(RpcAssoc *assoc,
00497                                               NDR_SCONTEXT SContext,
00498                                               void *CtxGuard,
00499                                               NDR_RUNDOWN rundown_routine)
00500 {
00501     RpcContextHandle *context_handle = (RpcContextHandle *)SContext;
00502     RPC_STATUS status;
00503 
00504     if (!RpcContextHandle_IsGuardCorrect((NDR_SCONTEXT)context_handle, CtxGuard))
00505         return ERROR_INVALID_HANDLE;
00506 
00507     EnterCriticalSection(&assoc->cs);
00508     if (UuidIsNil(&context_handle->uuid, &status))
00509     {
00510         /* add a ref for the data being valid */
00511         context_handle->refs++;
00512         UuidCreate(&context_handle->uuid);
00513         context_handle->rundown_routine = rundown_routine;
00514         TRACE("allocated uuid %s for context handle %p\n",
00515               debugstr_guid(&context_handle->uuid), context_handle);
00516     }
00517     LeaveCriticalSection(&assoc->cs);
00518 
00519     return RPC_S_OK;
00520 }
00521 
00522 void RpcContextHandle_GetUuid(NDR_SCONTEXT SContext, UUID *uuid)
00523 {
00524     RpcContextHandle *context_handle = (RpcContextHandle *)SContext;
00525     *uuid = context_handle->uuid;
00526 }
00527 
00528 static void RpcContextHandle_Destroy(RpcContextHandle *context_handle)
00529 {
00530     TRACE("freeing %p\n", context_handle);
00531 
00532     if (context_handle->user_context && context_handle->rundown_routine)
00533     {
00534         TRACE("calling rundown routine %p with user context %p\n",
00535               context_handle->rundown_routine, context_handle->user_context);
00536         context_handle->rundown_routine(context_handle->user_context);
00537     }
00538 
00539     RtlDeleteResource(&context_handle->rw_lock);
00540 
00541     HeapFree(GetProcessHeap(), 0, context_handle);
00542 }
00543 
00544 unsigned int RpcServerAssoc_ReleaseContextHandle(RpcAssoc *assoc, NDR_SCONTEXT SContext, BOOL release_lock)
00545 {
00546     RpcContextHandle *context_handle = (RpcContextHandle *)SContext;
00547     unsigned int refs;
00548 
00549     if (release_lock)
00550         RtlReleaseResource(&context_handle->rw_lock);
00551 
00552     EnterCriticalSection(&assoc->cs);
00553     refs = --context_handle->refs;
00554     if (!refs)
00555         list_remove(&context_handle->entry);
00556     LeaveCriticalSection(&assoc->cs);
00557 
00558     if (!refs)
00559         RpcContextHandle_Destroy(context_handle);
00560 
00561     return refs;
00562 }

Generated on Fri May 25 2012 04:24:13 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.