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