]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#10266 Linked clients should also be tagged for closing
authorOndřej Kuzník <ondra@mistotebe.net>
Mon, 19 Aug 2024 13:05:44 +0000 (14:05 +0100)
committerQuanah Gibson-Mount <quanah@openldap.org>
Wed, 19 Feb 2025 19:59:42 +0000 (19:59 +0000)
servers/lloadd/connection.c
servers/lloadd/upstream.c

index 1981ac8b892958053803d4217a3c6270d00552b8..55bf595918194a9aede3361407838c01d1d55032 100644 (file)
@@ -530,7 +530,7 @@ lload_connection_close( LloadConnection *c, void *arg )
             "marking connection connid=%lu closing\n",
             c->c_connid );
 
-    /* We were approached from the connection list or cn=monitor */
+    /* Caller makes sure we're safe to unlock */
     assert( IS_ALIVE( c, c_refcnt ) );
 
     /* Need to acquire this first, even if we won't need it */
index 7d558dc54abe3caab014cbf6e5c5cd55ae6fe94f..41e529e129c901c62c8a710b427353aa82eeed4c 100644 (file)
@@ -52,9 +52,6 @@ linked_upstream_lost( LloadConnection *client )
     int gentle = 1;
 
     CONNECTION_LOCK(client);
-    assert( client->c_restricted >= LLOAD_OP_RESTRICTED_UPSTREAM );
-    assert( client->c_linked_upstream );
-
     client->c_restricted = LLOAD_OP_NOT_RESTRICTED;
     client->c_linked_upstream = NULL;
     CONNECTION_UNLOCK(client);
@@ -169,6 +166,47 @@ handle_unsolicited( LloadConnection *c, BerElement *ber )
         CONNECTION_LOCK(c);
     };
 
+    /* Let all clients unlink */
+    node = ldap_tavl_end( c->c_linked, TAVL_DIR_LEFT );
+    while ( node ) {
+        LloadConnection *client;
+        int cmp = 0;
+
+        /*
+         * The upstream is CLOSING so it won't get new clients in, but
+         * releasing c_mutex allows clients to unregister themselves.
+         */
+        client = (LloadConnection *)node->avl_data;
+        while ( !acquire_ref( &client->c_refcnt ) ) {
+            node = ldap_tavl_next( node, TAVL_DIR_RIGHT );
+            if ( !node ) {
+                break;
+            }
+            client = node->avl_data;
+        }
+        if ( !node ) break;
+
+        CONNECTION_UNLOCK(c);
+        linked_upstream_lost( client );
+        CONNECTION_LOCK(c);
+
+        node = ldap_tavl_find3( c->c_linked, client, lload_upstream_entry_cmp, &cmp );
+        if ( node && cmp <= 0 ) {
+            TAvlnode *next = ldap_tavl_next( node, TAVL_DIR_RIGHT );
+            if ( client == node->avl_data ) {
+                ldap_tavl_delete( &c->c_linked, client, lload_upstream_entry_cmp );
+            }
+            node = next;
+        }
+        RELEASE_REF( client, c_refcnt, client->c_destroy );
+    }
+
+    if ( c->c_state == LLOAD_C_CLOSING && c->c_ops ) {
+        CONNECTION_UNLOCK(c);
+    } else {
+        CONNECTION_DESTROY(c);
+    }
+
 out:
     ber_free( ber, 1 );
     if ( c->c_state == LLOAD_C_CLOSING && c->c_ops ) {