]> git.sur5r.net Git - openldap/blob - servers/slapd/daemon.c
Import of FreeBSD LDAP 3.3 Port
[openldap] / servers / slapd / daemon.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <sys/types.h>
4 #include <sys/socket.h>
5 #include <errno.h>
6 #include <sys/time.h>
7 #include <netinet/in.h>
8 #include <arpa/inet.h>
9 #include <netdb.h>
10 #include <signal.h>
11 #ifdef _AIX
12 #include <sys/select.h>
13 #endif
14 #include "slap.h"
15 #include "portable.h"
16 #include "ldapconfig.h"
17 #ifdef NEED_FILIO
18 #include <sys/filio.h>
19 #else /* NEED_FILIO */
20 #include <sys/ioctl.h>
21 #endif /* NEED_FILIO */
22 #ifdef USE_SYSCONF
23 #include <unistd.h>
24 #endif /* USE_SYSCONF */
25
26 extern Operation        *op_add();
27
28 #ifndef SYSERRLIST_IN_STDIO
29 extern int              sys_nerr;
30 extern char             *sys_errlist[];
31 #endif
32 extern time_t           currenttime;
33 extern pthread_mutex_t  currenttime_mutex;
34 extern int              active_threads;
35 extern pthread_mutex_t  active_threads_mutex;
36 extern pthread_mutex_t  new_conn_mutex;
37 extern int              slapd_shutdown;
38 extern pthread_t        listener_tid;
39 extern int              num_conns;
40 extern pthread_mutex_t  ops_mutex;
41 extern int              g_argc;
42 extern char             **g_argv;
43
44 int             dtblsize;
45 Connection      *c;
46
47 static void     set_shutdown();
48 static void     do_nothing();
49
50 void
51 daemon(
52     int port
53 )
54 {
55         Operation               *o;
56         BerElement              ber;
57         unsigned long           len, tag, msgid;
58         int                     i;
59         int                     tcps, ns;
60         struct sockaddr_in      addr;
61         fd_set                  readfds;
62         fd_set                  writefds;
63         FILE                    *fp;
64         int                     on = 1;
65
66 #ifdef USE_SYSCONF
67         dtblsize = sysconf( _SC_OPEN_MAX );
68 #else /* USE_SYSCONF */
69         dtblsize = getdtablesize();
70 #endif /* USE_SYSCONF */
71         /*
72          * Add greg@greg.rim.or.jp
73          */
74         if(dtblsize > FD_SETSIZE) {
75                 dtblsize = FD_SETSIZE;
76         }
77         c = (Connection *) ch_calloc( 1, dtblsize * sizeof(Connection) );
78
79         for ( i = 0; i < dtblsize; i++ ) {
80                 c[i].c_dn = NULL;
81                 c[i].c_addr = NULL;
82                 c[i].c_domain = NULL;
83                 c[i].c_ops = NULL;
84                 c[i].c_sb.sb_sd = -1;
85                 c[i].c_sb.sb_options = LBER_NO_READ_AHEAD;
86                 c[i].c_sb.sb_naddr = 0;
87                 c[i].c_sb.sb_ber.ber_buf = NULL;
88                 c[i].c_sb.sb_ber.ber_ptr = NULL;
89                 c[i].c_sb.sb_ber.ber_end = NULL;
90                 c[i].c_writewaiter = 0;
91                 c[i].c_connid = 0;
92                 pthread_mutex_init( &c[i].c_dnmutex,
93                     pthread_mutexattr_default );
94                 pthread_mutex_init( &c[i].c_opsmutex,
95                     pthread_mutexattr_default );
96                 pthread_mutex_init( &c[i].c_pdumutex,
97                     pthread_mutexattr_default );
98                 pthread_cond_init( &c[i].c_wcv, pthread_condattr_default );
99         }
100
101         if ( (tcps = socket( AF_INET, SOCK_STREAM, 0 )) == -1 ) {
102                 Debug( LDAP_DEBUG_ANY, "socket() failed errno %d (%s)", errno,
103                     errno > -1 && errno < sys_nerr ? sys_errlist[errno] :
104                     "unknown", 0 );
105                 exit( 1 );
106         }
107
108         i = 1;
109         if ( setsockopt( tcps, SOL_SOCKET, SO_REUSEADDR, (char *) &i,
110             sizeof(i) ) == -1 ) {
111                 Debug( LDAP_DEBUG_ANY, "setsockopt() failed errno %d (%s)",
112                     errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] :
113                     "unknown", 0 );
114         }
115
116         (void) memset( (void *) &addr, '\0', sizeof(addr) );
117         addr.sin_family = AF_INET;
118         addr.sin_addr.s_addr = INADDR_ANY;
119         addr.sin_port = htons( port );
120         if ( bind( tcps, (struct sockaddr *) &addr, sizeof(addr) ) == -1 ) {
121                 Debug( LDAP_DEBUG_ANY, "bind() failed errno %d (%s)\n",
122                     errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] :
123                     "unknown", 0 );
124                 exit( 1 );
125         }
126
127         if ( listen( tcps, 5 ) == -1 ) {
128                 Debug( LDAP_DEBUG_ANY, "listen() failed errno %d (%s)",
129                     errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] :
130                     "unknown", 0 );
131                 exit( 1 );
132         }
133
134         (void) SIGNAL( SIGPIPE, SIG_IGN );
135         (void) SIGNAL( SIGUSR1, (void *) do_nothing );
136         (void) SIGNAL( SIGUSR2, (void *) set_shutdown );
137         (void) SIGNAL( SIGTERM, (void *) set_shutdown );
138         (void) SIGNAL( SIGINT, (void *) set_shutdown );
139         (void) SIGNAL( SIGHUP, (void *) set_shutdown );
140
141         Debug( LDAP_DEBUG_ANY, "slapd starting\n", 0, 0, 0 );
142 #ifdef SLAPD_PIDFILE
143         if ( (fp = fopen( SLAPD_PIDFILE, "w" )) != NULL ) {
144                 fprintf( fp, "%d\n", getpid() );
145                 fclose( fp );
146         }
147 #endif
148 #ifdef SLAPD_ARGSFILE
149         if ( (fp = fopen( SLAPD_ARGSFILE, "w" )) != NULL ) {
150                 for ( i = 0; i < g_argc; i++ ) {
151                         fprintf( fp, "%s ", g_argv[i] );
152                 }
153                 fprintf( fp, "\n" );
154                 fclose( fp );
155         }
156 #endif
157
158         while ( !slapd_shutdown ) {
159                 struct sockaddr_in      from;
160                 struct hostent          *hp;
161                 struct timeval          zero;
162                 struct timeval          *tvp;
163                 int                     len, pid;
164
165                 FD_ZERO( &writefds );
166                 FD_ZERO( &readfds );
167                 FD_SET( tcps, &readfds );
168
169                 pthread_mutex_lock( &active_threads_mutex );
170                 Debug( LDAP_DEBUG_CONNS,
171                     "listening for connections on %d, activity on:",
172                     tcps, 0, 0 );
173                 for ( i = 0; i < dtblsize; i++ ) {
174                         if ( c[i].c_sb.sb_sd != -1 ) {
175                                 FD_SET( c[i].c_sb.sb_sd, &readfds );
176
177                                 if ( c[i].c_writewaiter ) {
178                                         FD_SET( c[i].c_sb.sb_sd, &writefds );
179                                 }
180                                 Debug( LDAP_DEBUG_CONNS, " %dr%s", i,
181                                     c[i].c_writewaiter ? "w" : "", 0 );
182                         }
183                 }
184                 Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 );
185
186                 zero.tv_sec = 0;
187                 zero.tv_usec = 0;
188                 Debug( LDAP_DEBUG_CONNS, "before select active_threads %d\n",
189                     active_threads, 0, 0 );
190 #ifdef PTHREAD_PREEMPTIVE
191                 tvp = NULL;
192 #else
193                 tvp = active_threads ? &zero : NULL;
194 #endif
195                 pthread_mutex_unlock( &active_threads_mutex );
196
197                 switch ( select( dtblsize, &readfds, &writefds, 0, tvp ) ) {
198                 case -1:        /* failure - try again */
199                         Debug( LDAP_DEBUG_CONNS,
200                             "select failed errno %d (%s)\n",
201                             errno, errno > -1 && errno < sys_nerr ?
202                             sys_errlist[errno] : "unknown", 0 );
203                         continue;
204
205                 case 0:         /* timeout - let threads run */
206                         Debug( LDAP_DEBUG_CONNS, "select timeout - yielding\n",
207                             0, 0, 0 );
208                         pthread_yield();
209                         continue;
210
211                 default:        /* something happened - deal with it */
212                         Debug( LDAP_DEBUG_CONNS, "select activity\n", 0, 0, 0 );
213                         ;       /* FALL */
214                 }
215                 pthread_mutex_lock( &currenttime_mutex );
216                 time( &currenttime );
217                 pthread_mutex_unlock( &currenttime_mutex );
218
219                 /* new connection */
220                 pthread_mutex_lock( &new_conn_mutex );
221                 if ( FD_ISSET( tcps, &readfds ) ) {
222                         len = sizeof(from);
223                         if ( (ns = accept( tcps, (struct sockaddr *) &from,
224                             &len )) == -1 ) {
225                                 Debug( LDAP_DEBUG_ANY,
226                                     "accept() failed errno %d (%s)", errno,
227                                     errno > -1 && errno < sys_nerr ?
228                                     sys_errlist[errno] : "unknown", 0 );
229                                 pthread_mutex_unlock( &new_conn_mutex );
230                                 continue;
231                         }
232                         if ( ioctl( ns, FIONBIO, (caddr_t) &on ) == -1 ) {
233                                 Debug( LDAP_DEBUG_ANY,
234                                     "FIONBIO ioctl on %d faled\n", ns, 0, 0 );
235                         }
236                         c[ns].c_sb.sb_sd = ns;
237                         Debug( LDAP_DEBUG_CONNS, "new connection on %d\n", ns,
238                             0, 0 );
239
240                         pthread_mutex_lock( &ops_mutex );
241                         c[ns].c_connid = num_conns++;
242                         pthread_mutex_unlock( &ops_mutex );
243                         len = sizeof(from);
244                         if ( getpeername( ns, (struct sockaddr *) &from, &len )
245                             == 0 ) {
246                                 char    *s;
247 #ifdef REVERSE_LOOKUP
248                                 hp = gethostbyaddr( (char *)
249                                     &(from.sin_addr.s_addr),
250                                     sizeof(from.sin_addr.s_addr), AF_INET );
251 #else
252                                 hp = NULL;
253 #endif
254
255                                 Statslog( LDAP_DEBUG_STATS,
256                                     "conn=%d fd=%d connection from %s (%s)\n",
257                                     c[ns].c_connid, ns, hp == NULL ? "unknown"
258                                     : hp->h_name, inet_ntoa( from.sin_addr ),
259                                     0 );
260
261                                 if ( c[ns].c_addr != NULL ) {
262                                         free( c[ns].c_addr );
263                                 }
264                                 c[ns].c_addr = strdup( inet_ntoa(
265                                     from.sin_addr ) );
266                                 if ( c[ns].c_domain != NULL ) {
267                                         free( c[ns].c_domain );
268                                 }
269                                 c[ns].c_domain = strdup( hp == NULL ? "" :
270                                     hp->h_name );
271                                 /* normalize the domain */
272                                 for ( s = c[ns].c_domain; *s; s++ ) {
273                                         *s = TOLOWER( *s );
274                                 }
275                         } else {
276                                 Statslog( LDAP_DEBUG_STATS,
277                                     "conn=%d fd=%d connection from unknown\n",
278                                     c[ns].c_connid, ns, 0, 0, 0 );
279                         }
280                         pthread_mutex_lock( &c[ns].c_dnmutex );
281                         if ( c[ns].c_dn != NULL ) {
282                                 free( c[ns].c_dn );
283                                 c[ns].c_dn = NULL;
284                         }
285                         pthread_mutex_unlock( &c[ns].c_dnmutex );
286                         c[ns].c_starttime = currenttime;
287                         c[ns].c_opsinitiated = 0;
288                         c[ns].c_opscompleted = 0;
289                 }
290                 pthread_mutex_unlock( &new_conn_mutex );
291
292                 Debug( LDAP_DEBUG_CONNS, "activity on:", 0, 0, 0 );
293                 for ( i = 0; i < dtblsize; i++ ) {
294                         int     r, w;
295
296                         r = FD_ISSET( i, &readfds );
297                         w = FD_ISSET( i, &writefds );
298                         if ( i != tcps && (r || w) ) {
299                                 Debug( LDAP_DEBUG_CONNS, " %d%s%s", i,
300                                     r ? "r" : "", w ? "w" : "" );
301                         }
302                 }
303                 Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 );
304
305                 for ( i = 0; i < dtblsize; i++ ) {
306                         if ( i == tcps || (! FD_ISSET( i, &readfds ) &&
307                             ! FD_ISSET( i, &writefds )) ) {
308                                 continue;
309                         }
310
311                         if ( FD_ISSET( i, &writefds ) ) {
312                                 Debug( LDAP_DEBUG_CONNS,
313                                     "signaling write waiter on %d\n", i, 0, 0 );
314
315                                 pthread_mutex_lock( &active_threads_mutex );
316                                 pthread_cond_signal( &c[i].c_wcv );
317                                 c[i].c_writewaiter = 0;
318                                 active_threads++;
319                                 pthread_mutex_unlock( &active_threads_mutex );
320                         }
321
322                         if ( FD_ISSET( i, &readfds ) ) {
323                                 Debug( LDAP_DEBUG_CONNS,
324                                     "read activity on %d\n", i, 0, 0 );
325
326                                 connection_activity( &c[i] );
327                         }
328                 }
329
330                 pthread_yield();
331         }
332
333         close( tcps );
334         pthread_mutex_lock( &active_threads_mutex );
335         Debug( LDAP_DEBUG_ANY,
336             "slapd shutting down - waiting for %d threads to terminate\n",
337             active_threads, 0, 0 );
338         while ( active_threads > 0 ) {
339                 pthread_mutex_unlock( &active_threads_mutex );
340                 pthread_yield();
341                 pthread_mutex_lock( &active_threads_mutex );
342         }
343         pthread_mutex_unlock( &active_threads_mutex );
344
345         /* let backends do whatever cleanup they need to do */
346         Debug( LDAP_DEBUG_TRACE,
347             "slapd shutting down - waiting for backends to close down\n", 0, 0,
348             0 );
349         be_close();
350         Debug( LDAP_DEBUG_ANY, "slapd stopping\n", 0, 0, 0 );
351 }
352
353 static void
354 set_shutdown()
355 {
356         Debug( LDAP_DEBUG_ANY, "slapd got shutdown signal\n", 0, 0, 0 );
357         slapd_shutdown = 1;
358         pthread_kill( listener_tid, SIGUSR1 );
359         (void) SIGNAL( SIGUSR2, (void *) set_shutdown );
360         (void) SIGNAL( SIGTERM, (void *) set_shutdown );
361         (void) SIGNAL( SIGINT, (void *) set_shutdown );
362         (void) SIGNAL( SIGHUP, (void *) set_shutdown );
363 }
364
365 static void
366 do_nothing()
367 {
368         Debug( LDAP_DEBUG_TRACE, "slapd got SIGUSR1\n", 0, 0, 0 );
369         (void) SIGNAL( SIGUSR1, (void *) do_nothing );
370 }