]> git.sur5r.net Git - openldap/blob - servers/slapd/daemon.c
Fix typos SLAPD_NEXTID_CHUCK/SLAPD_NEXTID_CHUNCK -> SLAPD_NEXTID_CHUNK
[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 "ldapconfig.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 int dtblsize;
25
26 static ldap_pvt_thread_t        listener_tid;
27 static volatile sig_atomic_t slapd_shutdown = 0;
28 static volatile sig_atomic_t slapd_listener = 0;
29
30 struct slap_daemon {
31         ldap_pvt_thread_mutex_t sd_mutex;
32
33         int sd_nactives;
34
35 #ifndef HAVE_WINSOCK
36         /* In winsock, accept() returns values higher than dtblsize
37                 so don't bother with this optimization */
38         int sd_nfds;
39 #endif
40
41         fd_set sd_actives;
42         fd_set sd_readers;
43         fd_set sd_writers;
44 } slap_daemon; 
45
46 /*
47  * Add a descriptor to daemon control
48  */
49 static void slapd_add(int s) {
50         ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
51
52         assert( !FD_ISSET( s, &slap_daemon.sd_actives ));
53         assert( !FD_ISSET( s, &slap_daemon.sd_readers ));
54         assert( !FD_ISSET( s, &slap_daemon.sd_writers ));
55
56 #ifndef HAVE_WINSOCK
57         if (s >= slap_daemon.sd_nfds) {
58                 slap_daemon.sd_nfds = s + 1;
59         }
60 #endif
61
62         FD_SET( s, &slap_daemon.sd_actives );
63         FD_SET( s, &slap_daemon.sd_readers );
64
65         Debug( LDAP_DEBUG_CONNS, "daemon: added %d%s%s\n", s,
66             FD_ISSET(s, &slap_daemon.sd_readers) ? "r" : "",
67                 FD_ISSET(s, &slap_daemon.sd_writers) ? "w" : "" );
68
69         ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
70 }
71
72 /*
73  * Remove the descriptor from daemon control
74  */
75 void slapd_remove(int s) {
76         ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
77
78         assert( FD_ISSET( s, &slap_daemon.sd_actives ));
79
80         Debug( LDAP_DEBUG_CONNS, "daemon: removing %d%s%s\n", s,
81             FD_ISSET(s, &slap_daemon.sd_readers) ? "r" : "",
82                 FD_ISSET(s, &slap_daemon.sd_writers) ? "w" : "" );
83
84         FD_CLR( s, &slap_daemon.sd_actives );
85         FD_CLR( s, &slap_daemon.sd_readers );
86         FD_CLR( s, &slap_daemon.sd_writers );
87
88         ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
89 }
90
91 void slapd_clr_write(int s, int wake) {
92         ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
93
94         assert( FD_ISSET( s, &slap_daemon.sd_actives) );
95         FD_CLR( s, &slap_daemon.sd_writers );
96
97         ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
98
99         if( wake ) {
100                 ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );
101         }
102 }
103
104 void slapd_set_write(int s, int wake) {
105         ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
106
107         assert( FD_ISSET( s, &slap_daemon.sd_actives) );
108         FD_SET( s, &slap_daemon.sd_writers );
109
110         ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
111
112         if( wake ) {
113                 ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );
114         }
115 }
116
117 void slapd_clr_read(int s, int wake) {
118         ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
119
120         assert( FD_ISSET( s, &slap_daemon.sd_actives) );
121         FD_CLR( s, &slap_daemon.sd_readers );
122
123         ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
124
125         if( wake ) {
126                 ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );
127         }
128 }
129
130 void slapd_set_read(int s, int wake) {
131         ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
132
133         assert( FD_ISSET( s, &slap_daemon.sd_actives) );
134         FD_SET( s, &slap_daemon.sd_readers );
135
136         ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
137
138         if( wake ) {
139                 ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );
140         }
141 }
142
143 static void slapd_close(int s) {
144         slapd_remove(s);
145
146         Debug( LDAP_DEBUG_CONNS, "daemon: closing %d\n", s, 0, 0 );
147         tcp_close(s);
148 }
149
150 int
151 set_socket( struct sockaddr_in *addr )
152 {
153         int     tcps = -1;
154
155 #ifdef HAVE_SYSCONF
156         dtblsize = sysconf( _SC_OPEN_MAX );
157 #elif HAVE_GETDTABLESIZE
158         dtblsize = getdtablesize();
159 #else
160         dtblsize = FD_SETSIZE;
161 #endif
162
163 #ifdef FD_SETSIZE
164         if(dtblsize > FD_SETSIZE) {
165                 dtblsize = FD_SETSIZE;
166         }
167 #endif  /* !FD_SETSIZE */
168
169         if( addr != NULL ) {
170                 int     tmp;
171
172                 if ( (tcps = socket( AF_INET, SOCK_STREAM, 0 )) == -1 ) {
173                         int err = errno;
174                         Debug( LDAP_DEBUG_ANY,
175                                 "daemon: socket() failed errno %d (%s)\n", err,
176                         err > -1 && err < sys_nerr ? sys_errlist[err] :
177                         "unknown", 0 );
178                         exit( 1 );
179                 }
180
181 #ifndef HAVE_WINSOCK
182                 if ( tcps >= dtblsize ) {
183                         Debug( LDAP_DEBUG_ANY,
184                                 "daemon: listener descriptor %d is too great\n",
185                                 tcps, dtblsize, 0 );
186                         exit( 1 );
187                 }
188 #endif
189
190                 tmp = 1;
191                 if ( setsockopt( tcps, SOL_SOCKET, SO_REUSEADDR,
192                         (char *) &tmp, sizeof(tmp) ) == -1 )
193                 {
194                         int err = errno;
195                         Debug( LDAP_DEBUG_ANY,
196                                "slapd(%d): setsockopt() failed errno %d (%s)\n",
197                         tcps, err,
198                                 err > -1 && err < sys_nerr
199                                         ? sys_errlist[err] : "unknown" );
200                 }
201
202                 if ( bind( tcps, (struct sockaddr *) addr, sizeof(*addr) ) == -1 ) {
203                         int err = errno;
204                         Debug( LDAP_DEBUG_ANY, "daemon: bind(%d) failed errno %d (%s)\n",
205                         tcps, err,
206                                 err > -1 && err < sys_nerr
207                                         ? sys_errlist[err] : "unknown" );
208                         exit( 1 );
209                 }
210         }
211
212         return tcps;
213 }
214
215 static void *
216 slapd_daemon_task(
217         void *ptr
218 )
219 {
220         int inetd = ((int *)ptr) [0];
221         int tcps  = ((int *)ptr) [1];
222         free( ptr );
223
224         slapd_listener=1;
225
226         ldap_pvt_thread_mutex_init( &slap_daemon.sd_mutex );
227         FD_ZERO( &slap_daemon.sd_readers );
228         FD_ZERO( &slap_daemon.sd_writers );
229
230         if( !inetd ) {
231                 if ( listen( tcps, 5 ) == -1 ) {
232                         int err = errno;
233                         Debug( LDAP_DEBUG_ANY,
234                                 "daemon: listen(%d, 5) failed errno %d (%s)\n",
235                             tcps, err,
236                                 err > -1 && err < sys_nerr
237                                         ? sys_errlist[err] : "unknown" );
238                         exit( 1 );
239                 }
240
241                 slapd_add( tcps );
242
243         } else {
244                 if( connection_init( 0, NULL, NULL ) ) {
245                         Debug( LDAP_DEBUG_ANY,
246                                 "connection_init(%d) failed.\n",
247                                 0, 0, 0 );
248
249                         exit( 1 );
250                 }
251
252                 slapd_add( 0 );
253         }
254
255         while ( !slapd_shutdown ) {
256                 unsigned int i;
257                 int ns, nfds;
258
259                 fd_set                  readfds;
260                 fd_set                  writefds;
261
262                 struct sockaddr_in      from;
263 #if defined(SLAPD_RLOOKUPS) || defined(HAVE_TCPD)
264         struct hostent          *hp;
265 #endif
266         struct timeval          zero;
267                 struct timeval          *tvp;
268
269                 char    *client_name;
270                 char    *client_addr;
271
272                 FD_ZERO( &writefds );
273                 FD_ZERO( &readfds );
274
275                 zero.tv_sec = 0;
276                 zero.tv_usec = 0;
277
278                 ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
279
280 #ifdef FD_SET_MANUAL_COPY
281                 for( s = 0; s < nfds; s++ ) {
282                         if(FD_ISSET( &slap_sd_writers, s )) {
283                                 FD_SET( &writefds, s );
284                         }
285                         if(FD_ISSET( &slap_sd_writers, s )) {
286                                 FD_SET( &writefds, s );
287                         }
288                 }
289 #else
290                 memcpy( &readfds, &slap_daemon.sd_readers, sizeof(fd_set) );
291                 memcpy( &writefds, &slap_daemon.sd_writers, sizeof(fd_set) );
292 #endif
293
294                 FD_SET( tcps, &readfds );
295
296 #ifndef HAVE_WINSOCK
297                 nfds = slap_daemon.sd_nfds;
298 #else
299                 nfds = dtblsize;
300 #endif
301
302                 ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
303
304                 ldap_pvt_thread_mutex_lock( &active_threads_mutex );
305 #if defined( HAVE_YIELDING_SELECT ) || defined( NO_THREADS )
306                 tvp = NULL;
307 #else
308                 tvp = active_threads ? &zero : NULL;
309 #endif
310
311                 Debug( LDAP_DEBUG_CONNS,
312                         "daemon: select: tcps=%d active_threads=%d tvp=%s\n",
313                     tcps, active_threads,
314                         tvp == NULL ? "NULL" : "zero" );
315            
316
317                 ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
318
319                 switch(ns = select( nfds, &readfds, &writefds, 0, tvp )) {
320                 case -1: {      /* failure - try again */
321                                 int err = errno;
322                                 if( err != EINTR ) {
323                                         Debug( LDAP_DEBUG_CONNS,
324                                                 "daemon: select failed (%d): %s\n",
325                                                 err,
326                                                 err >= 0 && err < sys_nerr
327                                                         ? sys_errlist[err] : "unknown",
328                                                 0 );
329
330                                         slapd_shutdown = -1;
331                                 }
332                         }
333                         continue;
334
335                 case 0:         /* timeout - let threads run */
336                         Debug( LDAP_DEBUG_CONNS, "daemon: select timeout - yielding\n",
337                             0, 0, 0 );
338                 ldap_pvt_thread_yield();
339                         continue;
340
341                 default:        /* something happened - deal with it */
342                         Debug( LDAP_DEBUG_CONNS, "daemon: activity on %d descriptors\n",
343                                 ns, 0, 0 );
344                         /* FALL THRU */
345                 }
346
347                 if ( FD_ISSET( tcps, &readfds ) ) {
348                         int s;
349                         int len = sizeof(from);
350                         long id;
351
352                         if ( (s = accept( tcps,
353                                 (struct sockaddr *) &from, &len )) == -1 )
354                         {
355                                 int err = errno;
356                                 Debug( LDAP_DEBUG_ANY,
357                                     "daemon: accept(%d) failed errno %d (%s)\n", err,
358                                     tcps, err >= 0 && err < sys_nerr ?
359                                     sys_errlist[err] : "unknown");
360                                 continue;
361                         }
362
363                         assert( !FD_ISSET( 0, &slap_daemon.sd_actives) );
364                         assert( !FD_ISSET( 0, &slap_daemon.sd_readers) );
365                         assert( !FD_ISSET( 0, &slap_daemon.sd_writers) );
366
367 #ifndef HAVE_WINSOCK
368                         /* make sure descriptor number isn't too great */
369                         if ( s >= dtblsize ) {
370                                 Debug( LDAP_DEBUG_ANY,
371                                         "daemon: %d beyond descriptor table size %d\n",
372                                         s, dtblsize, 0 );
373                                 tcp_close(s);
374                                 continue;
375                         }
376 #endif
377                    
378                         Debug( LDAP_DEBUG_CONNS, "daemon: new connection on %d\n",
379                                 s, 0, 0 );
380
381                         len = sizeof(from);
382                         if ( getpeername( s, (struct sockaddr *) &from, &len ) == 0 ) {
383                                 client_addr = inet_ntoa( from.sin_addr );
384
385 #if defined(SLAPD_RLOOKUPS) || defined(HAVE_TCPD)
386                                 hp = gethostbyaddr( (char *)
387                                     &(from.sin_addr.s_addr),
388                                     sizeof(from.sin_addr.s_addr), AF_INET );
389
390                                 if(hp) {
391                                         char *p;
392                                         client_name = hp->h_name;
393
394                                         /* normalize the domain */
395                                         for ( p = client_name; *p; p++ ) {
396                                                 *p = TOLOWER( (unsigned char) *p );
397                                         }
398
399                                 } else {
400                                         client_name = NULL;
401                                 }
402 #else
403                                 client_name = NULL;
404 #endif
405
406                         } else {
407                                 client_name = NULL;;
408                                 client_addr = NULL;
409                         }
410
411 #ifdef HAVE_TCPD
412                         if(!hosts_ctl("slapd",
413                                 client_name != NULL ? client_name : STRING_UNKNOWN,
414                                 client_addr != NULL ? client_addr : STRING_UNKNOWN,
415                                 STRING_UNKNOWN))
416                         {
417                                 /* DENY ACCESS */
418                                 Statslog( LDAP_DEBUG_ANY,
419                                  "fd=%d connection from %s (%s) denied.\n",
420                                         s,
421                                         client_name == NULL ? "unknown" : client_name,
422                                         client_addr == NULL ? "unknown" : client_addr,
423                                   0, 0 );
424
425                                 tcp_close(s);
426                                 continue;
427                         }
428 #endif /* HAVE_TCPD */
429
430                         if( (id = connection_init(s, client_name, client_addr)) < 0 ) {
431                                 Debug( LDAP_DEBUG_ANY,
432                                         "daemon: connection_init(%d, %s, %s) failed.\n",
433                                         s,
434                                         client_name == NULL ? "unknown" : client_name,
435                                         client_addr == NULL ? "unknown" : client_addr);
436                                 tcp_close(s);
437                                 continue;
438                         }
439
440                         Statslog( LDAP_DEBUG_STATS,
441                                 "daemon: conn=%d fd=%d connection from %s (%s) accepted.\n",
442                                 id, s,
443                                 client_name == NULL ? "unknown" : client_name,
444                                 client_addr == NULL ? "unknown" : client_addr,
445                                 0 );
446
447                         slapd_add( s );
448                         continue;
449                 }
450
451 #ifdef LDAP_DEBUG
452                 Debug( LDAP_DEBUG_CONNS, "daemon: activity on:", 0, 0, 0 );
453 #ifdef HAVE_WINSOCK
454                 for ( i = 0; i < readfds.fd_count; i++ )
455                 {
456                         Debug( LDAP_DEBUG_CONNS, " %d%s", readfds.fd_array[i], "r" );
457                 }
458                 for ( i = 0; i < writefds.fd_count; i++ )
459                 {
460                         Debug( LDAP_DEBUG_CONNS, " %d%s", writefds.fd_array[i], "w" );
461                 }
462 #else
463                 for ( i = 0; i < nfds; i++ ) {
464                         int     a, r, w;
465
466                         r = FD_ISSET( i, &readfds );
467                         w = FD_ISSET( i, &writefds );
468                         if ( i != tcps && (r || w) ) {
469                                 Debug( LDAP_DEBUG_CONNS, " %d%s%s", i,
470                                     r ? "r" : "", w ? "w" : "" );
471                         }
472                 }
473 #endif
474                 Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 );
475 #endif
476
477                 /* loop through the writers */
478 #ifdef HAVE_WINSOCK
479                 for ( i = 0; i < writefds.fd_count; i++ ) {
480                         int wd = writefds.fd_array[i];
481
482                         if ( wd == tcps ) {
483                                 continue;
484                         }
485
486                         Debug( LDAP_DEBUG_CONNS,
487                                 "daemon: signalling write waiter on %d\n",
488                                 wd, 0, 0 );
489
490                         assert( FD_ISSET( wd, &slap_daemon.sd_actives) );
491
492                         slapd_clr_write( wd, 0 );
493                         if ( connection_write( wd ) < 0 ) {
494                                 FD_CLR( wd, &readfds );
495                                 slapd_close( wd );
496                         }
497                 }
498 #else
499                 for ( i = 0; i < nfds; i++ ) {
500                         if ( i == tcps ) {
501                                 continue;
502                         }
503                         if ( FD_ISSET( i, &writefds ) ) {
504                                 Debug( LDAP_DEBUG_CONNS,
505                                     "daemon: signaling write waiter on %d\n", i, 0, 0 );
506
507                                 assert( FD_ISSET( i, &slap_daemon.sd_actives) );
508
509                                 /* clear the write flag */
510                                 slapd_clr_write( i, 0 );
511                                 
512                                 if( connection_write( i ) < 0 ) { 
513                                         FD_CLR( i, &readfds );
514                                         slapd_close( i );
515                                 }
516                         }
517                 }
518 #endif
519
520 #ifdef HAVE_WINSOCK
521                 for ( i = 0; i < readfds.fd_count; i++ ) {
522                         int rd = readfds.fd_array[i];
523                         if ( rd == tcps ) {
524                                 continue;
525                         }
526                         Debug ( LDAP_DEBUG_CONNS,
527                                 "daemon: read activity on %d\n", rd, 0, 0 );
528                         assert( FD_ISSET( rd, &slap_daemon.sd_actives) );
529
530                         if ( connection_read( rd ) < 0 ) {
531                                 slapd_close( rd );
532                         }
533                 }
534 #else
535                 for ( i = 0; i < nfds; i++ ) {
536                         if ( i == tcps ) {
537                                 continue;
538                         }
539
540                         if ( FD_ISSET( i, &readfds ) ) {
541                                 Debug( LDAP_DEBUG_CONNS,
542                                     "daemon: read activity on %d\n", i, 0, 0 );
543
544                                 assert( FD_ISSET( i, &slap_daemon.sd_actives) );
545
546                                 if( connection_read( i ) < 0) {
547                                         slapd_close( i );
548                                 }
549                         }
550                 }
551 #endif
552                 ldap_pvt_thread_yield();
553         }
554
555         if( slapd_shutdown > 0 ) {
556                 Debug( LDAP_DEBUG_TRACE,
557                         "daemon: shutdown requested (%d) and initiated.\n",
558                         (int) slapd_shutdown, 0, 0 );
559
560         } else if ( slapd_shutdown < 0 ) {
561                 Debug( LDAP_DEBUG_TRACE,
562                         "daemon: abnormal condition (%d), shutdown initiated.\n",
563                         (int) slapd_shutdown, 0, 0 );
564         } else {
565                 Debug( LDAP_DEBUG_TRACE,
566                         "daemon: no active streams, shutdown initiated.\n",
567                         0, 0, 0 );
568         }
569
570         if( tcps >= 0 ) {
571                 tcp_close( tcps );
572         }
573
574         /* we only implement "quick" shutdown */
575         connections_shutdown();
576
577         ldap_pvt_thread_mutex_lock( &active_threads_mutex );
578         Debug( LDAP_DEBUG_ANY,
579             "slapd shutdown: waiting for %d threads to terminate\n",
580             active_threads, 0, 0 );
581         while ( active_threads > 0 ) {
582                 ldap_pvt_thread_cond_wait(&active_threads_cond, &active_threads_mutex);
583         }
584         ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
585
586         slapd_listener = 0;
587         return NULL;
588 }
589
590 int slapd_daemon( int inetd, int tcps )
591 {
592         int rc;
593         int *args = ch_malloc( sizeof( int[2] ) );
594         args[0] = inetd;
595         args[1] = tcps;
596
597 #ifdef HAVE_WINSOCK
598         {
599                 WORD    vers = MAKEWORD( 2, 0);
600                 int     err;
601                 WSADATA wsaData;
602                 err = WSAStartup( vers, &wsaData );
603         }
604 #endif
605
606         connections_init();
607
608 #define SLAPD_LISTENER_THREAD 1
609 #if SLAPD_LISTENER_THREAD
610         /* listener as a separate THREAD */
611         rc = ldap_pvt_thread_create( &listener_tid,
612                 0, slapd_daemon_task, args );
613
614         if ( rc != 0 ) {
615                 Debug( LDAP_DEBUG_ANY,
616                     "listener ldap_pvt_thread_create failed (%d)\n", rc, 0, 0 );
617                 goto destory;
618         }
619
620         /* wait for the listener thread to complete */
621         ldap_pvt_thread_join( listener_tid, (void *) NULL );
622 #else
623         /* expermimental code */
624         listener_tid = pthread_self();
625         slapd_daemon_task( args );
626 #endif
627
628         rc = 0;
629
630 destory:
631         connections_destroy();
632
633 #ifdef HAVE_WINSOCK
634     WSACleanup( );
635 #endif
636
637         return rc;
638 }
639
640 void
641 slap_set_shutdown( int sig )
642 {
643         slapd_shutdown = sig;
644
645         if(slapd_listener) {
646                 ldap_pvt_thread_kill( listener_tid, LDAP_SIGUSR1 );
647         }
648
649         /* reinstall self */
650         (void) SIGNAL( sig, slap_set_shutdown );
651 }
652
653 void
654 slap_do_nothing( int sig )
655 {
656         /* reinstall self */
657         (void) SIGNAL( sig, slap_do_nothing );
658 }