From 737510eeb6019596f6a838f5a86a346183893f8d Mon Sep 17 00:00:00 2001 From: Rob Shearman Date: Sun, 16 Dec 2007 12:11:49 +0000 Subject: [PATCH] rpcrt4: Move association code into a separate file. --- dlls/rpcrt4/Makefile.in | 1 + dlls/rpcrt4/rpc_assoc.c | 392 ++++++++++++++++++++++++++++++++++++ dlls/rpcrt4/rpc_assoc.h | 46 +++++ dlls/rpcrt4/rpc_binding.c | 2 +- dlls/rpcrt4/rpc_binding.h | 26 +-- dlls/rpcrt4/rpc_server.c | 1 + dlls/rpcrt4/rpc_transport.c | 357 -------------------------------- 7 files changed, 442 insertions(+), 383 deletions(-) create mode 100644 dlls/rpcrt4/rpc_assoc.c create mode 100644 dlls/rpcrt4/rpc_assoc.h diff --git a/dlls/rpcrt4/Makefile.in b/dlls/rpcrt4/Makefile.in index 847e88eeff..65ae475c31 100644 --- a/dlls/rpcrt4/Makefile.in +++ b/dlls/rpcrt4/Makefile.in @@ -18,6 +18,7 @@ C_SRCS = \ ndr_marshall.c \ ndr_ole.c \ ndr_stubless.c \ + rpc_assoc.c \ rpc_binding.c \ rpc_epmap.c \ rpc_message.c \ diff --git a/dlls/rpcrt4/rpc_assoc.c b/dlls/rpcrt4/rpc_assoc.c new file mode 100644 index 0000000000..173ba712d7 --- /dev/null +++ b/dlls/rpcrt4/rpc_assoc.c @@ -0,0 +1,392 @@ +/* + * Associations + * + * Copyright 2007 Robert Shearman (for CodeWeavers) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include +#include + +#include "rpc.h" +#include "rpcndr.h" + +#include "wine/unicode.h" +#include "wine/debug.h" + +#include "rpc_binding.h" +#include "rpc_assoc.h" +#include "rpc_message.h" + +WINE_DEFAULT_DEBUG_CHANNEL(rpc); + +static CRITICAL_SECTION assoc_list_cs; +static CRITICAL_SECTION_DEBUG assoc_list_cs_debug = +{ + 0, 0, &assoc_list_cs, + { &assoc_list_cs_debug.ProcessLocksList, &assoc_list_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": assoc_list_cs") } +}; +static CRITICAL_SECTION assoc_list_cs = { &assoc_list_cs_debug, -1, 0, 0, 0, 0 }; + +static struct list client_assoc_list = LIST_INIT(client_assoc_list); +static struct list server_assoc_list = LIST_INIT(server_assoc_list); + +static LONG last_assoc_group_id; + +static RPC_STATUS RpcAssoc_Alloc(LPCSTR Protseq, LPCSTR NetworkAddr, + LPCSTR Endpoint, LPCWSTR NetworkOptions, + RpcAssoc **assoc_out) +{ + RpcAssoc *assoc; + assoc = HeapAlloc(GetProcessHeap(), 0, sizeof(*assoc)); + if (!assoc) + return RPC_S_OUT_OF_RESOURCES; + assoc->refs = 1; + list_init(&assoc->free_connection_pool); + InitializeCriticalSection(&assoc->cs); + assoc->Protseq = RPCRT4_strdupA(Protseq); + assoc->NetworkAddr = RPCRT4_strdupA(NetworkAddr); + assoc->Endpoint = RPCRT4_strdupA(Endpoint); + assoc->NetworkOptions = NetworkOptions ? RPCRT4_strdupW(NetworkOptions) : NULL; + assoc->assoc_group_id = 0; + list_init(&assoc->entry); + *assoc_out = assoc; + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, + LPCSTR Endpoint, LPCWSTR NetworkOptions, + RpcAssoc **assoc_out) +{ + RpcAssoc *assoc; + RPC_STATUS status; + + EnterCriticalSection(&assoc_list_cs); + LIST_FOR_EACH_ENTRY(assoc, &client_assoc_list, RpcAssoc, entry) + { + if (!strcmp(Protseq, assoc->Protseq) && + !strcmp(NetworkAddr, assoc->NetworkAddr) && + !strcmp(Endpoint, assoc->Endpoint) && + ((!assoc->NetworkOptions && !NetworkOptions) || !strcmpW(NetworkOptions, assoc->NetworkOptions))) + { + assoc->refs++; + *assoc_out = assoc; + LeaveCriticalSection(&assoc_list_cs); + TRACE("using existing assoc %p\n", assoc); + return RPC_S_OK; + } + } + + status = RpcAssoc_Alloc(Protseq, NetworkAddr, Endpoint, NetworkOptions, &assoc); + if (status != RPC_S_OK) + { + LeaveCriticalSection(&assoc_list_cs); + return status; + } + list_add_head(&client_assoc_list, &assoc->entry); + *assoc_out = assoc; + + LeaveCriticalSection(&assoc_list_cs); + + TRACE("new assoc %p\n", assoc); + + return RPC_S_OK; +} + +RPC_STATUS RpcServerAssoc_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, + LPCSTR Endpoint, LPCWSTR NetworkOptions, + unsigned long assoc_gid, + RpcAssoc **assoc_out) +{ + RpcAssoc *assoc; + RPC_STATUS status; + + EnterCriticalSection(&assoc_list_cs); + if (assoc_gid) + { + LIST_FOR_EACH_ENTRY(assoc, &server_assoc_list, RpcAssoc, entry) + { + /* FIXME: NetworkAddr shouldn't be NULL */ + if (assoc->assoc_group_id == assoc_gid && + !strcmp(Protseq, assoc->Protseq) && + (!NetworkAddr || !assoc->NetworkAddr || !strcmp(NetworkAddr, assoc->NetworkAddr)) && + !strcmp(Endpoint, assoc->Endpoint) && + ((!assoc->NetworkOptions == !NetworkOptions) && + (!NetworkOptions || !strcmpW(NetworkOptions, assoc->NetworkOptions)))) + { + assoc->refs++; + *assoc_out = assoc; + LeaveCriticalSection(&assoc_list_cs); + TRACE("using existing assoc %p\n", assoc); + return RPC_S_OK; + } + } + *assoc_out = NULL; + return RPC_S_NO_CONTEXT_AVAILABLE; + } + + status = RpcAssoc_Alloc(Protseq, NetworkAddr, Endpoint, NetworkOptions, &assoc); + if (status != RPC_S_OK) + { + LeaveCriticalSection(&assoc_list_cs); + return status; + } + assoc->assoc_group_id = InterlockedIncrement(&last_assoc_group_id); + list_add_head(&server_assoc_list, &assoc->entry); + *assoc_out = assoc; + + LeaveCriticalSection(&assoc_list_cs); + + TRACE("new assoc %p\n", assoc); + + return RPC_S_OK; +} + +ULONG RpcAssoc_Release(RpcAssoc *assoc) +{ + ULONG refs; + + EnterCriticalSection(&assoc_list_cs); + refs = --assoc->refs; + if (!refs) + list_remove(&assoc->entry); + LeaveCriticalSection(&assoc_list_cs); + + if (!refs) + { + RpcConnection *Connection, *cursor2; + + TRACE("destroying assoc %p\n", assoc); + + LIST_FOR_EACH_ENTRY_SAFE(Connection, cursor2, &assoc->free_connection_pool, RpcConnection, conn_pool_entry) + { + list_remove(&Connection->conn_pool_entry); + RPCRT4_DestroyConnection(Connection); + } + + HeapFree(GetProcessHeap(), 0, assoc->NetworkOptions); + HeapFree(GetProcessHeap(), 0, assoc->Endpoint); + HeapFree(GetProcessHeap(), 0, assoc->NetworkAddr); + HeapFree(GetProcessHeap(), 0, assoc->Protseq); + + DeleteCriticalSection(&assoc->cs); + + HeapFree(GetProcessHeap(), 0, assoc); + } + + return refs; +} + +#define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1)) + +static RPC_STATUS RpcAssoc_BindConnection(const RpcAssoc *assoc, RpcConnection *conn, + const RPC_SYNTAX_IDENTIFIER *InterfaceId, + const RPC_SYNTAX_IDENTIFIER *TransferSyntax) +{ + RpcPktHdr *hdr; + RpcPktHdr *response_hdr; + RPC_MESSAGE msg; + RPC_STATUS status; + + TRACE("sending bind request to server\n"); + + hdr = RPCRT4_BuildBindHeader(NDR_LOCAL_DATA_REPRESENTATION, + RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, + assoc->assoc_group_id, + InterfaceId, TransferSyntax); + + status = RPCRT4_Send(conn, hdr, NULL, 0); + RPCRT4_FreeHeader(hdr); + if (status != RPC_S_OK) + return status; + + status = RPCRT4_Receive(conn, &response_hdr, &msg); + if (status != RPC_S_OK) + { + ERR("receive failed\n"); + return status; + } + + switch (response_hdr->common.ptype) + { + case PKT_BIND_ACK: + { + RpcAddressString *server_address = msg.Buffer; + if ((msg.BufferLength >= FIELD_OFFSET(RpcAddressString, string[0])) || + (msg.BufferLength >= ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4))) + { + unsigned short remaining = msg.BufferLength - + ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4); + RpcResults *results = (RpcResults*)((ULONG_PTR)server_address + + ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4)); + if ((results->num_results == 1) && (remaining >= sizeof(*results))) + { + switch (results->results[0].result) + { + case RESULT_ACCEPT: + conn->assoc_group_id = response_hdr->bind_ack.assoc_gid; + conn->MaxTransmissionSize = response_hdr->bind_ack.max_tsize; + conn->ActiveInterface = *InterfaceId; + break; + case RESULT_PROVIDER_REJECTION: + switch (results->results[0].reason) + { + case REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED: + ERR("syntax %s, %d.%d not supported\n", + debugstr_guid(&InterfaceId->SyntaxGUID), + InterfaceId->SyntaxVersion.MajorVersion, + InterfaceId->SyntaxVersion.MinorVersion); + status = RPC_S_UNKNOWN_IF; + break; + case REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED: + ERR("transfer syntax not supported\n"); + status = RPC_S_SERVER_UNAVAILABLE; + break; + case REASON_NONE: + default: + status = RPC_S_CALL_FAILED_DNE; + } + break; + case RESULT_USER_REJECTION: + default: + ERR("rejection result %d\n", results->results[0].result); + status = RPC_S_CALL_FAILED_DNE; + } + } + else + { + ERR("incorrect results size\n"); + status = RPC_S_CALL_FAILED_DNE; + } + } + else + { + ERR("bind ack packet too small (%d)\n", msg.BufferLength); + status = RPC_S_PROTOCOL_ERROR; + } + break; + } + case PKT_BIND_NACK: + switch (response_hdr->bind_nack.reject_reason) + { + case REJECT_LOCAL_LIMIT_EXCEEDED: + case REJECT_TEMPORARY_CONGESTION: + ERR("server too busy\n"); + status = RPC_S_SERVER_TOO_BUSY; + break; + case REJECT_PROTOCOL_VERSION_NOT_SUPPORTED: + ERR("protocol version not supported\n"); + status = RPC_S_PROTOCOL_ERROR; + break; + case REJECT_UNKNOWN_AUTHN_SERVICE: + ERR("unknown authentication service\n"); + status = RPC_S_UNKNOWN_AUTHN_SERVICE; + break; + case REJECT_INVALID_CHECKSUM: + ERR("invalid checksum\n"); + status = ERROR_ACCESS_DENIED; + break; + default: + ERR("rejected bind for reason %d\n", response_hdr->bind_nack.reject_reason); + status = RPC_S_CALL_FAILED_DNE; + } + break; + default: + ERR("wrong packet type received %d\n", response_hdr->common.ptype); + status = RPC_S_PROTOCOL_ERROR; + break; + } + + I_RpcFreeBuffer(&msg); + RPCRT4_FreeHeader(response_hdr); + return status; +} + +static RpcConnection *RpcAssoc_GetIdleConnection(RpcAssoc *assoc, + const RPC_SYNTAX_IDENTIFIER *InterfaceId, + const RPC_SYNTAX_IDENTIFIER *TransferSyntax, const RpcAuthInfo *AuthInfo, + const RpcQualityOfService *QOS) +{ + RpcConnection *Connection; + EnterCriticalSection(&assoc->cs); + /* try to find a compatible connection from the connection pool */ + LIST_FOR_EACH_ENTRY(Connection, &assoc->free_connection_pool, RpcConnection, conn_pool_entry) + { + if (!memcmp(&Connection->ActiveInterface, InterfaceId, + sizeof(RPC_SYNTAX_IDENTIFIER)) && + RpcAuthInfo_IsEqual(Connection->AuthInfo, AuthInfo) && + RpcQualityOfService_IsEqual(Connection->QOS, QOS)) + { + list_remove(&Connection->conn_pool_entry); + LeaveCriticalSection(&assoc->cs); + TRACE("got connection from pool %p\n", Connection); + return Connection; + } + } + + LeaveCriticalSection(&assoc->cs); + return NULL; +} + +RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc, + const RPC_SYNTAX_IDENTIFIER *InterfaceId, + const RPC_SYNTAX_IDENTIFIER *TransferSyntax, RpcAuthInfo *AuthInfo, + RpcQualityOfService *QOS, RpcConnection **Connection) +{ + RpcConnection *NewConnection; + RPC_STATUS status; + + *Connection = RpcAssoc_GetIdleConnection(assoc, InterfaceId, TransferSyntax, AuthInfo, QOS); + if (*Connection) + return RPC_S_OK; + + /* create a new connection */ + status = RPCRT4_CreateConnection(&NewConnection, FALSE /* is this a server connection? */, + assoc->Protseq, assoc->NetworkAddr, + assoc->Endpoint, assoc->NetworkOptions, + AuthInfo, QOS); + if (status != RPC_S_OK) + return status; + + status = RPCRT4_OpenClientConnection(NewConnection); + if (status != RPC_S_OK) + { + RPCRT4_DestroyConnection(NewConnection); + return status; + } + + status = RpcAssoc_BindConnection(assoc, NewConnection, InterfaceId, TransferSyntax); + if (status != RPC_S_OK) + { + RPCRT4_DestroyConnection(NewConnection); + return status; + } + + *Connection = NewConnection; + + return RPC_S_OK; +} + +void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection) +{ + assert(!Connection->server); + EnterCriticalSection(&assoc->cs); + if (!assoc->assoc_group_id) assoc->assoc_group_id = Connection->assoc_group_id; + list_add_head(&assoc->free_connection_pool, &Connection->conn_pool_entry); + LeaveCriticalSection(&assoc->cs); +} diff --git a/dlls/rpcrt4/rpc_assoc.h b/dlls/rpcrt4/rpc_assoc.h new file mode 100644 index 0000000000..a943324902 --- /dev/null +++ b/dlls/rpcrt4/rpc_assoc.h @@ -0,0 +1,46 @@ +/* + * Associations + * + * Copyright 2007 Robert Shearman (for CodeWeavers) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include "wine/list.h" + +typedef struct _RpcAssoc +{ + struct list entry; /* entry in the global list of associations */ + LONG refs; + + LPSTR Protseq; + LPSTR NetworkAddr; + LPSTR Endpoint; + LPWSTR NetworkOptions; + + /* id of this association group */ + ULONG assoc_group_id; + + CRITICAL_SECTION cs; + /* connections available to be used */ + struct list free_connection_pool; +} RpcAssoc; + +RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, RpcAssoc **assoc); +RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc, const RPC_SYNTAX_IDENTIFIER *InterfaceId, const RPC_SYNTAX_IDENTIFIER *TransferSyntax, RpcAuthInfo *AuthInfo, RpcQualityOfService *QOS, RpcConnection **Connection); +void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection); +ULONG RpcAssoc_Release(RpcAssoc *assoc); +RPC_STATUS RpcServerAssoc_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, unsigned long assoc_gid, RpcAssoc **assoc_out); diff --git a/dlls/rpcrt4/rpc_binding.c b/dlls/rpcrt4/rpc_binding.c index 2df1206007..24769e2ce6 100644 --- a/dlls/rpcrt4/rpc_binding.c +++ b/dlls/rpcrt4/rpc_binding.c @@ -39,7 +39,7 @@ #include "wine/debug.h" #include "rpc_binding.h" -#include "rpc_message.h" +#include "rpc_assoc.h" WINE_DEFAULT_DEBUG_CHANNEL(rpc); diff --git a/dlls/rpcrt4/rpc_binding.h b/dlls/rpcrt4/rpc_binding.h index c08d5e8be1..d4c4935b97 100644 --- a/dlls/rpcrt4/rpc_binding.h +++ b/dlls/rpcrt4/rpc_binding.h @@ -49,24 +49,6 @@ typedef struct _RpcQualityOfService RPC_SECURITY_QOS_V2_W *qos; } RpcQualityOfService; -typedef struct _RpcAssoc -{ - struct list entry; /* entry in the global list of associations */ - LONG refs; - - LPSTR Protseq; - LPSTR NetworkAddr; - LPSTR Endpoint; - LPWSTR NetworkOptions; - - /* id of this association group */ - ULONG assoc_group_id; - - CRITICAL_SECTION cs; - /* connections available to be used */ - struct list free_connection_pool; -} RpcAssoc; - struct connection_ops; typedef struct _RpcConnection @@ -127,7 +109,7 @@ typedef struct _RpcBinding RPC_BLOCKING_FN BlockingFn; ULONG ServerTid; RpcConnection* FromConn; - RpcAssoc *Assoc; + struct _RpcAssoc *Assoc; /* authentication */ RpcAuthInfo *AuthInfo; @@ -150,12 +132,6 @@ ULONG RpcQualityOfService_AddRef(RpcQualityOfService *qos); ULONG RpcQualityOfService_Release(RpcQualityOfService *qos); BOOL RpcQualityOfService_IsEqual(const RpcQualityOfService *qos1, const RpcQualityOfService *qos2); -RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, RpcAssoc **assoc); -RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc, const RPC_SYNTAX_IDENTIFIER *InterfaceId, const RPC_SYNTAX_IDENTIFIER *TransferSyntax, RpcAuthInfo *AuthInfo, RpcQualityOfService *QOS, RpcConnection **Connection); -void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection); -ULONG RpcAssoc_Release(RpcAssoc *assoc); -RPC_STATUS RpcServerAssoc_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, unsigned long assoc_gid, RpcAssoc **assoc_out); - RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS); RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection); RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection); diff --git a/dlls/rpcrt4/rpc_server.c b/dlls/rpcrt4/rpc_server.c index 8576f5c84a..098669c991 100644 --- a/dlls/rpcrt4/rpc_server.c +++ b/dlls/rpcrt4/rpc_server.c @@ -42,6 +42,7 @@ #include "wine/exception.h" #include "rpc_server.h" +#include "rpc_assoc.h" #include "rpc_message.h" #include "rpc_defs.h" #include "ncastatus.h" diff --git a/dlls/rpcrt4/rpc_transport.c b/dlls/rpcrt4/rpc_transport.c index da2db6049f..60087f35e1 100644 --- a/dlls/rpcrt4/rpc_transport.c +++ b/dlls/rpcrt4/rpc_transport.c @@ -79,20 +79,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(rpc); -static CRITICAL_SECTION assoc_list_cs; -static CRITICAL_SECTION_DEBUG assoc_list_cs_debug = -{ - 0, 0, &assoc_list_cs, - { &assoc_list_cs_debug.ProcessLocksList, &assoc_list_cs_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": assoc_list_cs") } -}; -static CRITICAL_SECTION assoc_list_cs = { &assoc_list_cs_debug, -1, 0, 0, 0, 0 }; - -static struct list client_assoc_list = LIST_INIT(client_assoc_list); -static struct list server_assoc_list = LIST_INIT(server_assoc_list); - -static LONG last_assoc_group_id; - /**** ncacn_np support ****/ typedef struct _RpcConnection_np @@ -1485,349 +1471,6 @@ RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, return RPC_S_OK; } -static RPC_STATUS RpcAssoc_Alloc(LPCSTR Protseq, LPCSTR NetworkAddr, - LPCSTR Endpoint, LPCWSTR NetworkOptions, - RpcAssoc **assoc_out) -{ - RpcAssoc *assoc; - assoc = HeapAlloc(GetProcessHeap(), 0, sizeof(*assoc)); - if (!assoc) - return RPC_S_OUT_OF_RESOURCES; - assoc->refs = 1; - list_init(&assoc->free_connection_pool); - InitializeCriticalSection(&assoc->cs); - assoc->Protseq = RPCRT4_strdupA(Protseq); - assoc->NetworkAddr = RPCRT4_strdupA(NetworkAddr); - assoc->Endpoint = RPCRT4_strdupA(Endpoint); - assoc->NetworkOptions = NetworkOptions ? RPCRT4_strdupW(NetworkOptions) : NULL; - assoc->assoc_group_id = 0; - list_init(&assoc->entry); - *assoc_out = assoc; - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, - LPCSTR Endpoint, LPCWSTR NetworkOptions, - RpcAssoc **assoc_out) -{ - RpcAssoc *assoc; - RPC_STATUS status; - - EnterCriticalSection(&assoc_list_cs); - LIST_FOR_EACH_ENTRY(assoc, &client_assoc_list, RpcAssoc, entry) - { - if (!strcmp(Protseq, assoc->Protseq) && - !strcmp(NetworkAddr, assoc->NetworkAddr) && - !strcmp(Endpoint, assoc->Endpoint) && - ((!assoc->NetworkOptions && !NetworkOptions) || !strcmpW(NetworkOptions, assoc->NetworkOptions))) - { - assoc->refs++; - *assoc_out = assoc; - LeaveCriticalSection(&assoc_list_cs); - TRACE("using existing assoc %p\n", assoc); - return RPC_S_OK; - } - } - - status = RpcAssoc_Alloc(Protseq, NetworkAddr, Endpoint, NetworkOptions, &assoc); - if (status != RPC_S_OK) - { - LeaveCriticalSection(&assoc_list_cs); - return status; - } - list_add_head(&client_assoc_list, &assoc->entry); - *assoc_out = assoc; - - LeaveCriticalSection(&assoc_list_cs); - - TRACE("new assoc %p\n", assoc); - - return RPC_S_OK; -} - -RPC_STATUS RpcServerAssoc_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, - LPCSTR Endpoint, LPCWSTR NetworkOptions, - unsigned long assoc_gid, - RpcAssoc **assoc_out) -{ - RpcAssoc *assoc; - RPC_STATUS status; - - EnterCriticalSection(&assoc_list_cs); - if (assoc_gid) - { - LIST_FOR_EACH_ENTRY(assoc, &server_assoc_list, RpcAssoc, entry) - { - /* FIXME: NetworkAddr shouldn't be NULL */ - if (assoc->assoc_group_id == assoc_gid && - !strcmp(Protseq, assoc->Protseq) && - (!NetworkAddr || !assoc->NetworkAddr || !strcmp(NetworkAddr, assoc->NetworkAddr)) && - !strcmp(Endpoint, assoc->Endpoint) && - ((!assoc->NetworkOptions == !NetworkOptions) && - (!NetworkOptions || !strcmpW(NetworkOptions, assoc->NetworkOptions)))) - { - assoc->refs++; - *assoc_out = assoc; - LeaveCriticalSection(&assoc_list_cs); - TRACE("using existing assoc %p\n", assoc); - return RPC_S_OK; - } - } - *assoc_out = NULL; - return RPC_S_NO_CONTEXT_AVAILABLE; - } - - status = RpcAssoc_Alloc(Protseq, NetworkAddr, Endpoint, NetworkOptions, &assoc); - if (status != RPC_S_OK) - { - LeaveCriticalSection(&assoc_list_cs); - return status; - } - assoc->assoc_group_id = InterlockedIncrement(&last_assoc_group_id); - list_add_head(&server_assoc_list, &assoc->entry); - *assoc_out = assoc; - - LeaveCriticalSection(&assoc_list_cs); - - TRACE("new assoc %p\n", assoc); - - return RPC_S_OK; -} - -ULONG RpcAssoc_Release(RpcAssoc *assoc) -{ - ULONG refs; - - EnterCriticalSection(&assoc_list_cs); - refs = --assoc->refs; - if (!refs) - list_remove(&assoc->entry); - LeaveCriticalSection(&assoc_list_cs); - - if (!refs) - { - RpcConnection *Connection, *cursor2; - - TRACE("destroying assoc %p\n", assoc); - - LIST_FOR_EACH_ENTRY_SAFE(Connection, cursor2, &assoc->free_connection_pool, RpcConnection, conn_pool_entry) - { - list_remove(&Connection->conn_pool_entry); - RPCRT4_DestroyConnection(Connection); - } - - HeapFree(GetProcessHeap(), 0, assoc->NetworkOptions); - HeapFree(GetProcessHeap(), 0, assoc->Endpoint); - HeapFree(GetProcessHeap(), 0, assoc->NetworkAddr); - HeapFree(GetProcessHeap(), 0, assoc->Protseq); - - DeleteCriticalSection(&assoc->cs); - - HeapFree(GetProcessHeap(), 0, assoc); - } - - return refs; -} - -#define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1)) - -static RPC_STATUS RpcAssoc_BindConnection(const RpcAssoc *assoc, RpcConnection *conn, - const RPC_SYNTAX_IDENTIFIER *InterfaceId, - const RPC_SYNTAX_IDENTIFIER *TransferSyntax) -{ - RpcPktHdr *hdr; - RpcPktHdr *response_hdr; - RPC_MESSAGE msg; - RPC_STATUS status; - - TRACE("sending bind request to server\n"); - - hdr = RPCRT4_BuildBindHeader(NDR_LOCAL_DATA_REPRESENTATION, - RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, - assoc->assoc_group_id, - InterfaceId, TransferSyntax); - - status = RPCRT4_Send(conn, hdr, NULL, 0); - RPCRT4_FreeHeader(hdr); - if (status != RPC_S_OK) - return status; - - status = RPCRT4_Receive(conn, &response_hdr, &msg); - if (status != RPC_S_OK) - { - ERR("receive failed\n"); - return status; - } - - switch (response_hdr->common.ptype) - { - case PKT_BIND_ACK: - { - RpcAddressString *server_address = msg.Buffer; - if ((msg.BufferLength >= FIELD_OFFSET(RpcAddressString, string[0])) || - (msg.BufferLength >= ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4))) - { - unsigned short remaining = msg.BufferLength - - ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4); - RpcResults *results = (RpcResults*)((ULONG_PTR)server_address + - ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4)); - if ((results->num_results == 1) && (remaining >= sizeof(*results))) - { - switch (results->results[0].result) - { - case RESULT_ACCEPT: - conn->assoc_group_id = response_hdr->bind_ack.assoc_gid; - conn->MaxTransmissionSize = response_hdr->bind_ack.max_tsize; - conn->ActiveInterface = *InterfaceId; - break; - case RESULT_PROVIDER_REJECTION: - switch (results->results[0].reason) - { - case REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED: - ERR("syntax %s, %d.%d not supported\n", - debugstr_guid(&InterfaceId->SyntaxGUID), - InterfaceId->SyntaxVersion.MajorVersion, - InterfaceId->SyntaxVersion.MinorVersion); - status = RPC_S_UNKNOWN_IF; - break; - case REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED: - ERR("transfer syntax not supported\n"); - status = RPC_S_SERVER_UNAVAILABLE; - break; - case REASON_NONE: - default: - status = RPC_S_CALL_FAILED_DNE; - } - break; - case RESULT_USER_REJECTION: - default: - ERR("rejection result %d\n", results->results[0].result); - status = RPC_S_CALL_FAILED_DNE; - } - } - else - { - ERR("incorrect results size\n"); - status = RPC_S_CALL_FAILED_DNE; - } - } - else - { - ERR("bind ack packet too small (%d)\n", msg.BufferLength); - status = RPC_S_PROTOCOL_ERROR; - } - break; - } - case PKT_BIND_NACK: - switch (response_hdr->bind_nack.reject_reason) - { - case REJECT_LOCAL_LIMIT_EXCEEDED: - case REJECT_TEMPORARY_CONGESTION: - ERR("server too busy\n"); - status = RPC_S_SERVER_TOO_BUSY; - break; - case REJECT_PROTOCOL_VERSION_NOT_SUPPORTED: - ERR("protocol version not supported\n"); - status = RPC_S_PROTOCOL_ERROR; - break; - case REJECT_UNKNOWN_AUTHN_SERVICE: - ERR("unknown authentication service\n"); - status = RPC_S_UNKNOWN_AUTHN_SERVICE; - break; - case REJECT_INVALID_CHECKSUM: - ERR("invalid checksum\n"); - status = ERROR_ACCESS_DENIED; - break; - default: - ERR("rejected bind for reason %d\n", response_hdr->bind_nack.reject_reason); - status = RPC_S_CALL_FAILED_DNE; - } - break; - default: - ERR("wrong packet type received %d\n", response_hdr->common.ptype); - status = RPC_S_PROTOCOL_ERROR; - break; - } - - I_RpcFreeBuffer(&msg); - RPCRT4_FreeHeader(response_hdr); - return status; -} - -static RpcConnection *RpcAssoc_GetIdleConnection(RpcAssoc *assoc, - const RPC_SYNTAX_IDENTIFIER *InterfaceId, - const RPC_SYNTAX_IDENTIFIER *TransferSyntax, const RpcAuthInfo *AuthInfo, - const RpcQualityOfService *QOS) -{ - RpcConnection *Connection; - EnterCriticalSection(&assoc->cs); - /* try to find a compatible connection from the connection pool */ - LIST_FOR_EACH_ENTRY(Connection, &assoc->free_connection_pool, RpcConnection, conn_pool_entry) - { - if (!memcmp(&Connection->ActiveInterface, InterfaceId, - sizeof(RPC_SYNTAX_IDENTIFIER)) && - RpcAuthInfo_IsEqual(Connection->AuthInfo, AuthInfo) && - RpcQualityOfService_IsEqual(Connection->QOS, QOS)) - { - list_remove(&Connection->conn_pool_entry); - LeaveCriticalSection(&assoc->cs); - TRACE("got connection from pool %p\n", Connection); - return Connection; - } - } - - LeaveCriticalSection(&assoc->cs); - return NULL; -} - -RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc, - const RPC_SYNTAX_IDENTIFIER *InterfaceId, - const RPC_SYNTAX_IDENTIFIER *TransferSyntax, RpcAuthInfo *AuthInfo, - RpcQualityOfService *QOS, RpcConnection **Connection) -{ - RpcConnection *NewConnection; - RPC_STATUS status; - - *Connection = RpcAssoc_GetIdleConnection(assoc, InterfaceId, TransferSyntax, AuthInfo, QOS); - if (*Connection) - return RPC_S_OK; - - /* create a new connection */ - status = RPCRT4_CreateConnection(&NewConnection, FALSE /* is this a server connection? */, - assoc->Protseq, assoc->NetworkAddr, - assoc->Endpoint, assoc->NetworkOptions, - AuthInfo, QOS); - if (status != RPC_S_OK) - return status; - - status = RPCRT4_OpenClientConnection(NewConnection); - if (status != RPC_S_OK) - { - RPCRT4_DestroyConnection(NewConnection); - return status; - } - - status = RpcAssoc_BindConnection(assoc, NewConnection, InterfaceId, TransferSyntax); - if (status != RPC_S_OK) - { - RPCRT4_DestroyConnection(NewConnection); - return status; - } - - *Connection = NewConnection; - - return RPC_S_OK; -} - -void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection) -{ - assert(!Connection->server); - EnterCriticalSection(&assoc->cs); - if (!assoc->assoc_group_id) assoc->assoc_group_id = Connection->assoc_group_id; - list_add_head(&assoc->free_connection_pool, &Connection->conn_pool_entry); - LeaveCriticalSection(&assoc->cs); -} - RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection) { -- 2.32.0.93.g670b81a890