From: Ondřej Kuzník Date: Mon, 19 Aug 2024 13:05:44 +0000 (+0100) Subject: ITS#10266 Linked clients should also be tagged for closing X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=37edfeceaaa3f58b45463a8ca46d478d28ab2793;p=thirdparty%2Fopenldap.git ITS#10266 Linked clients should also be tagged for closing --- diff --git a/servers/lloadd/connection.c b/servers/lloadd/connection.c index 1981ac8b89..55bf595918 100644 --- a/servers/lloadd/connection.c +++ b/servers/lloadd/connection.c @@ -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 */ diff --git a/servers/lloadd/upstream.c b/servers/lloadd/upstream.c index 7d558dc54a..41e529e129 100644 --- a/servers/lloadd/upstream.c +++ b/servers/lloadd/upstream.c @@ -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 ) {