]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/daemon.c
Plug mutex/rwlock leaks (destroy them)
[openldap] / servers / slapd / daemon.c
index 5f6496821fb028b9106dc591613708a1c2e10466..a504842ae0266acaac5593d44bbe82429ed7b007 100644 (file)
@@ -1,7 +1,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1998-2008 The OpenLDAP Foundation.
+ * Copyright 1998-2010 The OpenLDAP Foundation.
  * Portions Copyright 2007 by Howard Chu, Symas Corporation.
  * All rights reserved.
  *
@@ -73,15 +73,26 @@ ber_socket_t dtblsize;
 slap_ssf_t local_ssf = LDAP_PVT_SASL_LOCAL_SSF;
 struct runqueue_s slapd_rq;
 
+#ifdef LDAP_TCP_BUFFER
+int slapd_tcp_rmem;
+int slapd_tcp_wmem;
+#endif /* LDAP_TCP_BUFFER */
+
 Listener **slap_listeners = NULL;
 
 #ifndef SLAPD_LISTEN_BACKLOG
 #define SLAPD_LISTEN_BACKLOG 1024
 #endif /* ! SLAPD_LISTEN_BACKLOG */
 
-static ber_socket_t wake_sds[2];
+static ber_socket_t wake_sds[2]
+#ifdef HAVE_WINSOCK
+       = { INVALID_SOCKET, INVALID_SOCKET }
+#endif /* HAVE_WINSOCK */
+       ;
 static int emfile;
 
+static time_t chk_writetime;
+
 static volatile int waking;
 #ifdef NO_THREADS
 #define WAKE_LISTENER(w)       do { \
@@ -533,6 +544,7 @@ static struct slap_daemon {
        slap_daemon.sd_flags = (char *)(slapd_ws_sockets + dtblsize); \
        slap_daemon.sd_rflags = slap_daemon.sd_flags + dtblsize; \
        memset( slapd_ws_sockets, -1, dtblsize * sizeof(SOCKET) ); \
+       memset( slap_daemon.sd_flags, 0, dtblsize ); \
        slapd_ws_sockets[0] = wake_sds[0]; \
        slapd_ws_sockets[1] = wake_sds[1]; \
        wake_sds[0] = 0; \
@@ -680,16 +692,16 @@ slapd_slp_init( const char* urls )
        for ( i = 0; slapd_srvurls[i] != NULL; i++ ) {
                if ( strcmp( slapd_srvurls[i], "ldap:///" ) == 0 ) {
                        slapd_srvurls[i] = (char *) ch_realloc( slapd_srvurls[i],
-                               strlen( global_host ) +
+                               global_host_bv.bv_len +
                                sizeof( LDAP_SRVTYPE_PREFIX ) );
                        strcpy( lutil_strcopy(slapd_srvurls[i],
-                               LDAP_SRVTYPE_PREFIX ), global_host );
+                               LDAP_SRVTYPE_PREFIX ), global_host_bv.bv_val );
                } else if ( strcmp( slapd_srvurls[i], "ldaps:///" ) == 0 ) {
                        slapd_srvurls[i] = (char *) ch_realloc( slapd_srvurls[i],
-                               strlen( global_host ) +
+                               global_host_bv.bv_len +
                                sizeof( LDAPS_SRVTYPE_PREFIX ) );
                        strcpy( lutil_strcopy(slapd_srvurls[i],
-                               LDAPS_SRVTYPE_PREFIX ), global_host );
+                               LDAPS_SRVTYPE_PREFIX ), global_host_bv.bv_val );
                }
        }
 
@@ -928,9 +940,9 @@ slapd_clr_write( ber_socket_t s, int wake )
 {
        ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
 
-       assert( SLAP_SOCK_IS_ACTIVE( s ));
-
        if ( SLAP_SOCK_IS_WRITE( s )) {
+               assert( SLAP_SOCK_IS_ACTIVE( s ));
+
                SLAP_SOCK_CLR_WRITE( s );
                slap_daemon.sd_nwriters--;
        }
@@ -950,6 +962,9 @@ slapd_set_write( ber_socket_t s, int wake )
                SLAP_SOCK_SET_WRITE( s );
                slap_daemon.sd_nwriters++;
        }
+       if (( wake & 2 ) && global_writetimeout && !chk_writetime ) {
+               chk_writetime = slap_get_time();
+       }
 
        ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
        WAKE_LISTENER(wake);
