]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
Introduce a new connection status - gentle shutdown
authorOndřej Kuzník <okuznik@symas.com>
Wed, 14 Feb 2018 15:48:53 +0000 (15:48 +0000)
committerOndřej Kuzník <okuznik@symas.com>
Tue, 17 Nov 2020 17:58:14 +0000 (17:58 +0000)
servers/lloadd/client.c
servers/lloadd/connection.c
servers/lloadd/lload.h
servers/lloadd/proto-lload.h
servers/lloadd/upstream.c

index 5874b8860eafe92f5c745976f742baa08e2c9c11..87fb009dd22ac288aa95bc5f8e8247ed94daa5c1 100644 (file)
@@ -227,8 +227,7 @@ handle_one_request( LloadConnection *c )
         case LDAP_REQ_ABANDON:
             /* We can't send a response to abandon requests even if a bind is
              * currently in progress */
-            handler = request_abandon;
-            break;
+            return request_abandon( c, op );
         case LDAP_REQ_EXTENDED:
             handler = request_extended;
             break;
@@ -241,6 +240,11 @@ handle_one_request( LloadConnection *c )
             break;
     }
 
+    if ( c->c_state == LLOAD_C_CLOSING ) {
+        return operation_send_reject_locked(
+                op, LDAP_UNAVAILABLE, "connection is shutting down", 0 );
+    }
+
     return handler( c, op );
 }
 
@@ -510,7 +514,7 @@ client_destroy( LloadConnection *c )
         event_del( write_event );
     }
 
-    if ( state != LLOAD_C_CLOSING ) {
+    if ( state != LLOAD_C_DYING ) {
         ldap_pvt_thread_mutex_lock( &clients_mutex );
         LDAP_CIRCLEQ_REMOVE( &clients, c, c_next );
         ldap_pvt_thread_mutex_unlock( &clients_mutex );
@@ -537,7 +541,7 @@ client_destroy( LloadConnection *c )
      */
     assert( c->c_refcnt >= 0 );
     if ( c->c_refcnt ) {
-        c->c_state = LLOAD_C_CLOSING;
+        c->c_state = LLOAD_C_DYING;
         Debug( LDAP_DEBUG_CONNS, "client_destroy: "
                 "connid=%lu aborting with refcnt=%d\n",
                 c->c_connid, c->c_refcnt );
index 2740409cb17e78f695531aac99a0957a4989c53c..8f0f741a64c5982d08c050b5eba03a0676083487 100644 (file)
@@ -333,6 +333,38 @@ connection_destroy( LloadConnection *c )
     listeners_reactivate();
 }
 
+/*
+ * Expected to be run from lload_unpause_server, so there are no other threads
+ * running.
+ */
+void
+lload_connection_close( LloadConnection *c )
+{
+    TAvlnode *node;
+
+    /* We lock so we can use CONNECTION_UNLOCK_OR_DESTROY to drop the
+     * connection if we can */
+    CONNECTION_LOCK(c);
+
+    /* The first thing we do is make sure we don't get new Operations in */
+    c->c_state = LLOAD_C_CLOSING;
+
+    for ( node = tavl_end( c->c_ops, TAVL_DIR_LEFT ); node;
+            node = tavl_next( node, TAVL_DIR_RIGHT ) ) {
+        LloadOperation *op = node->avl_data;
+
+        if ( op->o_client_msgid == 0 ) {
+            if ( op->o_client == c ) {
+                operation_destroy_from_client( op );
+            } else {
+                assert( op->o_upstream == c );
+                operation_destroy_from_upstream( op );
+            }
+        }
+    }
+    CONNECTION_UNLOCK_OR_DESTROY(c);
+}
+
 LloadConnection *
 lload_connection_init( ber_socket_t s, const char *peername, int flags )
 {
index 73fde464fe57a76ef16937828dfc64c0c439a741..b75d971788dcaff071d48c02ac103488e777f966 100644 (file)
@@ -195,6 +195,7 @@ enum sc_state {
     LLOAD_C_CLOSING,     /* closing */
     LLOAD_C_ACTIVE,      /* exclusive operation (tls setup, ...) in progress */
     LLOAD_C_BINDING,     /* binding */
+    LLOAD_C_DYING, /* part-processed dead but someone still holds a reference */
 };
 enum sc_type {
     LLOAD_C_OPEN = 0,  /* regular connection */
@@ -246,6 +247,10 @@ struct LloadConnection {
 #define CONNECTION_UNLOCK_OR_DESTROY(c) \
     do { \
         assert( (c)->c_refcnt >= 0 ); \
+        if ( (c)->c_state == LLOAD_C_CLOSING && !( c )->c_ops ) { \
+            (c)->c_refcnt -= (c)->c_live; \
+            (c)->c_live = 0; \
+        } \
         if ( !( c )->c_refcnt ) { \
             Debug( LDAP_DEBUG_TRACE, "%s: destroying connection connid=%lu\n", \
                     __func__, (c)->c_connid ); \
index 25baf8b77542a779fa80d25e2834228425e3e535..bf7512fae66cc2aea5a67d2afbf83d586aee9c9e 100644 (file)
@@ -87,6 +87,7 @@ LDAP_SLAPD_F (int) lload_back_init_cf( BackendInfo *bi );
 LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) clients_mutex;
 LDAP_SLAPD_F (void) connection_write_cb( evutil_socket_t s, short what, void *arg );
 LDAP_SLAPD_F (void) connection_read_cb( evutil_socket_t s, short what, void *arg );
+LDAP_SLAPD_F (void) lload_connection_close( LloadConnection *c );
 LDAP_SLAPD_F (LloadConnection *) lload_connection_init( ber_socket_t s, const char *peername, int use_tls );
 LDAP_SLAPD_F (void) connection_destroy( LloadConnection *c );
 
index c4908363800cbfd2337497436a14137437d62efa..7db7da7d5a16ecca105f64597bfd7b4dc0c84e99 100644 (file)
@@ -101,7 +101,7 @@ forward_final_response(
 static int
 handle_unsolicited( LloadConnection *c, BerElement *ber )
 {
-    if ( c->c_state == LLOAD_C_READY ) {
+    if ( c->c_state != LLOAD_C_PREPARING ) {
         c->c_state = LLOAD_C_CLOSING;
     }
 
@@ -799,7 +799,7 @@ upstream_destroy( LloadConnection *c )
     }
 
     /* Remove from the backend on first pass */
-    if ( state != LLOAD_C_CLOSING ) {
+    if ( state != LLOAD_C_DYING ) {
         ldap_pvt_thread_mutex_lock( &b->b_mutex );
         if ( c->c_type == LLOAD_C_PREPARING ) {
             LDAP_CIRCLEQ_REMOVE( &b->b_preparing, c, c_next );
@@ -854,7 +854,7 @@ upstream_destroy( LloadConnection *c )
      */
     assert( c->c_refcnt >= 0 );
     if ( c->c_refcnt ) {
-        c->c_state = LLOAD_C_CLOSING;
+        c->c_state = LLOAD_C_DYING;
         Debug( LDAP_DEBUG_CONNS, "upstream_destroy: "
                 "connid=%lu aborting with refcnt=%d\n",
                 c->c_connid, c->c_refcnt );