From 8e38233736d468a058b5d08f398290dcb0a68a2b Mon Sep 17 00:00:00 2001
From: Ove Kaaven <ovek@transgaming.com>
Date: Sat, 19 Apr 2003 20:06:42 +0000
Subject: [PATCH] Implemented simple caching of client connections.

---
 dlls/rpcrt4/rpc_binding.c | 68 +++++++++++++++++++++++++++++++++++----
 dlls/rpcrt4/rpc_binding.h |  2 +-
 dlls/rpcrt4/rpc_server.c  |  2 +-
 3 files changed, 63 insertions(+), 9 deletions(-)

diff --git a/dlls/rpcrt4/rpc_binding.c b/dlls/rpcrt4/rpc_binding.c
index d10e7179b8c..868cd05ee2b 100644
--- a/dlls/rpcrt4/rpc_binding.c
+++ b/dlls/rpcrt4/rpc_binding.c
@@ -40,6 +40,9 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(ole);
 
+static RpcConnection* conn_cache;
+static CRITICAL_SECTION conn_cache_cs = CRITICAL_SECTION_INIT("conn_cache_cs");
+
 LPSTR RPCRT4_strndupA(LPSTR src, INT slen)
 {
   DWORD len;
@@ -93,7 +96,7 @@ void RPCRT4_strfree(LPSTR src)
   if (src) HeapFree(GetProcessHeap(), 0, src);
 }
 
-RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions)
+RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions, RpcBinding* Binding)
 {
   RpcConnection* NewConnection;
 
@@ -102,6 +105,12 @@ RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPST
   NewConnection->Protseq = RPCRT4_strdupA(Protseq);
   NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
   NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
+  NewConnection->Used = Binding;
+
+  EnterCriticalSection(&conn_cache_cs);
+  NewConnection->Next = conn_cache;
+  conn_cache = NewConnection;
+  LeaveCriticalSection(&conn_cache_cs);
 
   TRACE("connection: %p\n", NewConnection);
   *Connection = NewConnection;
@@ -111,8 +120,18 @@ RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPST
 
 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
 {
+  RpcConnection* PrevConnection;
+
   TRACE("connection: %p\n", Connection);
   if (Connection->Used) ERR("connection is still in use\n");
+
+  EnterCriticalSection(&conn_cache_cs);
+  PrevConnection = conn_cache;
+  while (PrevConnection && PrevConnection->Next != Connection)
+    PrevConnection = PrevConnection->Next;
+  if (PrevConnection) PrevConnection->Next = Connection->Next;
+  LeaveCriticalSection(&conn_cache_cs);
+
   RPCRT4_CloseConnection(Connection);
   RPCRT4_strfree(Connection->Endpoint);
   RPCRT4_strfree(Connection->NetworkAddr);
@@ -121,6 +140,44 @@ RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
   return RPC_S_OK;
 }
 
+RPC_STATUS RPCRT4_GetConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions, RpcBinding* Binding)
+{
+  RpcConnection* NewConnection;
+
+  if (!server) {
+    EnterCriticalSection(&conn_cache_cs);
+    for (NewConnection = conn_cache; NewConnection; NewConnection = NewConnection->Next) {
+      if (NewConnection->Used) continue;
+      if (NewConnection->server != server) continue;
+      if (Protseq && strcmp(NewConnection->Protseq, Protseq)) continue;
+      if (NetworkAddr && strcmp(NewConnection->NetworkAddr, NetworkAddr)) continue;
+      if (Endpoint && strcmp(NewConnection->Endpoint, Endpoint)) continue;
+      /* this connection fits the bill */
+      NewConnection->Used = Binding;
+      break;
+    }
+    LeaveCriticalSection(&conn_cache_cs);
+    if (NewConnection) {
+      TRACE("cached connection: %p\n", NewConnection);
+      *Connection = NewConnection;
+      return RPC_S_OK;
+    }
+  }
+  return RPCRT4_CreateConnection(Connection, server, Protseq, NetworkAddr, Endpoint, NetworkOptions, Binding);
+}
+
+RPC_STATUS RPCRT4_ReleaseConnection(RpcConnection* Connection)
+{
+  TRACE("connection: %p\n", Connection);
+  Connection->Used = NULL;
+  if (!Connection->server) {
+    /* cache the open connection for reuse later */
+    /* FIXME: we should probably clean the cache someday */
+    return RPC_S_OK;
+  }
+  return RPCRT4_DestroyConnection(Connection);
+}
+
 RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection)
 {
   TRACE("(Connection == ^%p)\n", Connection);
@@ -264,7 +321,7 @@ RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* Old
 {
   RpcConnection* NewConnection;
   RPC_STATUS err = RPCRT4_CreateConnection(&NewConnection, OldConnection->server, OldConnection->Protseq,
-                                           OldConnection->NetworkAddr, OldConnection->Endpoint, NULL);
+                                           OldConnection->NetworkAddr, OldConnection->Endpoint, NULL, NULL);
   if (err == RPC_S_OK) {
     /* because of the way named pipes work, we'll transfer the connected pipe
      * to the child, then reopen the server binding to continue listening */
@@ -418,9 +475,7 @@ RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection)
     return RPC_S_OK;
   }
 
-  /* FIXME: cache connections */
-  RPCRT4_CreateConnection(&NewConnection, Binding->server, Binding->Protseq, Binding->NetworkAddr, Binding->Endpoint, NULL);
-  NewConnection->Used = Binding;
+  RPCRT4_GetConnection(&NewConnection, Binding->server, Binding->Protseq, Binding->NetworkAddr, Binding->Endpoint, NULL, Binding);
   *Connection = NewConnection;
   return RPCRT4_OpenConnection(NewConnection);
 }
@@ -430,8 +485,7 @@ RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection)
   TRACE("(Binding == ^%p)\n", Binding);
   if (!Connection) return RPC_S_OK;
   if (Binding->FromConn == Connection) return RPC_S_OK;
-  Connection->Used = NULL;
-  return RPCRT4_DestroyConnection(Connection);
+  return RPCRT4_ReleaseConnection(Connection);
 }
 
 /* utility functions for string composing and parsing */
diff --git a/dlls/rpcrt4/rpc_binding.h b/dlls/rpcrt4/rpc_binding.h
index 7259abe4668..c39feaf0910 100644
--- a/dlls/rpcrt4/rpc_binding.h
+++ b/dlls/rpcrt4/rpc_binding.h
@@ -60,7 +60,7 @@ void RPCRT4_strfree(LPSTR src);
 #define RPCRT4_strdupA(x) RPCRT4_strndupA((x),-1)
 #define RPCRT4_strdupW(x) RPCRT4_strndupW((x),-1)
 
-RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions);
+RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions, RpcBinding* Binding);
 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection);
 RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection);
 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection);
diff --git a/dlls/rpcrt4/rpc_server.c b/dlls/rpcrt4/rpc_server.c
index 3c84a3da12c..95e9561e30f 100644
--- a/dlls/rpcrt4/rpc_server.c
+++ b/dlls/rpcrt4/rpc_server.c
@@ -433,7 +433,7 @@ static void RPCRT4_stop_listen(void)
 
 static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps)
 {
-  RPCRT4_CreateConnection(&ps->conn, TRUE, ps->Protseq, NULL, ps->Endpoint, NULL);
+  RPCRT4_CreateConnection(&ps->conn, TRUE, ps->Protseq, NULL, ps->Endpoint, NULL, NULL);
 
   EnterCriticalSection(&server_cs);
   ps->Next = protseqs;
-- 
GitLab