X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fdaemon.c;h=f8a45f357b72c9a56b2bf9108b92dee8c67bc9bd;hb=e2b5b211558ee778f07954d3843b914f19f6c6b5;hp=863ca497d322f7102c71c021939e724df3424aeb;hpb=8b2170bcf4a5c85b39840f481dd55064015bd6ad;p=openldap diff --git a/servers/slapd/daemon.c b/servers/slapd/daemon.c index 863ca497d3..f8a45f357b 100644 --- a/servers/slapd/daemon.c +++ b/servers/slapd/daemon.c @@ -1,297 +1,587 @@ +#include "portable.h" + #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef _AIX -#include -#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "ldap_defaults.h" #include "slap.h" -#include "portable.h" -#include "ldapconfig.h" -#ifdef NEED_FILIO -#include -#else /* NEED_FILIO */ -#include -#endif /* NEED_FILIO */ -#ifdef USE_SYSCONF -#include -#endif /* USE_SYSCONF */ - -extern Operation *op_add(); - -#ifndef SYSERRLIST_IN_STDIO -extern int sys_nerr; -extern char *sys_errlist[]; + +#ifdef HAVE_TCPD +#include + +int allow_severity = LOG_INFO; +int deny_severity = LOG_NOTICE; +#endif /* TCP Wrappers */ + +/* globals */ +ber_socket_t dtblsize; +static ber_socket_t tcps; + +#ifdef HAVE_WINSOCK2 +/* in nt_main.c */ +extern ldap_pvt_thread_cond_t started_event; + +/* forward reference */ +void hit_socket(); +/* In wsa_err.c */ +char *WSAGetLastErrorString(); +static ldap_pvt_thread_t hit_tid; + +#define WAKE_LISTENER(w) \ +do {\ + if( w ) {\ + ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );\ + hit_socket(); \ + }\ +} while(0) +#else +#define WAKE_LISTENER(w) \ +do {\ + if( w ) {\ + ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );\ + }\ +} while(0) #endif -extern time_t currenttime; -extern pthread_mutex_t currenttime_mutex; -extern int active_threads; -extern pthread_mutex_t active_threads_mutex; -extern pthread_mutex_t new_conn_mutex; -extern int slapd_shutdown; -extern pthread_t listener_tid; -extern int num_conns; -extern pthread_mutex_t ops_mutex; -extern int g_argc; -extern char **g_argv; - -int dtblsize; -Connection *c; - -static void set_shutdown(); -static void do_nothing(); -void -daemon( - int port -) -{ - Operation *o; - BerElement ber; - unsigned long len, tag, msgid; - int i; - int tcps, ns; - struct sockaddr_in addr; - fd_set readfds; - fd_set writefds; - FILE *fp; - int on = 1; - -#ifdef USE_SYSCONF - dtblsize = sysconf( _SC_OPEN_MAX ); -#else /* USE_SYSCONF */ - dtblsize = getdtablesize(); -#endif /* USE_SYSCONF */ - /* - * Add greg@greg.rim.or.jp - */ - if(dtblsize > FD_SETSIZE) { - dtblsize = FD_SETSIZE; - } - c = (Connection *) ch_calloc( 1, dtblsize * sizeof(Connection) ); - - for ( i = 0; i < dtblsize; i++ ) { - c[i].c_dn = NULL; - c[i].c_addr = NULL; - c[i].c_domain = NULL; - c[i].c_ops = NULL; - c[i].c_sb.sb_sd = -1; - c[i].c_sb.sb_options = LBER_NO_READ_AHEAD; - c[i].c_sb.sb_naddr = 0; - c[i].c_sb.sb_ber.ber_buf = NULL; - c[i].c_sb.sb_ber.ber_ptr = NULL; - c[i].c_sb.sb_ber.ber_end = NULL; - c[i].c_writewaiter = 0; - c[i].c_connid = 0; - pthread_mutex_init( &c[i].c_dnmutex, - pthread_mutexattr_default ); - pthread_mutex_init( &c[i].c_opsmutex, - pthread_mutexattr_default ); - pthread_mutex_init( &c[i].c_pdumutex, - pthread_mutexattr_default ); - pthread_cond_init( &c[i].c_wcv, pthread_condattr_default ); +#ifndef HAVE_WINSOCK +static +#endif +volatile sig_atomic_t slapd_shutdown = 0; + +static int daemon_initialized = 0; +static ldap_pvt_thread_t listener_tid; +static volatile sig_atomic_t slapd_listener = 0; +void sockinit(); + +struct slap_daemon { + ldap_pvt_thread_mutex_t sd_mutex; + + int sd_nactives; + +#ifndef HAVE_WINSOCK + /* In winsock, accept() returns values higher than dtblsize + so don't bother with this optimization */ + int sd_nfds; +#endif + + fd_set sd_actives; + fd_set sd_readers; + fd_set sd_writers; +} slap_daemon; + +/* + * Add a descriptor to daemon control + */ +static void slapd_add(ber_socket_t s) { + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + + assert( !FD_ISSET( s, &slap_daemon.sd_actives )); + assert( !FD_ISSET( s, &slap_daemon.sd_readers )); + assert( !FD_ISSET( s, &slap_daemon.sd_writers )); + +#ifndef HAVE_WINSOCK + if (s >= slap_daemon.sd_nfds) { + slap_daemon.sd_nfds = s + 1; } +#endif + + FD_SET( s, &slap_daemon.sd_actives ); + FD_SET( s, &slap_daemon.sd_readers ); + + Debug( LDAP_DEBUG_CONNS, "daemon: added %ld%s%s\n", + (long) s, + FD_ISSET(s, &slap_daemon.sd_readers) ? "r" : "", + FD_ISSET(s, &slap_daemon.sd_writers) ? "w" : "" ); + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); +} + +/* + * Remove the descriptor from daemon control + */ +void slapd_remove(ber_socket_t s, int wake) { + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + WAKE_LISTENER(wake); + + Debug( LDAP_DEBUG_CONNS, "daemon: removing %ld%s%s\n", + (long) s, + FD_ISSET(s, &slap_daemon.sd_readers) ? "r" : "", + FD_ISSET(s, &slap_daemon.sd_writers) ? "w" : "" ); + + FD_CLR( s, &slap_daemon.sd_actives ); + FD_CLR( s, &slap_daemon.sd_readers ); + FD_CLR( s, &slap_daemon.sd_writers ); + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); +} + +void slapd_clr_write(ber_socket_t s, int wake) { + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + WAKE_LISTENER(wake); - if ( (tcps = socket( AF_INET, SOCK_STREAM, 0 )) == -1 ) { - Debug( LDAP_DEBUG_ANY, "socket() failed errno %d (%s)", errno, - errno > -1 && errno < sys_nerr ? sys_errlist[errno] : - "unknown", 0 ); - exit( 1 ); + assert( FD_ISSET( s, &slap_daemon.sd_actives) ); + FD_CLR( s, &slap_daemon.sd_writers ); + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); + + if( wake ) { + ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 ); } +} + +void slapd_set_write(ber_socket_t s, int wake) { + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + WAKE_LISTENER(wake); - i = 1; - if ( setsockopt( tcps, SOL_SOCKET, SO_REUSEADDR, (char *) &i, - sizeof(i) ) == -1 ) { - Debug( LDAP_DEBUG_ANY, "setsockopt() failed errno %d (%s)", - errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] : - "unknown", 0 ); + assert( FD_ISSET( s, &slap_daemon.sd_actives) ); + FD_SET( (unsigned) s, &slap_daemon.sd_writers ); + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); + + if( wake ) { + ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 ); } +} - (void) memset( (void *) &addr, '\0', sizeof(addr) ); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = htons( port ); - if ( bind( tcps, (struct sockaddr *) &addr, sizeof(addr) ) == -1 ) { - Debug( LDAP_DEBUG_ANY, "bind() failed errno %d (%s)\n", - errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] : - "unknown", 0 ); - exit( 1 ); +void slapd_clr_read(ber_socket_t s, int wake) { + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + WAKE_LISTENER(wake); + + assert( FD_ISSET( s, &slap_daemon.sd_actives) ); + FD_CLR( s, &slap_daemon.sd_readers ); + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); + + if( wake ) { + ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 ); } +} + +void slapd_set_read(ber_socket_t s, int wake) { + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + WAKE_LISTENER(wake); + + assert( FD_ISSET( s, &slap_daemon.sd_actives) ); + FD_SET( s, &slap_daemon.sd_readers ); + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); - if ( listen( tcps, 5 ) == -1 ) { - Debug( LDAP_DEBUG_ANY, "listen() failed errno %d (%s)", - errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] : - "unknown", 0 ); - exit( 1 ); + if( wake ) { + ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 ); } +} + +static void slapd_close(ber_socket_t s) { + Debug( LDAP_DEBUG_CONNS, "daemon: closing %ld\n", + (long) s, 0, 0 ); + tcp_close(s); +} + + + +int +set_socket( struct sockaddr_in *addr ) +{ + ber_socket_t tcps = AC_SOCKET_INVALID; - (void) SIGNAL( SIGPIPE, SIG_IGN ); - (void) SIGNAL( SIGUSR1, (void *) do_nothing ); - (void) SIGNAL( SIGUSR2, (void *) set_shutdown ); - (void) SIGNAL( SIGTERM, (void *) set_shutdown ); - (void) SIGNAL( SIGINT, (void *) set_shutdown ); - (void) SIGNAL( SIGHUP, (void *) set_shutdown ); - - Debug( LDAP_DEBUG_ANY, "slapd starting\n", 0, 0, 0 ); -#ifdef SLAPD_PIDFILE - if ( (fp = fopen( SLAPD_PIDFILE, "w" )) != NULL ) { - fprintf( fp, "%d\n", getpid() ); - fclose( fp ); + if ( !daemon_initialized ) sockinit(); + +#ifdef HAVE_SYSCONF + dtblsize = sysconf( _SC_OPEN_MAX ); +#elif HAVE_GETDTABLESIZE + dtblsize = getdtablesize(); +#else + dtblsize = FD_SETSIZE; +#endif + +#ifdef FD_SETSIZE + if(dtblsize > FD_SETSIZE) { + dtblsize = FD_SETSIZE; } +#endif /* !FD_SETSIZE */ + + if( addr != NULL ) { + int tmp; + + if ( (tcps = socket( AF_INET, SOCK_STREAM, 0 )) == AC_SOCKET_INVALID ) { +#ifndef HAVE_WINSOCK + int err = errno; + Debug( LDAP_DEBUG_ANY, + "daemon: socket() failed errno %d (%s)\n", err, + err > -1 && err < sys_nerr ? sys_errlist[err] : + "unknown", 0 ); +#else + Debug( LDAP_DEBUG_ANY, + "daemon: socket() failed errno %d (%s)\n", + WSAGetLastError(), + WSAGetLastErrorString(), 0 ); +#endif + return( -1 ); + } + +#ifndef HAVE_WINSOCK + if ( tcps >= dtblsize ) { + Debug( LDAP_DEBUG_ANY, + "daemon: listener descriptor %ld is too great %ld\n", + (long) tcps, (long) dtblsize, 0 ); + return( -1); + } +#endif + +#ifdef SO_REUSEADDR + tmp = 1; + if ( setsockopt( tcps, SOL_SOCKET, SO_REUSEADDR, + (char *) &tmp, sizeof(tmp) ) == -1 ) + { + int err = errno; + Debug( LDAP_DEBUG_ANY, + "slapd(%ld): setsockopt() failed errno %d (%s)\n", + (long) tcps, err, + err > -1 && err < sys_nerr + ? sys_errlist[err] : "unknown" ); + } #endif -#ifdef SLAPD_ARGSFILE - if ( (fp = fopen( SLAPD_ARGSFILE, "w" )) != NULL ) { - for ( i = 0; i < g_argc; i++ ) { - fprintf( fp, "%s ", g_argv[i] ); +#ifdef SO_KEEPALIVE + tmp = 1; + if ( setsockopt( tcps, SOL_SOCKET, SO_KEEPALIVE, + (char *) &tmp, sizeof(tmp) ) == -1 ) + { + int err = errno; + Debug( LDAP_DEBUG_ANY, + "slapd(%ld): setsockopt(KEEPALIVE) failed errno %d (%s)\n", + (long) tcps, err, + err > -1 && err < sys_nerr + ? sys_errlist[err] : "unknown" ); + } +#endif + + + if ( bind( tcps, (struct sockaddr *) addr, sizeof(*addr) ) == -1 ) { + int err = errno; + Debug( LDAP_DEBUG_ANY, "daemon: bind(%ld) failed errno %d (%s)\n", + (long) tcps, err, + err > -1 && err < sys_nerr + ? sys_errlist[err] : "unknown" ); + return -1; } - fprintf( fp, "\n" ); - fclose( fp ); } + + return tcps; +} + +static void * +slapd_daemon_task( + void *ptr +) +{ + int inetd; + struct slapd_args *args = (struct slapd_args *) ptr; + struct sockaddr_in *slapd_addr = args->addr; + + tcps = args->tcps; + + inetd = ( slapd_addr == NULL); + if ( !daemon_initialized ) sockinit(); + + slapd_listener=1; + + ldap_pvt_thread_mutex_init( &slap_daemon.sd_mutex ); + FD_ZERO( &slap_daemon.sd_readers ); + FD_ZERO( &slap_daemon.sd_writers ); + + if( !inetd ) { + if ( listen( tcps, 5 ) == -1 ) { + int err = errno; + Debug( LDAP_DEBUG_ANY, + "daemon: listen(%ld, 5) failed errno %d (%s)\n", + (long) tcps, err, + err > -1 && err < sys_nerr + ? sys_errlist[err] : "unknown" ); + return( (void*)-1 ); + } + + slapd_add( tcps ); + + } else { + if( connection_init( (ber_socket_t) 0, NULL, NULL ) ) { + Debug( LDAP_DEBUG_ANY, + "connection_init(%d) failed.\n", + 0, 0, 0 ); + return( (void*)-1 ); + } + + slapd_add( 0 ); + } + +#ifdef HAVE_WINSOCK + if ( started_event != NULL ) + ldap_pvt_thread_cond_signal( &started_event ); #endif + /* initialization complete. Here comes the loop. */ while ( !slapd_shutdown ) { + ber_socket_t i; + int ns; + int at; + ber_socket_t nfds; +#define SLAPD_EBADF_LIMIT 10 + int ebadf = 0; + +#define SLAPD_IDLE_CHECK_LIMIT 4 + time_t last_idle_check = slap_get_time(); + time_t now; + + + fd_set readfds; + fd_set writefds; + struct sockaddr_in from; - struct hostent *hp; +#if defined(SLAPD_RLOOKUPS) || defined(HAVE_TCPD) + struct hostent *hp; +#endif struct timeval zero; struct timeval *tvp; - int len, pid; + + char *client_name; + char *client_addr; + + if( global_idletimeout > 0 && difftime( + last_idle_check+global_idletimeout/SLAPD_IDLE_CHECK_LIMIT, + now ) < 0 ) + { + connections_timeout_idle(now); + } FD_ZERO( &writefds ); FD_ZERO( &readfds ); - FD_SET( tcps, &readfds ); - pthread_mutex_lock( &active_threads_mutex ); - Debug( LDAP_DEBUG_CONNS, - "listening for connections on %d, activity on:", - tcps, 0, 0 ); - for ( i = 0; i < dtblsize; i++ ) { - if ( c[i].c_sb.sb_sd != -1 ) { - FD_SET( c[i].c_sb.sb_sd, &readfds ); - - if ( c[i].c_writewaiter ) { - FD_SET( c[i].c_sb.sb_sd, &writefds ); - } - Debug( LDAP_DEBUG_CONNS, " %dr%s", i, - c[i].c_writewaiter ? "w" : "", 0 ); + zero.tv_sec = 0; + zero.tv_usec = 0; + + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + +#ifdef FD_SET_MANUAL_COPY + for( s = 0; s < nfds; s++ ) { + if(FD_ISSET( &slap_sd_writers, s )) { + FD_SET( &writefds, s ); + } + if(FD_ISSET( &slap_sd_writers, s )) { + FD_SET( &writefds, s ); } } - Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 ); +#else + memcpy( &readfds, &slap_daemon.sd_readers, sizeof(fd_set) ); + memcpy( &writefds, &slap_daemon.sd_writers, sizeof(fd_set) ); +#endif - zero.tv_sec = 0; - zero.tv_usec = 0; - Debug( LDAP_DEBUG_CONNS, "before select active_threads %d\n", - active_threads, 0, 0 ); -#ifdef PTHREAD_PREEMPTIVE + FD_SET( (unsigned) tcps, &readfds ); + +#ifndef HAVE_WINSOCK + nfds = slap_daemon.sd_nfds; +#else + nfds = dtblsize; +#endif + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); + + ldap_pvt_thread_mutex_lock( &active_threads_mutex ); + at = active_threads; + ldap_pvt_thread_mutex_unlock( &active_threads_mutex ); + +#if defined( HAVE_YIELDING_SELECT ) || defined( NO_THREADS ) tvp = NULL; #else - tvp = active_threads ? &zero : NULL; + tvp = at ? &zero : NULL; #endif - pthread_mutex_unlock( &active_threads_mutex ); - switch ( select( dtblsize, &readfds, &writefds, 0, tvp ) ) { - case -1: /* failure - try again */ - Debug( LDAP_DEBUG_CONNS, - "select failed errno %d (%s)\n", - errno, errno > -1 && errno < sys_nerr ? - sys_errlist[errno] : "unknown", 0 ); + Debug( LDAP_DEBUG_CONNS, + "daemon: select: tcps=%d active_threads=%d tvp=%s\n", + tcps, at, + tvp == NULL ? "NULL" : "zero" ); + + + + switch(ns = select( nfds, &readfds, +#ifdef HAVE_WINSOCK + /* don't pass empty fd_set */ + ( writefds.fd_count > 0 ? &writefds : NULL ), +#else + &writefds, +#endif + NULL, tvp )) + { + case -1: { /* failure - try again */ +#ifdef HAVE_WINSOCK + int err = WSAGetLastError(); +#else + int err = errno; +#endif + + if( err == EBADF && ++ebadf < SLAPD_EBADF_LIMIT) { + continue; + } + + if( err != EINTR ) { + Debug( LDAP_DEBUG_CONNS, + "daemon: select failed (%d): %s\n", + err, + err >= 0 && err < sys_nerr + ? sys_errlist[err] : "unknown", + 0 ); + + + slapd_shutdown = -1; + } + } continue; case 0: /* timeout - let threads run */ - Debug( LDAP_DEBUG_CONNS, "select timeout - yielding\n", + ebadf = 0; + Debug( LDAP_DEBUG_CONNS, "daemon: select timeout - yielding\n", 0, 0, 0 ); - pthread_yield(); + ldap_pvt_thread_yield(); continue; default: /* something happened - deal with it */ - Debug( LDAP_DEBUG_CONNS, "select activity\n", 0, 0, 0 ); - ; /* FALL */ + ebadf = 0; + Debug( LDAP_DEBUG_CONNS, "daemon: activity on %d descriptors\n", + ns, 0, 0 ); + /* FALL THRU */ } - pthread_mutex_lock( ¤ttime_mutex ); - time( ¤ttime ); - pthread_mutex_unlock( ¤ttime_mutex ); - /* new connection */ - pthread_mutex_lock( &new_conn_mutex ); if ( FD_ISSET( tcps, &readfds ) ) { - len = sizeof(from); - if ( (ns = accept( tcps, (struct sockaddr *) &from, - &len )) == -1 ) { + ber_int_t s; + int len = sizeof(from); + long id; + + if ( (s = accept( tcps, + (struct sockaddr *) &from, &len )) == AC_SOCKET_INVALID ) + { + int err = errno; Debug( LDAP_DEBUG_ANY, - "accept() failed errno %d (%s)", errno, - errno > -1 && errno < sys_nerr ? - sys_errlist[errno] : "unknown", 0 ); - pthread_mutex_unlock( &new_conn_mutex ); + "daemon: accept(%ld) failed errno %d (%s)\n", err, + (long) tcps, err >= 0 && err < sys_nerr ? + sys_errlist[err] : "unknown"); continue; } - if ( ioctl( ns, FIONBIO, (caddr_t) &on ) == -1 ) { + +#ifdef LDAP_DEBUG + ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex ); + + /* newly accepted stream should not be in any of the FD SETS */ + + assert( !FD_ISSET( s, &slap_daemon.sd_actives) ); + assert( !FD_ISSET( s, &slap_daemon.sd_readers) ); + assert( !FD_ISSET( s, &slap_daemon.sd_writers) ); + + ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex ); +#endif + +#ifndef HAVE_WINSOCK + /* make sure descriptor number isn't too great */ + if ( s >= dtblsize ) { Debug( LDAP_DEBUG_ANY, - "FIONBIO ioctl on %d faled\n", ns, 0, 0 ); + "daemon: %ld beyond descriptor table size %ld\n", + (long) s, (long) dtblsize, 0 ); + slapd_close(s); + continue; } - c[ns].c_sb.sb_sd = ns; - Debug( LDAP_DEBUG_CONNS, "new connection on %d\n", ns, - 0, 0 ); +#endif + + Debug( LDAP_DEBUG_CONNS, "daemon: new connection on %ld\n", + (long) s, 0, 0 ); - pthread_mutex_lock( &ops_mutex ); - c[ns].c_connid = num_conns++; - pthread_mutex_unlock( &ops_mutex ); len = sizeof(from); - if ( getpeername( ns, (struct sockaddr *) &from, &len ) - == 0 ) { - char *s; -#ifdef REVERSE_LOOKUP + if ( getpeername( s, (struct sockaddr *) &from, &len ) == 0 ) { + client_addr = inet_ntoa( from.sin_addr ); + +#if defined(SLAPD_RLOOKUPS) || defined(HAVE_TCPD) hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr), sizeof(from.sin_addr.s_addr), AF_INET ); -#else - hp = NULL; -#endif - Statslog( LDAP_DEBUG_STATS, - "conn=%d fd=%d connection from %s (%s)\n", - c[ns].c_connid, ns, hp == NULL ? "unknown" - : hp->h_name, inet_ntoa( from.sin_addr ), - 0 ); + if(hp) { + char *p; + client_name = hp->h_name; - if ( c[ns].c_addr != NULL ) { - free( c[ns].c_addr ); - } - c[ns].c_addr = strdup( inet_ntoa( - from.sin_addr ) ); - if ( c[ns].c_domain != NULL ) { - free( c[ns].c_domain ); - } - c[ns].c_domain = strdup( hp == NULL ? "" : - hp->h_name ); - /* normalize the domain */ - for ( s = c[ns].c_domain; *s; s++ ) { - *s = TOLOWER( *s ); + /* normalize the domain */ + for ( p = client_name; *p; p++ ) { + *p = TOLOWER( (unsigned char) *p ); + } + + } else { + client_name = NULL; } +#else + client_name = NULL; +#endif + } else { - Statslog( LDAP_DEBUG_STATS, - "conn=%d fd=%d connection from unknown\n", - c[ns].c_connid, ns, 0, 0, 0 ); + client_name = NULL;; + client_addr = NULL; + } + +#ifdef HAVE_TCPD + if(!hosts_ctl("slapd", + client_name != NULL ? client_name : STRING_UNKNOWN, + client_addr != NULL ? client_addr : STRING_UNKNOWN, + STRING_UNKNOWN)) + { + /* DENY ACCESS */ + Statslog( LDAP_DEBUG_ANY, + "fd=%ld connection from %s (%s) denied.\n", + (long) s, + client_name == NULL ? "unknown" : client_name, + client_addr == NULL ? "unknown" : client_addr, + 0, 0 ); + + slapd_close(s); + continue; } - pthread_mutex_lock( &c[ns].c_dnmutex ); - if ( c[ns].c_dn != NULL ) { - free( c[ns].c_dn ); - c[ns].c_dn = NULL; +#endif /* HAVE_TCPD */ + + if( (id = connection_init(s, client_name, client_addr)) < 0 ) { + Debug( LDAP_DEBUG_ANY, + "daemon: connection_init(%ld, %s, %s) failed.\n", + (long) s, + client_name == NULL ? "unknown" : client_name, + client_addr == NULL ? "unknown" : client_addr); + slapd_close(s); + continue; } - pthread_mutex_unlock( &c[ns].c_dnmutex ); - c[ns].c_starttime = currenttime; - c[ns].c_opsinitiated = 0; - c[ns].c_opscompleted = 0; + + Statslog( LDAP_DEBUG_STATS, + "daemon: conn=%d fd=%ld connection from %s (%s) accepted.\n", + id, (long) s, + client_name == NULL ? "unknown" : client_name, + client_addr == NULL ? "unknown" : client_addr, + 0 ); + + slapd_add( s ); + continue; } - pthread_mutex_unlock( &new_conn_mutex ); - Debug( LDAP_DEBUG_CONNS, "activity on:", 0, 0, 0 ); - for ( i = 0; i < dtblsize; i++ ) { - int r, w; +#ifdef LDAP_DEBUG + Debug( LDAP_DEBUG_CONNS, "daemon: activity on:", 0, 0, 0 ); +#ifdef HAVE_WINSOCK + for ( i = 0; i < readfds.fd_count; i++ ) { + Debug( LDAP_DEBUG_CONNS, " %d%s", + readfds.fd_array[i], "r", 0 ); + } + for ( i = 0; i < writefds.fd_count; i++ ) { + Debug( LDAP_DEBUG_CONNS, " %d%s", + writefds.fd_array[i], "w", 0 ); + } +#else + for ( i = 0; i < nfds; i++ ) { + int a, r, w; r = FD_ISSET( i, &readfds ); w = FD_ISSET( i, &writefds ); @@ -300,71 +590,258 @@ daemon( r ? "r" : "", w ? "w" : "" ); } } +#endif Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 ); +#endif + + /* loop through the writers */ +#ifdef HAVE_WINSOCK + for ( i = 0; i < writefds.fd_count; i++ ) +#else + for ( i = 0; i < nfds; i++ ) +#endif + { + ber_socket_t wd; - for ( i = 0; i < dtblsize; i++ ) { - if ( i == tcps || (! FD_ISSET( i, &readfds ) && - ! FD_ISSET( i, &writefds )) ) { +#ifdef HAVE_WINSOCK + wd = writefds.fd_array[i]; +#else + if( ! FD_ISSET( i, &writefds ) ) { continue; } + wd = i; +#endif - if ( FD_ISSET( i, &writefds ) ) { - Debug( LDAP_DEBUG_CONNS, - "signaling write waiter on %d\n", i, 0, 0 ); + if ( wd == tcps ) { + continue; + } + Debug( LDAP_DEBUG_CONNS, + "daemon: write active on %d\n", + wd, 0, 0 ); + + /* + * NOTE: it is possible that the connection was closed + * and that the stream is now inactive. + * connection_write() must valid the stream is still + * active. + */ + + if ( connection_write( wd ) < 0 ) { + FD_CLR( (unsigned) wd, &readfds ); + slapd_close( wd ); + } + } + +#ifdef HAVE_WINSOCK + for ( i = 0; i < readfds.fd_count; i++ ) +#else + for ( i = 0; i < nfds; i++ ) +#endif + { + ber_socket_t rd; + +#ifdef HAVE_WINSOCK + rd = readfds.fd_array[i]; +#else + if( ! FD_ISSET( i, &readfds ) ) { + continue; + } + rd = i; +#endif - pthread_mutex_lock( &active_threads_mutex ); - pthread_cond_signal( &c[i].c_wcv ); - c[i].c_writewaiter = 0; - active_threads++; - pthread_mutex_unlock( &active_threads_mutex ); + if ( rd == tcps ) { + continue; } - if ( FD_ISSET( i, &readfds ) ) { - Debug( LDAP_DEBUG_CONNS, - "read activity on %d\n", i, 0, 0 ); + Debug ( LDAP_DEBUG_CONNS, + "daemon: read activity on %d\n", rd, 0, 0 ); - connection_activity( &c[i] ); + /* + * NOTE: it is possible that the connection was closed + * and that the stream is now inactive. + * connection_read() must valid the stream is still + * active. + */ + + if ( connection_read( rd ) < 0 ) { + slapd_close( rd ); } } + ldap_pvt_thread_yield(); + } + + if( slapd_shutdown > 0 ) { + Debug( LDAP_DEBUG_TRACE, + "daemon: shutdown requested and initiated.\n", + 0, 0, 0 ); + + } else if ( slapd_shutdown < 0 ) { + Debug( LDAP_DEBUG_TRACE, + "daemon: abnormal condition, shutdown initiated.\n", + 0, 0, 0 ); + } else { + Debug( LDAP_DEBUG_TRACE, + "daemon: no active streams, shutdown initiated.\n", + 0, 0, 0 ); + } - pthread_yield(); + if( tcps >= 0 ) { + slapd_close( tcps ); } - close( tcps ); - pthread_mutex_lock( &active_threads_mutex ); + ldap_pvt_thread_mutex_lock( &active_threads_mutex ); Debug( LDAP_DEBUG_ANY, - "slapd shutting down - waiting for %d threads to terminate\n", + "slapd shutdown: waiting for %d threads to terminate\n", active_threads, 0, 0 ); while ( active_threads > 0 ) { - pthread_mutex_unlock( &active_threads_mutex ); - pthread_yield(); - pthread_mutex_lock( &active_threads_mutex ); + ldap_pvt_thread_cond_wait(&active_threads_cond, &active_threads_mutex); } - pthread_mutex_unlock( &active_threads_mutex ); - - /* let backends do whatever cleanup they need to do */ - Debug( LDAP_DEBUG_TRACE, - "slapd shutting down - waiting for backends to close down\n", 0, 0, - 0 ); - be_close(); - Debug( LDAP_DEBUG_ANY, "slapd stopping\n", 0, 0, 0 ); + ldap_pvt_thread_mutex_unlock( &active_threads_mutex ); + + return NULL; } -static void -set_shutdown() + +int slapd_daemon( struct slapd_args *args ) { - Debug( LDAP_DEBUG_ANY, "slapd got shutdown signal\n", 0, 0, 0 ); - slapd_shutdown = 1; - pthread_kill( listener_tid, SIGUSR1 ); - (void) SIGNAL( SIGUSR2, (void *) set_shutdown ); - (void) SIGNAL( SIGTERM, (void *) set_shutdown ); - (void) SIGNAL( SIGINT, (void *) set_shutdown ); - (void) SIGNAL( SIGHUP, (void *) set_shutdown ); + int rc; + + if ( !daemon_initialized ) sockinit(); + + connections_init(); + +#define SLAPD_LISTENER_THREAD 1 +#if defined( SLAPD_LISTENER_THREAD ) || !defined(HAVE_PTHREADS) + + /* listener as a separate THREAD */ + rc = ldap_pvt_thread_create( &listener_tid, + 0, slapd_daemon_task, args ); + + if ( rc != 0 ) { + Debug( LDAP_DEBUG_ANY, + "listener ldap_pvt_thread_create failed (%d)\n", rc, 0, 0 ); + goto destory; + } + + /* wait for the listener thread to complete */ + ldap_pvt_thread_join( listener_tid, (void *) NULL ); +#else + /* expermimental code */ + listener_tid = pthread_self(); + slapd_daemon_task( args ); +#endif + + rc = 0; + +destory: + connections_destroy(); + +#ifdef HAVE_WINSOCK + WSACleanup( ); +#endif + + return rc; +} + +#ifdef HAVE_WINSOCK2 +void sockinit() +{ + WORD wVersionRequested; + WSADATA wsaData; + int err; + + wVersionRequested = MAKEWORD( 2, 0 ); + + err = WSAStartup( wVersionRequested, &wsaData ); + if ( err != 0 ) { + /* Tell the user that we couldn't find a usable */ + /* WinSock DLL. */ + return; + } + + /* Confirm that the WinSock DLL supports 2.0.*/ + /* Note that if the DLL supports versions greater */ + /* than 2.0 in addition to 2.0, it will still return */ + /* 2.0 in wVersion since that is the version we */ + /* requested. */ + + if ( LOBYTE( wsaData.wVersion ) != 2 || + HIBYTE( wsaData.wVersion ) != 0 ) + { + /* Tell the user that we couldn't find a usable */ + /* WinSock DLL. */ + WSACleanup( ); + return; + } + daemon_initialized = 1; +} /* The WinSock DLL is acceptable. Proceed. */ + +void hit_socket() +{ + ber_socket_t s; + int on = 1; + extern struct sockaddr_in bind_addr; + + /* throw something at the socket to terminate the select() in the daemon thread. */ + if (( s = socket( AF_INET, SOCK_STREAM, 0 )) == AC_SOCKET_INVALID ) + Debug( LDAP_DEBUG_ANY, + "slap_set_shutdown: socket failed\n\tWSAGetLastError=%d (%s)\n", + WSAGetLastError(), WSAGetLastErrorString(), 0 ); + + if ( ioctlsocket( s, FIONBIO, &on ) == -1 ) + Debug( LDAP_DEBUG_ANY, + "slap_set_shutdown:FIONBIO ioctl on %d faled\n\tWSAGetLastError=%d (%s)\n", + s, WSAGetLastError(), WSAGetLastError() ); + + bind_addr.sin_addr.s_addr = htonl( INADDR_LOOPBACK ); + + if ( connect( s, (struct sockaddr *)&bind_addr, sizeof( struct sockaddr_in )) == SOCKET_ERROR ) { + Debug( LDAP_DEBUG_ANY, + "hit_socket: error on connect: %d\n", + WSAGetLastError(), 0, 0 ); + /* we can probably expect some error to occur here, mostly WSAEWOULDBLOCK */ + } + + tcp_close(s); } -static void -do_nothing() +#elif HAVE_WINSOCK +void sockinit() +{ WSADATA wsaData; + if ( WSAStartup( 0x0101, &wsaData ) != 0 ) { + return( NULL ); + } + daemon_initialized = 1; +} +#else +void sockinit() +{ + daemon_initialized = 1; +} +#endif + +void +slap_set_shutdown( int sig ) +{ + slapd_shutdown = sig; +#ifndef HAVE_WINSOCK + if(slapd_listener) { + ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 ); + } +#else + Debug( LDAP_DEBUG_TRACE, "Shutdown %d ordered", sig, 0, 0 ); + /* trying to "hit" the socket seems to always get a */ + /* EWOULDBLOCK error, so just close the listen socket to */ + /* break out of the select since we're shutting down anyway */ + tcp_close( tcps ); +#endif + /* reinstall self */ + (void) SIGNAL( sig, slap_set_shutdown ); +} + +void +slap_do_nothing( int sig ) { - Debug( LDAP_DEBUG_TRACE, "slapd got SIGUSR1\n", 0, 0, 0 ); - (void) SIGNAL( SIGUSR1, (void *) do_nothing ); + /* reinstall self */ + (void) SIGNAL( sig, slap_do_nothing ); }