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