]> git.sur5r.net Git - openldap/blob - servers/slapd/daemon.c
Bind and listen on TLS port too
[openldap] / servers / slapd / daemon.c
1 #include "portable.h"
2
3 #include <stdio.h>
4
5 #include <ac/ctype.h>
6 #include <ac/errno.h>
7 #include <ac/signal.h>
8 #include <ac/socket.h>
9 #include <ac/string.h>
10 #include <ac/time.h>
11 #include <ac/unistd.h>
12
13 #include "ldap_defaults.h"
14 #include "slap.h"
15
16 #ifdef HAVE_TCPD
17 #include <tcpd.h>
18
19 int allow_severity = LOG_INFO;
20 int deny_severity = LOG_NOTICE;
21 #endif /* TCP Wrappers */
22
23 /* globals */
24 ber_socket_t dtblsize;
25 #ifdef HAVE_TLS
26 #define N_LISTENERS 2
27 #else
28 #define N_LISTENERS 1
29 #endif
30 struct listener_rec {
31         ber_socket_t            tcps;
32         struct sockaddr_in      *addr;
33         int                     use_tls;
34 } listeners[N_LISTENERS];
35
36 #ifdef HAVE_WINSOCK2
37 /* in nt_main.c */
38 extern ldap_pvt_thread_cond_t                   started_event;
39
40 /* forward reference */
41 void hit_socket();
42 /* In wsa_err.c */
43 char *WSAGetLastErrorString();
44 static ldap_pvt_thread_t hit_tid;
45
46 #define WAKE_LISTENER(w) \
47 do {\
48     if( w ) {\
49         ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );\
50         hit_socket(); \
51     }\
52 } while(0)
53 #else
54 #define WAKE_LISTENER(w) \
55 do {\
56     if( w ) {\
57         ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );\
58     }\
59 } while(0)
60 #endif
61
62 #ifndef HAVE_WINSOCK
63 static 
64 #endif
65 volatile sig_atomic_t slapd_shutdown = 0;
66
67 static int daemon_initialized = 0;
68 static ldap_pvt_thread_t        listener_tid;
69 static volatile sig_atomic_t slapd_listener = 0;
70 void sockinit();
71
72 struct slap_daemon {
73         ldap_pvt_thread_mutex_t sd_mutex;
74
75         int sd_nactives;
76
77 #ifndef HAVE_WINSOCK
78         /* In winsock, accept() returns values higher than dtblsize
79                 so don't bother with this optimization */
80         int sd_nfds;
81 #endif
82
83         fd_set sd_actives;
84         fd_set sd_readers;
85         fd_set sd_writers;
86 } slap_daemon; 
87
88 /*
89  * Add a descriptor to daemon control
90  */
91 static void slapd_add(ber_socket_t s) {
92         ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
93
94         assert( !FD_ISSET( s, &slap_daemon.sd_actives ));
95         assert( !FD_ISSET( s, &slap_daemon.sd_readers ));
96         assert( !FD_ISSET( s, &slap_daemon.sd_writers ));
97
98 #ifndef HAVE_WINSOCK
99         if (s >= slap_daemon.sd_nfds) {
100                 slap_daemon.sd_nfds = s + 1;
101         }
102 #endif
103
104         FD_SET( s, &slap_daemon.sd_actives );
105         FD_SET( s, &slap_daemon.sd_readers );
106
107         Debug( LDAP_DEBUG_CONNS, "daemon: added %ld%s%s\n",
108                 (long) s,
109             FD_ISSET(s, &slap_daemon.sd_readers) ? "r" : "",
110                 FD_ISSET(s, &slap_daemon.sd_writers) ? "w" : "" );
111
112         ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
113 }
114
115 /*
116  * Remove the descriptor from daemon control
117  */
118 void slapd_remove(ber_socket_t s, int wake) {
119         ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
120         WAKE_LISTENER(wake);
121
122         Debug( LDAP_DEBUG_CONNS, "daemon: removing %ld%s%s\n",
123                 (long) s,
124             FD_ISSET(s, &slap_daemon.sd_readers) ? "r" : "",
125                 FD_ISSET(s, &slap_daemon.sd_writers) ? "w" : "" );
126
127         FD_CLR( s, &slap_daemon.sd_actives );
128         FD_CLR( s, &slap_daemon.sd_readers );
129         FD_CLR( s, &slap_daemon.sd_writers );
130
131         ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
132 }
133
134 void slapd_clr_write(ber_socket_t s, int wake) {
135         ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
136         WAKE_LISTENER(wake);
137
138         assert( FD_ISSET( s, &slap_daemon.sd_actives) );
139         FD_CLR( s, &slap_daemon.sd_writers );
140
141         ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
142
143         if( wake ) {
144                 ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );
145         }
146 }
147
148 void slapd_set_write(ber_socket_t s, int wake) {
149         ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
150     WAKE_LISTENER(wake);
151
152         assert( FD_ISSET( s, &slap_daemon.sd_actives) );
153         FD_SET( (unsigned) s, &slap_daemon.sd_writers );
154
155         ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
156
157         if( wake ) {
158                 ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );
159         }
160 }
161
162 void slapd_clr_read(ber_socket_t s, int wake) {
163         ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
164     WAKE_LISTENER(wake);
165
166         assert( FD_ISSET( s, &slap_daemon.sd_actives) );
167         FD_CLR( s, &slap_daemon.sd_readers );
168
169         ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
170
171         if( wake ) {
172                 ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );
173         }
174 }
175
176 void slapd_set_read(ber_socket_t s, int wake) {
177         ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
178     WAKE_LISTENER(wake);
179
180         assert( FD_ISSET( s, &slap_daemon.sd_actives) );
181         FD_SET( s, &slap_daemon.sd_readers );
182
183         ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
184
185         if( wake ) {
186                 ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );
187         }
188 }
189
190 static void slapd_close(ber_socket_t s) {
191         Debug( LDAP_DEBUG_CONNS, "daemon: closing %ld\n",
192                 (long) s, 0, 0 );
193         tcp_close(s);
194 }
195
196
197
198 int
199 set_socket( struct sockaddr_in *addr )
200 {
201         ber_socket_t    tcps = AC_SOCKET_INVALID;
202
203     if ( !daemon_initialized ) sockinit();
204
205 #ifdef HAVE_SYSCONF
206         dtblsize = sysconf( _SC_OPEN_MAX );
207 #elif HAVE_GETDTABLESIZE
208         dtblsize = getdtablesize();
209 #else
210         dtblsize = FD_SETSIZE;
211 #endif
212
213 #ifdef FD_SETSIZE
214         if(dtblsize > FD_SETSIZE) {
215                 dtblsize = FD_SETSIZE;
216         }
217 #endif  /* !FD_SETSIZE */
218
219         if( addr != NULL ) {
220                 int     tmp;
221
222                 if ( (tcps = socket( AF_INET, SOCK_STREAM, 0 )) == AC_SOCKET_INVALID ) {
223 #ifndef HAVE_WINSOCK
224                         int err = errno;
225                         Debug( LDAP_DEBUG_ANY,
226                                 "daemon: socket() failed errno %d (%s)\n", err,
227                         err > -1 && err < sys_nerr ? sys_errlist[err] :
228                         "unknown", 0 );
229 #else
230                         Debug( LDAP_DEBUG_ANY, 
231                                 "daemon: socket() failed errno %d (%s)\n",
232                                 WSAGetLastError(),
233                         WSAGetLastErrorString(), 0 );
234 #endif
235                         return( -1 );
236                 }
237
238 #ifndef HAVE_WINSOCK
239                 if ( tcps >= dtblsize ) {
240                         Debug( LDAP_DEBUG_ANY,
241                                 "daemon: listener descriptor %ld is too great %ld\n",
242                                 (long) tcps, (long) dtblsize, 0 );
243                         return( -1);
244                 }
245 #endif
246
247 #ifdef SO_REUSEADDR
248                 tmp = 1;
249                 if ( setsockopt( tcps, SOL_SOCKET, SO_REUSEADDR,
250                         (char *) &tmp, sizeof(tmp) ) == -1 )
251                 {
252                         int err = errno;
253                         Debug( LDAP_DEBUG_ANY,
254                                "slapd(%ld): setsockopt() failed errno %d (%s)\n",
255                         (long) tcps, err,
256                                 err > -1 && err < sys_nerr
257                                         ? sys_errlist[err] : "unknown" );
258                 }
259 #endif
260 #ifdef SO_KEEPALIVE
261                 tmp = 1;
262                 if ( setsockopt( tcps, SOL_SOCKET, SO_KEEPALIVE,
263                         (char *) &tmp, sizeof(tmp) ) == -1 )
264                 {
265                         int err = errno;
266                         Debug( LDAP_DEBUG_ANY,
267                                 "slapd(%ld): setsockopt(KEEPALIVE) failed errno %d (%s)\n",
268                         (long) tcps, err,
269                                 err > -1 && err < sys_nerr
270                                         ? sys_errlist[err] : "unknown" );
271                 }
272 #endif
273
274
275                 if ( bind( tcps, (struct sockaddr *) addr, sizeof(*addr) ) == -1 ) {
276                         int err = errno;
277                         Debug( LDAP_DEBUG_ANY, "daemon: bind(%ld) failed errno %d (%s)\n",
278                         (long) tcps, err,
279                                 err > -1 && err < sys_nerr
280                                         ? sys_errlist[err] : "unknown" );
281                         return -1;
282                 }
283         }
284
285         return tcps;
286 }
287
288 static void *
289 slapd_daemon_task(
290         void *ptr
291 )
292 {
293         int inetd;
294         struct slapd_args *args = (struct slapd_args *) ptr;
295         int l;
296
297         listeners[0].tcps = args->tcps;
298         listeners[0].addr = args->addr;
299         listeners[0].use_tls = 0;
300 #ifdef HAVE_TLS
301         listeners[1].tcps = args->tls_tcps;
302         listeners[1].addr = args->tls_addr;
303         listeners[1].use_tls = 1;
304 #endif
305
306         inetd = ( listeners[0].addr == NULL);
307     if ( !daemon_initialized ) sockinit();
308
309         slapd_listener=1;
310
311         ldap_pvt_thread_mutex_init( &slap_daemon.sd_mutex );
312         FD_ZERO( &slap_daemon.sd_readers );
313         FD_ZERO( &slap_daemon.sd_writers );
314
315         if( !inetd ) {
316                 for ( l = 0; l < N_LISTENERS; l++ ) {
317                         if ( listen( listeners[l].tcps, 5 ) == -1 ) {
318                                 int err = errno;
319                                 Debug( LDAP_DEBUG_ANY,
320                                 "daemon: listen(%ld, 5) failed errno %d (%s)\n",
321                                        (long) listeners[l].tcps, err,
322                                        err > -1 && err < sys_nerr
323                                        ? sys_errlist[err] : "unknown" );
324                                 return( (void*)-1 );
325                         }
326
327                         slapd_add( listeners[l].tcps );
328                 }
329
330         } else {
331                 if( connection_init( (ber_socket_t) 0, NULL, NULL ) ) {
332                         Debug( LDAP_DEBUG_ANY,
333                                 "connection_init(%d) failed.\n",
334                                 0, 0, 0 );
335                         return( (void*)-1 );
336                 }
337
338                 slapd_add( 0 );
339         }
340
341 #ifdef HAVE_WINSOCK
342         if ( started_event != NULL )
343                 ldap_pvt_thread_cond_signal( &started_event );
344 #endif
345         /* initialization complete. Here comes the loop. */
346
347         while ( !slapd_shutdown ) {
348                 ber_socket_t i;
349                 int ns;
350                 int at;
351                 ber_socket_t nfds;
352 #define SLAPD_EBADF_LIMIT 10
353                 int ebadf = 0;
354
355 #define SLAPD_IDLE_CHECK_LIMIT 4
356                 time_t  last_idle_check = slap_get_time();
357                 time_t  now;
358
359
360                 fd_set                  readfds;
361                 fd_set                  writefds;
362
363                 struct sockaddr_in      from;
364 #if defined(SLAPD_RLOOKUPS) || defined(HAVE_TCPD)
365         struct hostent          *hp;
366 #endif
367                 struct timeval          zero;
368                 struct timeval          *tvp;
369
370                 char    *client_name;
371                 char    *client_addr;
372
373                 if( global_idletimeout > 0 && difftime(
374                         last_idle_check+global_idletimeout/SLAPD_IDLE_CHECK_LIMIT,
375                         now ) < 0 )
376                 {
377                         connections_timeout_idle(now);
378                 }
379
380                 FD_ZERO( &writefds );
381                 FD_ZERO( &readfds );
382
383                 zero.tv_sec = 0;
384                 zero.tv_usec = 0;
385
386                 ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
387
388 #ifdef FD_SET_MANUAL_COPY
389                 for( s = 0; s < nfds; s++ ) {
390                         if(FD_ISSET( &slap_sd_writers, s )) {
391                                 FD_SET( &writefds, s );
392                         }
393                         if(FD_ISSET( &slap_sd_writers, s )) {
394                                 FD_SET( &writefds, s );
395                         }
396                 }
397 #else
398                 memcpy( &readfds, &slap_daemon.sd_readers, sizeof(fd_set) );
399                 memcpy( &writefds, &slap_daemon.sd_writers, sizeof(fd_set) );
400 #endif
401
402                 for ( l = 0; l < N_LISTENERS; l++ ) {
403                         FD_SET( (unsigned) listeners[l].tcps, &readfds );
404                 }
405
406 #ifndef HAVE_WINSOCK
407                 nfds = slap_daemon.sd_nfds;
408 #else
409                 nfds = dtblsize;
410 #endif
411
412                 ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
413
414                 ldap_pvt_thread_mutex_lock( &active_threads_mutex );
415                 at = active_threads;
416                 ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
417
418 #if defined( HAVE_YIELDING_SELECT ) || defined( NO_THREADS )
419                 tvp = NULL;
420 #else
421                 tvp = at ? &zero : NULL;
422 #endif
423
424                 for ( i = 0; i < N_LISTENERS; i++ ) {
425                         Debug( LDAP_DEBUG_CONNS,
426                         "daemon: select: tcps=%d active_threads=%d tvp=%s\n",
427                                listeners[i].tcps, at,
428                                tvp == NULL ? "NULL" : "zero" );
429                 }
430
431                 switch(ns = select( nfds, &readfds,
432 #ifdef HAVE_WINSOCK
433                         /* don't pass empty fd_set */
434                         ( writefds.fd_count > 0 ? &writefds : NULL ),
435 #else
436                         &writefds,
437 #endif
438                         NULL, tvp ))
439                 {
440                 case -1: {      /* failure - try again */
441 #ifdef HAVE_WINSOCK
442                                 int err = WSAGetLastError();
443 #else
444                                 int err = errno;
445 #endif
446
447                                 if( err == EBADF && ++ebadf < SLAPD_EBADF_LIMIT) {
448                                         continue;
449                                 }
450
451                                 if( err != EINTR ) {
452                                         Debug( LDAP_DEBUG_CONNS,
453                                                 "daemon: select failed (%d): %s\n",
454                                                 err,
455                                                 err >= 0 && err < sys_nerr
456                                                         ? sys_errlist[err] : "unknown",
457                                                 0 );
458
459
460                                 slapd_shutdown = -1;
461                                 }
462                         }
463                         continue;
464
465                 case 0:         /* timeout - let threads run */
466                         ebadf = 0;
467                         Debug( LDAP_DEBUG_CONNS, "daemon: select timeout - yielding\n",
468                             0, 0, 0 );
469                 ldap_pvt_thread_yield();
470                         continue;
471
472                 default:        /* something happened - deal with it */
473                         ebadf = 0;
474                         Debug( LDAP_DEBUG_CONNS, "daemon: activity on %d descriptors\n",
475                                 ns, 0, 0 );
476                         /* FALL THRU */
477                 }
478
479                 for ( l = 0; l < N_LISTENERS; l++ ) {
480                         ber_int_t s;
481                         int len = sizeof(from);
482                         long id;
483
484                         if ( !FD_ISSET( listeners[l].tcps, &readfds ) )
485                                 continue;
486
487                         if ( (s = accept( listeners[l].tcps,
488                                 (struct sockaddr *) &from, &len )) == AC_SOCKET_INVALID )
489                         {
490                                 int err = errno;
491                                 Debug( LDAP_DEBUG_ANY,
492                                     "daemon: accept(%ld) failed errno %d (%s)\n", err,
493                                     (long) listeners[l].tcps,
494                                     err >= 0 && err < sys_nerr ?
495                                     sys_errlist[err] : "unknown");
496                                 continue;
497                         }
498
499 #ifdef LDAP_DEBUG
500                         ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
501
502                         /* newly accepted stream should not be in any of the FD SETS */
503
504                         assert( !FD_ISSET( s, &slap_daemon.sd_actives) );
505                         assert( !FD_ISSET( s, &slap_daemon.sd_readers) );
506                         assert( !FD_ISSET( s, &slap_daemon.sd_writers) );
507
508                         ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
509 #endif
510
511 #ifndef HAVE_WINSOCK
512                         /* make sure descriptor number isn't too great */
513                         if ( s >= dtblsize ) {
514                                 Debug( LDAP_DEBUG_ANY,
515                                         "daemon: %ld beyond descriptor table size %ld\n",
516                                         (long) s, (long) dtblsize, 0 );
517                                 slapd_close(s);
518                                 continue;
519                         }
520 #endif
521                    
522                         Debug( LDAP_DEBUG_CONNS, "daemon: new connection on %ld\n",
523                                 (long) s, 0, 0 );
524
525                         len = sizeof(from);
526                         if ( getpeername( s, (struct sockaddr *) &from, &len ) == 0 ) {
527                                 client_addr = inet_ntoa( from.sin_addr );
528
529 #if defined(SLAPD_RLOOKUPS) || defined(HAVE_TCPD)
530                                 hp = gethostbyaddr( (char *)
531                                     &(from.sin_addr.s_addr),
532                                     sizeof(from.sin_addr.s_addr), AF_INET );
533
534                                 if(hp) {
535                                         char *p;
536                                         client_name = hp->h_name;
537
538                                         /* normalize the domain */
539                                         for ( p = client_name; *p; p++ ) {
540                                                 *p = TOLOWER( (unsigned char) *p );
541                                         }
542
543                                 } else {
544                                         client_name = NULL;
545                                 }
546 #else
547                                 client_name = NULL;
548 #endif
549
550                         } else {
551                                 client_name = NULL;;
552                                 client_addr = NULL;
553                         }
554
555 #ifdef HAVE_TCPD
556                         if(!hosts_ctl("slapd",
557                                 client_name != NULL ? client_name : STRING_UNKNOWN,
558                                 client_addr != NULL ? client_addr : STRING_UNKNOWN,
559                                 STRING_UNKNOWN))
560                         {
561                                 /* DENY ACCESS */
562                                 Statslog( LDAP_DEBUG_ANY,
563                                  "fd=%ld connection from %s (%s) denied.\n",
564                                         (long) s,
565                                         client_name == NULL ? "unknown" : client_name,
566                                         client_addr == NULL ? "unknown" : client_addr,
567                                   0, 0 );
568
569                                 slapd_close(s);
570                                 continue;
571                         }
572 #endif /* HAVE_TCPD */
573
574                         if( (id = connection_init(s, client_name, client_addr)) < 0 ) {
575                                 Debug( LDAP_DEBUG_ANY,
576                                         "daemon: connection_init(%ld, %s, %s) failed.\n",
577                                         (long) s,
578                                         client_name == NULL ? "unknown" : client_name,
579                                         client_addr == NULL ? "unknown" : client_addr);
580                                 slapd_close(s);
581                                 continue;
582                         }
583
584                         Statslog( LDAP_DEBUG_STATS,
585                                 "daemon: conn=%d fd=%ld connection from %s (%s) accepted.\n",
586                                 id, (long) s,
587                                 client_name == NULL ? "unknown" : client_name,
588                                 client_addr == NULL ? "unknown" : client_addr,
589                                 0 );
590
591                         slapd_add( s );
592                         continue;
593                 }
594
595 #ifdef LDAP_DEBUG
596                 Debug( LDAP_DEBUG_CONNS, "daemon: activity on:", 0, 0, 0 );
597 #ifdef HAVE_WINSOCK
598                 for ( i = 0; i < readfds.fd_count; i++ ) {
599                         Debug( LDAP_DEBUG_CONNS, " %d%s",
600                                 readfds.fd_array[i], "r", 0 );
601                 }
602                 for ( i = 0; i < writefds.fd_count; i++ ) {
603                         Debug( LDAP_DEBUG_CONNS, " %d%s",
604                                 writefds.fd_array[i], "w", 0 );
605                 }
606 #else
607                 for ( i = 0; i < nfds; i++ ) {
608                         int     a, r, w;
609                         int     is_listener = 0;
610
611                         for ( l = 0; l < N_LISTENERS; l++ ) {
612                                 if ( i == listeners[l].tcps ) {
613                                         is_listener = 1;
614                                         break;
615                                 }
616                         }
617                         if ( is_listener ) {
618                                 continue;
619                         }
620                         r = FD_ISSET( i, &readfds );
621                         w = FD_ISSET( i, &writefds );
622                         if ( r || w ) {
623                                 Debug( LDAP_DEBUG_CONNS, " %d%s%s", i,
624                                     r ? "r" : "", w ? "w" : "" );
625                         }
626                 }
627 #endif
628                 Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 );
629 #endif
630
631                 /* loop through the writers */
632 #ifdef HAVE_WINSOCK
633                 for ( i = 0; i < writefds.fd_count; i++ )
634 #else
635                 for ( i = 0; i < nfds; i++ )
636 #endif
637                 {
638                         ber_socket_t wd;
639                         int is_listener = 0;
640 #ifdef HAVE_WINSOCK
641                         wd = writefds.fd_array[i];
642 #else
643                         if( ! FD_ISSET( i, &writefds ) ) {
644                                 continue;
645                         }
646                         wd = i;
647 #endif
648
649                         for ( l = 0; l < N_LISTENERS; l++ ) {
650                                 if ( wd == listeners[l].tcps ) {
651                                         is_listener = 1;
652                                         break;
653                                 }
654                         }
655                         if ( is_listener ) {
656                                 continue;
657                         }
658                         Debug( LDAP_DEBUG_CONNS,
659                                 "daemon: write active on %d\n",
660                                 wd, 0, 0 );
661
662                         /*
663                          * NOTE: it is possible that the connection was closed
664                          * and that the stream is now inactive.
665                          * connection_write() must valid the stream is still
666                          * active.
667                          */
668
669                         if ( connection_write( wd ) < 0 ) {
670                                 FD_CLR( (unsigned) wd, &readfds );
671                                 slapd_close( wd );
672                         }
673                 }
674
675 #ifdef HAVE_WINSOCK
676                 for ( i = 0; i < readfds.fd_count; i++ )
677 #else
678                 for ( i = 0; i < nfds; i++ )
679 #endif
680                 {
681                         ber_socket_t rd;
682                         int is_listener = 0;
683
684 #ifdef HAVE_WINSOCK
685                         rd = readfds.fd_array[i];
686 #else
687                         if( ! FD_ISSET( i, &readfds ) ) {
688                                 continue;
689                         }
690                         rd = i;
691 #endif
692
693                         for ( l = 0; l < N_LISTENERS; l++ ) {
694                                 if ( rd == listeners[l].tcps ) {
695                                         is_listener = 1;
696                                         break;
697                                 }
698                         }
699                         if ( is_listener ) {
700                                 continue;
701                         }
702
703                         Debug ( LDAP_DEBUG_CONNS,
704                                 "daemon: read activity on %d\n", rd, 0, 0 );
705
706                         /*
707                          * NOTE: it is possible that the connection was closed
708                          * and that the stream is now inactive.
709                          * connection_read() must valid the stream is still
710                          * active.
711                          */
712
713                         if ( connection_read( rd ) < 0 ) {
714                                 slapd_close( rd );
715                         }
716                 }
717                 ldap_pvt_thread_yield();
718         }
719
720         if( slapd_shutdown > 0 ) {
721                 Debug( LDAP_DEBUG_TRACE,
722                         "daemon: shutdown requested and initiated.\n",
723                         0, 0, 0 );
724
725         } else if ( slapd_shutdown < 0 ) {
726                 Debug( LDAP_DEBUG_TRACE,
727                         "daemon: abnormal condition, shutdown initiated.\n",
728                         0, 0, 0 );
729         } else {
730                 Debug( LDAP_DEBUG_TRACE,
731                         "daemon: no active streams, shutdown initiated.\n",
732                         0, 0, 0 );
733         }
734
735         for ( l = 0; l < N_LISTENERS; l++ ) {
736                 if ( listeners[l].tcps >= 0 ) {
737                         slapd_close( listeners[l].tcps );
738                 }
739         }
740
741         ldap_pvt_thread_mutex_lock( &active_threads_mutex );
742         Debug( LDAP_DEBUG_ANY,
743             "slapd shutdown: waiting for %d threads to terminate\n",
744             active_threads, 0, 0 );
745         while ( active_threads > 0 ) {
746                 ldap_pvt_thread_cond_wait(&active_threads_cond, &active_threads_mutex);
747         }
748         ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
749
750         return NULL;
751 }
752
753
754 int slapd_daemon( struct slapd_args *args )
755 {
756         int rc;
757
758     if ( !daemon_initialized ) sockinit();
759
760         connections_init();
761
762 #define SLAPD_LISTENER_THREAD 1
763 #if defined( SLAPD_LISTENER_THREAD ) || !defined(HAVE_PTHREADS)
764
765         /* listener as a separate THREAD */
766         rc = ldap_pvt_thread_create( &listener_tid,
767                 0, slapd_daemon_task, args );
768
769         if ( rc != 0 ) {
770                 Debug( LDAP_DEBUG_ANY,
771                     "listener ldap_pvt_thread_create failed (%d)\n", rc, 0, 0 );
772                 goto destory;
773         }
774
775         /* wait for the listener thread to complete */
776         ldap_pvt_thread_join( listener_tid, (void *) NULL );
777 #else
778         /* expermimental code */
779         listener_tid = pthread_self();
780         slapd_daemon_task( args );
781 #endif
782
783         rc = 0;
784
785 destory:
786         connections_destroy();
787
788 #ifdef HAVE_WINSOCK
789     WSACleanup( );
790 #endif
791
792         return rc;
793 }
794
795 #ifdef HAVE_WINSOCK2
796 void sockinit()
797 {
798     WORD wVersionRequested;
799         WSADATA wsaData;
800         int err;
801  
802         wVersionRequested = MAKEWORD( 2, 0 );
803  
804         err = WSAStartup( wVersionRequested, &wsaData );
805         if ( err != 0 ) {
806                 /* Tell the user that we couldn't find a usable */
807                 /* WinSock DLL.                                  */
808                 return;
809         }
810  
811         /* Confirm that the WinSock DLL supports 2.0.*/
812         /* Note that if the DLL supports versions greater    */
813         /* than 2.0 in addition to 2.0, it will still return */
814         /* 2.0 in wVersion since that is the version we      */
815         /* requested.                                        */
816  
817         if ( LOBYTE( wsaData.wVersion ) != 2 ||
818                 HIBYTE( wsaData.wVersion ) != 0 )
819         {
820             /* Tell the user that we couldn't find a usable */
821             /* WinSock DLL.                                  */
822             WSACleanup( );
823             return; 
824         }
825     daemon_initialized = 1;
826 }       /* The WinSock DLL is acceptable. Proceed. */
827
828 void hit_socket()
829 {
830         ber_socket_t s;
831         int on = 1;
832         extern struct sockaddr_in       bind_addr;
833
834         /* throw something at the socket to terminate the select() in the daemon thread. */
835         if (( s = socket( AF_INET, SOCK_STREAM, 0 )) == AC_SOCKET_INVALID )
836                 Debug( LDAP_DEBUG_ANY,
837                         "slap_set_shutdown: socket failed\n\tWSAGetLastError=%d (%s)\n",
838                         WSAGetLastError(), WSAGetLastErrorString(), 0 );
839
840         if ( ioctlsocket( s, FIONBIO, &on ) == -1 ) 
841                 Debug( LDAP_DEBUG_ANY,
842                         "slap_set_shutdown:FIONBIO ioctl on %d faled\n\tWSAGetLastError=%d (%s)\n",
843                         s, WSAGetLastError(), WSAGetLastError() );
844         
845         bind_addr.sin_addr.s_addr = htonl( INADDR_LOOPBACK );
846
847         if ( connect( s, (struct sockaddr *)&bind_addr, sizeof( struct sockaddr_in )) == SOCKET_ERROR ) {
848                 Debug( LDAP_DEBUG_ANY,
849                         "hit_socket: error on connect: %d\n",
850                         WSAGetLastError(), 0, 0 );
851                 /* we can probably expect some error to occur here, mostly WSAEWOULDBLOCK */
852         }
853
854         tcp_close(s);
855 }
856
857 #elif HAVE_WINSOCK
858 void sockinit()
859 {       WSADATA wsaData;
860         if ( WSAStartup( 0x0101, &wsaData ) != 0 ) {
861             return( NULL );
862         }
863     daemon_initialized = 1;
864 }
865 #else
866 void sockinit()
867 {
868     daemon_initialized = 1;
869 }
870 #endif
871
872 void
873 slap_set_shutdown( int sig )
874 {
875         int l;
876         slapd_shutdown = sig;
877 #ifndef HAVE_WINSOCK
878         if(slapd_listener) {
879                 ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );
880         }
881 #else
882         Debug( LDAP_DEBUG_TRACE, "Shutdown %d ordered", sig, 0, 0 );
883         /* trying to "hit" the socket seems to always get a */
884         /* EWOULDBLOCK error, so just close the listen socket to */
885         /* break out of the select since we're shutting down anyway */
886         for ( l = 0; l < N_LISTENERS; l++ ) {
887                 if ( listeners[l].tcps >= 0 ) {
888                         tcp_close( listeners[l].tcps );
889                 }
890         }
891 #endif
892         /* reinstall self */
893         (void) SIGNAL( sig, slap_set_shutdown );
894 }
895
896 void
897 slap_do_nothing( int sig )
898 {
899         /* reinstall self */
900         (void) SIGNAL( sig, slap_do_nothing );
901 }