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