11 #include <ac/unistd.h>
13 #include "ldapconfig.h"
19 int allow_severity = LOG_INFO;
20 int deny_severity = LOG_NOTICE;
21 #endif /* TCP Wrappers */
27 /* forward reference */
30 char *WSAGetLastErrorString();
32 #define WAKE_LISTENER \
34 ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );\
38 #define WAKE_LISTENER \
40 ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );\
44 static int daemon_initialized = 0;
45 static ldap_pvt_thread_t listener_tid;
46 static volatile sig_atomic_t slapd_shutdown = 0;
47 static volatile sig_atomic_t slapd_listener = 0;
51 ldap_pvt_thread_mutex_t sd_mutex;
56 /* In winsock, accept() returns values higher than dtblsize
57 so don't bother with this optimization */
67 * Add a descriptor to daemon control
69 static void slapd_add(int s) {
70 ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
72 assert( !FD_ISSET( s, &slap_daemon.sd_actives ));
73 assert( !FD_ISSET( s, &slap_daemon.sd_readers ));
74 assert( !FD_ISSET( s, &slap_daemon.sd_writers ));
77 if (s >= slap_daemon.sd_nfds) {
78 slap_daemon.sd_nfds = s + 1;
82 FD_SET( (unsigned) s, &slap_daemon.sd_actives );
83 FD_SET( (unsigned) s, &slap_daemon.sd_readers );
85 Debug( LDAP_DEBUG_CONNS, "daemon: added %d%s%s\n", s,
86 FD_ISSET(s, &slap_daemon.sd_readers) ? "r" : "",
87 FD_ISSET(s, &slap_daemon.sd_writers) ? "w" : "" );
89 ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
93 * Remove the descriptor from daemon control
95 void slapd_remove(int s) {
96 ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
98 assert( FD_ISSET( s, &slap_daemon.sd_actives ));
100 Debug( LDAP_DEBUG_CONNS, "daemon: removing %d%s%s\n", s,
101 FD_ISSET(s, &slap_daemon.sd_readers) ? "r" : "",
102 FD_ISSET(s, &slap_daemon.sd_writers) ? "w" : "" );
104 FD_CLR( (unsigned) s, &slap_daemon.sd_actives );
105 FD_CLR( (unsigned) s, &slap_daemon.sd_readers );
106 FD_CLR( (unsigned) s, &slap_daemon.sd_writers );
108 ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
111 void slapd_clr_write(int s, int wake) {
112 ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
114 assert( FD_ISSET( (unsigned) s, &slap_daemon.sd_actives) );
115 FD_CLR( (unsigned) s, &slap_daemon.sd_writers );
117 ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
122 void slapd_set_write(int s, int wake) {
123 ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
125 assert( FD_ISSET( s, &slap_daemon.sd_actives) );
126 FD_SET( (unsigned) s, &slap_daemon.sd_writers );
128 ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
133 void slapd_clr_read(int s, int wake) {
134 ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
136 assert( FD_ISSET( s, &slap_daemon.sd_actives) );
137 FD_CLR( (unsigned) s, &slap_daemon.sd_readers );
139 ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
144 void slapd_set_read(int s, int wake) {
145 ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
147 assert( FD_ISSET( s, &slap_daemon.sd_actives) );
148 FD_SET( (unsigned) s, &slap_daemon.sd_readers );
150 ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
155 static void slapd_close(int s) {
158 Debug( LDAP_DEBUG_CONNS, "daemon: closing %d\n", s, 0, 0 );
163 set_socket( struct sockaddr_in *addr )
166 if ( !daemon_initialized ) sockinit();
169 dtblsize = sysconf( _SC_OPEN_MAX );
170 #elif HAVE_GETDTABLESIZE
171 dtblsize = getdtablesize();
173 dtblsize = FD_SETSIZE;
177 if(dtblsize > FD_SETSIZE) {
178 dtblsize = FD_SETSIZE;
180 #endif /* !FD_SETSIZE */
185 if ( (tcps = socket( AF_INET, SOCK_STREAM, 0 )) == -1 ) {
188 Debug( LDAP_DEBUG_ANY,
189 "daemon: socket() failed errno %d (%s)\n", err,
190 err > -1 && err < sys_nerr ? sys_errlist[err] :
194 Debug( LDAP_DEBUG_ANY,
195 "daemon: socket() failed errno %d (%s)\n", WSAGetLastError(),
196 WSAGetLastErrorString(), 0 );
202 if ( tcps >= dtblsize ) {
203 Debug( LDAP_DEBUG_ANY,
204 "daemon: listener descriptor %d is too great\n",
211 if ( setsockopt( tcps, SOL_SOCKET, SO_REUSEADDR,
212 (char *) &tmp, sizeof(tmp) ) == -1 )
215 Debug( LDAP_DEBUG_ANY,
216 "slapd(%d): setsockopt() failed errno %d (%s)\n",
218 err > -1 && err < sys_nerr
219 ? sys_errlist[err] : "unknown" );
222 if ( bind( tcps, (struct sockaddr *) addr, sizeof(*addr) ) == -1 ) {
224 Debug( LDAP_DEBUG_ANY, "daemon: bind(%d) failed errno %d (%s)\n",
226 err > -1 && err < sys_nerr
227 ? sys_errlist[err] : "unknown" );
240 int inetd = ((int *)ptr) [0];
241 int tcps = ((int *)ptr) [1];
244 if ( !daemon_initialized ) sockinit();
248 ldap_pvt_thread_mutex_init( &slap_daemon.sd_mutex );
249 FD_ZERO( &slap_daemon.sd_readers );
250 FD_ZERO( &slap_daemon.sd_writers );
253 if ( listen( tcps, 5 ) == -1 ) {
255 Debug( LDAP_DEBUG_ANY,
256 "daemon: listen(%d, 5) failed errno %d (%s)\n",
258 err > -1 && err < sys_nerr
259 ? sys_errlist[err] : "unknown" );
266 if( connection_init( 0, NULL, NULL ) ) {
267 Debug( LDAP_DEBUG_ANY,
268 "connection_init(%d) failed.\n",
277 while ( !slapd_shutdown ) {
284 struct sockaddr_in from;
285 #if defined(SLAPD_RLOOKUPS) || defined(HAVE_TCPD)
294 FD_ZERO( &writefds );
300 ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
302 #ifdef FD_SET_MANUAL_COPY
303 for( s = 0; s < nfds; s++ ) {
304 if(FD_ISSET( &slap_sd_writers, s )) {
305 FD_SET( &writefds, s );
307 if(FD_ISSET( &slap_sd_writers, s )) {
308 FD_SET( &writefds, s );
312 memcpy( &readfds, &slap_daemon.sd_readers, sizeof(fd_set) );
313 memcpy( &writefds, &slap_daemon.sd_writers, sizeof(fd_set) );
316 FD_SET( (unsigned) tcps, &readfds );
319 nfds = slap_daemon.sd_nfds;
324 ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
326 ldap_pvt_thread_mutex_lock( &active_threads_mutex );
327 #if defined( HAVE_YIELDING_SELECT ) || defined( NO_THREADS )
330 tvp = active_threads ? &zero : NULL;
333 Debug( LDAP_DEBUG_CONNS,
334 "daemon: select: tcps=%d active_threads=%d tvp=%s\n",
335 tcps, active_threads,
336 tvp == NULL ? "NULL" : "zero" );
339 ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
341 switch(ns = select( nfds, &readfds, &writefds, 0, tvp )) {
342 case -1: { /* failure - try again */
345 Debug( LDAP_DEBUG_CONNS,
346 "daemon: select failed (%d): %s\n",
348 err >= 0 && err < sys_nerr
349 ? sys_errlist[err] : "unknown",
357 case 0: /* timeout - let threads run */
358 Debug( LDAP_DEBUG_CONNS, "daemon: select timeout - yielding\n",
360 ldap_pvt_thread_yield();
363 default: /* something happened - deal with it */
364 Debug( LDAP_DEBUG_CONNS, "daemon: activity on %d descriptors\n",
369 if ( FD_ISSET( tcps, &readfds ) ) {
371 int len = sizeof(from);
374 if ( (s = accept( tcps,
375 (struct sockaddr *) &from, &len )) == -1 )
378 Debug( LDAP_DEBUG_ANY,
379 "daemon: accept(%d) failed errno %d (%s)\n", err,
380 tcps, err >= 0 && err < sys_nerr ?
381 sys_errlist[err] : "unknown");
385 assert( !FD_ISSET( 0, &slap_daemon.sd_actives) );
386 assert( !FD_ISSET( 0, &slap_daemon.sd_readers) );
387 assert( !FD_ISSET( 0, &slap_daemon.sd_writers) );
390 /* make sure descriptor number isn't too great */
391 if ( s >= dtblsize ) {
392 Debug( LDAP_DEBUG_ANY,
393 "daemon: %d beyond descriptor table size %d\n",
400 Debug( LDAP_DEBUG_CONNS, "daemon: new connection on %d\n",
404 if ( getpeername( s, (struct sockaddr *) &from, &len ) == 0 ) {
405 client_addr = inet_ntoa( from.sin_addr );
407 #if defined(SLAPD_RLOOKUPS) || defined(HAVE_TCPD)
408 hp = gethostbyaddr( (char *)
409 &(from.sin_addr.s_addr),
410 sizeof(from.sin_addr.s_addr), AF_INET );
414 client_name = hp->h_name;
416 /* normalize the domain */
417 for ( p = client_name; *p; p++ ) {
418 *p = TOLOWER( (unsigned char) *p );
434 if(!hosts_ctl("slapd",
435 client_name != NULL ? client_name : STRING_UNKNOWN,
436 client_addr != NULL ? client_addr : STRING_UNKNOWN,
440 Statslog( LDAP_DEBUG_ANY,
441 "fd=%d connection from %s (%s) denied.\n",
443 client_name == NULL ? "unknown" : client_name,
444 client_addr == NULL ? "unknown" : client_addr,
450 #endif /* HAVE_TCPD */
452 if( (id = connection_init(s, client_name, client_addr)) < 0 ) {
453 Debug( LDAP_DEBUG_ANY,
454 "daemon: connection_init(%d, %s, %s) failed.\n",
456 client_name == NULL ? "unknown" : client_name,
457 client_addr == NULL ? "unknown" : client_addr);
462 Statslog( LDAP_DEBUG_STATS,
463 "daemon: conn=%d fd=%d connection from %s (%s) accepted.\n",
465 client_name == NULL ? "unknown" : client_name,
466 client_addr == NULL ? "unknown" : client_addr,
474 Debug( LDAP_DEBUG_CONNS, "daemon: activity on:", 0, 0, 0 );
476 for ( i = 0; i < readfds.fd_count; i++ )
478 Debug( LDAP_DEBUG_CONNS, " %d%s", readfds.fd_array[i], "r" );
480 for ( i = 0; i < writefds.fd_count; i++ )
482 Debug( LDAP_DEBUG_CONNS, " %d%s", writefds.fd_array[i], "w" );
485 for ( i = 0; i < nfds; i++ ) {
488 r = FD_ISSET( i, &readfds );
489 w = FD_ISSET( i, &writefds );
490 if ( i != tcps && (r || w) ) {
491 Debug( LDAP_DEBUG_CONNS, " %d%s%s", i,
492 r ? "r" : "", w ? "w" : "" );
496 Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 );
499 /* loop through the writers */
501 for ( i = 0; i < writefds.fd_count; i++ ) {
502 int wd = writefds.fd_array[i];
508 Debug( LDAP_DEBUG_CONNS,
509 "daemon: signalling write waiter on %d\n",
512 assert( FD_ISSET( wd, &slap_daemon.sd_actives) );
514 slapd_clr_write( wd, 0 );
515 if ( connection_write( wd ) < 0 ) {
516 FD_CLR( (unsigned) wd, &readfds );
521 for ( i = 0; i < nfds; i++ ) {
525 if ( FD_ISSET( i, &writefds ) ) {
526 Debug( LDAP_DEBUG_CONNS,
527 "daemon: signaling write waiter on %d\n", i, 0, 0 );
529 assert( FD_ISSET( i, &slap_daemon.sd_actives) );
531 /* clear the write flag */
532 slapd_clr_write( i, 0 );
534 if( connection_write( i ) < 0 ) {
535 FD_CLR( i, &readfds );
543 for ( i = 0; i < readfds.fd_count; i++ ) {
544 int rd = readfds.fd_array[i];
548 Debug ( LDAP_DEBUG_CONNS,
549 "daemon: read activity on %d\n", rd, 0, 0 );
550 assert( FD_ISSET( rd, &slap_daemon.sd_actives) );
552 if ( connection_read( rd ) < 0 ) {
557 for ( i = 0; i < nfds; i++ ) {
562 if ( FD_ISSET( i, &readfds ) ) {
563 Debug( LDAP_DEBUG_CONNS,
564 "daemon: read activity on %d\n", i, 0, 0 );
566 assert( FD_ISSET( i, &slap_daemon.sd_actives) );
568 if( connection_read( i ) < 0) {
574 ldap_pvt_thread_yield();
577 if( slapd_shutdown > 0 ) {
578 Debug( LDAP_DEBUG_TRACE,
579 "daemon: shutdown requested (%d) and initiated.\n",
580 (int) slapd_shutdown, 0, 0 );
582 } else if ( slapd_shutdown < 0 ) {
583 Debug( LDAP_DEBUG_TRACE,
584 "daemon: abnormal condition (%d), shutdown initiated.\n",
585 (int) slapd_shutdown, 0, 0 );
587 Debug( LDAP_DEBUG_TRACE,
588 "daemon: no active streams, shutdown initiated.\n",
596 /* we only implement "quick" shutdown */
597 connections_shutdown();
599 ldap_pvt_thread_mutex_lock( &active_threads_mutex );
600 Debug( LDAP_DEBUG_ANY,
601 "slapd shutdown: waiting for %d threads to terminate\n",
602 active_threads, 0, 0 );
603 while ( active_threads > 0 ) {
604 ldap_pvt_thread_cond_wait(&active_threads_cond, &active_threads_mutex);
606 ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
612 int slapd_daemon( int inetd, int tcps )
615 int *args = ch_malloc( sizeof( int[2] ) );
619 if ( !daemon_initialized ) sockinit();
623 #define SLAPD_LISTENER_THREAD 1
624 #if SLAPD_LISTENER_THREAD
625 /* listener as a separate THREAD */
626 rc = ldap_pvt_thread_create( &listener_tid,
627 0, slapd_daemon_task, args );
630 Debug( LDAP_DEBUG_ANY,
631 "listener ldap_pvt_thread_create failed (%d)\n", rc, 0, 0 );
635 /* wait for the listener thread to complete */
636 ldap_pvt_thread_join( listener_tid, (void *) NULL );
638 /* expermimental code */
639 listener_tid = pthread_self();
640 slapd_daemon_task( args );
646 connections_destroy();
658 WORD wVersionRequested;
662 wVersionRequested = MAKEWORD( 2, 0 );
664 err = WSAStartup( wVersionRequested, &wsaData );
666 /* Tell the user that we couldn't find a usable */
671 /* Confirm that the WinSock DLL supports 2.0.*/
672 /* Note that if the DLL supports versions greater */
673 /* than 2.0 in addition to 2.0, it will still return */
674 /* 2.0 in wVersion since that is the version we */
677 if ( LOBYTE( wsaData.wVersion ) != 2 ||
678 HIBYTE( wsaData.wVersion ) != 0 )
680 /* Tell the user that we couldn't find a usable */
685 daemon_initialized = 1;
686 } /* The WinSock DLL is acceptable. Proceed. */
688 void hit_socket( void )
691 extern struct sockaddr_in bind_addr;
693 /* throw something at the socket to terminate the select() in the daemon thread. */
694 if (( s = socket( AF_INET, SOCK_STREAM, 0 )) == INVALID_SOCKET )
695 Debug( LDAP_DEBUG_TRACE, "slap_set_shutdown: socket failed\n\tWSAGetLastError=%d (%s)\n", WSAGetLastError(), WSAGetLastErrorString(), 0 );
696 if ( ioctlsocket( s, FIONBIO, &on ) == -1 )
697 Debug( LDAP_DEBUG_TRACE, "slap_set_shutdown:FIONBIO ioctl on %d faled\n\tWSAGetLastError=%d (%s)\n", s, WSAGetLastError(), WSAGetLastError() );
699 bind_addr.sin_addr.s_addr = htonl( INADDR_LOOPBACK );
700 if ( connect( s, (struct sockaddr *)&bind_addr, sizeof( struct sockaddr_in )) == SOCKET_ERROR ) {
701 /* we can probably expect some error to occur here, mostly WSAEWOULDBLOCK */
707 if ( WSAStartup( 0x0101, &wsaData ) != 0 ) {
710 daemon_initialized = 1;
715 daemon_initialized = 1;
721 slap_set_shutdown( int sig )
723 slapd_shutdown = sig;
726 ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );
732 (void) SIGNAL( sig, slap_set_shutdown );
736 slap_do_nothing( int sig )
739 (void) SIGNAL( sig, slap_do_nothing );