]> git.sur5r.net Git - openldap/blob - servers/slapd/daemon.c
53490b9927dbe59260930098acb7e2be71392d04
[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 ) ) {
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)) < 0 ) {
583                                 Debug( LDAP_DEBUG_ANY,
584                                         "daemon: connection_init(%ld, %s, %s) failed.\n",
585                                         (long) s,
586                                         client_name == NULL ? "unknown" : client_name,
587                                         client_addr == NULL ? "unknown" : client_addr);
588                                 slapd_close(s);
589                                 continue;
590                         }
591
592                         Statslog( LDAP_DEBUG_STATS,
593                                 "daemon: conn=%d fd=%ld connection from %s (%s) accepted.\n",
594                                 id, (long) s,
595                                 client_name == NULL ? "unknown" : client_name,
596                                 client_addr == NULL ? "unknown" : client_addr,
597                                 0 );
598
599                         slapd_add( s );
600                         continue;
601                 }
602
603 #ifdef LDAP_DEBUG
604                 Debug( LDAP_DEBUG_CONNS, "daemon: activity on:", 0, 0, 0 );
605 #ifdef HAVE_WINSOCK
606                 for ( i = 0; i < readfds.fd_count; i++ ) {
607                         Debug( LDAP_DEBUG_CONNS, " %d%s",
608                                 readfds.fd_array[i], "r", 0 );
609                 }
610                 for ( i = 0; i < writefds.fd_count; i++ ) {
611                         Debug( LDAP_DEBUG_CONNS, " %d%s",
612                                 writefds.fd_array[i], "w", 0 );
613                 }
614 #else
615                 for ( i = 0; i < nfds; i++ ) {
616                         int     a, r, w;
617                         int     is_listener = 0;
618
619                         for ( l = 0; l < N_LISTENERS; l++ ) {
620                                 if ( i == listeners[l].tcps ) {
621                                         is_listener = 1;
622                                         break;
623                                 }
624                         }
625                         if ( is_listener ) {
626                                 continue;
627                         }
628                         r = FD_ISSET( i, &readfds );
629                         w = FD_ISSET( i, &writefds );
630                         if ( r || w ) {
631                                 Debug( LDAP_DEBUG_CONNS, " %d%s%s", i,
632                                     r ? "r" : "", w ? "w" : "" );
633                         }
634                 }
635 #endif
636                 Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 );
637 #endif
638
639                 /* loop through the writers */
640 #ifdef HAVE_WINSOCK
641                 for ( i = 0; i < writefds.fd_count; i++ )
642 #else
643                 for ( i = 0; i < nfds; i++ )
644 #endif
645                 {
646                         ber_socket_t wd;
647                         int is_listener = 0;
648 #ifdef HAVE_WINSOCK
649                         wd = writefds.fd_array[i];
650 #else
651                         if( ! FD_ISSET( i, &writefds ) ) {
652                                 continue;
653                         }
654                         wd = i;
655 #endif
656
657                         for ( l = 0; l < N_LISTENERS; l++ ) {
658                                 if ( wd == listeners[l].tcps ) {
659                                         is_listener = 1;
660                                         break;
661                                 }
662                         }
663                         if ( is_listener ) {
664                                 continue;
665                         }
666                         Debug( LDAP_DEBUG_CONNS,
667                                 "daemon: write active on %d\n",
668                                 wd, 0, 0 );
669
670                         /*
671                          * NOTE: it is possible that the connection was closed
672                          * and that the stream is now inactive.
673                          * connection_write() must valid the stream is still
674                          * active.
675                          */
676
677                         if ( connection_write( wd ) < 0 ) {
678                                 FD_CLR( (unsigned) wd, &readfds );
679                                 slapd_close( wd );
680                         }
681                 }
682
683 #ifdef HAVE_WINSOCK
684                 for ( i = 0; i < readfds.fd_count; i++ )
685 #else
686                 for ( i = 0; i < nfds; i++ )
687 #endif
688                 {
689                         ber_socket_t rd;
690                         int is_listener = 0;
691
692 #ifdef HAVE_WINSOCK
693                         rd = readfds.fd_array[i];
694 #else
695                         if( ! FD_ISSET( i, &readfds ) ) {
696                                 continue;
697                         }
698                         rd = i;
699 #endif
700
701                         for ( l = 0; l < N_LISTENERS; l++ ) {
702                                 if ( rd == listeners[l].tcps ) {
703                                         is_listener = 1;
704                                         break;
705                                 }
706                         }
707                         if ( is_listener ) {
708                                 continue;
709                         }
710
711                         Debug ( LDAP_DEBUG_CONNS,
712                                 "daemon: read activity on %d\n", rd, 0, 0 );
713
714                         /*
715                          * NOTE: it is possible that the connection was closed
716                          * and that the stream is now inactive.
717                          * connection_read() must valid the stream is still
718                          * active.
719                          */
720
721                         if ( connection_read( rd ) < 0 ) {
722                                 slapd_close( rd );
723                         }
724                 }
725                 ldap_pvt_thread_yield();
726         }
727
728         if( slapd_shutdown > 0 ) {
729                 Debug( LDAP_DEBUG_TRACE,
730                         "daemon: shutdown requested and initiated.\n",
731                         0, 0, 0 );
732
733         } else if ( slapd_shutdown < 0 ) {
734                 Debug( LDAP_DEBUG_TRACE,
735                         "daemon: abnormal condition, shutdown initiated.\n",
736                         0, 0, 0 );
737         } else {
738                 Debug( LDAP_DEBUG_TRACE,
739                         "daemon: no active streams, shutdown initiated.\n",
740                         0, 0, 0 );
741         }
742
743         for ( l = 0; l < N_LISTENERS; l++ ) {
744                 if ( listeners[l].tcps >= 0 ) {
745                         slapd_close( listeners[l].tcps );
746                 }
747         }
748
749         ldap_pvt_thread_mutex_lock( &active_threads_mutex );
750         Debug( LDAP_DEBUG_ANY,
751             "slapd shutdown: waiting for %d threads to terminate\n",
752             active_threads, 0, 0 );
753         while ( active_threads > 0 ) {
754                 ldap_pvt_thread_cond_wait(&active_threads_cond, &active_threads_mutex);
755         }
756         ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
757
758         return NULL;
759 }
760
761
762 int slapd_daemon( struct slapd_args *args )
763 {
764         int rc;
765
766     if ( !daemon_initialized ) sockinit();
767
768         connections_init();
769
770 #define SLAPD_LISTENER_THREAD 1
771 #if defined( SLAPD_LISTENER_THREAD ) || !defined(HAVE_PTHREADS)
772
773         /* listener as a separate THREAD */
774         rc = ldap_pvt_thread_create( &listener_tid,
775                 0, slapd_daemon_task, args );
776
777         if ( rc != 0 ) {
778                 Debug( LDAP_DEBUG_ANY,
779                     "listener ldap_pvt_thread_create failed (%d)\n", rc, 0, 0 );
780                 goto destory;
781         }
782
783         /* wait for the listener thread to complete */
784         ldap_pvt_thread_join( listener_tid, (void *) NULL );
785 #else
786         /* expermimental code */
787         listener_tid = pthread_self();
788         slapd_daemon_task( args );
789 #endif
790
791         rc = 0;
792
793 destory:
794         connections_destroy();
795
796 #ifdef HAVE_WINSOCK
797     WSACleanup( );
798 #endif
799
800         return rc;
801 }
802
803 #ifdef HAVE_WINSOCK2
804 void sockinit()
805 {
806     WORD wVersionRequested;
807         WSADATA wsaData;
808         int err;
809  
810         wVersionRequested = MAKEWORD( 2, 0 );
811  
812         err = WSAStartup( wVersionRequested, &wsaData );
813         if ( err != 0 ) {
814                 /* Tell the user that we couldn't find a usable */
815                 /* WinSock DLL.                                  */
816                 return;
817         }
818  
819         /* Confirm that the WinSock DLL supports 2.0.*/
820         /* Note that if the DLL supports versions greater    */
821         /* than 2.0 in addition to 2.0, it will still return */
822         /* 2.0 in wVersion since that is the version we      */
823         /* requested.                                        */
824  
825         if ( LOBYTE( wsaData.wVersion ) != 2 ||
826                 HIBYTE( wsaData.wVersion ) != 0 )
827         {
828             /* Tell the user that we couldn't find a usable */
829             /* WinSock DLL.                                  */
830             WSACleanup( );
831             return; 
832         }
833     daemon_initialized = 1;
834 }       /* The WinSock DLL is acceptable. Proceed. */
835
836 void hit_socket()
837 {
838         ber_socket_t s;
839         int on = 1;
840         extern struct sockaddr_in       bind_addr;
841
842         /* throw something at the socket to terminate the select() in the daemon thread. */
843         if (( s = socket( AF_INET, SOCK_STREAM, 0 )) == AC_SOCKET_INVALID )
844                 Debug( LDAP_DEBUG_ANY,
845                         "slap_set_shutdown: socket failed\n\tWSAGetLastError=%d (%s)\n",
846                         WSAGetLastError(), WSAGetLastErrorString(), 0 );
847
848         if ( ioctlsocket( s, FIONBIO, &on ) == -1 ) 
849                 Debug( LDAP_DEBUG_ANY,
850                         "slap_set_shutdown:FIONBIO ioctl on %d faled\n\tWSAGetLastError=%d (%s)\n",
851                         s, WSAGetLastError(), WSAGetLastError() );
852         
853         bind_addr.sin_addr.s_addr = htonl( INADDR_LOOPBACK );
854
855         if ( connect( s, (struct sockaddr *)&bind_addr, sizeof( struct sockaddr_in )) == SOCKET_ERROR ) {
856                 Debug( LDAP_DEBUG_ANY,
857                         "hit_socket: error on connect: %d\n",
858                         WSAGetLastError(), 0, 0 );
859                 /* we can probably expect some error to occur here, mostly WSAEWOULDBLOCK */
860         }
861
862         tcp_close(s);
863 }
864
865 #elif HAVE_WINSOCK
866 void sockinit()
867 {       WSADATA wsaData;
868         if ( WSAStartup( 0x0101, &wsaData ) != 0 ) {
869             return( NULL );
870         }
871     daemon_initialized = 1;
872 }
873 #else
874 void sockinit()
875 {
876     daemon_initialized = 1;
877 }
878 #endif
879
880 void
881 slap_set_shutdown( int sig )
882 {
883         int l;
884         slapd_shutdown = sig;
885 #ifndef HAVE_WINSOCK
886         if(slapd_listener) {
887                 ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );
888         }
889 #else
890         Debug( LDAP_DEBUG_TRACE, "Shutdown %d ordered", sig, 0, 0 );
891         /* trying to "hit" the socket seems to always get a */
892         /* EWOULDBLOCK error, so just close the listen socket to */
893         /* break out of the select since we're shutting down anyway */
894         for ( l = 0; l < N_LISTENERS; l++ ) {
895                 if ( listeners[l].tcps >= 0 ) {
896                         tcp_close( listeners[l].tcps );
897                 }
898         }
899 #endif
900         /* reinstall self */
901         (void) SIGNAL( sig, slap_set_shutdown );
902 }
903
904 void
905 slap_do_nothing( int sig )
906 {
907         /* reinstall self */
908         (void) SIGNAL( sig, slap_do_nothing );
909 }