diff --git a/CHANGES b/CHANGES index 1e09175e619e60b9cdd22fed686356f98c9e489a..7c25ecd22a17c6a24bcf6fb3a9919b0e8b1412d6 100644 --- a/CHANGES +++ b/CHANGES @@ -41,6 +41,7 @@ OpenLDAP 2.4.24 Engineering Fixed slapd support for BDB 5.0+ (ITS#6698) Fixed slapd config leak with olcDbDirectory (ITS#6634) Fixed slapd connectionless warnings (ITS#6747) + Fixed slapd listeners destruction (ITS#6736) Fixed slapd to free controls if needed (ITS#6629) Fixed slapd to stop if given unknown options (ITS#6754) Fixed slapd entry comparisons (ITS#6753) diff --git a/servers/slapd/daemon.c b/servers/slapd/daemon.c index 05cc6b69f4048f5c272684c9399d6912ed44e120..2a7a48eaf8141039920435588567a09c7c193946 100644 --- a/servers/slapd/daemon.c +++ b/servers/slapd/daemon.c @@ -83,6 +83,7 @@ int slapd_tcp_wmem; #endif /* LDAP_TCP_BUFFER */ Listener **slap_listeners = NULL; +static volatile sig_atomic_t listening = 1; /* 0 when slap_listeners closed */ #ifndef SLAPD_LISTEN_BACKLOG #define SLAPD_LISTEN_BACKLOG 1024 @@ -907,7 +908,7 @@ slapd_remove( * the select() loop. Now that we're removing a session from our * control, we can try to resume a dropped listener to use. */ - if ( emfile ) { + if ( emfile && listening ) { int i; for ( i = 0; slap_listeners[i] != NULL; i++ ) { Listener *lr = slap_listeners[i]; @@ -1739,9 +1740,12 @@ close_listeners( { int l; + if ( !listening ) + return; + listening = 0; + for ( l = 0; slap_listeners[l] != NULL; l++ ) { Listener *lr = slap_listeners[l]; - slap_listeners[l] = NULL; if ( lr->sl_sd != AC_SOCKET_INVALID ) { int s = lr->sl_sd; @@ -1756,7 +1760,18 @@ close_listeners( slapd_close( s ); } + } +} + +static void +destroy_listeners( void ) +{ + Listener *lr, **ll = slap_listeners; + + if ( ll == NULL ) + return; + while ( (lr = *ll++) != NULL ) { if ( lr->sl_url.bv_val ) { ber_memfree( lr->sl_url.bv_val ); } @@ -1767,6 +1782,9 @@ close_listeners( free( lr ); } + + free( slap_listeners ); + slap_listeners = NULL; } static int @@ -2408,6 +2426,7 @@ loop: nwriters = slap_daemon[tid].sd_nwriters; + if ( listening ) for ( l = 0; slap_listeners[l] != NULL; l++ ) { Listener *lr = slap_listeners[l]; @@ -2566,6 +2585,7 @@ loop: * true for Unix select and poll. We treat Windows select * like this too, even though it's a kludge. */ + if ( listening ) for ( l = 0; slap_listeners[l] != NULL; l++ ) { int rc; @@ -2807,7 +2827,7 @@ loop: 0, 0, 0 ); } - if ( slapd_gentle_shutdown != 2 ) close_listeners ( 0 ); + close_listeners( 0 ); if ( !slapd_gentle_shutdown ) { slapd_abrupt_shutdown = 1; @@ -2822,9 +2842,6 @@ loop: } ldap_pvt_thread_pool_destroy( &connection_pool, 1 ); - free( slap_listeners ); - slap_listeners = NULL; - return NULL; } @@ -2904,6 +2921,7 @@ slapd_daemon( void ) for ( i=0; i<slapd_daemon_threads; i++ ) ldap_pvt_thread_join( listener_tid[i], (void *)NULL ); + destroy_listeners(); ch_free( listener_tid ); return 0; @@ -3023,6 +3041,10 @@ slapd_add_internal( ber_socket_t s, int isactive ) Listener ** slapd_get_listeners( void ) { + /* Could return array with no listeners if !listening, but current + * callers mostly look at the URLs. E.g. syncrepl uses this to + * identify the server, which means it wants the startup arguments. + */ return slap_listeners; }