@@ -974,13 +989,36 @@ slapd_clr_read( ber_socket_t s, int wake )
 void
 slapd_set_read( ber_socket_t s, int wake )
 {
+       int do_wake = 1;
        ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
 
-       assert( SLAP_SOCK_IS_ACTIVE( s ));
-       if (!SLAP_SOCK_IS_READ( s )) SLAP_SOCK_SET_READ( s );
+       if( SLAP_SOCK_IS_ACTIVE( s ) && !SLAP_SOCK_IS_READ( s )) {
+               SLAP_SOCK_SET_READ( s );
+       } else {
+               do_wake = 0;
+       }
+       ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
+       if ( do_wake )
+               WAKE_LISTENER(wake);
+}
 
+time_t
+slapd_get_writetime()
+{
+       time_t cur;
+       ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
+       cur = chk_writetime;
+       ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
+       return cur;
+}
+
+void
+slapd_clr_writetime( time_t old )
+{
+       ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
+       if ( chk_writetime == old )
+               chk_writetime = 0;
        ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
-       WAKE_LISTENER(wake);
 }
 
 static void
@@ -1286,6 +1324,11 @@ slap_open_listener(
        }
 #endif /* HAVE_TLS */
 
+#ifdef LDAP_TCP_BUFFER
+       l.sl_tcp_rmem = 0;
+       l.sl_tcp_wmem = 0;
+#endif /* LDAP_TCP_BUFFER */
+
        port = (unsigned short) lud->lud_port;
 
        tmp = ldap_pvt_url_scheme2proto(lud->lud_scheme);
