[PATCH 1/13] rpcrt4: Implement associations which are intermediary
objects that track the relationship between the client and a given
endpoint on the server.
Robert Shearman
rob at codeweavers.com
Mon Mar 26 12:13:49 CDT 2007
Use these to encapsulate the connection pool so that the lifetimes of
connections are properly handled again.
---
dlls/rpcrt4/rpc_binding.c | 37 +++++++++++--
dlls/rpcrt4/rpc_binding.h | 23 ++++++++
dlls/rpcrt4/rpc_transport.c | 120
+++++++++++++++++++++++++++++++++++--------
3 files changed, 151 insertions(+), 29 deletions(-)
-------------- next part --------------
diff --git a/dlls/rpcrt4/rpc_binding.c b/dlls/rpcrt4/rpc_binding.c
index eb6fb14..b554e7f 100644
--- a/dlls/rpcrt4/rpc_binding.c
+++ b/dlls/rpcrt4/rpc_binding.c
@@ -139,6 +139,8 @@ static RPC_STATUS RPCRT4_CreateBindingW(
static RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPSTR NetworkAddr,
LPSTR Endpoint, LPSTR NetworkOptions)
{
+ RPC_STATUS status;
+
TRACE("(RpcBinding == ^%p, NetworkAddr == %s, EndPoint == %s, NetworkOptions == %s)\n", Binding,
debugstr_a(NetworkAddr), debugstr_a(Endpoint), debugstr_a(NetworkOptions));
@@ -154,12 +156,20 @@ static RPC_STATUS RPCRT4_CompleteBinding
Binding->NetworkOptions = RPCRT4_strdupAtoW(NetworkOptions);
if (!Binding->Endpoint) ERR("out of memory?\n");
+ status = RPCRT4_GetAssociation(Binding->Protseq, Binding->NetworkAddr,
+ Binding->Endpoint, Binding->NetworkOptions,
+ &Binding->Assoc);
+ if (status != RPC_S_OK)
+ return status;
+
return RPC_S_OK;
}
static RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPWSTR NetworkAddr,
LPWSTR Endpoint, LPWSTR NetworkOptions)
{
+ RPC_STATUS status;
+
TRACE("(RpcBinding == ^%p, NetworkAddr == %s, EndPoint == %s, NetworkOptions == %s)\n", Binding,
debugstr_w(NetworkAddr), debugstr_w(Endpoint), debugstr_w(NetworkOptions));
@@ -175,16 +185,32 @@ static RPC_STATUS RPCRT4_CompleteBinding
HeapFree(GetProcessHeap(), 0, Binding->NetworkOptions);
Binding->NetworkOptions = RPCRT4_strdupW(NetworkOptions);
+ status = RPCRT4_GetAssociation(Binding->Protseq, Binding->NetworkAddr,
+ Binding->Endpoint, Binding->NetworkOptions,
+ &Binding->Assoc);
+ if (status != RPC_S_OK)
+ return status;
+
return RPC_S_OK;
}
RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPSTR Endpoint)
{
+ RPC_STATUS status;
+
TRACE("(RpcBinding == ^%p, EndPoint == \"%s\"\n", Binding, Endpoint);
RPCRT4_strfree(Binding->Endpoint);
Binding->Endpoint = RPCRT4_strdupA(Endpoint);
+ RpcAssoc_Release(Binding->Assoc);
+ Binding->Assoc = NULL;
+ status = RPCRT4_GetAssociation(Binding->Protseq, Binding->NetworkAddr,
+ Binding->Endpoint, Binding->NetworkOptions,
+ &Binding->Assoc);
+ if (status != RPC_S_OK)
+ return status;
+
return RPC_S_OK;
}
@@ -226,7 +252,7 @@ RPC_STATUS RPCRT4_DestroyBinding(RpcBind
return RPC_S_OK;
TRACE("binding: %p\n", Binding);
- /* FIXME: release connections */
+ if (Binding->Assoc) RpcAssoc_Release(Binding->Assoc);
RPCRT4_strfree(Binding->Endpoint);
RPCRT4_strfree(Binding->NetworkAddr);
RPCRT4_strfree(Binding->Protseq);
@@ -248,9 +274,8 @@ RPC_STATUS RPCRT4_OpenBinding(RpcBinding
if (!Binding->server) {
/* try to find a compatible connection from the connection pool */
- NewConnection = RPCRT4_GetIdleConnection(InterfaceId, TransferSyntax,
- Binding->Protseq, Binding->NetworkAddr, Binding->Endpoint,
- Binding->AuthInfo, Binding->QOS);
+ NewConnection = RpcAssoc_GetIdleConnection(Binding->Assoc, InterfaceId,
+ TransferSyntax, Binding->AuthInfo, Binding->QOS);
if (NewConnection) {
*Connection = NewConnection;
return RPC_S_OK;
@@ -340,7 +365,7 @@ RPC_STATUS RPCRT4_CloseBinding(RpcBindin
return RPCRT4_DestroyConnection(Connection);
}
else {
- RPCRT4_ReleaseIdleConnection(Connection);
+ RpcAssoc_ReleaseIdleConnection(Binding->Assoc, Connection);
return RPC_S_OK;
}
}
@@ -881,6 +906,8 @@ RPC_STATUS RPC_ENTRY RpcBindingCopy(
DestBinding->NetworkAddr = RPCRT4_strndupA(SrcBinding->NetworkAddr, -1);
DestBinding->Endpoint = RPCRT4_strndupA(SrcBinding->Endpoint, -1);
DestBinding->NetworkOptions = RPCRT4_strdupW(SrcBinding->NetworkOptions);
+ if (SrcBinding->Assoc) SrcBinding->Assoc->refs++;
+ DestBinding->Assoc = SrcBinding->Assoc;
if (SrcBinding->AuthInfo) RpcAuthInfo_AddRef(SrcBinding->AuthInfo);
DestBinding->AuthInfo = SrcBinding->AuthInfo;
diff --git a/dlls/rpcrt4/rpc_binding.h b/dlls/rpcrt4/rpc_binding.h
index 651d79e..2ad90f8 100644
--- a/dlls/rpcrt4/rpc_binding.h
+++ b/dlls/rpcrt4/rpc_binding.h
@@ -43,6 +43,21 @@ 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;
+ RpcAuthInfo *AuthInfo;
+
+ CRITICAL_SECTION cs;
+ struct list connection_pool;
+} RpcAssoc;
+
struct connection_ops;
typedef struct _RpcConnection
@@ -97,6 +112,7 @@ typedef struct _RpcBinding
RPC_BLOCKING_FN BlockingFn;
ULONG ServerTid;
RpcConnection* FromConn;
+ RpcAssoc *Assoc;
/* authentication */
RpcAuthInfo *AuthInfo;
@@ -117,8 +133,11 @@ ULONG RpcAuthInfo_Release(RpcAuthInfo *A
ULONG RpcQualityOfService_AddRef(RpcQualityOfService *qos);
ULONG RpcQualityOfService_Release(RpcQualityOfService *qos);
-RpcConnection *RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER *InterfaceId, const RPC_SYNTAX_IDENTIFIER *TransferSyntax, LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, const RpcAuthInfo* AuthInfo, const RpcQualityOfService *QOS);
-void RPCRT4_ReleaseIdleConnection(RpcConnection *Connection);
+RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, RpcAssoc **assoc);
+RpcConnection *RpcAssoc_GetIdleConnection(RpcAssoc *assoc, const RPC_SYNTAX_IDENTIFIER *InterfaceId, const RPC_SYNTAX_IDENTIFIER *TransferSyntax, const RpcAuthInfo *AuthInfo, const RpcQualityOfService *QOS);
+void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection);
+ULONG RpcAssoc_Release(RpcAssoc *assoc);
+
RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS, RpcBinding* Binding);
RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection);
RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection);
diff --git a/dlls/rpcrt4/rpc_transport.c b/dlls/rpcrt4/rpc_transport.c
index 5f3966f..e1d29bb 100644
--- a/dlls/rpcrt4/rpc_transport.c
+++ b/dlls/rpcrt4/rpc_transport.c
@@ -80,16 +80,16 @@ #endif
WINE_DEFAULT_DEBUG_CHANNEL(rpc);
-static CRITICAL_SECTION connection_pool_cs;
-static CRITICAL_SECTION_DEBUG connection_pool_cs_debug =
+static CRITICAL_SECTION assoc_list_cs;
+static CRITICAL_SECTION_DEBUG assoc_list_cs_debug =
{
- 0, 0, &connection_pool_cs,
- { &connection_pool_cs_debug.ProcessLocksList, &connection_pool_cs_debug.ProcessLocksList },
- 0, 0, { (DWORD_PTR)(__FILE__ ": connection_pool") }
+ 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 connection_pool_cs = { &connection_pool_cs_debug, -1, 0, 0, 0, 0 };
+static CRITICAL_SECTION assoc_list_cs = { &assoc_list_cs_debug, -1, 0, 0, 0, 0 };
-static struct list connection_pool = LIST_INIT(connection_pool);
+static struct list assoc_list = LIST_INIT(assoc_list);
/**** ncacn_np support ****/
@@ -1393,38 +1393,114 @@ RPC_STATUS RPCRT4_CreateConnection(RpcCo
return RPC_S_OK;
}
-RpcConnection *RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER *InterfaceId,
- const RPC_SYNTAX_IDENTIFIER *TransferSyntax, LPCSTR Protseq, LPCSTR NetworkAddr,
- LPCSTR Endpoint, const RpcAuthInfo* AuthInfo, const RpcQualityOfService *QOS)
+RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr,
+ LPCSTR Endpoint, LPCWSTR NetworkOptions,
+ RpcAssoc **assoc_out)
+{
+ RpcAssoc *assoc;
+
+ EnterCriticalSection(&assoc_list_cs);
+ LIST_FOR_EACH_ENTRY(assoc, &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;
+ }
+ }
+
+ assoc = HeapAlloc(GetProcessHeap(), 0, sizeof(*assoc));
+ if (!assoc)
+ {
+ LeaveCriticalSection(&assoc_list_cs);
+ return RPC_S_OUT_OF_RESOURCES;
+ }
+ assoc->refs = 1;
+ list_init(&assoc->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;
+ list_add_head(&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->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);
+
+ HeapFree(GetProcessHeap(), 0, assoc);
+ }
+
+ return refs;
+}
+
+RpcConnection *RpcAssoc_GetIdleConnection(RpcAssoc *assoc,
+ const RPC_SYNTAX_IDENTIFIER *InterfaceId,
+ const RPC_SYNTAX_IDENTIFIER *TransferSyntax, const RpcAuthInfo *AuthInfo,
+ const RpcQualityOfService *QOS)
{
RpcConnection *Connection;
/* try to find a compatible connection from the connection pool */
- EnterCriticalSection(&connection_pool_cs);
- LIST_FOR_EACH_ENTRY(Connection, &connection_pool, RpcConnection, conn_pool_entry)
+ EnterCriticalSection(&assoc->cs);
+ LIST_FOR_EACH_ENTRY(Connection, &assoc->connection_pool, RpcConnection, conn_pool_entry)
if ((Connection->AuthInfo == AuthInfo) &&
(Connection->QOS == QOS) &&
!memcmp(&Connection->ActiveInterface, InterfaceId,
- sizeof(RPC_SYNTAX_IDENTIFIER)) &&
- !strcmp(rpcrt4_conn_get_name(Connection), Protseq) &&
- !strcmp(Connection->NetworkAddr, NetworkAddr) &&
- !strcmp(Connection->Endpoint, Endpoint))
+ sizeof(RPC_SYNTAX_IDENTIFIER)))
{
list_remove(&Connection->conn_pool_entry);
- LeaveCriticalSection(&connection_pool_cs);
+ LeaveCriticalSection(&assoc->cs);
TRACE("got connection from pool %p\n", Connection);
return Connection;
}
- LeaveCriticalSection(&connection_pool_cs);
+ LeaveCriticalSection(&assoc->cs);
return NULL;
}
-void RPCRT4_ReleaseIdleConnection(RpcConnection *Connection)
+void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection)
{
assert(!Connection->server);
- EnterCriticalSection(&connection_pool_cs);
- list_add_head(&connection_pool, &Connection->conn_pool_entry);
- LeaveCriticalSection(&connection_pool_cs);
+ EnterCriticalSection(&assoc->cs);
+ list_add_head(&assoc->connection_pool, &Connection->conn_pool_entry);
+ LeaveCriticalSection(&assoc->cs);
}
More information about the wine-patches
mailing list