]> git.sur5r.net Git - openldap/blob - servers/slapd/daemon.c
connection_init now takes one more argument that indicates whether to
[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 ( listeners[l].tcps < 0 )
318                                 continue;
319                         if ( listen( listeners[l].tcps, 5 ) == -1 ) {
320                                 int err = errno;
321                                 Debug( LDAP_DEBUG_ANY,
322                                 "daemon: listen(%ld, 5) failed errno %d (%s)\n",
323                                        (long) listeners[l].tcps, err,
324                                        err > -1 && err < sys_nerr
325                                        ? sys_errlist[err] : "unknown" );
326                                 return( (void*)-1 );
327                         }
328
329                         slapd_add( listeners[l].tcps );
330                 }
331
332         } else {
333                 if( connection_init( (ber_socket_t) 0, NULL, NULL, 0 ) ) {
334                         Debug( LDAP_DEBUG_ANY,
335                                 "connection_init(%d) failed.\n",
336                                 0, 0, 0 );
337                         return( (void*)-1 );
338                 }
339
340                 slapd_add( 0 );
341         }
342
343 #ifdef HAVE_WINSOCK
344         if ( started_event != NULL )
345                 ldap_pvt_thread_cond_signal( &started_event );
346 #endif
347         /* initialization complete. Here comes the loop. */
348
349         while ( !slapd_shutdown ) {
350                 ber_socket_t i;
351                 int ns;
352                 int at;
353                 ber_socket_t nfds;
354 #define SLAPD_EBADF_LIMIT 10
355                 int ebadf = 0;
356
357 #define SLAPD_IDLE_CHECK_LIMIT 4
358                 time_t  last_idle_check = slap_get_time();
359                 time_t  now;
360
361
362                 fd_set                  readfds;
363                 fd_set                  writefds;
364
365                 struct sockaddr_in      from;
366 #if defined(SLAPD_RLOOKUPS) || defined(HAVE_TCPD)
367         struct hostent          *hp;
368 #endif
369                 struct timeval          zero;
370                 struct timeval          *tvp;
371
372                 char    *client_name;
373                 char    *client_addr;
374
375                 if( global_idletimeout > 0 && difftime(
376                         last_idle_check+global_idletimeout/SLAPD_IDLE_CHECK_LIMIT,
377                         now ) < 0 )
378                 {
379                         connections_timeout_idle(now);
380                 }
381
382                 FD_ZERO( &writefds );
383                 FD_ZERO( &readfds );
384
385                 zero.tv_sec = 0;
386                 zero.tv_usec = 0;
387
388                 ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
389
390 #ifdef FD_SET_MANUAL_COPY
391                 for( s = 0; s < nfds; s++ ) {
392                         if(FD_ISSET( &slap_sd_writers, s )) {
393                                 FD_SET( &writefds, s );
394                         }
395                         if(FD_ISSET( &slap_sd_writers, s )) {
396                                 FD_SET( &writefds, s );
397                         }
398                 }
399 #else
400                 memcpy( &readfds, &slap_daemon.sd_readers, sizeof(fd_set) );
401                 memcpy( &writefds, &slap_daemon.sd_writers, sizeof(fd_set) );
402 #endif
403
404                 for ( l = 0; l < N_LISTENERS; l++ ) {
405                         if ( listeners[l].tcps < 0 )
406                                 continue;
407                         FD_SET( (unsigned) listeners[l].tcps, &readfds );
408                 }
409
410 #ifndef HAVE_WINSOCK
411                 nfds = slap_daemon.sd_nfds;
412 #else
413                 nfds = dtblsize;
414 #endif
415
416                 ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
417
418                 ldap_pvt_thread_mutex_lock( &active_threads_mutex );
419                 at = active_threads;
420                 ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
421
422 #if defined( HAVE_YIELDING_SELECT ) || defined( NO_THREADS )
423                 tvp = NULL;
424 #else
425                 tvp = at ? &zero : NULL;
426 #endif
427
428                 for ( i = 0; i < N_LISTENERS; i++ ) {
429                         if ( listeners[l].tcps < 0 )
430                                 continue;
431                         Debug( LDAP_DEBUG_CONNS,
432                         "daemon: select: tcps=%d active_threads=%d tvp=%s\n",
433                                listeners[i].tcps, at,
434                                tvp == NULL ? "NULL" : "zero" );
435                 }
436
437                 switch(ns = select( nfds, &readfds,
438 #ifdef HAVE_WINSOCK
439                         /* don't pass empty fd_set */
440                         ( writefds.fd_count > 0 ? &writefds : NULL ),
441 #else
442                         &writefds,
443 #endif
444                         NULL, tvp ))
445                 {
446                 case -1: {      /* failure - try again */
447 #ifdef HAVE_WINSOCK
448                                 int err = WSAGetLastError();
449 #else
450                                 int err = errno;
451 #endif
452
453                                 if( err == EBADF && ++ebadf < SLAPD_EBADF_LIMIT) {
454                                         continue;
455                                 }
456
457                                 if( err != EINTR ) {
458                                         Debug( LDAP_DEBUG_CONNS,
459                                                 "daemon: select failed (%d): %s\n",
460                                                 err,
461                                                 err >= 0 && err < sys_nerr
462                                                         ? sys_errlist[err] : "unknown",
463                                                 0 );
464
465
466                                 slapd_shutdown = -1;
467                                 }
468                         }
469                         continue;
470
471                 case 0:         /* timeout - let threads run */
472                         ebadf = 0;
473                         Debug( LDAP_DEBUG_CONNS, "daemon: select timeout - yielding\n",
474                             0, 0, 0 );
475                 ldap_pvt_thread_yield();
476                         continue;
477
478                 default:        /* something happened - deal with it */
479                         ebadf = 0;
480                         Debug( LDAP_DEBUG_CONNS, "daemon: activity on %d descriptors\n",
481                                 ns, 0, 0 );
482                         /* FALL THRU */
483                 }
484
485                 for ( l = 0; l < N_LISTENERS; l++ ) {
486                         ber_int_t s;
487                         int len = sizeof(from);
488                         long id;
489
490                         if ( listeners[l].tcps < 0 )
491                                 continue;
492                         if ( !FD_ISSET( listeners[l].tcps, &readfds ) )
493                                 continue;
494
495                         if ( (s = accept( listeners[l].tcps,
496                                 (struct sockaddr *) &from, &len )) == AC_SOCKET_INVALID )
497                         {
498                                 int err = errno;
499                                 Debug( LDAP_DEBUG_ANY,
500                                     "daemon: accept(%ld) failed errno %d (%s)\n", err,
501                                     (long) listeners[l].tcps,
502                                     err >= 0 && err < sys_nerr ?
503                                     sys_errlist[err] : "unknown");
504                                 continue;
505                         }
506
507 #ifdef LDAP_DEBUG
508                         ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
509
510                         /* newly accepted stream should not be in any of the FD SETS */
511
512                         assert( !FD_ISSET( s, &slap_daemon.sd_actives) );
513                         assert( !FD_ISSET( s, &slap_daemon.sd_readers) );
514                         assert( !FD_ISSET( s, &slap_daemon.sd_writers) );
515
516                         ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
517 #endif
518
519 #ifndef HAVE_WINSOCK
520                         /* make sure descriptor number isn't too great */
521                         if ( s >= dtblsize ) {
522                                 Debug( LDAP_DEBUG_ANY,
523                                         "daemon: %ld beyond descriptor table size %ld\n",
524                                         (long) s, (long) dtblsize, 0 );
525                                 slapd_close(s);
526                                 continue;
527                         }
528 #endif
529                    
530                         Debug( LDAP_DEBUG_CONNS, "daemon: new connection on %ld\n",
531                                 (long) s, 0, 0 );
532
533                         len = sizeof(from);
534                         if ( getpeername( s, (struct sockaddr *) &from, &len ) == 0 ) {
535                                 client_addr = inet_ntoa( from.sin_addr );
536
537 #if defined(SLAPD_RLOOKUPS) || defined(HAVE_TCPD)
538                                 hp = gethostbyaddr( (char *)
539                                     &(from.sin_addr.s_addr),
540                                     sizeof(from.sin_addr.s_addr), AF_INET );
541
542                                 if(hp) {
543                                         char *p;
544                                         client_name = hp->h_name;
545
546                                         /* normalize the domain */
547                                         for ( p = client_name; *p; p++ ) {
548                                                 *p = TOLOWER( (unsigned char) *p );
549                                         }
550
551                                 } else {
552                                         client_name = NULL;
553                                 }
554 #else
555                                 client_name = NULL;
556 #endif
557
558                         } else {
559                                 client_name = NULL;;
560                                 client_addr = NULL;
561                         }
562
563 #ifdef HAVE_TCPD
564                         if(!hosts_ctl("slapd",
565                                 client_name != NULL ? client_name : STRING_UNKNOWN,
566                                 client_addr != NULL ? client_addr : STRING_UNKNOWN,
567                                 STRING_UNKNOWN))
568                         {
569                                 /* DENY ACCESS */
570                                 Statslog( LDAP_DEBUG_ANY,
571                                  "fd=%ld connection from %s (%s) denied.\n",
572                                         (long) s,
573                                         client_name == NULL ? "unknown" : client_name,
574                                         client_addr == NULL ? "unknown" : client_addr,
575                                   0, 0 );
576
577                                 slapd_close(s);
578                                 continue;
579                         }
580 #endif /* HAVE_TCPD */
581
582                         if( (id = connection_init(s, client_name, client_addr,
583                                                   listeners[l].use_tls)) < 0 ) {
584                                 Debug( LDAP_DEBUG_ANY,
585                                         "daemon: connection_init(%ld, %s, %s) failed.\n",
586                                         (long) s,
587                                         client_name == NULL ? "unknown" : client_name,
588                                         client_addr == NULL ? "unknown" : client_addr);
589                                 slapd_close(s);
590                                 continue;
591                         }
592
593                         Statslog( LDAP_DEBUG_STATS,
594                                 "daemon: conn=%d fd=%ld connection from %s (%s) accepted.\n",
595                                 id, (long) s,
596                                 client_name == NULL ? "unknown" : client_name,
597                                 client_addr == NULL ? "unknown" : client_addr,
598                                 0 );
599
600                         slapd_add( s );
601                         continue;
602                 }
603
604 #ifdef LDAP_DEBUG
605                 Debug( LDAP_DEBUG_CONNS, "daemon: activity on:", 0, 0, 0 );
606 #ifdef HAVE_WINSOCK
607                 for ( i = 0; i < readfds.fd_count; i++ ) {
608                         Debug( LDAP_DEBUG_CONNS, " %d%s",
609                                 readfds.fd_array[i], "r", 0 );
610                 }
611                 for ( i = 0; i < writefds.fd_count; i++ ) {
612                         Debug( LDAP_DEBUG_CONNS, " %d%s",
613                                 writefds.fd_array[i], "w", 0 );
614                 }
615 #else
616                 for ( i = 0; i < nfds; i++ ) {
617                         int     a, r, w;
618                         int     is_listener = 0;
619
620                         for ( l = 0; l < N_LISTENERS; l++ ) {
621                                 if ( i == listeners[l].tcps ) {
622                                         is_listener = 1;
623                                         break;
624                                 }
625                         }
626                         if ( is_listener ) {
627                                 continue;
628                         }
629                         r = FD_ISSET( i, &readfds );
630                         w = FD_ISSET( i, &writefds );
631                         if ( r || w ) {
632                                 Debug( LDAP_DEBUG_CONNS, " %d%s%s", i,
633                                     r ? "r" : "", w ? "w" : "" );
634                         }
635                 }
636 #endif
637                 Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 );
638 #endif
639
640                 /* loop through the writers */
641 #ifdef HAVE_WINSOCK
642                 for ( i = 0; i < writefds.fd_count; i++ )
643 #else
644                 for ( i = 0; i < nfds; i++ )
645 #endif
646                 {
647                         ber_socket_t wd;
648                         int is_listener = 0;
649 #ifdef HAVE_WINSOCK
650                         wd = writefds.fd_array[i];
651 #else
652                         if( ! FD_ISSET( i, &writefds ) ) {
653                                 continue;
654                         }
655                         wd = i;
656 #endif
657
658                         for ( l = 0; l < N_LISTENERS; l++ ) {
659                                 if ( wd == listeners[l].tcps ) {
660                                         is_listener = 1;
661                                         break;
662                                 }
663                         }
664                         if ( is_listener ) {
665                                 continue;
666                         }
667                         Debug( LDAP_DEBUG_CONNS,
668                                 "daemon: write active on %d\n",
669                                 wd, 0, 0 );
670
671                         /*
672                          * NOTE: it is possible that the connection was closed
673                          * and that the stream is now inactive.
674                          * connection_write() must valid the stream is still
675                          * active.
676                          */
677
678                         if ( connection_write( wd ) < 0 ) {
679                                 FD_CLR( (unsigned) wd, &readfds );
680                                 slapd_close( wd );
681                         }
682                 }
683
684 #ifdef HAVE_WINSOCK
685                 for ( i = 0; i < readfds.fd_count; i++ )
686 #else
687                 for ( i = 0; i < nfds; i++ )
688 #endif
689                 {
690                         ber_socket_t rd;
691                         int is_listener = 0;
692
693 #ifdef HAVE_WINSOCK
694                         rd = readfds.fd_array[i];
695 #else
696                         if( ! FD_ISSET( i, &readfds ) ) {
697                                 continue;
698                         }
699                         rd = i;
700 #endif
701
702                         for ( l = 0; l < N_LISTENERS; l++ ) {
703                                 if ( rd == listeners[l].tcps ) {
704                                         is_listener = 1;
705                                         break;
706                                 }
707                         }
708                         if ( is_listener ) {
709                                 continue;
710                         }
711
712                         Debug ( LDAP_DEBUG_CONNS,
713                                 "daemon: read activity on %d\n", rd, 0, 0 );
714
715                         /*
716                          * NOTE: it is possible that the connection was closed
717                          * and that the stream is now inactive.
718                          * connection_read() must valid the stream is still
719                          * active.
720                          */
721
722                         if ( connection_read( rd ) < 0 ) {
723                                 slapd_close( rd );
724                         }
725                 }
726                 ldap_pvt_thread_yield();
727         }
728
729         if( slapd_shutdown > 0 ) {
730                 Debug( LDAP_DEBUG_TRACE,
731                         "daemon: shutdown requested and initiated.\n",
732                         0, 0, 0 );
733
734         } else if ( slapd_shutdown < 0 ) {
735                 Debug( LDAP_DEBUG_TRACE,
736                         "daemon: abnormal condition, shutdown initiated.\n",
737                         0, 0, 0 );
738         } else {
739                 Debug( LDAP_DEBUG_TRACE,
740                         "daemon: no active streams, shutdown initiated.\n",
741                         0, 0, 0 );
742         }
743
744         for ( l = 0; l < N_LISTENERS; l++ ) {
745                 if ( listeners[l].tcps >= 0 ) {
746                         slapd_close( listeners[l].tcps );
747                 }
748         }
749
750         ldap_pvt_thread_mutex_lock( &active_threads_mutex );
751         Debug( LDAP_DEBUG_ANY,
752             "slapd shutdown: waiting for %d threads to terminate\n",
753             active_threads, 0, 0 );
754         while ( active_threads > 0 ) {
755                 ldap_pvt_thread_cond_wait(&active_threads_cond, &active_threads_mutex);
756         }
757         ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
758
759         return NULL;
760 }
761
762
763 int slapd_daemon( struct slapd_args *args )
764 {
765         int rc;
766
767     if ( !daemon_initialized ) sockinit();
768
769         connections_init();
770
771 #define SLAPD_LISTENER_THREAD 1
772 #if defined( SLAPD_LISTENER_THREAD ) || !defined(HAVE_PTHREADS)
773
774         /* listener as a separate THREAD */
775         rc = ldap_pvt_thread_create( &listener_tid,
776                 0, slapd_daemon_task, args );
777
778         if ( rc != 0 ) {
779                 Debug( LDAP_DEBUG_ANY,
780                     "listener ldap_pvt_thread_create failed (%d)\n", rc, 0, 0 );
781                 goto destory;
782         }
783
784         /* wait for the listener thread to complete */
785         ldap_pvt_thread_join( listener_tid, (void *) NULL );
786 #else
787         /* expermimental code */
788         listener_tid = pthread_self();
789         slapd_daemon_task( args );
790 #endif
791
792         rc = 0;
793
794 destory:
795         connections_destroy();
796
797 #ifdef HAVE_WINSOCK
798     WSACleanup( );
799 #endif
800
801         return rc;
802 }
803
804 #ifdef HAVE_WINSOCK2
805 void sockinit()
806 {
807     WORD wVersionRequested;
808         WSADATA wsaData;
809         int err;
810  
811         wVersionRequested = MAKEWORD( 2, 0 );
812  
813         err = WSAStartup( wVersionRequested, &wsaData );
814         if ( err != 0 ) {
815                 /* Tell the user that we couldn't find a usable */
816                 /* WinSock DLL.                                  */
817                 return;
818         }
819  
820         /* Confirm that the WinSock DLL supports 2.0.*/
821         /* Note that if the DLL supports versions greater    */
822         /* than 2.0 in addition to 2.0, it will still return */
823         /* 2.0 in wVersion since that is the version we      */
824         /* requested.                                        */
825  
826         if ( LOBYTE( wsaData.wVersion ) != 2 ||
827                 HIBYTE( wsaData.wVersion ) != 0 )
828         {
829             /* Tell the user that we couldn't find a usable */
830             /* WinSock DLL.                                  */
831             WSACleanup( );
832             return; 
833         }
834     daemon_initialized = 1;
835 }       /* The WinSock DLL is acceptable. Proceed. */
836
837 void hit_socket()
838 {
839         ber_socket_t s;
840         int on = 1;
841         extern struct sockaddr_in       bind_addr;
842
843         /* throw something at the socket to terminate the select() in the daemon thread. */
844         if (( s = socket( AF_INET, SOCK_STREAM, 0 )) == AC_SOCKET_INVALID )
845                 Debug( LDAP_DEBUG_ANY,
846                         "slap_set_shutdown: socket failed\n\tWSAGetLastError=%d (%s)\n",
847                         WSAGetLastError(), WSAGetLastErrorString(), 0 );
848
849         if ( ioctlsocket( s, FIONBIO, &on ) == -1 ) 
850                 Debug( LDAP_DEBUG_ANY,
851                         "slap_set_shutdown:FIONBIO ioctl on %d faled\n\tWSAGetLastError=%d (%s)\n",
852                         s, WSAGetLastError(), WSAGetLastError() );
853         
854         bind_addr.sin_addr.s_addr = htonl( INADDR_LOOPBACK );
855
856         if ( connect( s, (struct sockaddr *)&bind_addr, sizeof( struct sockaddr_in )) == SOCKET_ERROR ) {
857                 Debug( LDAP_DEBUG_ANY,
858                         "hit_socket: error on connect: %d\n",
859                         WSAGetLastError(), 0, 0 );
860                 /* we can probably expect some error to occur here, mostly WSAEWOULDBLOCK */
861         }
862
863         tcp_close(s);
864 }
865
866 #elif HAVE_WINSOCK
867 void sockinit()
868 {       WSADATA wsaData;
869         if ( WSAStartup( 0x0101, &wsaData ) != 0 ) {
870             return( NULL );
871         }
872     daemon_initialized = 1;
873 }
874 #else
875 void sockinit()
876 {
877     daemon_initialized = 1;
878 }
879 #endif
880
881 void
882 slap_set_shutdown( int sig )
883 {
884         int l;
885         slapd_shutdown = sig;
886 #ifndef HAVE_WINSOCK
887         if(slapd_listener) {
888                 ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );
889         }
890 #else
891         Debug( LDAP_DEBUG_TRACE, "Shutdown %d ordered", sig, 0, 0 );
892         /* trying to "hit" the socket seems to always get a */
893         /* EWOULDBLOCK error, so just close the listen socket to */
894         /* break out of the select since we're shutting down anyway */
895         for ( l = 0; l < N_LISTENERS; l++ ) {
896                 if ( listeners[l].tcps >= 0 ) {
897                         tcp_close( listeners[l].tcps );
898                 }
899         }
900 #endif
901         /* reinstall self */
902         (void) SIGNAL( sig, slap_set_shutdown );
903 }
904
905 void
906 slap_do_nothing( int sig )
907 {
908         /* reinstall self */
909         (void) SIGNAL( sig, slap_do_nothing );
910 }