@@ -1449,7 +1492,7 @@ slap_open_listener(
                 * create/unlink the socket; likely need exec perms to access
                 * the socket (ITS#4709) */
                {
-                       mode_t old_umask;
+                       mode_t old_umask = 0;
 
                        if ( (*sal)->sa_family == AF_LOCAL ) {
                                old_umask = umask( 0 );
@@ -1457,7 +1500,7 @@ slap_open_listener(
 #endif /* LDAP_PF_LOCAL */
                        rc = bind( s, *sal, addrlen );
 #ifdef LDAP_PF_LOCAL
-                       if ( (*sal)->sa_family == AF_LOCAL ) {
+                       if ( old_umask != 0 ) {
                                umask( old_umask );
                        }
                }
@@ -1581,6 +1624,7 @@ slapd_daemon_init( const char *urls )
                        "daemon: lutil_pair() failed rc=%d\n", rc, 0, 0 );
                return rc;
        }
+       ber_pvt_socket_set_nonblock( wake_sds[1], 1 );
 
        SLAP_SOCK_INIT;
 
@@ -1641,8 +1685,15 @@ int
 slapd_daemon_destroy( void )
 {
        connections_destroy();
-       tcp_close( SLAP_FD2SOCK(wake_sds[1]) );
-       tcp_close( SLAP_FD2SOCK(wake_sds[0]) );
+#ifdef HAVE_WINSOCK
+       if ( wake_sds[1] != INVALID_SOCKET &&
+               SLAP_FD2SOCK( wake_sds[1] ) != SLAP_FD2SOCK( wake_sds[0] ))
+#endif /* HAVE_WINSOCK */
+               tcp_close( SLAP_FD2SOCK(wake_sds[1]) );
+#ifdef HAVE_WINSOCK
+       if ( wake_sds[0] != INVALID_SOCKET )
+#endif /* HAVE_WINSOCK */
+               tcp_close( SLAP_FD2SOCK(wake_sds[0]) );
        sockdestroy();
 
 #ifdef HAVE_SLP
@@ -1669,9 +1720,12 @@ close_listeners(
 
        for ( l = 0; slap_listeners[l] != NULL; l++ ) {
                Listener *lr = slap_listeners[l];
+               slap_listeners[l] = NULL;
 
                if ( lr->sl_sd != AC_SOCKET_INVALID ) {
-                       if ( remove ) slapd_remove( lr->sl_sd, NULL, 0, 0, 0 );
+                       int s = lr->sl_sd;
+                       lr->sl_sd = AC_SOCKET_INVALID;
+                       if ( remove ) slapd_remove( s, NULL, 0, 0, 0 );
 
 #ifdef LDAP_PF_LOCAL
                        if ( lr->sl_sa.sa_addr.sa_family == AF_LOCAL ) {
@@ -1679,7 +1733,7 @@ close_listeners(
                        }
 #endif /* LDAP_PF_LOCAL */
 
-                       slapd_close( lr->sl_sd );
+                       slapd_close( s );
                }
 
                if ( lr->sl_url.bv_val ) {
@@ -1691,7 +1745,6 @@ close_listeners(
                }
 
                free( lr );
-               slap_listeners[l] = NULL;
        }
 }
 
@@ -2023,24 +2076,12 @@ slapd_daemon_task(
 {
        int l;
        time_t last_idle_check = 0;
-       struct timeval idle;
        int ebadf = 0;
 
 #define SLAPD_IDLE_CHECK_LIMIT 4
 
        if ( global_idletimeout > 0 ) {
                last_idle_check = slap_get_time();
-               /* Set the select timeout.
-                * Don't just truncate, preserve the fractions of
-                * seconds to prevent sleeping for zero time.
-                */
-               idle.tv_sec = global_idletimeout / SLAPD_IDLE_CHECK_LIMIT;
-               idle.tv_usec = global_idletimeout - \
-                       ( idle.tv_sec * SLAPD_IDLE_CHECK_LIMIT );
-               idle.tv_usec *= 1000000 / SLAPD_IDLE_CHECK_LIMIT;
-       } else {
-               idle.tv_sec = 0;
-               idle.tv_usec = 0;
        }
 
        slapd_add( wake_sds[0], 0, NULL );
@@ -2057,6 +2098,131 @@ slapd_daemon_task(
                        continue;
 #endif /* LDAP_CONNECTIONLESS */
 
+               /* FIXME: TCP-only! */
+#ifdef LDAP_TCP_BUFFER
+               if ( 1 ) {
+                       int origsize, size, realsize, rc;
+                       socklen_t optlen;
+                       char buf[ SLAP_TEXT_BUFLEN ];
+
+                       size = 0;
+                       if ( slap_listeners[l]->sl_tcp_rmem > 0 ) {
+                               size = slap_listeners[l]->sl_tcp_rmem;
+                       } else if ( slapd_tcp_rmem > 0 ) {
+                               size = slapd_tcp_rmem;
+                       }
+
+                       if ( size > 0 ) {
+                               optlen = sizeof( origsize );
+                               rc = getsockopt( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ),
+                                       SOL_SOCKET,
+                                       SO_RCVBUF,
+                                       (void *)&origsize,
+                                       &optlen );
+
+                               if ( rc ) {
+                                       int err = sock_errno();
+                                       Debug( LDAP_DEBUG_ANY,
+                                               "slapd_daemon_task: getsockopt(SO_RCVBUF) failed errno=%d (%s)\n",
+                                               err, sock_errstr(err), 0 );
+                               }
+
+                               optlen = sizeof( size );
+                               rc = setsockopt( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ),
+                                       SOL_SOCKET,
+                                       SO_RCVBUF,
+                                       (const void *)&size,
+                                       optlen );
+
+                               if ( rc ) {
+                                       int err = sock_errno();
+                                       Debug( LDAP_DEBUG_ANY,
+                                               "slapd_daemon_task: setsockopt(SO_RCVBUF) failed errno=%d (%s)\n",
+                                               err, sock_errstr(err), 0 );
+                               }
+
+                               optlen = sizeof( realsize );
+                               rc = getsockopt( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ),
+                                       SOL_SOCKET,
+                                       SO_RCVBUF,
+                                       (void *)&realsize,
+                                       &optlen );
+
+                               if ( rc ) {
+                                       int err = sock_errno();
+                                       Debug( LDAP_DEBUG_ANY,
+                                               "slapd_daemon_task: getsockopt(SO_RCVBUF) failed errno=%d (%s)\n",
+                                               err, sock_errstr(err), 0 );
+                               }
+
+                               snprintf( buf, sizeof( buf ),
+                                       "url=%s (#%d) RCVBUF original size=%d requested size=%d real size=%d", 
+                                       slap_listeners[l]->sl_url.bv_val, l, origsize, size, realsize );
+                               Debug( LDAP_DEBUG_ANY,
+                                       "slapd_daemon_task: %s\n",
+                                       buf, 0, 0 );
+                       }
+
+                       size = 0;
+                       if ( slap_listeners[l]->sl_tcp_wmem > 0 ) {
+                               size = slap_listeners[l]->sl_tcp_wmem;
+                       } else if ( slapd_tcp_wmem > 0 ) {
+                               size = slapd_tcp_wmem;
+                       }
+
+                       if ( size > 0 ) {
+                               optlen = sizeof( origsize );
+                               rc = getsockopt( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ),
+                                       SOL_SOCKET,
+                                       SO_SNDBUF,
+                                       (void *)&origsize,
+                                       &optlen );
+
+                               if ( rc ) {
+                                       int err = sock_errno();
+                                       Debug( LDAP_DEBUG_ANY,
+                                               "slapd_daemon_task: getsockopt(SO_SNDBUF) failed errno=%d (%s)\n",
+                                               err, sock_errstr(err), 0 );
+                               }
+
+                               optlen = sizeof( size );
+                               rc = setsockopt( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ),
+                                       SOL_SOCKET,
+                                       SO_SNDBUF,
+                                       (const void *)&size,
+                                       optlen );
+
+                               if ( rc ) {
+                                       int err = sock_errno();
+                                       Debug( LDAP_DEBUG_ANY,
+                                               "slapd_daemon_task: setsockopt(SO_SNDBUF) failed errno=%d (%s)",
+                                               err, sock_errstr(err), 0 );
+                               }
+
+                               optlen = sizeof( realsize );
+                               rc = getsockopt( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ),
+                                       SOL_SOCKET,
+                                       SO_SNDBUF,
+                                       (void *)&realsize,
+                                       &optlen );
+
+                               if ( rc ) {
+                                       int err = sock_errno();
+                                       Debug( LDAP_DEBUG_ANY,
+                                               "slapd_daemon_task: getsockopt(SO_SNDBUF) failed errno=%d (%s)\n",
+                                               err, sock_errstr(err), 0 );
+                               }
+
+                               snprintf( buf, sizeof( buf ),
+                                       "url=%s (#%d) SNDBUF original size=%d requested size=%d real size=%d", 
+                                       slap_listeners[l]->sl_url.bv_val, l, origsize, size, realsize );
+                               Debug( LDAP_DEBUG_ANY,
+                                       "slapd_daemon_task: %s\n",
+                                       buf, 0, 0 );
+                       }
+               }
+#endif /* LDAP_TCP_BUFFER */
+
                if ( listen( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ), SLAPD_LISTEN_BACKLOG ) == -1 ) {
                        int err = sock_errno();
 
@@ -2145,14 +2311,34 @@ slapd_daemon_task(
 
                now = slap_get_time();
 
-               if ( ( global_idletimeout > 0 ) &&
-                       difftime( last_idle_check +
-                               global_idletimeout/SLAPD_IDLE_CHECK_LIMIT, now ) < 0 )
-               {
-                       connections_timeout_idle( now );
-                       last_idle_check = now;
+               if ( global_idletimeout > 0 || chk_writetime ) {
+                       int check = 0;
+                       /* Set the select timeout.
+                        * Don't just truncate, preserve the fractions of
+                        * seconds to prevent sleeping for zero time.
+                        */
+                       if ( chk_writetime ) {
+                               tv.tv_sec = global_writetimeout;
+                               tv.tv_usec = 0;
+                               if ( difftime( chk_writetime, now ) < 0 )
+                                       check = 2;
+                       } else {
+                               tv.tv_sec = global_idletimeout / SLAPD_IDLE_CHECK_LIMIT;
+                               tv.tv_usec = global_idletimeout - \
+                                       ( tv.tv_sec * SLAPD_IDLE_CHECK_LIMIT );
+                               tv.tv_usec *= 1000000 / SLAPD_IDLE_CHECK_LIMIT;
+                               if ( difftime( last_idle_check +
+                                       global_idletimeout/SLAPD_IDLE_CHECK_LIMIT, now ) < 0 )
+                                       check = 1;
+                       }
+                       if ( check ) {
+                               connections_timeout_idle( now );
+                               last_idle_check = now;
+                       }
+               } else {
+                       tv.tv_sec = 0;
+                       tv.tv_usec = 0;
                }
-               tv = idle;
 
 #ifdef SIGHUP
                if ( slapd_gentle_shutdown ) {
@@ -2201,7 +2387,7 @@ slapd_daemon_task(
 
                nfds = SLAP_EVENT_MAX;
 
-               if ( global_idletimeout && slap_daemon.sd_nactives ) at = 1;
+               if (( chk_writetime || global_idletimeout ) && slap_daemon.sd_nactives ) at = 1;
 
                ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
 
@@ -2291,7 +2477,7 @@ slapd_daemon_task(
                                                Debug( LDAP_DEBUG_ANY,
                                                        "daemon: "
                                                        SLAP_EVENT_FNAME
-                                                       "failed count %d "
+                                                       " failed count %d "
                                                        "err (%d): %s\n",
                                                        ebadf, err,
                                                        sock_errstr( err ) );
@@ -2485,7 +2671,7 @@ slapd_daemon_task(
 #endif /* LDAP_DEBUG */
 
                for ( i = 0; i < ns; i++ ) {
-                       int rc = 1, fd;
+                       int rc = 1, fd, w = 0, r = 0;
 
                        if ( SLAP_EVENT_IS_LISTENER( i ) ) {
                                rc = slap_listener_activate( SLAP_EVENT_LISTENER( i ) );
@@ -2503,7 +2689,7 @@ slapd_daemon_task(
                                        char c[BUFSIZ];
                                        waking = 0;
                                        tcp_read( SLAP_FD2SOCK(wake_sds[0]), c, sizeof(c) );
-                                       break;
+                                       continue;
                                }
 
                                if ( SLAP_EVENT_IS_WRITE( i ) ) {
@@ -2512,6 +2698,7 @@ slapd_daemon_task(
                                                fd, 0, 0 );
 
                                        SLAP_EVENT_CLR_WRITE( i );
+                                       w = 1;
 
                                        /*
                                         * NOTE: it is possible that the connection was closed
@@ -2524,16 +2711,25 @@ slapd_daemon_task(
                                        }
                                }
                                /* If event is a read */
-                               if ( SLAP_EVENT_IS_READ( i ) ) {
+                               if ( SLAP_EVENT_IS_READ( i ))
+                                       r = 1;
+                               if ( r || !w ) {
                                        Debug( LDAP_DEBUG_CONNS,
                                                "daemon: read active on %d\n",
                                                fd, 0, 0 );
 
-                                       SLAP_EVENT_CLR_READ( i );
+                                       if ( r ) {
+                                               SLAP_EVENT_CLR_READ( i );
+                                       } else {
+#ifdef HAVE_EPOLL
+                                               /* Don't keep reporting the hangup
+                                                */
+                                               if ( SLAP_SOCK_IS_ACTIVE( fd )) {
+                                                       SLAP_EPOLL_SOCK_SET( fd, EPOLLET );
+                                               }
+#endif
+                                       }
                                        connection_read_activate( fd );
-                               } else {
-                                       Debug( LDAP_DEBUG_CONNS,
-                                               "daemon: hangup on %d\n", fd, 0, 0 );
                                }
                        }
                }
@@ -2572,9 +2768,12 @@ slapd_daemon_task(
                connections_shutdown();
        }
 
-       Debug( LDAP_DEBUG_ANY,
-               "slapd shutdown: waiting for %d threads to terminate\n",
-               ldap_pvt_thread_pool_backload( &connection_pool ), 0, 0 );
+       if ( LogTest( LDAP_DEBUG_ANY )) {
+               int t = ldap_pvt_thread_pool_backload( &connection_pool );
+               Debug( LDAP_DEBUG_ANY,
+                       "slapd shutdown: waiting for %d operations/tasks to finish\n",
+                       t, 0, 0 );
+       }
        ldap_pvt_thread_pool_destroy( &connection_pool, 1 );
 
        free( slap_listeners );
@@ -2605,7 +2804,7 @@ connectionless_init( void )
                if ( !c ) {
                        Debug( LDAP_DEBUG_TRACE,
                                "connectionless_init: failed on %s (%d)\n",
-                               lr->sl_url, lr->sl_sd, 0 );
+                               lr->sl_url.bv_val, lr->sl_sd, 0 );
                        return -1;
                }
                lr->sl_is_udp++;
@@ -2620,7 +2819,6 @@ slapd_daemon( void )
 {
        int rc;
 
-       connections_init();
 #ifdef LDAP_CONNECTIONLESS
        connectionless_init();
 #endif /* LDAP_CONNECTIONLESS */
@@ -2706,6 +2904,8 @@ sockdestroy( void )
 RETSIGTYPE
 slap_sig_shutdown( int sig )
 {
+       int save_errno = errno;
+
 #if 0
        Debug(LDAP_DEBUG_TRACE, "slap_sig_shutdown: signal %d\n", sig, 0, 0);
 #endif
@@ -2734,15 +2934,21 @@ slap_sig_shutdown( int sig )
 
        /* reinstall self */
        (void) SIGNAL_REINSTALL( sig, slap_sig_shutdown );
+
+       errno = save_errno;
 }
 
 RETSIGTYPE
 slap_sig_wake( int sig )
 {
+       int save_errno = errno;
+
        WAKE_LISTENER(1);
 
        /* reinstall self */
        (void) SIGNAL_REINSTALL( sig, slap_sig_wake );
+
+       errno = save_errno;
 }