]> git.sur5r.net Git - openldap/blob - servers/slapd/daemon.c
Initial revision
[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         c = (Connection *) ch_calloc( 1, dtblsize * sizeof(Connection) );
73
74         for ( i = 0; i < dtblsize; i++ ) {
75                 c[i].c_dn = NULL;
76                 c[i].c_addr = NULL;
77                 c[i].c_domain = NULL;
78                 c[i].c_ops = NULL;
79                 c[i].c_sb.sb_sd = -1;
80                 c[i].c_sb.sb_options = LBER_NO_READ_AHEAD;
81                 c[i].c_sb.sb_naddr = 0;
82                 c[i].c_sb.sb_ber.ber_buf = NULL;
83                 c[i].c_sb.sb_ber.ber_ptr = NULL;
84                 c[i].c_sb.sb_ber.ber_end = NULL;
85                 c[i].c_writewaiter = 0;
86                 c[i].c_connid = 0;
87                 pthread_mutex_init( &c[i].c_dnmutex,
88                     pthread_mutexattr_default );
89                 pthread_mutex_init( &c[i].c_opsmutex,
90                     pthread_mutexattr_default );
91                 pthread_mutex_init( &c[i].c_pdumutex,
92                     pthread_mutexattr_default );
93                 pthread_cond_init( &c[i].c_wcv, pthread_condattr_default );
94         }
95
96         if ( (tcps = socket( AF_INET, SOCK_STREAM, 0 )) == -1 ) {
97                 Debug( LDAP_DEBUG_ANY, "socket() failed errno %d (%s)", errno,
98                     errno > -1 && errno < sys_nerr ? sys_errlist[errno] :
99                     "unknown", 0 );
100                 exit( 1 );
101         }
102
103         i = 1;
104         if ( setsockopt( tcps, SOL_SOCKET, SO_REUSEADDR, (char *) &i,
105             sizeof(i) ) == -1 ) {
106                 Debug( LDAP_DEBUG_ANY, "setsockopt() failed errno %d (%s)",
107                     errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] :
108                     "unknown", 0 );
109         }
110
111         (void) memset( (void *) &addr, '\0', sizeof(addr) );
112         addr.sin_family = AF_INET;
113         addr.sin_addr.s_addr = INADDR_ANY;
114         addr.sin_port = htons( port );
115         if ( bind( tcps, (struct sockaddr *) &addr, sizeof(addr) ) == -1 ) {
116                 Debug( LDAP_DEBUG_ANY, "bind() failed errno %d (%s)\n",
117                     errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] :
118                     "unknown", 0 );
119                 exit( 1 );
120         }
121
122         if ( listen( tcps, 5 ) == -1 ) {
123                 Debug( LDAP_DEBUG_ANY, "listen() failed errno %d (%s)",
124                     errno, errno > -1 && errno < sys_nerr ? sys_errlist[errno] :
125                     "unknown", 0 );
126                 exit( 1 );
127         }
128
129         (void) SIGNAL( SIGPIPE, SIG_IGN );
130         (void) SIGNAL( SIGUSR1, (void *) do_nothing );
131         (void) SIGNAL( SIGUSR2, (void *) set_shutdown );
132         (void) SIGNAL( SIGTERM, (void *) set_shutdown );
133         (void) SIGNAL( SIGHUP, (void *) set_shutdown );
134
135         Debug( LDAP_DEBUG_ANY, "slapd starting\n", 0, 0, 0 );
136 #ifdef SLAPD_PIDFILE
137         if ( (fp = fopen( SLAPD_PIDFILE, "w" )) != NULL ) {
138                 fprintf( fp, "%d\n", getpid() );
139                 fclose( fp );
140         }
141 #endif
142 #ifdef SLAPD_ARGSFILE
143         if ( (fp = fopen( SLAPD_ARGSFILE, "w" )) != NULL ) {
144                 for ( i = 0; i < g_argc; i++ ) {
145                         fprintf( fp, "%s ", g_argv[i] );
146                 }
147                 fprintf( fp, "\n" );
148                 fclose( fp );
149         }
150 #endif
151
152         while ( !slapd_shutdown ) {
153                 struct sockaddr_in      from;
154                 struct hostent          *hp;
155                 struct timeval          zero;
156                 struct timeval          *tvp;
157                 int                     len, pid;
158
159                 FD_ZERO( &writefds );
160                 FD_ZERO( &readfds );
161                 FD_SET( tcps, &readfds );
162
163                 pthread_mutex_lock( &active_threads_mutex );
164                 Debug( LDAP_DEBUG_CONNS,
165                     "listening for connections on %d, activity on:",
166                     tcps, 0, 0 );
167                 for ( i = 0; i < dtblsize; i++ ) {
168                         if ( c[i].c_sb.sb_sd != -1 ) {
169                                 FD_SET( c[i].c_sb.sb_sd, &readfds );
170
171                                 if ( c[i].c_writewaiter ) {
172                                         FD_SET( c[i].c_sb.sb_sd, &writefds );
173                                 }
174                                 Debug( LDAP_DEBUG_CONNS, " %dr%s", i,
175                                     c[i].c_writewaiter ? "w" : "", 0 );
176                         }
177                 }
178                 Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 );
179
180                 zero.tv_sec = 0;
181                 zero.tv_usec = 0;
182                 Debug( LDAP_DEBUG_CONNS, "before select active_threads %d\n",
183                     active_threads, 0, 0 );
184 #ifdef PTHREAD_PREEMPTIVE
185                 tvp = NULL;
186 #else
187                 tvp = active_threads ? &zero : NULL;
188 #endif
189                 pthread_mutex_unlock( &active_threads_mutex );
190
191                 switch ( select( dtblsize, &readfds, &writefds, 0, tvp ) ) {
192                 case -1:        /* failure - try again */
193                         Debug( LDAP_DEBUG_CONNS,
194                             "select failed errno %d (%s)\n",
195                             errno, errno > -1 && errno < sys_nerr ?
196                             sys_errlist[errno] : "unknown", 0 );
197                         continue;
198
199                 case 0:         /* timeout - let threads run */
200                         Debug( LDAP_DEBUG_CONNS, "select timeout - yielding\n",
201                             0, 0, 0 );
202                         pthread_yield();
203                         continue;
204
205                 default:        /* something happened - deal with it */
206                         Debug( LDAP_DEBUG_CONNS, "select activity\n", 0, 0, 0 );
207                         ;       /* FALL */
208                 }
209                 pthread_mutex_lock( &currenttime_mutex );
210                 time( &currenttime );
211                 pthread_mutex_unlock( &currenttime_mutex );
212
213                 /* new connection */
214                 pthread_mutex_lock( &new_conn_mutex );
215                 if ( FD_ISSET( tcps, &readfds ) ) {
216                         len = sizeof(from);
217                         if ( (ns = accept( tcps, (struct sockaddr *) &from,
218                             &len )) == -1 ) {
219                                 Debug( LDAP_DEBUG_ANY,
220                                     "accept() failed errno %d (%s)", errno,
221                                     errno > -1 && errno < sys_nerr ?
222                                     sys_errlist[errno] : "unknown", 0 );
223                                 pthread_mutex_unlock( &new_conn_mutex );
224                                 continue;
225                         }
226                         if ( ioctl( ns, FIONBIO, (caddr_t) &on ) == -1 ) {
227                                 Debug( LDAP_DEBUG_ANY,
228                                     "FIONBIO ioctl on %d faled\n", ns, 0, 0 );
229                         }
230                         c[ns].c_sb.sb_sd = ns;
231                         Debug( LDAP_DEBUG_CONNS, "new connection on %d\n", ns,
232                             0, 0 );
233
234                         pthread_mutex_lock( &ops_mutex );
235                         c[ns].c_connid = num_conns++;
236                         pthread_mutex_unlock( &ops_mutex );
237                         len = sizeof(from);
238                         if ( getpeername( ns, (struct sockaddr *) &from, &len )
239                             == 0 ) {
240                                 char    *s;
241 #ifdef REVERSE_LOOKUP
242                                 hp = gethostbyaddr( (char *)
243                                     &(from.sin_addr.s_addr),
244                                     sizeof(from.sin_addr.s_addr), AF_INET );
245 #else
246                                 hp = NULL;
247 #endif
248
249                                 Statslog( LDAP_DEBUG_STATS,
250                                     "conn=%d fd=%d connection from %s (%s)\n",
251                                     c[ns].c_connid, ns, hp == NULL ? "unknown"
252                                     : hp->h_name, inet_ntoa( from.sin_addr ),
253                                     0 );
254
255                                 if ( c[ns].c_addr != NULL ) {
256                                         free( c[ns].c_addr );
257                                 }
258                                 c[ns].c_addr = strdup( inet_ntoa(
259                                     from.sin_addr ) );
260                                 if ( c[ns].c_domain != NULL ) {
261                                         free( c[ns].c_domain );
262                                 }
263                                 c[ns].c_domain = strdup( hp == NULL ? "" :
264                                     hp->h_name );
265                                 /* normalize the domain */
266                                 for ( s = c[ns].c_domain; *s; s++ ) {
267                                         *s = TOLOWER( *s );
268                                 }
269                         } else {
270                                 Statslog( LDAP_DEBUG_STATS,
271                                     "conn=%d fd=%d connection from unknown\n",
272                                     c[ns].c_connid, ns, 0, 0, 0 );
273                         }
274                         pthread_mutex_lock( &c[ns].c_dnmutex );
275                         if ( c[ns].c_dn != NULL ) {
276                                 free( c[ns].c_dn );
277                                 c[ns].c_dn = NULL;
278                         }
279                         pthread_mutex_unlock( &c[ns].c_dnmutex );
280                         c[ns].c_starttime = currenttime;
281                         c[ns].c_opsinitiated = 0;
282                         c[ns].c_opscompleted = 0;
283                 }
284                 pthread_mutex_unlock( &new_conn_mutex );
285
286                 Debug( LDAP_DEBUG_CONNS, "activity on:", 0, 0, 0 );
287                 for ( i = 0; i < dtblsize; i++ ) {
288                         int     r, w;
289
290                         r = FD_ISSET( i, &readfds );
291                         w = FD_ISSET( i, &writefds );
292                         if ( i != tcps && (r || w) ) {
293                                 Debug( LDAP_DEBUG_CONNS, " %d%s%s", i,
294                                     r ? "r" : "", w ? "w" : "" );
295                         }
296                 }
297                 Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 );
298
299                 for ( i = 0; i < dtblsize; i++ ) {
300                         if ( i == tcps || (! FD_ISSET( i, &readfds ) &&
301                             ! FD_ISSET( i, &writefds )) ) {
302                                 continue;
303                         }
304
305                         if ( FD_ISSET( i, &writefds ) ) {
306                                 Debug( LDAP_DEBUG_CONNS,
307                                     "signaling write waiter on %d\n", i, 0, 0 );
308
309                                 pthread_mutex_lock( &active_threads_mutex );
310                                 pthread_cond_signal( &c[i].c_wcv );
311                                 c[i].c_writewaiter = 0;
312                                 active_threads++;
313                                 pthread_mutex_unlock( &active_threads_mutex );
314                         }
315
316                         if ( FD_ISSET( i, &readfds ) ) {
317                                 Debug( LDAP_DEBUG_CONNS,
318                                     "read activity on %d\n", i, 0, 0 );
319
320                                 connection_activity( &c[i] );
321                         }
322                 }
323
324                 pthread_yield();
325         }
326
327         close( tcps );
328         pthread_mutex_lock( &active_threads_mutex );
329         Debug( LDAP_DEBUG_ANY,
330             "slapd shutting down - waiting for %d threads to terminate\n",
331             active_threads, 0, 0 );
332         while ( active_threads > 0 ) {
333                 pthread_mutex_unlock( &active_threads_mutex );
334                 pthread_yield();
335                 pthread_mutex_lock( &active_threads_mutex );
336         }
337         pthread_mutex_unlock( &active_threads_mutex );
338
339         /* let backends do whatever cleanup they need to do */
340         Debug( LDAP_DEBUG_TRACE,
341             "slapd shutting down - waiting for backends to close down\n", 0, 0,
342             0 );
343         be_close();
344         Debug( LDAP_DEBUG_ANY, "slapd stopping\n", 0, 0, 0 );
345 }
346
347 static void
348 set_shutdown()
349 {
350         Debug( LDAP_DEBUG_ANY, "slapd got shutdown signal\n", 0, 0, 0 );
351         slapd_shutdown = 1;
352         pthread_kill( listener_tid, SIGUSR1 );
353         (void) SIGNAL( SIGUSR2, (void *) set_shutdown );
354         (void) SIGNAL( SIGTERM, (void *) set_shutdown );
355         (void) SIGNAL( SIGHUP, (void *) set_shutdown );
356 }
357
358 static void
359 do_nothing()
360 {
361         Debug( LDAP_DEBUG_TRACE, "slapd got SIGUSR1\n", 0, 0, 0 );
362         (void) SIGNAL( SIGUSR1, (void *) do_nothing );
363 }