Begun implimentation of a really good thread control interface.
[citadel.git] / citadel / sysdep.c
1 /*
2  * $Id$
3  *
4  * Citadel "system dependent" stuff.
5  * See copyright.txt for copyright information.
6  *
7  * Here's where we (hopefully) have most parts of the Citadel server that
8  * would need to be altered to run the server in a non-POSIX environment.
9  * 
10  * If we ever port to a different platform and either have multiple
11  * variants of this file or simply load it up with #ifdefs.
12  *
13  */
14
15 #include "sysdep.h"
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <stdio.h>
19 #include <fcntl.h>
20 #include <ctype.h>
21 #include <signal.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <sys/wait.h>
25 #include <sys/socket.h>
26 #include <syslog.h>
27 #include <sys/syslog.h>
28
29 #if TIME_WITH_SYS_TIME
30 # include <sys/time.h>
31 # include <time.h>
32 #else
33 # if HAVE_SYS_TIME_H
34 #  include <sys/time.h>
35 # else
36 #  include <time.h>
37 # endif
38 #endif
39
40 #include <limits.h>
41 #include <sys/resource.h>
42 #include <netinet/in.h>
43 #include <netinet/tcp.h>
44 #include <arpa/inet.h>
45 #include <netdb.h>
46 #include <sys/un.h>
47 #include <string.h>
48 #include <pwd.h>
49 #include <errno.h>
50 #include <stdarg.h>
51 #include <grp.h>
52 #ifdef HAVE_PTHREAD_H
53 #include <pthread.h>
54 #endif
55 #include <libcitadel.h>
56 #include "citadel.h"
57 #include "server.h"
58 #include "sysdep_decls.h"
59 #include "citserver.h"
60 #include "support.h"
61 #include "config.h"
62 #include "database.h"
63 #include "housekeeping.h"
64 #include "modules/crypto/serv_crypto.h" /* Needed for init_ssl, client_write_ssl, client_read_ssl, destruct_ssl */
65 #include "ecrash.h"
66
67 #ifdef HAVE_SYS_SELECT_H
68 #include <sys/select.h>
69 #endif
70
71 #ifndef HAVE_SNPRINTF
72 #include "snprintf.h"
73 #endif
74
75
76 #ifdef DEBUG_MEMORY_LEAKS
77 struct igheap {
78         struct igheap *next;
79         char file[32];
80         int line;
81         void *block;
82 };
83
84 struct igheap *igheap = NULL;
85 #endif
86
87
88 pthread_mutex_t Critters[MAX_SEMAPHORES];       /* Things needing locking */
89 pthread_key_t MyConKey;                         /* TSD key for MyContext() */
90
91 int verbosity = DEFAULT_VERBOSITY;              /* Logging level */
92
93 struct CitContext masterCC;
94 time_t last_purge = 0;                          /* Last dead session purge */
95 static int num_threads = 0;                     /* Current number of threads */
96 int num_sessions = 0;                           /* Current number of sessions */
97
98 int syslog_facility = LOG_DAEMON;
99 int enable_syslog = 0;
100
101 void DestroyWorkerList(void);
102
103
104 /*
105  * Create an interface to lprintf that follows the coding convention.
106  * This is here until such time as we have replaced all calls to lprintf with CtdlLogPrintf
107  */
108  
109 void CtdlLogPrintf(enum LogLevel loglevel, const char *format, ...)
110 {
111         va_list arg_ptr;
112         va_start(arg_ptr, format);
113         vlprintf(loglevel, format, arg_ptr);
114         va_end(arg_ptr);
115 }
116
117
118 /*
119  * lprintf()  ...   Write logging information
120  */
121 void lprintf(enum LogLevel loglevel, const char *format, ...) {   
122         va_list arg_ptr;
123         va_start(arg_ptr, format);
124         vlprintf(loglevel, format, arg_ptr);
125         va_end(arg_ptr);
126 }
127
128 void vlprintf(enum LogLevel loglevel, const char *format, va_list arg_ptr)
129 {
130         char buf[SIZ], buf2[SIZ];
131
132         if (enable_syslog) {
133                 vsyslog((syslog_facility | loglevel), format, arg_ptr);
134         }
135
136         /* stderr output code */
137         if (enable_syslog || running_as_daemon) return;
138
139         /* if we run in forground and syslog is disabled, log to terminal */
140         if (loglevel <= verbosity) { 
141                 struct timeval tv;
142                 struct tm tim;
143                 time_t unixtime;
144
145                 gettimeofday(&tv, NULL);
146                 /* Promote to time_t; types differ on some OSes (like darwin) */
147                 unixtime = tv.tv_sec;
148                 localtime_r(&unixtime, &tim);
149                 if (CC->cs_pid != 0) {
150                         sprintf(buf,
151                                 "%04d/%02d/%02d %2d:%02d:%02d.%06ld [%3d] ",
152                                 tim.tm_year + 1900, tim.tm_mon + 1,
153                                 tim.tm_mday, tim.tm_hour, tim.tm_min,
154                                 tim.tm_sec, (long)tv.tv_usec,
155                                 CC->cs_pid);
156                 } else {
157                         sprintf(buf,
158                                 "%04d/%02d/%02d %2d:%02d:%02d.%06ld ",
159                                 tim.tm_year + 1900, tim.tm_mon + 1,
160                                 tim.tm_mday, tim.tm_hour, tim.tm_min,
161                                 tim.tm_sec, (long)tv.tv_usec);
162                 }
163                 vsprintf(buf2, format, arg_ptr);   
164
165                 fprintf(stderr, "%s%s", buf, buf2);
166                 fflush(stderr);
167         }
168 }   
169
170
171
172 /*
173  * Signal handler to shut down the server.
174  */
175
176 volatile int time_to_die = 0;
177 volatile int shutdown_and_halt = 0;
178 volatile int restart_server = 0;
179 volatile int running_as_daemon = 0;
180
181 static RETSIGTYPE signal_cleanup(int signum) {
182         lprintf(CTDL_DEBUG, "Caught signal %d; shutting down.\n", signum);
183         time_to_die = 1;
184         master_cleanup(signum);
185 }
186
187
188
189
190 void InitialiseSemaphores(void)
191 {
192         int i;
193
194         /* Set up a bunch of semaphores to be used for critical sections */
195         for (i=0; i<MAX_SEMAPHORES; ++i) {
196                 pthread_mutex_init(&Critters[i], NULL);
197         }
198 }
199
200
201
202 /*
203  * Some initialization stuff...
204  */
205 void init_sysdep(void) {
206         sigset_t set;
207
208         /* Avoid vulnerabilities related to FD_SETSIZE if we can. */
209 #ifdef FD_SETSIZE
210 #ifdef RLIMIT_NOFILE
211         struct rlimit rl;
212         getrlimit(RLIMIT_NOFILE, &rl);
213         rl.rlim_cur = FD_SETSIZE;
214         rl.rlim_max = FD_SETSIZE;
215         setrlimit(RLIMIT_NOFILE, &rl);
216 #endif
217 #endif
218
219         /* If we've got OpenSSL, we're going to use it. */
220 #ifdef HAVE_OPENSSL
221         init_ssl();
222 #endif
223
224         /*
225          * Set up a place to put thread-specific data.
226          * We only need a single pointer per thread - it points to the
227          * CitContext structure (in the ContextList linked list) of the
228          * session to which the calling thread is currently bound.
229          */
230         if (pthread_key_create(&MyConKey, NULL) != 0) {
231                 lprintf(CTDL_CRIT, "Can't create TSD key: %s\n",
232                         strerror(errno));
233         }
234
235         /*
236          * The action for unexpected signals and exceptions should be to
237          * call signal_cleanup() to gracefully shut down the server.
238          */
239         sigemptyset(&set);
240         sigaddset(&set, SIGINT);
241         sigaddset(&set, SIGQUIT);
242         sigaddset(&set, SIGHUP);
243         sigaddset(&set, SIGTERM);
244         // sigaddset(&set, SIGSEGV);    commented out because
245         // sigaddset(&set, SIGILL);     we want core dumps
246         // sigaddset(&set, SIGBUS);
247         sigprocmask(SIG_UNBLOCK, &set, NULL);
248
249         signal(SIGINT, signal_cleanup);
250         signal(SIGQUIT, signal_cleanup);
251         signal(SIGHUP, signal_cleanup);
252         signal(SIGTERM, signal_cleanup);
253         // signal(SIGSEGV, signal_cleanup);     commented out because
254         // signal(SIGILL, signal_cleanup);      we want core dumps
255         // signal(SIGBUS, signal_cleanup);
256
257         /*
258          * Do not shut down the server on broken pipe signals, otherwise the
259          * whole Citadel service would come down whenever a single client
260          * socket breaks.
261          */
262         signal(SIGPIPE, SIG_IGN);
263 }
264
265
266 /*
267  * Obtain a semaphore lock to begin a critical section.
268  */
269 void begin_critical_section(int which_one)
270 {
271         /* lprintf(CTDL_DEBUG, "begin_critical_section(%d)\n", which_one); */
272
273         /* For all types of critical sections except those listed here,
274          * ensure nobody ever tries to do a critical section within a
275          * transaction; this could lead to deadlock.
276          */
277         if (    (which_one != S_FLOORCACHE)
278 #ifdef DEBUG_MEMORY_LEAKS
279                 && (which_one != S_DEBUGMEMLEAKS)
280 #endif
281                 && (which_one != S_RPLIST)
282         ) {
283                 cdb_check_handles();
284         }
285         pthread_mutex_lock(&Critters[which_one]);
286 }
287
288 /*
289  * Release a semaphore lock to end a critical section.
290  */
291 void end_critical_section(int which_one)
292 {
293         pthread_mutex_unlock(&Critters[which_one]);
294 }
295
296
297
298 /*
299  * This is a generic function to set up a master socket for listening on
300  * a TCP port.  The server shuts down if the bind fails.
301  *
302  */
303 int ig_tcp_server(char *ip_addr, int port_number, int queue_len, char **errormessage)
304 {
305         struct sockaddr_in sin;
306         int s, i;
307         int actual_queue_len;
308
309         actual_queue_len = queue_len;
310         if (actual_queue_len < 5) actual_queue_len = 5;
311
312         memset(&sin, 0, sizeof(sin));
313         sin.sin_family = AF_INET;
314         sin.sin_port = htons((u_short)port_number);
315         if (ip_addr == NULL) {
316                 sin.sin_addr.s_addr = INADDR_ANY;
317         }
318         else {
319                 sin.sin_addr.s_addr = inet_addr(ip_addr);
320         }
321                                                                                 
322         if (sin.sin_addr.s_addr == !INADDR_ANY) {
323                 sin.sin_addr.s_addr = INADDR_ANY;
324         }
325
326         s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
327
328         if (s < 0) {
329                 *errormessage = (char*) malloc(SIZ + 1);
330                 snprintf(*errormessage, SIZ, 
331                                  "citserver: Can't create a socket: %s",
332                                  strerror(errno));
333                 lprintf(CTDL_EMERG, "%s\n", *errormessage);
334                 return(-1);
335         }
336
337         i = 1;
338         setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
339
340         if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
341                 *errormessage = (char*) malloc(SIZ + 1);
342                 snprintf(*errormessage, SIZ, 
343                                  "citserver: Can't bind: %s",
344                                  strerror(errno));
345                 lprintf(CTDL_EMERG, "%s\n", *errormessage);
346                 close(s);
347                 return(-1);
348         }
349
350         /* set to nonblock - we need this for some obscure situations */
351         if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) {
352                 *errormessage = (char*) malloc(SIZ + 1);
353                 snprintf(*errormessage, SIZ, 
354                                  "citserver: Can't set socket to non-blocking: %s",
355                                  strerror(errno));
356                 lprintf(CTDL_EMERG, "%s\n", *errormessage);
357                 close(s);
358                 return(-1);
359         }
360
361         if (listen(s, actual_queue_len) < 0) {
362                 *errormessage = (char*) malloc(SIZ + 1);
363                 snprintf(*errormessage, SIZ, 
364                                  "citserver: Can't listen: %s",
365                                  strerror(errno));
366                 lprintf(CTDL_EMERG, "%s\n", *errormessage);
367                 close(s);
368                 return(-1);
369         }
370
371         return(s);
372 }
373
374
375
376 /*
377  * Create a Unix domain socket and listen on it
378  */
379 int ig_uds_server(char *sockpath, int queue_len, char **errormessage)
380 {
381         struct sockaddr_un addr;
382         int s;
383         int i;
384         int actual_queue_len;
385
386         actual_queue_len = queue_len;
387         if (actual_queue_len < 5) actual_queue_len = 5;
388
389         i = unlink(sockpath);
390         if (i != 0) if (errno != ENOENT) {
391                 *errormessage = (char*) malloc(SIZ + 1);
392                 snprintf(*errormessage, SIZ, "citserver: can't unlink %s: %s",
393                         sockpath, strerror(errno));
394                 lprintf(CTDL_EMERG, "%s\n", *errormessage);
395                 return(-1);
396         }
397
398         memset(&addr, 0, sizeof(addr));
399         addr.sun_family = AF_UNIX;
400         safestrncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
401
402         s = socket(AF_UNIX, SOCK_STREAM, 0);
403         if (s < 0) {
404                 *errormessage = (char*) malloc(SIZ + 1);
405                 snprintf(*errormessage, SIZ, 
406                          "citserver: Can't create a socket: %s",
407                          strerror(errno));
408                 lprintf(CTDL_EMERG, "%s\n", *errormessage);
409                 return(-1);
410         }
411
412         if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
413                 *errormessage = (char*) malloc(SIZ + 1);
414                 snprintf(*errormessage, SIZ, 
415                          "citserver: Can't bind: %s",
416                          strerror(errno));
417                 lprintf(CTDL_EMERG, "%s\n", *errormessage);
418                 return(-1);
419         }
420
421         /* set to nonblock - we need this for some obscure situations */
422         if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) {
423                 *errormessage = (char*) malloc(SIZ + 1);
424                 snprintf(*errormessage, SIZ, 
425                          "citserver: Can't set socket to non-blocking: %s",
426                          strerror(errno));
427                 lprintf(CTDL_EMERG, "%s\n", *errormessage);
428                 close(s);
429                 return(-1);
430         }
431
432         if (listen(s, actual_queue_len) < 0) {
433                 *errormessage = (char*) malloc(SIZ + 1);
434                 snprintf(*errormessage, SIZ, 
435                          "citserver: Can't listen: %s",
436                          strerror(errno));
437                 lprintf(CTDL_EMERG, "%s\n", *errormessage);
438                 return(-1);
439         }
440
441         chmod(sockpath, S_ISGID|S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
442         return(s);
443 }
444
445
446
447 /*
448  * Return a pointer to the CitContext structure bound to the thread which
449  * called this function.  If there's no such binding (for example, if it's
450  * called by the housekeeper thread) then a generic 'master' CC is returned.
451  *
452  * This function is used *VERY* frequently and must be kept small.
453  */
454 struct CitContext *MyContext(void) {
455
456         register struct CitContext *c;
457
458         return ((c = (struct CitContext *) pthread_getspecific(MyConKey),
459                 c == NULL) ? &masterCC : c
460         );
461 }
462
463
464 /*
465  * Initialize a new context and place it in the list.  The session number
466  * used to be the PID (which is why it's called cs_pid), but that was when we
467  * had one process per session.  Now we just assign them sequentially, starting
468  * at 1 (don't change it to 0 because masterCC uses 0).
469  */
470 struct CitContext *CreateNewContext(void) {
471         struct CitContext *me;
472         static int next_pid = 0;
473
474         me = (struct CitContext *) malloc(sizeof(struct CitContext));
475         if (me == NULL) {
476                 lprintf(CTDL_ALERT, "citserver: can't allocate memory!!\n");
477                 return NULL;
478         }
479         memset(me, 0, sizeof(struct CitContext));
480
481         /* The new context will be created already in the CON_EXECUTING state
482          * in order to prevent another thread from grabbing it while it's
483          * being set up.
484          */
485         me->state = CON_EXECUTING;
486
487         /*
488          * Generate a unique session number and insert this context into
489          * the list.
490          */
491         begin_critical_section(S_SESSION_TABLE);
492         me->cs_pid = ++next_pid;
493         me->prev = NULL;
494         me->next = ContextList;
495         ContextList = me;
496         if (me->next != NULL) {
497                 me->next->prev = me;
498         }
499         ++num_sessions;
500         end_critical_section(S_SESSION_TABLE);
501         return(me);
502 }
503
504
505 /*
506  * The following functions implement output buffering. If the kernel supplies
507  * native TCP buffering (Linux & *BSD), use that; otherwise, emulate it with
508  * user-space buffering.
509  */
510 #ifndef HAVE_DARWIN
511 #ifdef TCP_CORK
512 #       define HAVE_TCP_BUFFERING
513 #else
514 #       ifdef TCP_NOPUSH
515 #               define HAVE_TCP_BUFFERING
516 #               define TCP_CORK TCP_NOPUSH
517 #       endif
518 #endif /* TCP_CORK */
519 #endif /* HAVE_DARWIN */
520
521 #ifdef HAVE_TCP_BUFFERING
522 static unsigned on = 1, off = 0;
523 void buffer_output(void) {
524         struct CitContext *ctx = MyContext();
525         setsockopt(ctx->client_socket, IPPROTO_TCP, TCP_CORK, &on, 4);
526         ctx->buffering = 1;
527 }
528
529 void unbuffer_output(void) {
530         struct CitContext *ctx = MyContext();
531         setsockopt(ctx->client_socket, IPPROTO_TCP, TCP_CORK, &off, 4);
532         ctx->buffering = 0;
533 }
534
535 void flush_output(void) {
536         struct CitContext *ctx = MyContext();
537         setsockopt(ctx->client_socket, IPPROTO_TCP, TCP_CORK, &off, 4);
538         setsockopt(ctx->client_socket, IPPROTO_TCP, TCP_CORK, &on, 4);
539 }
540 #else 
541 #ifdef HAVE_DARWIN
542 /* Stub functions for Darwin/OS X where TCP buffering isn't liked at all */
543 void buffer_output(void) {
544         CC->buffering = 0;
545 }
546 void unbuffer_output(void) {
547         CC->buffering = 0;
548 }
549 void flush_output(void) {
550 }
551 #else
552 void buffer_output(void) {
553         if (CC->buffering == 0) {
554                 CC->buffering = 1;
555                 CC->buffer_len = 0;
556                 CC->output_buffer = malloc(SIZ);
557         }
558 }
559
560 void flush_output(void) {
561         if (CC->buffering == 1) {
562                 client_write(CC->output_buffer, CC->buffer_len);
563                 CC->buffer_len = 0;
564         }
565 }
566
567 void unbuffer_output(void) {
568         if (CC->buffering == 1) {
569                 CC->buffering = 0;
570                 /* We don't call flush_output because we can't. */
571                 client_write(CC->output_buffer, CC->buffer_len);
572                 CC->buffer_len = 0;
573                 free(CC->output_buffer);
574                 CC->output_buffer = NULL;
575         }
576 }
577 #endif /* HAVE_DARWIN */
578 #endif /* HAVE_TCP_BUFFERING */
579
580
581
582 /*
583  * client_write()   ...    Send binary data to the client.
584  */
585 void client_write(char *buf, int nbytes)
586 {
587         int bytes_written = 0;
588         int retval;
589 #ifndef HAVE_TCP_BUFFERING
590         int old_buffer_len = 0;
591 #endif
592         t_context *Ctx;
593
594         Ctx = CC;
595         if (Ctx->redirect_buffer != NULL) {
596                 if ((Ctx->redirect_len + nbytes + 2) >= Ctx->redirect_alloc) {
597                         Ctx->redirect_alloc = (Ctx->redirect_alloc * 2) + nbytes;
598                         Ctx->redirect_buffer = realloc(Ctx->redirect_buffer,
599                                                 Ctx->redirect_alloc);
600                 }
601                 memcpy(&Ctx->redirect_buffer[Ctx->redirect_len], buf, nbytes);
602                 Ctx->redirect_len += nbytes;
603                 Ctx->redirect_buffer[Ctx->redirect_len] = 0;
604                 return;
605         }
606
607 #ifndef HAVE_TCP_BUFFERING
608         /* If we're buffering for later, do that now. */
609         if (Ctx->buffering) {
610                 old_buffer_len = Ctx->buffer_len;
611                 Ctx->buffer_len += nbytes;
612                 Ctx->output_buffer = realloc(Ctx->output_buffer, Ctx->buffer_len);
613                 memcpy(&Ctx->output_buffer[old_buffer_len], buf, nbytes);
614                 return;
615         }
616 #endif
617
618         /* Ok, at this point we're not buffering.  Go ahead and write. */
619
620 #ifdef HAVE_OPENSSL
621         if (Ctx->redirect_ssl) {
622                 client_write_ssl(buf, nbytes);
623                 return;
624         }
625 #endif
626
627         while (bytes_written < nbytes) {
628                 retval = write(Ctx->client_socket, &buf[bytes_written],
629                         nbytes - bytes_written);
630                 if (retval < 1) {
631                         lprintf(CTDL_ERR,
632                                 "client_write(%d bytes) failed: %s (%d)\n",
633                                 nbytes - bytes_written,
634                                 strerror(errno), errno);
635                         cit_backtrace();
636                         // lprintf(CTDL_DEBUG, "Tried to send: %s",  &buf[bytes_written]);
637                         Ctx->kill_me = 1;
638                         return;
639                 }
640                 bytes_written = bytes_written + retval;
641         }
642 }
643
644
645 /*
646  * cprintf()  ...   Send formatted printable data to the client.   It is
647  *                implemented in terms of client_write() but remains in
648  *                sysdep.c in case we port to somewhere without va_args...
649  */
650 void cprintf(const char *format, ...) {   
651         va_list arg_ptr;   
652         char buf[1024];   
653    
654         va_start(arg_ptr, format);   
655         if (vsnprintf(buf, sizeof buf, format, arg_ptr) == -1)
656                 buf[sizeof buf - 2] = '\n';
657         client_write(buf, strlen(buf)); 
658         va_end(arg_ptr);
659 }   
660
661
662 /*
663  * Read data from the client socket.
664  * Return values are:
665  *      1       Requested number of bytes has been read.
666  *      0       Request timed out.
667  *      -1      The socket is broken.
668  * If the socket breaks, the session will be terminated.
669  */
670 int client_read_to(char *buf, int bytes, int timeout)
671 {
672         int len,rlen;
673         fd_set rfds;
674         int fd;
675         struct timeval tv;
676         int retval;
677
678 #ifdef HAVE_OPENSSL
679         if (CC->redirect_ssl) {
680                 return (client_read_ssl(buf, bytes, timeout));
681         }
682 #endif
683         len = 0;
684         fd = CC->client_socket;
685         while(len<bytes) {
686                 FD_ZERO(&rfds);
687                 FD_SET(fd, &rfds);
688                 tv.tv_sec = timeout;
689                 tv.tv_usec = 0;
690
691                 retval = select( (fd)+1, 
692                                  &rfds, NULL, NULL, &tv);
693
694                 if (FD_ISSET(fd, &rfds) == 0) {
695                         return(0);
696                 }
697
698                 rlen = read(fd, &buf[len], bytes-len);
699                 if (rlen<1) {
700                         /* The socket has been disconnected! */
701                         CC->kill_me = 1;
702                         return(-1);
703                 }
704                 len = len + rlen;
705         }
706         return(1);
707 }
708
709 /*
710  * Read data from the client socket with default timeout.
711  * (This is implemented in terms of client_read_to() and could be
712  * justifiably moved out of sysdep.c)
713  */
714 INLINE int client_read(char *buf, int bytes)
715 {
716         return(client_read_to(buf, bytes, config.c_sleeping));
717 }
718
719
720 /*
721  * client_getln()   ...   Get a LF-terminated line of text from the client.
722  * (This is implemented in terms of client_read() and could be
723  * justifiably moved out of sysdep.c)
724  */
725 int client_getln(char *buf, int bufsize)
726 {
727         int i, retval;
728
729         /* Read one character at a time.
730          */
731         for (i = 0;;i++) {
732                 retval = client_read(&buf[i], 1);
733                 if (retval != 1 || buf[i] == '\n' || i == (bufsize-1))
734                         break;
735         }
736
737         /* If we got a long line, discard characters until the newline.
738          */
739         if (i == (bufsize-1))
740                 while (buf[i] != '\n' && retval == 1)
741                         retval = client_read(&buf[i], 1);
742
743         /* Strip the trailing LF, and the trailing CR if present.
744          */
745         buf[i] = 0;
746         while ( (i > 0)
747                 && ( (buf[i - 1]==13)
748                      || ( buf[i - 1]==10)) ) {
749                 i--;
750                 buf[i] = 0;
751         }
752         if (retval < 0) safestrncpy(&buf[i], "000", bufsize - i);
753         return(retval);
754 }
755
756
757
758 /*
759  * The system-dependent part of master_cleanup() - close the master socket.
760  */
761 void sysdep_master_cleanup(void) {
762         struct ServiceFunctionHook *serviceptr;
763
764 /////   DestroyWorkerList();
765         /*
766          * close all protocol master sockets
767          */
768         for (serviceptr = ServiceHookTable; serviceptr != NULL;
769             serviceptr = serviceptr->next ) {
770
771                 if (serviceptr->tcp_port > 0)
772                         lprintf(CTDL_INFO, "Closing listener on port %d\n",
773                                 serviceptr->tcp_port);
774
775                 if (serviceptr->sockpath != NULL)
776                         lprintf(CTDL_INFO, "Closing listener on '%s'\n",
777                                 serviceptr->sockpath);
778
779                 close(serviceptr->msock);
780
781                 /* If it's a Unix domain socket, remove the file. */
782                 if (serviceptr->sockpath != NULL) {
783                         unlink(serviceptr->sockpath);
784                 }
785         }
786 #ifdef HAVE_OPENSSL
787         destruct_ssl();
788 #endif
789         serv_calendar_destroy();        // FIXME: Shouldn't be here, should be by a cleanup hook surely.
790         CtdlDestroyProtoHooks();
791         CtdlDestroyDeleteHooks();
792         CtdlDestroyXmsgHooks();
793         CtdlDestroyNetprocHooks();
794         CtdlDestroyUserHooks();
795         CtdlDestroyMessageHook();
796         CtdlDestroyCleanupHooks();
797         CtdlDestroyFixedOutputHooks();  
798         CtdlDestroySessionHooks();
799         CtdlDestroyServiceHook();
800         #ifdef HAVE_BACKTRACE
801         eCrash_Uninit();
802         #endif
803 }
804
805
806
807
808 /*
809  * Terminate another session.
810  * (This could justifiably be moved out of sysdep.c because it
811  * no longer does anything that is system-dependent.)
812  */
813 void kill_session(int session_to_kill) {
814         struct CitContext *ptr;
815
816         begin_critical_section(S_SESSION_TABLE);
817         for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
818                 if (ptr->cs_pid == session_to_kill) {
819                         ptr->kill_me = 1;
820                 }
821         }
822         end_critical_section(S_SESSION_TABLE);
823 }
824
825 pid_t current_child;
826 void graceful_shutdown(int signum) {
827         kill(current_child, signum);
828         unlink(file_pid_file);
829         exit(0);
830 }
831
832
833 /*
834  * Start running as a daemon.
835  */
836 void start_daemon(int unused) {
837         int status = 0;
838         pid_t child = 0;
839         FILE *fp;
840         int do_restart = 0;
841
842         current_child = 0;
843
844         /* Close stdin/stdout/stderr and replace them with /dev/null.
845          * We don't just call close() because we don't want these fd's
846          * to be reused for other files.
847          */
848         chdir(ctdl_run_dir);
849
850         child = fork();
851         if (child != 0) {
852                 exit(0);
853         }
854         
855         signal(SIGHUP, SIG_IGN);
856         signal(SIGINT, SIG_IGN);
857         signal(SIGQUIT, SIG_IGN);
858
859         setsid();
860         umask(0);
861         freopen("/dev/null", "r", stdin);
862         freopen("/dev/null", "w", stdout);
863         freopen("/dev/null", "w", stderr);
864
865         do {
866                 current_child = fork();
867
868                 signal(SIGTERM, graceful_shutdown);
869         
870                 if (current_child < 0) {
871                         perror("fork");
872                         exit(errno);
873                 }
874         
875                 else if (current_child == 0) {
876                         return; /* continue starting citadel. */
877                 }
878         
879                 else {
880                         fp = fopen(file_pid_file, "w");
881                         if (fp != NULL) {
882                 /*
883                  * NB.. The pid file contains the pid of the actual server.
884                  * This is not the pid of the watcher process
885                  */
886                                 fprintf(fp, ""F_PID_T"\n", current_child);
887                                 fclose(fp);
888                         }
889                         waitpid(current_child, &status, 0);
890                 }
891
892                 do_restart = 0;
893
894                 /* Did the main process exit with an actual exit code? */
895                 if (WIFEXITED(status)) {
896
897                         /* Exit code 0 means the watcher should exit */
898                         if (WEXITSTATUS(status) == 0) {
899                                 do_restart = 0;
900                         }
901
902                         /* Exit code 101-109 means the watcher should exit */
903                         else if ( (WEXITSTATUS(status) >= 101) && (WEXITSTATUS(status) <= 109) ) {
904                                 do_restart = 0;
905                         }
906
907                         /* Any other exit code means we should restart. */
908                         else {
909                                 do_restart = 1;
910                         }
911                 }
912
913                 /* Any other type of termination (signals, etc.) should also restart. */
914                 else {
915                         do_restart = 1;
916                 }
917
918         } while (do_restart);
919
920         unlink(file_pid_file);
921         exit(WEXITSTATUS(status));
922 }
923
924
925
926 /*
927  * Generic routine to convert a login name to a full name (gecos)
928  * Returns nonzero if a conversion took place
929  */
930 int convert_login(char NameToConvert[]) {
931         struct passwd *pw;
932         int a;
933
934         pw = getpwnam(NameToConvert);
935         if (pw == NULL) {
936                 return(0);
937         }
938         else {
939                 strcpy(NameToConvert, pw->pw_gecos);
940                 for (a=0; a<strlen(NameToConvert); ++a) {
941                         if (NameToConvert[a] == ',') NameToConvert[a] = 0;
942                 }
943                 return(1);
944         }
945 }
946
947
948
949 /*
950  * New thread interface.
951  * To create a thread you must call one of the create thread functions.
952  * You must pass it the address of (a pointer to a CtdlThreadNode initialised to NULL) like this
953  * struct CtdlThreadNode *node = NULL;
954  * pass in &node
955  * If the thread is created *node will point to the thread control structure for the created thread.
956  * If the thread creation fails *node remains NULL
957  * Do not free the memory pointed to by *node, it doesn't belong to you.
958  * If your thread function returns it will be started again without creating a new thread.
959  * If your thread function wants to exit it should call CtdlThreadExit(ret_code);
960  * This new interface duplicates much of the eCrash stuff. We should go for closer integration since that would
961  * remove the need for the calls to eCrashRegisterThread and friends
962  */
963
964 // FIXME: these defines should be else where
965 #define CTDLTHREAD_BIGSTACK     0x0001
966
967 struct CtdlThreadNode *CtdlThreadList = NULL;
968 static pthread_mutex_t ThreadWaiterMutex = PTHREAD_MUTEX_INITIALIZER;
969 static pthread_cond_t ThreadWaiterCond = PTHREAD_COND_INITIALIZER;
970
971
972 /*
973  * So we now have a sleep command that works with threads but it is in seconds
974  */
975 void CtdlThreadSleep(int secs)
976 {
977
978         struct timespec wake_time;
979         struct timeval time_now;
980         
981         
982         memset (&wake_time, 0, sizeof(struct timespec));
983         gettimeofday(&time_now, NULL);
984         wake_time.tv_sec = time_now.tv_sec + secs;
985         pthread_cond_timedwait(&ThreadWaiterCond, &ThreadWaiterMutex, &wake_time);
986 }
987
988
989 /*
990  * Routine to clean up our thread function on exit
991  */
992 void ctdl_internal_thread_cleanup(void *arg)
993 {
994         struct CtdlThreadNode *this_thread;
995         // arg is a pointer to our thread structure
996         this_thread = (struct CtdlThreadNode *) arg;
997         if (this_thread->valid)
998         {
999                 /*
1000                  * In here we were called by the current thread because it is exiting
1001                  * NB. WE ARE THE CURRENT THREAD
1002                  */
1003                 CtdlLogPrintf(CTDL_NOTICE, "Thread \"%s\" (%ld) exited.\n", this_thread->name, this_thread->tid);
1004                 this_thread->running = FALSE;
1005                 this_thread->valid = FALSE;     // needs to be last thing else house keeping will unlink us too early
1006                 /*
1007                  * Our thread is exiting either because it wanted to end or because the server is stopping
1008                  * We need to clean up
1009                  */
1010                 #ifdef HAVE_BACKTRACE
1011                 eCrash_UnregisterThread();
1012                 #endif
1013         }
1014         else
1015         {
1016                 if (this_thread->tid == pthread_self())
1017                 {
1018                         CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC a thread is trying to clean up after itself.\n");
1019                         time_to_die = -1;
1020                         return;
1021                 }
1022                 /*
1023                  * In here we were called by some other thread that wants to clean up any dead threads
1024                  * NB. WE ARE NOT THE THREAD BEING CLEANED
1025                  */
1026                 // We probably got called by house keeping or master shutdown so we unlink the dead threads here
1027                 num_threads--;
1028                 
1029                 begin_critical_section(S_THREAD_LIST);
1030                 if(this_thread->name)
1031                         free(this_thread->name);
1032                 if(this_thread->prev)
1033                         this_thread->prev->next = this_thread->next;
1034                 if(this_thread->next)
1035                         this_thread->next->prev = this_thread->next;
1036                 end_critical_section(S_THREAD_LIST);
1037                 free(this_thread);
1038         }
1039 }
1040
1041
1042 /*
1043  * Garbage collection routine.
1044  * Gets called by do_housekeeping() and in master_cleanup() to clean up the thread list
1045  */
1046 void ctdl_internal_thread_gc (int shutdown)
1047 {
1048         struct CtdlThreadNode *this_thread, *that_thread;
1049         
1050         this_thread = CtdlThreadList;
1051         while(this_thread)
1052         {
1053                 that_thread = this_thread;
1054                 this_thread = this_thread->next;
1055                 
1056                 if(shutdown && that_thread->valid)
1057                 {       // We want the threads to shutdown so first ask it nicely
1058                         that_thread->running = FALSE;
1059                         // Wait for it to exit
1060                         CtdlThreadSleep(1);
1061                         
1062                         if(that_thread->valid)  // Be more brutal about it
1063                                 pthread_cancel (that_thread->tid);
1064                         // Wait for it to exit
1065                         CtdlThreadSleep(1);
1066                 }
1067                 
1068                 if (that_thread->valid == FALSE)
1069                 {
1070                         CtdlLogPrintf(CTDL_NOTICE, "Joining thread \"%s\" (%ld)\n", that_thread->name, that_thread->tid);
1071                         pthread_join(that_thread->tid, NULL);
1072                         ctdl_internal_thread_cleanup(that_thread);
1073                 }
1074         }
1075 }
1076  
1077 /*
1078  * Runtime function for a Citadel Thread.
1079  * This initialises the threads environment and then calls the user supplied thread function
1080  * Note that this is the REAL thread function and wraps the users thread function.
1081  */ 
1082 void *ctdl_internal_thread_func (void *arg)
1083 {
1084         struct CtdlThreadNode *this_thread;
1085         void *ret = NULL;
1086
1087         // Get our thread data structure
1088         this_thread = (struct CtdlThreadNode *) arg;
1089         // Tell the world we are here
1090         CtdlLogPrintf(CTDL_NOTICE, "Spawned a new thread \"%s\" (%ld). \n", this_thread->name, this_thread->tid);
1091
1092         num_threads++;  // Increase the count of threads in the system.
1093         
1094         // Register for tracing
1095         #ifdef HAVE_BACKTRACE
1096         eCrash_RegisterThread(this_thread->name, 0);
1097         #endif
1098
1099         // Register the cleanup function to take care of when we exit.
1100         pthread_cleanup_push(ctdl_internal_thread_cleanup, arg);
1101         
1102         this_thread->running = TRUE;
1103         
1104         while ((!time_to_die) && (this_thread->running))
1105         {       // Call the users thread function
1106                 ret = (this_thread->thread_func)(this_thread->user_args);
1107         }
1108         
1109         /*
1110          * Our thread is exiting either because it wanted to end or because the server is stopping
1111          * We need to clean up
1112          */
1113         #ifdef HAVE_BACKTRACE
1114         eCrash_UnregisterThread();
1115         #endif
1116         
1117         pthread_cleanup_pop(1); // Execute our cleanup routine and remove it
1118         
1119         return(ret);
1120 }
1121
1122
1123  
1124 /*
1125  * Internal function to create a thread.
1126  * Must be called from within a S_THREAD_LIST critical section
1127  */ 
1128 int ctdl_internal_create_thread(char *name, int flags, void *(*thread_func) (void *arg), void *arg, struct CtdlThreadNode **new_thread)
1129 {
1130         int ret = 0;
1131         pthread_attr_t attr;
1132         struct CtdlThreadNode *this_thread;
1133         
1134         if (*new_thread)
1135         {
1136                 lprintf(CTDL_EMERG, "Possible attempt to overwrite an existing thread!!!\n");
1137                 return -1;
1138         }
1139         
1140         this_thread = malloc(sizeof(struct CtdlThreadNode));
1141         if (this_thread == NULL) {
1142                 lprintf(CTDL_EMERG, "can't allocate CtdlThreadNode, exiting\n");
1143                 return ret;
1144         }
1145         // Ensuring this is zero'd means we make sure the thread doesn't start doing its thing until we are ready.
1146         memset (this_thread, 0, sizeof(struct CtdlThreadNode));
1147         
1148         if ((ret = pthread_attr_init(&attr))) {
1149                 lprintf(CTDL_EMERG, "pthread_attr_init: %s\n", strerror(ret));
1150                 free(this_thread);
1151                 return ret;
1152         }
1153
1154         /* Our per-thread stacks need to be bigger than the default size,
1155          * otherwise the MIME parser crashes on FreeBSD, and the IMAP service
1156          * crashes on 64-bit Linux.
1157          */
1158         if (flags & CTDLTHREAD_BIGSTACK)
1159         {
1160                 if ((ret = pthread_attr_setstacksize(&attr, THREADSTACKSIZE))) {
1161                         lprintf(CTDL_EMERG, "pthread_attr_setstacksize: %s\n",
1162                                 strerror(ret));
1163                         pthread_attr_destroy(&attr);
1164                         free(this_thread);
1165                         return ret;
1166                 }
1167         }
1168
1169         /*
1170          * If we got here we are going to create the thread so we must initilise the structure
1171          * first because most implimentations of threading can't create it in a stopped state
1172          * and it might want to do things with its structure that aren't initialised otherwise.
1173          */
1174         if(name)
1175         {
1176                 this_thread->name = strdup(name);
1177         }
1178         else
1179         {
1180                 this_thread->name = strdup("Unknown Thread");
1181         }
1182         this_thread->flags = flags;
1183         this_thread->thread_func = thread_func;
1184         this_thread->user_args = arg;
1185         this_thread->valid = 1; // Need this to prevent house keeping unlinking us from the list
1186         /*
1187          * We pass this_thread into the thread as its args so that it can find out information
1188          * about itself and it has a bit of storage space for itself, not to mention that the REAL
1189          * thread function needs to finish off the setup of the structure
1190          */
1191         if ((ret = pthread_create(&this_thread->tid, &attr, ctdl_internal_thread_func, this_thread) != 0))
1192         {
1193
1194                 lprintf(CTDL_ALERT, "Can't create thread: %s\n",
1195                         strerror(ret));
1196                 if (this_thread->name)
1197                         free (this_thread->name);
1198                 free(this_thread);
1199                 pthread_attr_destroy(&attr);
1200                 return ret;
1201         }
1202         
1203         this_thread->next = CtdlThreadList;
1204         CtdlThreadList = this_thread;
1205         *new_thread = this_thread;
1206         pthread_attr_destroy(&attr);
1207         return 0;
1208 }
1209
1210 /*
1211  * Wrapper function to create a thread
1212  * ensures the critical section and other protections are in place.
1213  * char *name = name to give to thread, if NULL, use generic name
1214  * int flags = flags to determine type of thread and standard facilities
1215  */
1216 int CtdlCreateThread(char *name, int flags, void *(*thread_func) (void *arg), void *arg,  struct CtdlThreadNode **new_thread)
1217 {
1218         int ret;
1219         
1220         begin_critical_section(S_THREAD_LIST);
1221         ret = ctdl_internal_create_thread(name, flags, thread_func, arg, new_thread);
1222         end_critical_section(S_THREAD_LIST);
1223         return ret;
1224 }
1225
1226
1227         
1228 /*
1229  * Old thread interface.
1230  */
1231
1232
1233 struct worker_node *worker_list = NULL;
1234
1235
1236 /*
1237  * create a worker thread. this function must always be called from within
1238  * an S_WORKER_LIST critical section!
1239  */
1240 void create_worker(void) {
1241         int ret;
1242         struct worker_node *n;
1243         pthread_attr_t attr;
1244
1245         n = malloc(sizeof(struct worker_node));
1246         if (n == NULL) {
1247                 lprintf(CTDL_EMERG, "can't allocate worker_node, exiting\n");
1248                 time_to_die = -1;
1249                 return;
1250         }
1251
1252         if ((ret = pthread_attr_init(&attr))) {
1253                 lprintf(CTDL_EMERG, "pthread_attr_init: %s\n", strerror(ret));
1254                 time_to_die = -1;
1255                 free(n);
1256                 return;
1257         }
1258
1259         /* Our per-thread stacks need to be bigger than the default size,
1260          * otherwise the MIME parser crashes on FreeBSD, and the IMAP service
1261          * crashes on 64-bit Linux.
1262          */
1263         if ((ret = pthread_attr_setstacksize(&attr, THREADSTACKSIZE))) {
1264                 lprintf(CTDL_EMERG, "pthread_attr_setstacksize: %s\n",
1265                         strerror(ret));
1266                 time_to_die = -1;
1267                 pthread_attr_destroy(&attr);
1268                 free(n);
1269                 return;
1270         }
1271
1272         if ((ret = pthread_create(&n->tid, &attr, worker_thread, NULL) != 0))
1273         {
1274
1275                 lprintf(CTDL_ALERT, "Can't create worker thread: %s\n",
1276                         strerror(ret));
1277                 time_to_die = -1;
1278                 pthread_attr_destroy(&attr);
1279                 free(n);
1280                 return;
1281         }
1282
1283         n->next = worker_list;
1284         worker_list = n;
1285         pthread_attr_destroy(&attr);
1286 }
1287
1288 void DestroyWorkerList(void)
1289 {
1290         struct CitContext *ptr;         /* general-purpose utility pointer */
1291         struct CitContext *rem = NULL;  /* list of sessions to be destroyed */
1292
1293         begin_critical_section(S_SESSION_TABLE);
1294         ptr = ContextList;
1295         while (ptr != NULL){
1296                 /* Remove the session from the active list */
1297                 rem = ptr->next;
1298                 --num_sessions;
1299                 
1300                 lprintf(CTDL_DEBUG, "Purging session %d\n", rem->cs_pid);
1301                 end_critical_section(S_SESSION_TABLE);
1302                 RemoveContext(ptr);
1303                 begin_critical_section(S_SESSION_TABLE);
1304                 free (ptr);
1305                 ptr = rem;
1306         }
1307         end_critical_section(S_SESSION_TABLE);
1308
1309         struct worker_node *cur, *p;
1310         cur = worker_list;
1311         while (cur != NULL)
1312         {
1313                 p = cur->next;
1314                 free (cur);
1315                 cur = p;
1316         }
1317         worker_list = NULL;
1318 }
1319
1320 /*
1321  * Create the maintenance threads and begin their operation.
1322  */
1323 void create_maintenance_threads(void) {
1324         int ret;
1325         pthread_attr_t attr;
1326
1327         if ((ret = pthread_attr_init(&attr))) {
1328                 lprintf(CTDL_EMERG, "pthread_attr_init: %s\n", strerror(ret));
1329                 time_to_die = -1;
1330                 return;
1331         }
1332
1333         /* Our per-thread stacks need to be bigger than the default size,
1334          * otherwise the MIME parser crashes on FreeBSD, and the IMAP service
1335          * crashes on 64-bit Linux.
1336          */
1337         if ((ret = pthread_attr_setstacksize(&attr, THREADSTACKSIZE))) {
1338                 lprintf(CTDL_EMERG, "pthread_attr_setstacksize: %s\n",
1339                         strerror(ret));
1340                 time_to_die = -1;
1341                 pthread_attr_destroy(&attr);
1342                 return;
1343         }
1344         
1345         struct MaintenanceThreadHook *fcn;
1346
1347         lprintf(CTDL_DEBUG, "Performing startup of maintenance thread hooks\n");
1348
1349         for (fcn = MaintenanceThreadHookTable; fcn != NULL; fcn = fcn->next) {
1350                 if ((ret = pthread_create(&(fcn->MaintenanceThread_tid), &attr, fcn->fcn_ptr, NULL) != 0)) {
1351                         lprintf(CTDL_ALERT, "Can't create thread: %s\n", strerror(ret));
1352                 }
1353                 else
1354                 {
1355                         lprintf(CTDL_NOTICE, "Spawned a new maintenance thread \"%s\" (%ld). \n", fcn->name,
1356                                 fcn->MaintenanceThread_tid);
1357                 }
1358         }
1359
1360
1361         pthread_attr_destroy(&attr);
1362 }
1363
1364
1365
1366 /*
1367  * Purge all sessions which have the 'kill_me' flag set.
1368  * This function has code to prevent it from running more than once every
1369  * few seconds, because running it after every single unbind would waste a lot
1370  * of CPU time and keep the context list locked too much.  To force it to run
1371  * anyway, set "force" to nonzero.
1372  *
1373  *
1374  * After that's done, we raise the size of the worker thread pool
1375  * if such an action is appropriate.
1376  */
1377 void dead_session_purge(int force) {
1378         struct CitContext *ptr;         /* general-purpose utility pointer */
1379         struct CitContext *rem = NULL;  /* list of sessions to be destroyed */
1380
1381         if (force == 0) {
1382                 if ( (time(NULL) - last_purge) < 5 ) {
1383                         return; /* Too soon, go away */
1384                 }
1385         }
1386         time(&last_purge);
1387
1388         begin_critical_section(S_SESSION_TABLE);
1389         for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
1390                 if ( (ptr->state == CON_IDLE) && (ptr->kill_me) ) {
1391
1392                         /* Remove the session from the active list */
1393                         if (ptr->prev) {
1394                                 ptr->prev->next = ptr->next;
1395                         }
1396                         else {
1397                                 ContextList = ptr->next;
1398                         }
1399                         if (ptr->next) {
1400                                 ptr->next->prev = ptr->prev;
1401                         }
1402
1403                         --num_sessions;
1404
1405                         /* And put it on our to-be-destroyed list */
1406                         ptr->next = rem;
1407                         rem = ptr;
1408
1409                 }
1410         }
1411         end_critical_section(S_SESSION_TABLE);
1412
1413         /* Now that we no longer have the session list locked, we can take
1414          * our time and destroy any sessions on the to-be-killed list, which
1415          * is allocated privately on this thread's stack.
1416          */
1417         while (rem != NULL) {
1418                 lprintf(CTDL_DEBUG, "Purging session %d\n", rem->cs_pid);
1419                 RemoveContext(rem);
1420                 ptr = rem;
1421                 rem = rem->next;
1422                 free(ptr);
1423         }
1424
1425         /* Raise the size of the worker thread pool if necessary. */
1426         if ( (num_sessions > num_threads)
1427            && (num_threads < config.c_max_workers) ) {
1428                 begin_critical_section(S_WORKER_LIST);
1429                 create_worker();
1430                 end_critical_section(S_WORKER_LIST);
1431         }
1432 }
1433
1434
1435
1436
1437
1438 /*
1439  * masterCC is the context we use when not attached to a session.  This
1440  * function initializes it.
1441  */
1442 void InitializeMasterCC(void) {
1443         memset(&masterCC, 0, sizeof(struct CitContext));
1444         masterCC.internal_pgm = 1;
1445         masterCC.cs_pid = 0;
1446 }
1447
1448
1449
1450
1451
1452
1453 /*
1454  * Bind a thread to a context.  (It's inline merely to speed things up.)
1455  */
1456 INLINE void become_session(struct CitContext *which_con) {
1457         pthread_setspecific(MyConKey, (void *)which_con );
1458 }
1459
1460
1461
1462 /* 
1463  * This loop just keeps going and going and going...
1464  */     
1465 void *worker_thread(void *arg) {
1466         int i;
1467         int highest;
1468         struct CitContext *ptr;
1469         struct CitContext *bind_me = NULL;
1470         fd_set readfds;
1471         int retval = 0;
1472         struct CitContext *con= NULL;   /* Temporary context pointer */
1473         struct ServiceFunctionHook *serviceptr;
1474         int ssock;                      /* Descriptor for client socket */
1475         struct timeval tv;
1476         int force_purge = 0;
1477         int m;
1478
1479         num_threads++;
1480
1481         cdb_allocate_tsd();
1482
1483         // Register for tracing
1484         #ifdef HAVE_BACKTRACE
1485         eCrash_RegisterThread("WorkerThread", 0);
1486         #endif
1487         while (!time_to_die) {
1488
1489                 /* make doubly sure we're not holding any stale db handles
1490                  * which might cause a deadlock.
1491                  */
1492                 cdb_check_handles();
1493 do_select:      force_purge = 0;
1494                 bind_me = NULL;         /* Which session shall we handle? */
1495
1496                 /* Initialize the fdset. */
1497                 FD_ZERO(&readfds);
1498                 highest = 0;
1499
1500                 begin_critical_section(S_SESSION_TABLE);
1501                 for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
1502                         if (ptr->state == CON_IDLE) {
1503                                 FD_SET(ptr->client_socket, &readfds);
1504                                 if (ptr->client_socket > highest)
1505                                         highest = ptr->client_socket;
1506                         }
1507                         if ((bind_me == NULL) && (ptr->state == CON_READY)) {
1508                                 bind_me = ptr;
1509                                 ptr->state = CON_EXECUTING;
1510                         }
1511                 }
1512                 end_critical_section(S_SESSION_TABLE);
1513
1514                 if (bind_me) {
1515                         goto SKIP_SELECT;
1516                 }
1517
1518                 /* If we got this far, it means that there are no sessions
1519                  * which a previous thread marked for attention, so we go
1520                  * ahead and get ready to select().
1521                  */
1522
1523                 /* First, add the various master sockets to the fdset. */
1524                 for (serviceptr = ServiceHookTable; serviceptr != NULL;
1525                 serviceptr = serviceptr->next ) {
1526                         m = serviceptr->msock;
1527                         FD_SET(m, &readfds);
1528                         if (m > highest) {
1529                                 highest = m;
1530                         }
1531                 }
1532
1533                 if (!time_to_die) {
1534                         tv.tv_sec = 1;          /* wake up every second if no input */
1535                         tv.tv_usec = 0;
1536                         retval = select(highest + 1, &readfds, NULL, NULL, &tv);
1537                 }
1538
1539                 if (time_to_die) return(NULL);
1540
1541                 /* Now figure out who made this select() unblock.
1542                  * First, check for an error or exit condition.
1543                  */
1544                 if (retval < 0) {
1545                         if (errno == EBADF) {
1546                                 lprintf(CTDL_NOTICE, "select() failed: (%s)\n",
1547                                         strerror(errno));
1548                                 goto do_select;
1549                         }
1550                         if (errno != EINTR) {
1551                                 lprintf(CTDL_EMERG, "Exiting (%s)\n", strerror(errno));
1552                                 time_to_die = 1;
1553                         } else if (!time_to_die)
1554                                 goto do_select;
1555                 }
1556
1557                 /* Next, check to see if it's a new client connecting
1558                  * on a master socket.
1559                  */
1560                 else for (serviceptr = ServiceHookTable; serviceptr != NULL;
1561                      serviceptr = serviceptr->next ) {
1562
1563                         if (FD_ISSET(serviceptr->msock, &readfds)) {
1564                                 ssock = accept(serviceptr->msock, NULL, 0);
1565                                 if (ssock >= 0) {
1566                                         lprintf(CTDL_DEBUG,
1567                                                 "New client socket %d\n",
1568                                                 ssock);
1569
1570                                         /* The master socket is non-blocking but the client
1571                                          * sockets need to be blocking, otherwise certain
1572                                          * operations barf on FreeBSD.  Not a fatal error.
1573                                          */
1574                                         if (fcntl(ssock, F_SETFL, 0) < 0) {
1575                                                 lprintf(CTDL_EMERG,
1576                                                         "citserver: Can't set socket to blocking: %s\n",
1577                                                         strerror(errno));
1578                                         }
1579
1580                                         /* New context will be created already
1581                                          * set up in the CON_EXECUTING state.
1582                                          */
1583                                         con = CreateNewContext();
1584
1585                                         /* Assign our new socket number to it. */
1586                                         con->client_socket = ssock;
1587                                         con->h_command_function =
1588                                                 serviceptr->h_command_function;
1589                                         con->h_async_function =
1590                                                 serviceptr->h_async_function;
1591                                         con->ServiceName =
1592                                                 serviceptr->ServiceName;
1593                                         
1594                                         /* Determine whether it's a local socket */
1595                                         if (serviceptr->sockpath != NULL)
1596                                                 con->is_local_socket = 1;
1597         
1598                                         /* Set the SO_REUSEADDR socket option */
1599                                         i = 1;
1600                                         setsockopt(ssock, SOL_SOCKET,
1601                                                 SO_REUSEADDR,
1602                                                 &i, sizeof(i));
1603
1604                                         become_session(con);
1605                                         begin_session(con);
1606                                         serviceptr->h_greeting_function();
1607                                         become_session(NULL);
1608                                         con->state = CON_IDLE;
1609                                         goto do_select;
1610                                 }
1611                         }
1612                 }
1613
1614                 /* It must be a client socket.  Find a context that has data
1615                  * waiting on its socket *and* is in the CON_IDLE state.  Any
1616                  * active sockets other than our chosen one are marked as
1617                  * CON_READY so the next thread that comes around can just bind
1618                  * to one without having to select() again.
1619                  */
1620                 begin_critical_section(S_SESSION_TABLE);
1621                 for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
1622                         if ( (FD_ISSET(ptr->client_socket, &readfds))
1623                            && (ptr->state != CON_EXECUTING) ) {
1624                                 ptr->input_waiting = 1;
1625                                 if (!bind_me) {
1626                                         bind_me = ptr;  /* I choose you! */
1627                                         bind_me->state = CON_EXECUTING;
1628                                 }
1629                                 else {
1630                                         ptr->state = CON_READY;
1631                                 }
1632                         }
1633                 }
1634                 end_critical_section(S_SESSION_TABLE);
1635
1636 SKIP_SELECT:
1637                 /* We're bound to a session */
1638                 if (bind_me != NULL) {
1639                         become_session(bind_me);
1640
1641                         /* If the client has sent a command, execute it. */
1642                         if (CC->input_waiting) {
1643                                 CC->h_command_function();
1644                                 CC->input_waiting = 0;
1645                         }
1646
1647                         /* If there are asynchronous messages waiting and the
1648                          * client supports it, do those now */
1649                         if ((CC->is_async) && (CC->async_waiting)
1650                            && (CC->h_async_function != NULL)) {
1651                                 CC->h_async_function();
1652                                 CC->async_waiting = 0;
1653                         }
1654                         
1655                         force_purge = CC->kill_me;
1656                         become_session(NULL);
1657                         bind_me->state = CON_IDLE;
1658                 }
1659
1660                 dead_session_purge(force_purge);
1661                 do_housekeeping();
1662                 check_sched_shutdown();
1663         }
1664         if (con != NULL) free (con);//// TODO: could this harm other threads? 
1665         /* If control reaches this point, the server is shutting down */        
1666         #ifdef HAVE_BACKTRACE
1667         eCrash_UnregisterThread();
1668         #endif
1669         return(NULL);
1670 }
1671
1672
1673
1674
1675 /*
1676  * SyslogFacility()
1677  * Translate text facility name to syslog.h defined value.
1678  */
1679 int SyslogFacility(char *name)
1680 {
1681         int i;
1682         struct
1683         {
1684                 int facility;
1685                 char *name;
1686         }   facTbl[] =
1687         {
1688                 {   LOG_KERN,   "kern"          },
1689                 {   LOG_USER,   "user"          },
1690                 {   LOG_MAIL,   "mail"          },
1691                 {   LOG_DAEMON, "daemon"        },
1692                 {   LOG_AUTH,   "auth"          },
1693                 {   LOG_SYSLOG, "syslog"        },
1694                 {   LOG_LPR,    "lpr"           },
1695                 {   LOG_NEWS,   "news"          },
1696                 {   LOG_UUCP,   "uucp"          },
1697                 {   LOG_LOCAL0, "local0"        },
1698                 {   LOG_LOCAL1, "local1"        },
1699                 {   LOG_LOCAL2, "local2"        },
1700                 {   LOG_LOCAL3, "local3"        },
1701                 {   LOG_LOCAL4, "local4"        },
1702                 {   LOG_LOCAL5, "local5"        },
1703                 {   LOG_LOCAL6, "local6"        },
1704                 {   LOG_LOCAL7, "local7"        },
1705                 {   0,            NULL          }
1706         };
1707         for(i = 0; facTbl[i].name != NULL; i++) {
1708                 if(!strcasecmp(name, facTbl[i].name))
1709                         return facTbl[i].facility;
1710         }
1711         enable_syslog = 0;
1712         return LOG_DAEMON;
1713 }
1714
1715
1716 /********** MEM CHEQQER ***********/
1717
1718 #ifdef DEBUG_MEMORY_LEAKS
1719
1720 #undef malloc
1721 #undef realloc
1722 #undef strdup
1723 #undef free
1724
1725 void *tracked_malloc(size_t size, char *file, int line) {
1726         struct igheap *thisheap;
1727         void *block;
1728
1729         block = malloc(size);
1730         if (block == NULL) return(block);
1731
1732         thisheap = malloc(sizeof(struct igheap));
1733         if (thisheap == NULL) {
1734                 free(block);
1735                 return(NULL);
1736         }
1737
1738         thisheap->block = block;
1739         strcpy(thisheap->file, file);
1740         thisheap->line = line;
1741         
1742         begin_critical_section(S_DEBUGMEMLEAKS);
1743         thisheap->next = igheap;
1744         igheap = thisheap;
1745         end_critical_section(S_DEBUGMEMLEAKS);
1746
1747         return(block);
1748 }
1749
1750
1751 void *tracked_realloc(void *ptr, size_t size, char *file, int line) {
1752         struct igheap *thisheap;
1753         void *block;
1754
1755         block = realloc(ptr, size);
1756         if (block == NULL) return(block);
1757
1758         thisheap = malloc(sizeof(struct igheap));
1759         if (thisheap == NULL) {
1760                 free(block);
1761                 return(NULL);
1762         }
1763
1764         thisheap->block = block;
1765         strcpy(thisheap->file, file);
1766         thisheap->line = line;
1767         
1768         begin_critical_section(S_DEBUGMEMLEAKS);
1769         thisheap->next = igheap;
1770         igheap = thisheap;
1771         end_critical_section(S_DEBUGMEMLEAKS);
1772
1773         return(block);
1774 }
1775
1776
1777
1778 void tracked_free(void *ptr) {
1779         struct igheap *thisheap;
1780         struct igheap *trash;
1781
1782         free(ptr);
1783
1784         if (igheap == NULL) return;
1785         begin_critical_section(S_DEBUGMEMLEAKS);
1786         for (thisheap = igheap; thisheap != NULL; thisheap = thisheap->next) {
1787                 if (thisheap->next != NULL) {
1788                         if (thisheap->next->block == ptr) {
1789                                 trash = thisheap->next;
1790                                 thisheap->next = thisheap->next->next;
1791                                 free(trash);
1792                         }
1793                 }
1794         }
1795         if (igheap->block == ptr) {
1796                 trash = igheap;
1797                 igheap = igheap->next;
1798                 free(trash);
1799         }
1800         end_critical_section(S_DEBUGMEMLEAKS);
1801 }
1802
1803 char *tracked_strdup(const char *s, char *file, int line) {
1804         char *ptr;
1805
1806         if (s == NULL) return(NULL);
1807         ptr = tracked_malloc(strlen(s) + 1, file, line);
1808         if (ptr == NULL) return(NULL);
1809         strncpy(ptr, s, strlen(s));
1810         return(ptr);
1811 }
1812
1813 void dump_heap(void) {
1814         struct igheap *thisheap;
1815
1816         for (thisheap = igheap; thisheap != NULL; thisheap = thisheap->next) {
1817                 lprintf(CTDL_CRIT, "UNFREED: %30s : %d\n",
1818                         thisheap->file, thisheap->line);
1819         }
1820 }
1821
1822 #endif /*  DEBUG_MEMORY_LEAKS */