a0ccfc8f10fb01e07d1c1550c84fb420ebf48cb8
[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 #include "ctdl_module.h"
76
77 #ifdef DEBUG_MEMORY_LEAKS
78 struct igheap {
79         struct igheap *next;
80         char file[32];
81         int line;
82         void *block;
83 };
84
85 struct igheap *igheap = NULL;
86 #endif
87
88
89 pthread_mutex_t Critters[MAX_SEMAPHORES];       /* Things needing locking */
90 pthread_key_t MyConKey;                         /* TSD key for MyContext() */
91
92 int verbosity = DEFAULT_VERBOSITY;              /* Logging level */
93
94 struct CitContext masterCC;
95 time_t last_purge = 0;                          /* Last dead session purge */
96 static int num_threads = 0;                     /* Current number of threads */
97 static int num_workers = 0;                     /* Current number of worker threads */
98 int num_sessions = 0;                           /* Current number of sessions */
99
100 int syslog_facility = LOG_DAEMON;
101 int enable_syslog = 0;
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 exit_signal = 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         CtdlLogPrintf(CTDL_DEBUG, "Caught signal %d; shutting down.\n", signum);
183 #ifdef THREADS_USESIGNALS
184         if (CT)
185         {
186                 CtdlLogPrintf(CTDL_DEBUG, "Thread \"%s\" caught signal %d.\n", CT->name, signum);
187                 CT->signal = signum;
188         }
189         else
190 #endif
191                 exit_signal = signum;
192 }
193
194
195
196
197 void InitialiseSemaphores(void)
198 {
199         int i;
200
201         /* Set up a bunch of semaphores to be used for critical sections */
202         for (i=0; i<MAX_SEMAPHORES; ++i) {
203                 pthread_mutex_init(&Critters[i], NULL);
204         }
205 }
206
207
208
209 /*
210  * Some initialization stuff...
211  */
212 void init_sysdep(void) {
213         sigset_t set;
214
215         /* Avoid vulnerabilities related to FD_SETSIZE if we can. */
216 #ifdef FD_SETSIZE
217 #ifdef RLIMIT_NOFILE
218         struct rlimit rl;
219         getrlimit(RLIMIT_NOFILE, &rl);
220         rl.rlim_cur = FD_SETSIZE;
221         rl.rlim_max = FD_SETSIZE;
222         setrlimit(RLIMIT_NOFILE, &rl);
223 #endif
224 #endif
225
226         /* If we've got OpenSSL, we're going to use it. */
227 #ifdef HAVE_OPENSSL
228         init_ssl();
229 #endif
230
231         /*
232          * Set up a place to put thread-specific data.
233          * We only need a single pointer per thread - it points to the
234          * CitContext structure (in the ContextList linked list) of the
235          * session to which the calling thread is currently bound.
236          */
237         if (pthread_key_create(&MyConKey, NULL) != 0) {
238                 CtdlLogPrintf(CTDL_CRIT, "Can't create TSD key: %s\n",
239                         strerror(errno));
240         }
241
242         /*
243          * The action for unexpected signals and exceptions should be to
244          * call signal_cleanup() to gracefully shut down the server.
245          */
246         sigemptyset(&set);
247         sigaddset(&set, SIGINT);
248         sigaddset(&set, SIGQUIT);
249         sigaddset(&set, SIGHUP);
250         sigaddset(&set, SIGTERM);
251         // sigaddset(&set, SIGSEGV);    commented out because
252         // sigaddset(&set, SIGILL);     we want core dumps
253         // sigaddset(&set, SIGBUS);
254         sigprocmask(SIG_UNBLOCK, &set, NULL);
255
256         signal(SIGINT, signal_cleanup);
257         signal(SIGQUIT, signal_cleanup);
258         signal(SIGHUP, signal_cleanup);
259         signal(SIGTERM, signal_cleanup);
260         // signal(SIGSEGV, signal_cleanup);     commented out because
261         // signal(SIGILL, signal_cleanup);      we want core dumps
262         // signal(SIGBUS, signal_cleanup);
263
264         /*
265          * Do not shut down the server on broken pipe signals, otherwise the
266          * whole Citadel service would come down whenever a single client
267          * socket breaks.
268          */
269         signal(SIGPIPE, SIG_IGN);
270 }
271
272
273
274 /*
275  * Obtain a semaphore lock to begin a critical section.
276  * but only if no one else has one
277  */
278 int try_critical_section(int which_one)
279 {
280         /* For all types of critical sections except those listed here,
281          * ensure nobody ever tries to do a critical section within a
282          * transaction; this could lead to deadlock.
283          */
284         if (    (which_one != S_FLOORCACHE)
285 #ifdef DEBUG_MEMORY_LEAKS
286                 && (which_one != S_DEBUGMEMLEAKS)
287 #endif
288                 && (which_one != S_RPLIST)
289         ) {
290                 cdb_check_handles();
291         }
292         return (pthread_mutex_trylock(&Critters[which_one]));
293 }
294
295
296 /*
297  * Obtain a semaphore lock to begin a critical section.
298  */
299 void begin_critical_section(int which_one)
300 {
301         /* CtdlLogPrintf(CTDL_DEBUG, "begin_critical_section(%d)\n", which_one); */
302
303         /* For all types of critical sections except those listed here,
304          * ensure nobody ever tries to do a critical section within a
305          * transaction; this could lead to deadlock.
306          */
307         if (    (which_one != S_FLOORCACHE)
308 #ifdef DEBUG_MEMORY_LEAKS
309                 && (which_one != S_DEBUGMEMLEAKS)
310 #endif
311                 && (which_one != S_RPLIST)
312         ) {
313                 cdb_check_handles();
314         }
315         pthread_mutex_lock(&Critters[which_one]);
316 }
317
318 /*
319  * Release a semaphore lock to end a critical section.
320  */
321 void end_critical_section(int which_one)
322 {
323         pthread_mutex_unlock(&Critters[which_one]);
324 }
325
326
327
328 /*
329  * This is a generic function to set up a master socket for listening on
330  * a TCP port.  The server shuts down if the bind fails.
331  *
332  */
333 int ig_tcp_server(char *ip_addr, int port_number, int queue_len, char **errormessage)
334 {
335         struct sockaddr_in sin;
336         int s, i;
337         int actual_queue_len;
338
339         actual_queue_len = queue_len;
340         if (actual_queue_len < 5) actual_queue_len = 5;
341
342         memset(&sin, 0, sizeof(sin));
343         sin.sin_family = AF_INET;
344         sin.sin_port = htons((u_short)port_number);
345         if (ip_addr == NULL) {
346                 sin.sin_addr.s_addr = INADDR_ANY;
347         }
348         else {
349                 sin.sin_addr.s_addr = inet_addr(ip_addr);
350         }
351                                                                                 
352         if (sin.sin_addr.s_addr == !INADDR_ANY) {
353                 sin.sin_addr.s_addr = INADDR_ANY;
354         }
355
356         s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
357
358         if (s < 0) {
359                 *errormessage = (char*) malloc(SIZ + 1);
360                 snprintf(*errormessage, SIZ, 
361                                  "citserver: Can't create a socket: %s",
362                                  strerror(errno));
363                 CtdlLogPrintf(CTDL_EMERG, "%s\n", *errormessage);
364                 return(-1);
365         }
366
367         i = 1;
368         setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
369
370         if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
371                 *errormessage = (char*) malloc(SIZ + 1);
372                 snprintf(*errormessage, SIZ, 
373                                  "citserver: Can't bind: %s",
374                                  strerror(errno));
375                 CtdlLogPrintf(CTDL_EMERG, "%s\n", *errormessage);
376                 close(s);
377                 return(-1);
378         }
379
380         /* set to nonblock - we need this for some obscure situations */
381         if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) {
382                 *errormessage = (char*) malloc(SIZ + 1);
383                 snprintf(*errormessage, SIZ, 
384                                  "citserver: Can't set socket to non-blocking: %s",
385                                  strerror(errno));
386                 CtdlLogPrintf(CTDL_EMERG, "%s\n", *errormessage);
387                 close(s);
388                 return(-1);
389         }
390
391         if (listen(s, actual_queue_len) < 0) {
392                 *errormessage = (char*) malloc(SIZ + 1);
393                 snprintf(*errormessage, SIZ, 
394                                  "citserver: Can't listen: %s",
395                                  strerror(errno));
396                 CtdlLogPrintf(CTDL_EMERG, "%s\n", *errormessage);
397                 close(s);
398                 return(-1);
399         }
400
401         return(s);
402 }
403
404
405
406 /*
407  * Create a Unix domain socket and listen on it
408  */
409 int ig_uds_server(char *sockpath, int queue_len, char **errormessage)
410 {
411         struct sockaddr_un addr;
412         int s;
413         int i;
414         int actual_queue_len;
415
416         actual_queue_len = queue_len;
417         if (actual_queue_len < 5) actual_queue_len = 5;
418
419         i = unlink(sockpath);
420         if (i != 0) if (errno != ENOENT) {
421                 *errormessage = (char*) malloc(SIZ + 1);
422                 snprintf(*errormessage, SIZ, "citserver: can't unlink %s: %s",
423                         sockpath, strerror(errno));
424                 CtdlLogPrintf(CTDL_EMERG, "%s\n", *errormessage);
425                 return(-1);
426         }
427
428         memset(&addr, 0, sizeof(addr));
429         addr.sun_family = AF_UNIX;
430         safestrncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
431
432         s = socket(AF_UNIX, SOCK_STREAM, 0);
433         if (s < 0) {
434                 *errormessage = (char*) malloc(SIZ + 1);
435                 snprintf(*errormessage, SIZ, 
436                          "citserver: Can't create a socket: %s",
437                          strerror(errno));
438                 CtdlLogPrintf(CTDL_EMERG, "%s\n", *errormessage);
439                 return(-1);
440         }
441
442         if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
443                 *errormessage = (char*) malloc(SIZ + 1);
444                 snprintf(*errormessage, SIZ, 
445                          "citserver: Can't bind: %s",
446                          strerror(errno));
447                 CtdlLogPrintf(CTDL_EMERG, "%s\n", *errormessage);
448                 return(-1);
449         }
450
451         /* set to nonblock - we need this for some obscure situations */
452         if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) {
453                 *errormessage = (char*) malloc(SIZ + 1);
454                 snprintf(*errormessage, SIZ, 
455                          "citserver: Can't set socket to non-blocking: %s",
456                          strerror(errno));
457                 CtdlLogPrintf(CTDL_EMERG, "%s\n", *errormessage);
458                 close(s);
459                 return(-1);
460         }
461
462         if (listen(s, actual_queue_len) < 0) {
463                 *errormessage = (char*) malloc(SIZ + 1);
464                 snprintf(*errormessage, SIZ, 
465                          "citserver: Can't listen: %s",
466                          strerror(errno));
467                 CtdlLogPrintf(CTDL_EMERG, "%s\n", *errormessage);
468                 return(-1);
469         }
470
471         chmod(sockpath, S_ISGID|S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
472         return(s);
473 }
474
475
476
477 /*
478  * Return a pointer to the CitContext structure bound to the thread which
479  * called this function.  If there's no such binding (for example, if it's
480  * called by the housekeeper thread) then a generic 'master' CC is returned.
481  *
482  * This function is used *VERY* frequently and must be kept small.
483  */
484 struct CitContext *MyContext(void) {
485
486         register struct CitContext *c;
487
488         return ((c = (struct CitContext *) pthread_getspecific(MyConKey),
489                 c == NULL) ? &masterCC : c
490         );
491 }
492
493
494 /*
495  * Initialize a new context and place it in the list.  The session number
496  * used to be the PID (which is why it's called cs_pid), but that was when we
497  * had one process per session.  Now we just assign them sequentially, starting
498  * at 1 (don't change it to 0 because masterCC uses 0).
499  */
500 struct CitContext *CreateNewContext(void) {
501         struct CitContext *me;
502         static int next_pid = 0;
503
504         me = (struct CitContext *) malloc(sizeof(struct CitContext));
505         if (me == NULL) {
506                 CtdlLogPrintf(CTDL_ALERT, "citserver: can't allocate memory!!\n");
507                 return NULL;
508         }
509         memset(me, 0, sizeof(struct CitContext));
510
511         /* The new context will be created already in the CON_EXECUTING state
512          * in order to prevent another thread from grabbing it while it's
513          * being set up.
514          */
515         me->state = CON_EXECUTING;
516
517         /*
518          * Generate a unique session number and insert this context into
519          * the list.
520          */
521         begin_critical_section(S_SESSION_TABLE);
522         me->cs_pid = ++next_pid;
523         me->prev = NULL;
524         me->next = ContextList;
525         ContextList = me;
526         if (me->next != NULL) {
527                 me->next->prev = me;
528         }
529         ++num_sessions;
530         end_critical_section(S_SESSION_TABLE);
531         return(me);
532 }
533
534
535 /*
536  * The following functions implement output buffering. If the kernel supplies
537  * native TCP buffering (Linux & *BSD), use that; otherwise, emulate it with
538  * user-space buffering.
539  */
540 #ifndef HAVE_DARWIN
541 #ifdef TCP_CORK
542 #       define HAVE_TCP_BUFFERING
543 #else
544 #       ifdef TCP_NOPUSH
545 #               define HAVE_TCP_BUFFERING
546 #               define TCP_CORK TCP_NOPUSH
547 #       endif
548 #endif /* TCP_CORK */
549 #endif /* HAVE_DARWIN */
550
551 #ifdef HAVE_TCP_BUFFERING
552 static unsigned on = 1, off = 0;
553 void buffer_output(void) {
554         struct CitContext *ctx = MyContext();
555         setsockopt(ctx->client_socket, IPPROTO_TCP, TCP_CORK, &on, 4);
556         ctx->buffering = 1;
557 }
558
559 void unbuffer_output(void) {
560         struct CitContext *ctx = MyContext();
561         setsockopt(ctx->client_socket, IPPROTO_TCP, TCP_CORK, &off, 4);
562         ctx->buffering = 0;
563 }
564
565 void flush_output(void) {
566         struct CitContext *ctx = MyContext();
567         setsockopt(ctx->client_socket, IPPROTO_TCP, TCP_CORK, &off, 4);
568         setsockopt(ctx->client_socket, IPPROTO_TCP, TCP_CORK, &on, 4);
569 }
570 #else 
571 #ifdef HAVE_DARWIN
572 /* Stub functions for Darwin/OS X where TCP buffering isn't liked at all */
573 void buffer_output(void) {
574         CC->buffering = 0;
575 }
576 void unbuffer_output(void) {
577         CC->buffering = 0;
578 }
579 void flush_output(void) {
580 }
581 #else
582 void buffer_output(void) {
583         if (CC->buffering == 0) {
584                 CC->buffering = 1;
585                 CC->buffer_len = 0;
586                 CC->output_buffer = malloc(SIZ);
587         }
588 }
589
590 void flush_output(void) {
591         if (CC->buffering == 1) {
592                 client_write(CC->output_buffer, CC->buffer_len);
593                 CC->buffer_len = 0;
594         }
595 }
596
597 void unbuffer_output(void) {
598         if (CC->buffering == 1) {
599                 CC->buffering = 0;
600                 /* We don't call flush_output because we can't. */
601                 client_write(CC->output_buffer, CC->buffer_len);
602                 CC->buffer_len = 0;
603                 free(CC->output_buffer);
604                 CC->output_buffer = NULL;
605         }
606 }
607 #endif /* HAVE_DARWIN */
608 #endif /* HAVE_TCP_BUFFERING */
609
610
611
612 /*
613  * client_write()   ...    Send binary data to the client.
614  */
615 void client_write(char *buf, int nbytes)
616 {
617         int bytes_written = 0;
618         int retval;
619 #ifndef HAVE_TCP_BUFFERING
620         int old_buffer_len = 0;
621 #endif
622         t_context *Ctx;
623
624         Ctx = CC;
625         if (Ctx->redirect_buffer != NULL) {
626                 if ((Ctx->redirect_len + nbytes + 2) >= Ctx->redirect_alloc) {
627                         Ctx->redirect_alloc = (Ctx->redirect_alloc * 2) + nbytes;
628                         Ctx->redirect_buffer = realloc(Ctx->redirect_buffer,
629                                                 Ctx->redirect_alloc);
630                 }
631                 memcpy(&Ctx->redirect_buffer[Ctx->redirect_len], buf, nbytes);
632                 Ctx->redirect_len += nbytes;
633                 Ctx->redirect_buffer[Ctx->redirect_len] = 0;
634                 return;
635         }
636
637 #ifndef HAVE_TCP_BUFFERING
638         /* If we're buffering for later, do that now. */
639         if (Ctx->buffering) {
640                 old_buffer_len = Ctx->buffer_len;
641                 Ctx->buffer_len += nbytes;
642                 Ctx->output_buffer = realloc(Ctx->output_buffer, Ctx->buffer_len);
643                 memcpy(&Ctx->output_buffer[old_buffer_len], buf, nbytes);
644                 return;
645         }
646 #endif
647
648         /* Ok, at this point we're not buffering.  Go ahead and write. */
649
650 #ifdef HAVE_OPENSSL
651         if (Ctx->redirect_ssl) {
652                 client_write_ssl(buf, nbytes);
653                 return;
654         }
655 #endif
656
657         while (bytes_written < nbytes) {
658                 retval = write(Ctx->client_socket, &buf[bytes_written],
659                         nbytes - bytes_written);
660                 if (retval < 1) {
661                         CtdlLogPrintf(CTDL_ERR,
662                                 "client_write(%d bytes) failed: %s (%d)\n",
663                                 nbytes - bytes_written,
664                                 strerror(errno), errno);
665                         cit_backtrace();
666                         // CtdlLogPrintf(CTDL_DEBUG, "Tried to send: %s",  &buf[bytes_written]);
667                         Ctx->kill_me = 1;
668                         return;
669                 }
670                 bytes_written = bytes_written + retval;
671         }
672 }
673
674
675 /*
676  * cprintf()  ...   Send formatted printable data to the client.   It is
677  *                implemented in terms of client_write() but remains in
678  *                sysdep.c in case we port to somewhere without va_args...
679  */
680 void cprintf(const char *format, ...) {   
681         va_list arg_ptr;   
682         char buf[1024];   
683    
684         va_start(arg_ptr, format);   
685         if (vsnprintf(buf, sizeof buf, format, arg_ptr) == -1)
686                 buf[sizeof buf - 2] = '\n';
687         client_write(buf, strlen(buf)); 
688         va_end(arg_ptr);
689 }   
690
691
692 /*
693  * Read data from the client socket.
694  * Return values are:
695  *      1       Requested number of bytes has been read.
696  *      0       Request timed out.
697  *      -1      The socket is broken.
698  * If the socket breaks, the session will be terminated.
699  */
700 int client_read_to(char *buf, int bytes, int timeout)
701 {
702         int len,rlen;
703         fd_set rfds;
704         int fd;
705         struct timeval tv;
706         int retval;
707
708 #ifdef HAVE_OPENSSL
709         if (CC->redirect_ssl) {
710                 return (client_read_ssl(buf, bytes, timeout));
711         }
712 #endif
713         len = 0;
714         fd = CC->client_socket;
715         while(len<bytes) {
716                 FD_ZERO(&rfds);
717                 FD_SET(fd, &rfds);
718                 tv.tv_sec = timeout;
719                 tv.tv_usec = 0;
720
721                 retval = select( (fd)+1, 
722                                  &rfds, NULL, NULL, &tv);
723
724                 if (FD_ISSET(fd, &rfds) == 0) {
725                         return(0);
726                 }
727
728                 rlen = read(fd, &buf[len], bytes-len);
729                 if (rlen<1) {
730                         /* The socket has been disconnected! */
731                         CC->kill_me = 1;
732                         return(-1);
733                 }
734                 len = len + rlen;
735         }
736         return(1);
737 }
738
739 /*
740  * Read data from the client socket with default timeout.
741  * (This is implemented in terms of client_read_to() and could be
742  * justifiably moved out of sysdep.c)
743  */
744 INLINE int client_read(char *buf, int bytes)
745 {
746         return(client_read_to(buf, bytes, config.c_sleeping));
747 }
748
749
750 /*
751  * client_getln()   ...   Get a LF-terminated line of text from the client.
752  * (This is implemented in terms of client_read() and could be
753  * justifiably moved out of sysdep.c)
754  */
755 int client_getln(char *buf, int bufsize)
756 {
757         int i, retval;
758
759         /* Read one character at a time.
760          */
761         for (i = 0;;i++) {
762                 retval = client_read(&buf[i], 1);
763                 if (retval != 1 || buf[i] == '\n' || i == (bufsize-1))
764                         break;
765         }
766
767         /* If we got a long line, discard characters until the newline.
768          */
769         if (i == (bufsize-1))
770                 while (buf[i] != '\n' && retval == 1)
771                         retval = client_read(&buf[i], 1);
772
773         /* Strip the trailing LF, and the trailing CR if present.
774          */
775         buf[i] = 0;
776         while ( (i > 0)
777                 && ( (buf[i - 1]==13)
778                      || ( buf[i - 1]==10)) ) {
779                 i--;
780                 buf[i] = 0;
781         }
782         if (retval < 0) safestrncpy(&buf[i], "000", bufsize - i);
783         return(retval);
784 }
785
786
787 /*
788  * Cleanup any contexts that are left lying around
789  */
790 void context_cleanup(void)
791 {
792         struct CitContext *ptr = NULL;
793         struct CitContext *rem = NULL;
794
795         /*
796          * Clean up the contexts.
797          * There are no threads so no critical_section stuff is needed.
798          */
799         ptr = ContextList;
800         
801         /* We need to update the ContextList because some modules may want to itterate it
802          * Question is should we NULL it before iterating here or should we just keep updating it
803          * as we remove items?
804          *
805          * Answer is to NULL it first to prevent modules from doing any actions on the list at all
806          */
807         ContextList=NULL;
808         while (ptr != NULL){
809                 /* Remove the session from the active list */
810                 rem = ptr->next;
811                 --num_sessions;
812                 
813                 lprintf(CTDL_DEBUG, "Purging session %d\n", ptr->cs_pid);
814                 RemoveContext(ptr);
815                 free (ptr);
816                 ptr = rem;
817         }
818 }
819
820
821 /*
822  * The system-dependent part of master_cleanup() - close the master socket.
823  */
824 void sysdep_master_cleanup(void) {
825         struct ServiceFunctionHook *serviceptr;
826         
827         /*
828          * close all protocol master sockets
829          */
830         for (serviceptr = ServiceHookTable; serviceptr != NULL;
831             serviceptr = serviceptr->next ) {
832
833                 if (serviceptr->tcp_port > 0)
834                         CtdlLogPrintf(CTDL_INFO, "Closing listener on port %d\n",
835                                 serviceptr->tcp_port);
836
837                 if (serviceptr->sockpath != NULL)
838                         CtdlLogPrintf(CTDL_INFO, "Closing listener on '%s'\n",
839                                 serviceptr->sockpath);
840
841                 close(serviceptr->msock);
842
843                 /* If it's a Unix domain socket, remove the file. */
844                 if (serviceptr->sockpath != NULL) {
845                         unlink(serviceptr->sockpath);
846                 }
847         }
848         
849         context_cleanup();
850         
851 #ifdef HAVE_OPENSSL
852         destruct_ssl();
853 #endif
854         CtdlDestroyProtoHooks();
855         CtdlDestroyDeleteHooks();
856         CtdlDestroyXmsgHooks();
857         CtdlDestroyNetprocHooks();
858         CtdlDestroyUserHooks();
859         CtdlDestroyMessageHook();
860         CtdlDestroyCleanupHooks();
861         CtdlDestroyFixedOutputHooks();  
862         CtdlDestroySessionHooks();
863         CtdlDestroyServiceHook();
864         CtdlDestroyRoomHooks();
865         CtdlDestroyDirectoryServiceFuncs();
866         #ifdef HAVE_BACKTRACE
867         eCrash_Uninit();
868         #endif
869 }
870
871
872
873 /*
874  * Terminate another session.
875  * (This could justifiably be moved out of sysdep.c because it
876  * no longer does anything that is system-dependent.)
877  */
878 void kill_session(int session_to_kill) {
879         struct CitContext *ptr;
880
881         begin_critical_section(S_SESSION_TABLE);
882         for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
883                 if (ptr->cs_pid == session_to_kill) {
884                         ptr->kill_me = 1;
885                 }
886         }
887         end_critical_section(S_SESSION_TABLE);
888 }
889
890 pid_t current_child;
891 void graceful_shutdown(int signum) {
892         kill(current_child, signum);
893         unlink(file_pid_file);
894         exit(0);
895 }
896
897
898 /*
899  * Start running as a daemon.
900  */
901 void start_daemon(int unused) {
902         int status = 0;
903         pid_t child = 0;
904         FILE *fp;
905         int do_restart = 0;
906
907         current_child = 0;
908
909         /* Close stdin/stdout/stderr and replace them with /dev/null.
910          * We don't just call close() because we don't want these fd's
911          * to be reused for other files.
912          */
913         chdir(ctdl_run_dir);
914
915         child = fork();
916         if (child != 0) {
917                 exit(0);
918         }
919         
920         signal(SIGHUP, SIG_IGN);
921         signal(SIGINT, SIG_IGN);
922         signal(SIGQUIT, SIG_IGN);
923
924         setsid();
925         umask(0);
926         freopen("/dev/null", "r", stdin);
927         freopen("/dev/null", "w", stdout);
928         freopen("/dev/null", "w", stderr);
929
930         do {
931                 current_child = fork();
932
933                 signal(SIGTERM, graceful_shutdown);
934         
935                 if (current_child < 0) {
936                         perror("fork");
937                         exit(errno);
938                 }
939         
940                 else if (current_child == 0) {
941                         return; /* continue starting citadel. */
942                 }
943         
944                 else {
945                         fp = fopen(file_pid_file, "w");
946                         if (fp != NULL) {
947                 /*
948                  * NB.. The pid file contains the pid of the actual server.
949                  * This is not the pid of the watcher process
950                  */
951                                 fprintf(fp, ""F_PID_T"\n", current_child);
952                                 fclose(fp);
953                         }
954                         waitpid(current_child, &status, 0);
955                 }
956
957                 do_restart = 0;
958
959                 /* Did the main process exit with an actual exit code? */
960                 if (WIFEXITED(status)) {
961
962                         /* Exit code 0 means the watcher should exit */
963                         if (WEXITSTATUS(status) == 0) {
964                                 do_restart = 0;
965                         }
966
967                         /* Exit code 101-109 means the watcher should exit */
968                         else if ( (WEXITSTATUS(status) >= 101) && (WEXITSTATUS(status) <= 109) ) {
969                                 do_restart = 0;
970                         }
971
972                         /* Any other exit code means we should restart. */
973                         else {
974                                 do_restart = 1;
975                         }
976                 }
977
978                 /* Any other type of termination (signals, etc.) should also restart. */
979                 else {
980                         do_restart = 1;
981                 }
982
983         } while (do_restart);
984
985         unlink(file_pid_file);
986         exit(WEXITSTATUS(status));
987 }
988
989
990
991 /*
992  * Generic routine to convert a login name to a full name (gecos)
993  * Returns nonzero if a conversion took place
994  */
995 int convert_login(char NameToConvert[]) {
996         struct passwd *pw;
997         int a;
998
999         pw = getpwnam(NameToConvert);
1000         if (pw == NULL) {
1001                 return(0);
1002         }
1003         else {
1004                 strcpy(NameToConvert, pw->pw_gecos);
1005                 for (a=0; a<strlen(NameToConvert); ++a) {
1006                         if (NameToConvert[a] == ',') NameToConvert[a] = 0;
1007                 }
1008                 return(1);
1009         }
1010 }
1011
1012
1013
1014 /*
1015  * New thread interface.
1016  * To create a thread you must call one of the create thread functions.
1017  * You must pass it the address of (a pointer to a CtdlThreadNode initialised to NULL) like this
1018  * struct CtdlThreadNode *node = NULL;
1019  * pass in &node
1020  * If the thread is created *node will point to the thread control structure for the created thread.
1021  * If the thread creation fails *node remains NULL
1022  * Do not free the memory pointed to by *node, it doesn't belong to you.
1023  * This new interface duplicates much of the eCrash stuff. We should go for closer integration since that would
1024  * remove the need for the calls to eCrashRegisterThread and friends
1025  */
1026
1027
1028 struct CtdlThreadNode *CtdlThreadList = NULL;
1029 struct CtdlThreadNode *CtdlThreadSchedList = NULL;
1030
1031 /*
1032  * Condition variable and Mutex for thread garbage collection
1033  */
1034 /*static pthread_mutex_t thread_gc_mutex = PTHREAD_MUTEX_INITIALIZER;
1035 static pthread_cond_t thread_gc_cond = PTHREAD_COND_INITIALIZER;
1036 */
1037 static pthread_t GC_thread;
1038 static char *CtdlThreadStates[CTDL_THREAD_LAST_STATE];
1039 double CtdlThreadLoadAvg = 0;
1040 double CtdlThreadWorkerAvg = 0;
1041 pthread_key_t ThreadKey;
1042
1043 /*
1044  * A function to destroy the TSD
1045  */
1046 static void ctdl_thread_internal_dest_tsd(void *arg)
1047 {
1048         if (arg != NULL) {
1049                 check_handles(arg);
1050                 free(arg);
1051         }
1052 }
1053
1054
1055 /*
1056  * A function to initialise the thread TSD
1057  */
1058 void ctdl_thread_internal_init_tsd(void)
1059 {
1060         int ret;
1061         
1062         if ((ret = pthread_key_create(&ThreadKey, ctdl_thread_internal_dest_tsd))) {
1063                 lprintf(CTDL_EMERG, "pthread_key_create: %s\n",
1064                         strerror(ret));
1065                 exit(CTDLEXIT_DB);
1066         }
1067 }
1068
1069 /*
1070  * Ensure that we have a key for thread-specific data. 
1071  *
1072  * This should be called immediately after startup by any thread 
1073  * 
1074  */
1075 void CtdlThreadAllocTSD(void)
1076 {
1077         ThreadTSD *tsd;
1078
1079         if (pthread_getspecific(ThreadKey) != NULL)
1080                 return;
1081
1082         tsd = malloc(sizeof(ThreadTSD));
1083
1084         tsd->tid = NULL;
1085
1086         memset(tsd->cursors, 0, sizeof tsd->cursors);
1087         tsd->self = NULL;
1088         
1089         pthread_setspecific(ThreadKey, tsd);
1090 }
1091
1092
1093 void ctdl_thread_internal_free_tsd(void)
1094 {
1095         ctdl_thread_internal_dest_tsd(pthread_getspecific(ThreadKey));
1096         pthread_setspecific(ThreadKey, NULL);
1097 }
1098
1099
1100 void ctdl_thread_internal_cleanup(void)
1101 {
1102         int i;
1103         struct CtdlThreadNode *this_thread, *that_thread;
1104         
1105         for (i=0; i<CTDL_THREAD_LAST_STATE; i++)
1106         {
1107                 free (CtdlThreadStates[i]);
1108         }
1109         
1110         /* Clean up the scheduled thread list */
1111         this_thread = CtdlThreadSchedList;
1112         while (this_thread)
1113         {
1114                 that_thread = this_thread;
1115                 this_thread = this_thread->next;
1116                 pthread_mutex_destroy(&that_thread->ThreadMutex);
1117                 pthread_cond_destroy(&that_thread->ThreadCond);
1118                 pthread_mutex_destroy(&that_thread->SleepMutex);
1119                 pthread_cond_destroy(&that_thread->SleepCond);
1120                 pthread_attr_destroy(&that_thread->attr);
1121                 free(that_thread);
1122         }
1123         ctdl_thread_internal_free_tsd();
1124 }
1125
1126 void ctdl_thread_internal_init(void)
1127 {
1128         struct CtdlThreadNode *this_thread;
1129         int ret = 0;
1130         
1131         GC_thread = pthread_self();
1132         CtdlThreadStates[CTDL_THREAD_INVALID] = strdup ("Invalid Thread");
1133         CtdlThreadStates[CTDL_THREAD_VALID] = strdup("Valid Thread");
1134         CtdlThreadStates[CTDL_THREAD_CREATE] = strdup("Thread being Created");
1135         CtdlThreadStates[CTDL_THREAD_CANCELLED] = strdup("Thread Cancelled");
1136         CtdlThreadStates[CTDL_THREAD_EXITED] = strdup("Thread Exited");
1137         CtdlThreadStates[CTDL_THREAD_STOPPING] = strdup("Thread Stopping");
1138         CtdlThreadStates[CTDL_THREAD_STOP_REQ] = strdup("Thread Stop Requested");
1139         CtdlThreadStates[CTDL_THREAD_SLEEPING] = strdup("Thread Sleeping");
1140         CtdlThreadStates[CTDL_THREAD_RUNNING] = strdup("Thread Running");
1141         CtdlThreadStates[CTDL_THREAD_BLOCKED] = strdup("Thread Blocked");
1142         
1143         /* Get ourself a thread entry */
1144         this_thread = malloc(sizeof(struct CtdlThreadNode));
1145         if (this_thread == NULL) {
1146                 CtdlLogPrintf(CTDL_EMERG, "Thread system, can't allocate CtdlThreadNode, exiting\n");
1147                 return;
1148         }
1149         // Ensuring this is zero'd means we make sure the thread doesn't start doing its thing until we are ready.
1150         memset (this_thread, 0, sizeof(struct CtdlThreadNode));
1151         
1152         pthread_mutex_init (&(this_thread->ThreadMutex), NULL);
1153         pthread_cond_init (&(this_thread->ThreadCond), NULL);
1154         pthread_mutex_init (&(this_thread->SleepMutex), NULL);
1155         pthread_cond_init (&(this_thread->SleepCond), NULL);
1156         
1157         /* We are garbage collector so create us as running */
1158         this_thread->state = CTDL_THREAD_RUNNING;
1159         
1160         if ((ret = pthread_attr_init(&this_thread->attr))) {
1161                 CtdlLogPrintf(CTDL_EMERG, "Thread system, pthread_attr_init: %s\n", strerror(ret));
1162                 free(this_thread);
1163                 return;
1164         }
1165
1166         this_thread->name = "Garbage Collection Thread";
1167         
1168         this_thread->tid = GC_thread;
1169         CT = this_thread;
1170         
1171         num_threads++;  // Increase the count of threads in the system.
1172
1173         this_thread->next = CtdlThreadList;
1174         CtdlThreadList = this_thread;
1175         if (this_thread->next)
1176                 this_thread->next->prev = this_thread;
1177         /* Set up start times */
1178         gettimeofday(&this_thread->start_time, NULL);           /* Time this thread started */
1179         memcpy(&this_thread->last_state_change, &this_thread->start_time, sizeof (struct timeval));     /* Changed state so mark it. */
1180 }
1181
1182
1183 /*
1184  * A function to update a threads load averages
1185  */
1186  void ctdl_thread_internal_update_avgs(struct CtdlThreadNode *this_thread)
1187  {
1188         struct timeval now, result;
1189         double last_duration;
1190
1191         gettimeofday(&now, NULL);
1192         timersub(&now, &(this_thread->last_state_change), &result);
1193         pthread_mutex_lock(&this_thread->ThreadMutex);
1194         // result now has a timeval for the time we spent in the last state since we last updated
1195         last_duration = (double)result.tv_sec + ((double)result.tv_usec / (double) 1000000);
1196         if (this_thread->state == CTDL_THREAD_SLEEPING)
1197                 this_thread->avg_sleeping += last_duration;
1198         if (this_thread->state == CTDL_THREAD_RUNNING)
1199                 this_thread->avg_running += last_duration;
1200         if (this_thread->state == CTDL_THREAD_BLOCKED)
1201                 this_thread->avg_blocked += last_duration;
1202         memcpy (&this_thread->last_state_change, &now, sizeof (struct timeval));
1203         pthread_mutex_unlock(&this_thread->ThreadMutex);
1204 }
1205
1206 /*
1207  * A function to chenge the state of a thread
1208  */
1209 void ctdl_thread_internal_change_state (struct CtdlThreadNode *this_thread, enum CtdlThreadState new_state)
1210 {
1211         /*
1212          * Wether we change state or not we need update the load values
1213          */
1214         ctdl_thread_internal_update_avgs(this_thread);
1215         pthread_mutex_lock(&this_thread->ThreadMutex); /* To prevent race condition of a sleeping thread */
1216         if ((new_state == CTDL_THREAD_STOP_REQ) && (this_thread->state > CTDL_THREAD_STOP_REQ))
1217                 this_thread->state = new_state;
1218         if (((new_state == CTDL_THREAD_SLEEPING) || (new_state == CTDL_THREAD_BLOCKED)) && (this_thread->state == CTDL_THREAD_RUNNING))
1219                 this_thread->state = new_state;
1220         if ((new_state == CTDL_THREAD_RUNNING) && ((this_thread->state == CTDL_THREAD_SLEEPING) || (this_thread->state == CTDL_THREAD_BLOCKED)))
1221                 this_thread->state = new_state;
1222         pthread_mutex_unlock(&this_thread->ThreadMutex);
1223 }
1224
1225
1226 /*
1227  * A function to tell all threads to exit
1228  */
1229 void CtdlThreadStopAll(void)
1230 {
1231         //FIXME: The signalling of the condition should not be in the critical_section
1232         // We need to build a list of threads we are going to signal and then signal them afterwards
1233         
1234         struct CtdlThreadNode *this_thread;
1235         
1236         begin_critical_section(S_THREAD_LIST);
1237         this_thread = CtdlThreadList;
1238         while(this_thread)
1239         {
1240 #ifdef THREADS_USESIGNALS
1241                 pthread_kill(this_thread->tid, SIGHUP);
1242 #endif
1243                 ctdl_thread_internal_change_state (this_thread, CTDL_THREAD_STOP_REQ);
1244                 pthread_cond_signal(&this_thread->ThreadCond);
1245                 pthread_cond_signal(&this_thread->SleepCond);
1246                 CtdlLogPrintf(CTDL_DEBUG, "Thread system stopping thread \"%s\" (%ld).\n", this_thread->name, this_thread->tid);
1247                 this_thread = this_thread->next;
1248         }
1249         end_critical_section(S_THREAD_LIST);
1250 }
1251
1252
1253 /*
1254  * A function to wake up all sleeping threads
1255  */
1256 void CtdlThreadWakeAll(void)
1257 {
1258         struct CtdlThreadNode *this_thread;
1259         
1260         CtdlLogPrintf(CTDL_DEBUG, "Thread system waking all threads.\n");
1261         
1262         begin_critical_section(S_THREAD_LIST);
1263         this_thread = CtdlThreadList;
1264         while(this_thread)
1265         {
1266                 if (!this_thread->thread_func)
1267                 {
1268                         pthread_cond_signal(&this_thread->ThreadCond);
1269                         pthread_cond_signal(&this_thread->SleepCond);
1270                 }
1271                 this_thread = this_thread->next;
1272         }
1273         end_critical_section(S_THREAD_LIST);
1274 }
1275
1276
1277 /*
1278  * A function to return the number of threads running in the system
1279  */
1280 int CtdlThreadGetCount(void)
1281 {
1282         return  num_threads;
1283 }
1284
1285 int CtdlThreadGetWorkers(void)
1286 {
1287         return  num_workers;
1288 }
1289
1290 double CtdlThreadGetWorkerAvg(void)
1291 {
1292         double ret;
1293         
1294         begin_critical_section(S_THREAD_LIST);
1295         ret =  CtdlThreadWorkerAvg;
1296         end_critical_section(S_THREAD_LIST);
1297         return ret;
1298 }
1299
1300 double CtdlThreadGetLoadAvg(void)
1301 {
1302         double ret;
1303         
1304         begin_critical_section(S_THREAD_LIST);
1305         ret =  CtdlThreadLoadAvg;
1306         end_critical_section(S_THREAD_LIST);
1307         return ret;
1308 }
1309
1310
1311
1312
1313 /*
1314  * A function to rename a thread
1315  * Returns a const char *
1316  */
1317 const char *CtdlThreadName(const char *name)
1318 {
1319         const char *old_name;
1320         
1321         if (!CT)
1322         {
1323                 CtdlLogPrintf(CTDL_WARNING, "Thread system WARNING. Attempt to CtdlThreadRename() a non thread. %s\n", name);
1324                 return NULL;
1325         }
1326 // FIXME: do we need this lock? I think not since the pointer asignmaent should be atomic
1327         pthread_mutex_lock(&CT->ThreadMutex);
1328         old_name = CT->name;
1329         if (name)
1330                 CT->name = name;
1331         pthread_mutex_unlock(&CT->ThreadMutex);
1332         return (old_name);
1333 }       
1334
1335
1336 /*
1337  * A function to force a thread to exit
1338  */
1339 void CtdlThreadCancel(struct CtdlThreadNode *thread)
1340 {
1341         struct CtdlThreadNode *this_thread;
1342         
1343         if (!thread)
1344                 this_thread = CT;
1345         else
1346                 this_thread = thread;
1347         if (!this_thread)
1348         {
1349                 CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC. Attempt to CtdlThreadCancel() a non thread.\n");
1350                 CtdlThreadStopAll();
1351                 return;
1352         }
1353         
1354         if (!this_thread->thread_func)
1355         {
1356                 CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC. Attempt to CtdlThreadCancel() the garbage collector.\n");
1357                 CtdlThreadStopAll();
1358                 return;
1359         }
1360         
1361         ctdl_thread_internal_change_state (this_thread, CTDL_THREAD_CANCELLED);
1362         pthread_cancel(this_thread->tid);
1363 }
1364
1365
1366
1367 /*
1368  * A function for a thread to check if it has been asked to stop
1369  */
1370 int CtdlThreadCheckStop(void)
1371 {
1372         int state;
1373         
1374         if (!CT)
1375         {
1376                 CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC, CtdlThreadCheckStop() called by a non thread.\n");
1377                 CtdlThreadStopAll();
1378                 return -1;
1379         }
1380         
1381         state = CT->state;
1382
1383 #ifdef THREADS_USERSIGNALS
1384         if (CT->signal)
1385                 CtdlLogPrintf(CTDL_DEBUG, "Thread \"%s\" caught signal %d.\n", CT->name, CT->signal);
1386 #endif
1387         pthread_mutex_lock(&CT->ThreadMutex);
1388         if(state == CTDL_THREAD_STOP_REQ)
1389         {
1390                 CT->state = CTDL_THREAD_STOPPING;
1391                 pthread_mutex_unlock(&CT->ThreadMutex);
1392                 return -1;
1393         }
1394         else if((state < CTDL_THREAD_STOP_REQ) && (state > CTDL_THREAD_CREATE))
1395         {
1396                 pthread_mutex_unlock(&CT->ThreadMutex);
1397                 return -1;
1398         }
1399         pthread_mutex_unlock(&CT->ThreadMutex);
1400         return 0;
1401 }
1402
1403
1404 /*
1405  * A function to ask a thread to exit
1406  * The thread must call CtdlThreadCheckStop() periodically to determine if it should exit
1407  */
1408 void CtdlThreadStop(struct CtdlThreadNode *thread)
1409 {
1410         struct CtdlThreadNode *this_thread;
1411         
1412         if (!thread)
1413                 this_thread = CT;
1414         else
1415                 this_thread = thread;
1416         if (!this_thread)
1417                 return;
1418         if (!(this_thread->thread_func))
1419                 return;         // Don't stop garbage collector
1420 #ifdef THREADS_USESIGNALS
1421         pthread_kill(this_thread->tid, SIGHUP); 
1422 #endif
1423         ctdl_thread_internal_change_state (this_thread, CTDL_THREAD_STOP_REQ);
1424         pthread_cond_signal(&this_thread->ThreadCond);
1425         pthread_cond_signal(&this_thread->SleepCond);
1426 }
1427
1428 /*
1429  * So we now have a sleep command that works with threads but it is in seconds
1430  */
1431 void CtdlThreadSleep(int secs)
1432 {
1433         struct timespec wake_time;
1434         struct timeval time_now;
1435         
1436         
1437         if (!CT)
1438         {
1439                 CtdlLogPrintf(CTDL_WARNING, "CtdlThreadSleep() called by something that is not a thread. Should we die?\n");
1440                 return;
1441         }
1442         
1443         memset (&wake_time, 0, sizeof(struct timespec));
1444         gettimeofday(&time_now, NULL);
1445         wake_time.tv_sec = time_now.tv_sec + secs;
1446         wake_time.tv_nsec = time_now.tv_usec * 10;
1447
1448         ctdl_thread_internal_change_state (CT, CTDL_THREAD_SLEEPING);
1449         
1450         pthread_mutex_lock(&CT->ThreadMutex); /* Prevent something asking us to awaken before we've gone to sleep */
1451         pthread_cond_timedwait(&CT->SleepCond, &CT->ThreadMutex, &wake_time);
1452         pthread_mutex_unlock(&CT->ThreadMutex);
1453         
1454         ctdl_thread_internal_change_state (CT, CTDL_THREAD_RUNNING);
1455 }
1456
1457
1458 /*
1459  * Routine to clean up our thread function on exit
1460  */
1461 static void ctdl_internal_thread_cleanup(void *arg)
1462 {
1463         /*
1464          * In here we were called by the current thread because it is exiting
1465          * NB. WE ARE THE CURRENT THREAD
1466          */
1467         CtdlLogPrintf(CTDL_NOTICE, "Thread \"%s\" (%ld) exited.\n", CT->name, CT->tid);
1468         
1469         #ifdef HAVE_BACKTRACE
1470         eCrash_UnregisterThread();
1471         #endif
1472         
1473         pthread_mutex_lock(&CT->ThreadMutex);
1474         CT->state = CTDL_THREAD_EXITED; // needs to be last thing else house keeping will unlink us too early
1475         pthread_mutex_unlock(&CT->ThreadMutex);
1476 }
1477
1478 /*
1479  * A quick function to show the load averages
1480  */
1481 void ctdl_thread_internal_calc_loadavg(void)
1482 {
1483         struct CtdlThreadNode *that_thread;
1484         double load_avg, worker_avg;
1485         int workers = 0;
1486
1487         that_thread = CtdlThreadList;
1488         load_avg = 0;
1489         worker_avg = 0;
1490         while(that_thread)
1491         {
1492                 /* Update load averages */
1493                 ctdl_thread_internal_update_avgs(that_thread);
1494                 pthread_mutex_lock(&that_thread->ThreadMutex);
1495                 that_thread->load_avg = that_thread->avg_sleeping + that_thread->avg_running + that_thread->avg_blocked;
1496                 that_thread->load_avg = that_thread->avg_running / that_thread->load_avg * 100;
1497                 that_thread->avg_sleeping /= 2;
1498                 that_thread->avg_running /= 2;
1499                 that_thread->avg_blocked /= 2;
1500                 load_avg += that_thread->load_avg;
1501                 if (that_thread->flags & CTDLTHREAD_WORKER)
1502                 {
1503                         worker_avg += that_thread->load_avg;
1504                         workers++;
1505                 }
1506 #ifdef WITH_THREADLOG
1507                 CtdlLogPrintf(CTDL_DEBUG, "CtdlThread, \"%s\" (%ld) \"%s\" %f %f %f %f.\n",
1508                         that_thread->name,
1509                         that_thread->tid,
1510                         CtdlThreadStates[that_thread->state],
1511                         that_thread->avg_sleeping,
1512                         that_thread->avg_running,
1513                         that_thread->avg_blocked,
1514                         that_thread->load_avg);
1515 #endif
1516                 pthread_mutex_unlock(&that_thread->ThreadMutex);
1517                 that_thread = that_thread->next;
1518         }
1519         CtdlThreadLoadAvg = load_avg/num_threads;
1520         CtdlThreadWorkerAvg = worker_avg/workers;
1521 #ifdef WITH_THREADLOG
1522         CtdlLogPrintf(CTDL_INFO, "System load average %f, workers averag %f, threads %d, workers %d, sessions %d\n", CtdlThreadLoadAvg, CtdlThreadWorkerAvg, num_threads, num_workers, num_sessions);
1523 #endif
1524 }
1525
1526
1527 /*
1528  * Garbage collection routine.
1529  * Gets called by main() in a loop to clean up the thread list periodically.
1530  */
1531 void CtdlThreadGC (void)
1532 {
1533         struct CtdlThreadNode *this_thread, *that_thread;
1534         int workers = 0;
1535         int ret=0;
1536         
1537         begin_critical_section(S_THREAD_LIST);
1538         
1539         /* Handle exiting of garbage collector thread */
1540         if(num_threads == 1)
1541                 CtdlThreadList->state = CTDL_THREAD_EXITED;
1542         
1543 #ifdef WITH_THREADLOG
1544         CtdlLogPrintf(CTDL_DEBUG, "Thread system running garbage collection.\n");
1545 #endif
1546         /*
1547          * Woke up to do garbage collection
1548          */
1549         this_thread = CtdlThreadList;
1550         while(this_thread)
1551         {
1552                 that_thread = this_thread;
1553                 this_thread = this_thread->next;
1554                 
1555                 /* Do we need to clean up this thread? */
1556                 pthread_mutex_lock(&that_thread->ThreadMutex);
1557                 if (that_thread->state != CTDL_THREAD_EXITED)
1558                 {
1559                         if(that_thread->flags & CTDLTHREAD_WORKER)
1560                                 workers++;      /* Sanity check on number of worker threads */
1561                         pthread_mutex_unlock(&that_thread->ThreadMutex);
1562                         continue;
1563                 }
1564                 
1565                 if (pthread_equal(that_thread->tid, pthread_self()) && that_thread->thread_func)
1566                 {       /* Sanity check */
1567                         pthread_mutex_unlock(&that_thread->ThreadMutex);
1568                         end_critical_section(S_THREAD_LIST);
1569                         CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC, a thread is trying to clean up after itself.\n");
1570                         abort();
1571                         return;
1572                 }
1573                 
1574                 if (num_threads <= 0)
1575                 {       /* Sanity check */
1576                         pthread_mutex_unlock(&that_thread->ThreadMutex);
1577                         end_critical_section(S_THREAD_LIST);
1578                         CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC, num_threads <= 0 and trying to do Garbage Collection.\n");
1579                         abort();
1580                         return;
1581                 }
1582
1583                 if(that_thread->flags & CTDLTHREAD_WORKER)
1584                         num_workers--;  /* This is a wroker thread so reduce the count. */
1585                 num_threads--;
1586                 /* If we are unlinking the list head then the next becomes the list head */
1587                 if(that_thread->prev)
1588                         that_thread->prev->next = that_thread->next;
1589                 else
1590                         CtdlThreadList = that_thread->next;
1591                 if(that_thread->next)
1592                         that_thread->next->prev = that_thread->prev;
1593                 
1594                 pthread_mutex_unlock(&that_thread->ThreadMutex);
1595                 pthread_cond_signal(&that_thread->ThreadCond);
1596                 pthread_cond_signal(&that_thread->SleepCond);   // Make sure this thread is awake
1597                 pthread_mutex_lock(&that_thread->ThreadMutex);  // Make sure it has done what its doing
1598                 pthread_mutex_unlock(&that_thread->ThreadMutex);
1599                 /*
1600                  * Join on the thread to do clean up and prevent memory leaks
1601                  * Also makes sure the thread has cleaned up after itself before we remove it from the list
1602                  * We can join on the garbage collector thread the join should just return EDEADLCK
1603                  */
1604                 ret = pthread_join (that_thread->tid, NULL);
1605                 if (ret == EDEADLK)
1606                         CtdlLogPrintf(CTDL_DEBUG, "Garbage collection on own thread.\n");
1607                 else if (ret == EINVAL)
1608                         CtdlLogPrintf(CTDL_DEBUG, "Garbage collection, that thread already joined on.\n");
1609                 else if (ret == ESRCH)
1610                         CtdlLogPrintf(CTDL_DEBUG, "Garbage collection, no thread to join on.\n");
1611                 else if (ret != 0)
1612                         CtdlLogPrintf(CTDL_DEBUG, "Garbage collection, pthread_join returned an unknown error.\n");
1613                 /*
1614                  * Now we own that thread entry
1615                  */
1616                 CtdlLogPrintf(CTDL_INFO, "Garbage Collection for thread \"%s\" (%ld).\n", that_thread->name, that_thread->tid);
1617                 pthread_mutex_destroy(&that_thread->ThreadMutex);
1618                 pthread_cond_destroy(&that_thread->ThreadCond);
1619                 pthread_mutex_destroy(&that_thread->SleepMutex);
1620                 pthread_cond_destroy(&that_thread->SleepCond);
1621                 pthread_attr_destroy(&that_thread->attr);
1622                 free(that_thread);
1623         }
1624         
1625         /* Sanity check number of worker threads */
1626         if (workers != num_workers)
1627         {
1628                 end_critical_section(S_THREAD_LIST);
1629                 CtdlLogPrintf(CTDL_EMERG,
1630                         "Thread system PANIC, discrepancy in number of worker threads. Counted %d, should be %d.\n",
1631                         workers, num_workers
1632                         );
1633                 abort();
1634         }
1635         end_critical_section(S_THREAD_LIST);
1636 }
1637
1638
1639
1640  
1641 /*
1642  * Runtime function for a Citadel Thread.
1643  * This initialises the threads environment and then calls the user supplied thread function
1644  * Note that this is the REAL thread function and wraps the users thread function.
1645  */ 
1646 static void *ctdl_internal_thread_func (void *arg)
1647 {
1648         struct CtdlThreadNode *this_thread;
1649         void *ret = NULL;
1650
1651         /* lock and unlock the thread list.
1652          * This causes this thread to wait until all its creation stuff has finished before it
1653          * can continue its execution.
1654          */
1655         begin_critical_section(S_THREAD_LIST);
1656         this_thread = (struct CtdlThreadNode *) arg;
1657         gettimeofday(&this_thread->start_time, NULL);           /* Time this thread started */
1658         pthread_mutex_lock(&this_thread->ThreadMutex);
1659         
1660         // Register the cleanup function to take care of when we exit.
1661         pthread_cleanup_push(ctdl_internal_thread_cleanup, NULL);
1662         // Get our thread data structure
1663         CtdlThreadAllocTSD();
1664         CT = this_thread;
1665         this_thread->pid = getpid();
1666         memcpy(&this_thread->last_state_change, &this_thread->start_time, sizeof (struct timeval));     /* Changed state so mark it. */
1667         /* Only change to running state if we weren't asked to stop during the create cycle
1668          * Other wise there is a window to allow this threads creation to continue to full grown and
1669          * therby prevent a shutdown of the server.
1670          */
1671         pthread_mutex_unlock(&this_thread->ThreadMutex);
1672                 
1673         if (!CtdlThreadCheckStop())
1674         {
1675                 pthread_mutex_lock(&this_thread->ThreadMutex);
1676                 this_thread->state = CTDL_THREAD_RUNNING;
1677                 pthread_mutex_unlock(&this_thread->ThreadMutex);
1678         }
1679         end_critical_section(S_THREAD_LIST);
1680         
1681         // Register for tracing
1682         #ifdef HAVE_BACKTRACE
1683         eCrash_RegisterThread(this_thread->name, 0);
1684         #endif
1685         
1686         // Tell the world we are here
1687         CtdlLogPrintf(CTDL_NOTICE, "Created a new thread \"%s\" (%ld). \n", this_thread->name, this_thread->tid);
1688
1689         
1690         
1691         /*
1692          * run the thread to do the work but only if we haven't been asked to stop
1693          */
1694         if (!CtdlThreadCheckStop())
1695                 ret = (this_thread->thread_func)(this_thread->user_args);
1696         
1697         /*
1698          * Our thread is exiting either because it wanted to end or because the server is stopping
1699          * We need to clean up
1700          */
1701         pthread_cleanup_pop(1); // Execute our cleanup routine and remove it
1702         
1703         return(ret);
1704 }
1705
1706
1707  
1708 /*
1709  * Internal function to create a thread.
1710  * Must be called from within a S_THREAD_LIST critical section
1711  */ 
1712 struct CtdlThreadNode *ctdl_internal_create_thread(char *name, long flags, void *(*thread_func) (void *arg), void *args)
1713 {
1714         int ret = 0;
1715         struct CtdlThreadNode *this_thread;
1716
1717         if (num_threads >= 32767)
1718         {
1719                 CtdlLogPrintf(CTDL_EMERG, "Thread system. Thread list full.\n");
1720                 return NULL;
1721         }
1722                 
1723         this_thread = malloc(sizeof(struct CtdlThreadNode));
1724         if (this_thread == NULL) {
1725                 CtdlLogPrintf(CTDL_EMERG, "Thread system, can't allocate CtdlThreadNode, exiting\n");
1726                 return NULL;
1727         }
1728         // Ensuring this is zero'd means we make sure the thread doesn't start doing its thing until we are ready.
1729         memset (this_thread, 0, sizeof(struct CtdlThreadNode));
1730         
1731         /* Create the mutex's early so we can use them */
1732         pthread_mutex_init (&(this_thread->ThreadMutex), NULL);
1733         pthread_cond_init (&(this_thread->ThreadCond), NULL);
1734         pthread_mutex_init (&(this_thread->SleepMutex), NULL);
1735         pthread_cond_init (&(this_thread->SleepCond), NULL);
1736         
1737         pthread_mutex_lock(&this_thread->ThreadMutex);
1738         
1739         this_thread->state = CTDL_THREAD_CREATE;
1740         
1741         if ((ret = pthread_attr_init(&this_thread->attr))) {
1742                 pthread_mutex_unlock(&this_thread->ThreadMutex);
1743                 pthread_mutex_destroy(&(this_thread->ThreadMutex));
1744                 pthread_cond_destroy(&(this_thread->ThreadCond));
1745                 pthread_mutex_destroy(&(this_thread->SleepMutex));
1746                 pthread_cond_destroy(&(this_thread->SleepCond));
1747                 CtdlLogPrintf(CTDL_EMERG, "Thread system, pthread_attr_init: %s\n", strerror(ret));
1748                 free(this_thread);
1749                 return NULL;
1750         }
1751
1752         /* Our per-thread stacks need to be bigger than the default size,
1753          * otherwise the MIME parser crashes on FreeBSD, and the IMAP service
1754          * crashes on 64-bit Linux.
1755          */
1756         if (flags & CTDLTHREAD_BIGSTACK)
1757         {
1758 #ifdef WITH_THREADLOG
1759                 CtdlLogPrintf(CTDL_INFO, "Thread system. Creating BIG STACK thread.\n");
1760 #endif
1761                 if ((ret = pthread_attr_setstacksize(&this_thread->attr, THREADSTACKSIZE))) {
1762                         pthread_mutex_unlock(&this_thread->ThreadMutex);
1763                         pthread_mutex_destroy(&(this_thread->ThreadMutex));
1764                         pthread_cond_destroy(&(this_thread->ThreadCond));
1765                         pthread_mutex_destroy(&(this_thread->SleepMutex));
1766                         pthread_cond_destroy(&(this_thread->SleepCond));
1767                         pthread_attr_destroy(&this_thread->attr);
1768                         CtdlLogPrintf(CTDL_EMERG, "Thread system, pthread_attr_setstacksize: %s\n",
1769                                 strerror(ret));
1770                         free(this_thread);
1771                         return NULL;
1772                 }
1773         }
1774
1775         /*
1776          * If we got here we are going to create the thread so we must initilise the structure
1777          * first because most implimentations of threading can't create it in a stopped state
1778          * and it might want to do things with its structure that aren't initialised otherwise.
1779          */
1780         if(name)
1781         {
1782                 this_thread->name = name;
1783         }
1784         else
1785         {
1786                 this_thread->name = "Un-named Thread";
1787         }
1788         
1789         this_thread->flags = flags;
1790         this_thread->thread_func = thread_func;
1791         this_thread->user_args = args;
1792         /* Set this new thread with an avg_blocked of 2. We do this so that its creation affects the
1793          * load average for the system. If we don't do this then we create a mass of threads at the same time 
1794          * because the creation didn't affect the load average.
1795          */
1796         this_thread->avg_blocked = 2;
1797         
1798         /*
1799          * We pass this_thread into the thread as its args so that it can find out information
1800          * about itself and it has a bit of storage space for itself, not to mention that the REAL
1801          * thread function needs to finish off the setup of the structure
1802          */
1803         if ((ret = pthread_create(&this_thread->tid, &this_thread->attr, ctdl_internal_thread_func, this_thread) != 0))
1804         {
1805
1806                 CtdlLogPrintf(CTDL_ALERT, "Thread system, Can't create thread: %s\n",
1807                         strerror(ret));
1808                 pthread_mutex_unlock(&this_thread->ThreadMutex);
1809                 pthread_mutex_destroy(&(this_thread->ThreadMutex));
1810                 pthread_cond_destroy(&(this_thread->ThreadCond));
1811                 pthread_mutex_destroy(&(this_thread->SleepMutex));
1812                 pthread_cond_destroy(&(this_thread->SleepCond));
1813                 pthread_attr_destroy(&this_thread->attr);
1814                 free(this_thread);
1815                 return NULL;
1816         }
1817         
1818         num_threads++;  // Increase the count of threads in the system.
1819         if(this_thread->flags & CTDLTHREAD_WORKER)
1820                 num_workers++;
1821
1822         this_thread->next = CtdlThreadList;
1823         CtdlThreadList = this_thread;
1824         if (this_thread->next)
1825                 this_thread->next->prev = this_thread;
1826         
1827         pthread_mutex_unlock(&this_thread->ThreadMutex);
1828         
1829         ctdl_thread_internal_calc_loadavg();
1830         return this_thread;
1831 }
1832
1833 /*
1834  * Wrapper function to create a thread
1835  * ensures the critical section and other protections are in place.
1836  * char *name = name to give to thread, if NULL, use generic name
1837  * int flags = flags to determine type of thread and standard facilities
1838  */
1839 struct CtdlThreadNode *CtdlThreadCreate(char *name, long flags, void *(*thread_func) (void *arg), void *args)
1840 {
1841         struct CtdlThreadNode *ret = NULL;
1842         
1843         begin_critical_section(S_THREAD_LIST);
1844         ret = ctdl_internal_create_thread(name, flags, thread_func, args);
1845         end_critical_section(S_THREAD_LIST);
1846         return ret;
1847 }
1848
1849
1850
1851 /*
1852  * Internal function to schedule a thread.
1853  * Must be called from within a S_THREAD_LIST critical section
1854  */ 
1855 struct CtdlThreadNode *CtdlThreadSchedule(char *name, long flags, void *(*thread_func) (void *arg), void *args, time_t when)
1856 {
1857         int ret = 0;
1858         struct CtdlThreadNode *this_thread;
1859
1860         if (num_threads >= 32767)
1861         {
1862                 CtdlLogPrintf(CTDL_EMERG, "Thread system. Thread list full.\n");
1863                 return NULL;
1864         }
1865                 
1866         this_thread = malloc(sizeof(struct CtdlThreadNode));
1867         if (this_thread == NULL) {
1868                 CtdlLogPrintf(CTDL_EMERG, "Thread system, can't allocate CtdlThreadNode, exiting\n");
1869                 return NULL;
1870         }
1871         // Ensuring this is zero'd means we make sure the thread doesn't start doing its thing until we are ready.
1872         memset (this_thread, 0, sizeof(struct CtdlThreadNode));
1873         
1874         /* Create the mutex's early so we can use them */
1875         pthread_mutex_init (&(this_thread->ThreadMutex), NULL);
1876         pthread_cond_init (&(this_thread->ThreadCond), NULL);
1877         pthread_mutex_init (&(this_thread->SleepMutex), NULL);
1878         pthread_cond_init (&(this_thread->SleepCond), NULL);
1879         
1880         this_thread->state = CTDL_THREAD_CREATE;
1881         
1882         if ((ret = pthread_attr_init(&this_thread->attr))) {
1883                 pthread_mutex_destroy(&(this_thread->ThreadMutex));
1884                 pthread_cond_destroy(&(this_thread->ThreadCond));
1885                 pthread_mutex_destroy(&(this_thread->SleepMutex));
1886                 pthread_cond_destroy(&(this_thread->SleepCond));
1887                 CtdlLogPrintf(CTDL_EMERG, "Thread system, pthread_attr_init: %s\n", strerror(ret));
1888                 free(this_thread);
1889                 return NULL;
1890         }
1891
1892         /* Our per-thread stacks need to be bigger than the default size,
1893          * otherwise the MIME parser crashes on FreeBSD, and the IMAP service
1894          * crashes on 64-bit Linux.
1895          */
1896         if (flags & CTDLTHREAD_BIGSTACK)
1897         {
1898                 CtdlLogPrintf(CTDL_INFO, "Thread system. Creating BIG STACK thread.\n");
1899                 if ((ret = pthread_attr_setstacksize(&this_thread->attr, THREADSTACKSIZE))) {
1900                         pthread_mutex_destroy(&(this_thread->ThreadMutex));
1901                         pthread_cond_destroy(&(this_thread->ThreadCond));
1902                         pthread_mutex_destroy(&(this_thread->SleepMutex));
1903                         pthread_cond_destroy(&(this_thread->SleepCond));
1904                         pthread_attr_destroy(&this_thread->attr);
1905                         CtdlLogPrintf(CTDL_EMERG, "Thread system, pthread_attr_setstacksize: %s\n",
1906                                 strerror(ret));
1907                         free(this_thread);
1908                         return NULL;
1909                 }
1910         }
1911
1912         /*
1913          * If we got here we are going to create the thread so we must initilise the structure
1914          * first because most implimentations of threading can't create it in a stopped state
1915          * and it might want to do things with its structure that aren't initialised otherwise.
1916          */
1917         if(name)
1918         {
1919                 this_thread->name = name;
1920         }
1921         else
1922         {
1923                 this_thread->name = "Un-named Thread";
1924         }
1925         
1926         this_thread->flags = flags;
1927         this_thread->thread_func = thread_func;
1928         this_thread->user_args = args;
1929         /* Set this new thread with an avg_blocked of 2. We do this so that its creation affects the
1930          * load average for the system. If we don't do this then we create a mass of threads at the same time 
1931          * because the creation didn't affect the load average.
1932          */
1933         this_thread->avg_blocked = 2;
1934         
1935         /*
1936          * When to start this thread
1937          */
1938         this_thread->when = when;
1939
1940         begin_critical_section(S_SCHEDULE_LIST);
1941         this_thread->next = CtdlThreadSchedList;
1942         CtdlThreadSchedList = this_thread;
1943         if (this_thread->next)
1944                 this_thread->next->prev = this_thread;
1945         end_critical_section(S_SCHEDULE_LIST);
1946         
1947         return this_thread;
1948 }
1949
1950
1951
1952 struct CtdlThreadNode *ctdl_thread_internal_start_scheduled (struct CtdlThreadNode *this_thread)
1953 {
1954         int ret = 0;
1955         
1956         /*
1957          * We pass this_thread into the thread as its args so that it can find out information
1958          * about itself and it has a bit of storage space for itself, not to mention that the REAL
1959          * thread function needs to finish off the setup of the structure
1960          */
1961         if ((ret = pthread_create(&this_thread->tid, &this_thread->attr, ctdl_internal_thread_func, this_thread) != 0))
1962         {
1963
1964                 CtdlLogPrintf(CTDL_ALERT, "Thread system, Can't create thread: %s\n",
1965                         strerror(ret));
1966                 return NULL;
1967         }
1968         
1969         
1970         num_threads++;  // Increase the count of threads in the system.
1971         if(this_thread->flags & CTDLTHREAD_WORKER)
1972                 num_workers++;
1973
1974         this_thread->next = CtdlThreadList;
1975         CtdlThreadList = this_thread;
1976         if (this_thread->next)
1977                 this_thread->next->prev = this_thread;
1978         
1979         return this_thread;
1980 }
1981
1982
1983
1984 void ctdl_thread_internal_check_scheduled(void)
1985 {
1986         struct CtdlThreadNode *this_thread, *that_thread;
1987         time_t now;
1988         
1989         if (try_critical_section(S_SCHEDULE_LIST))
1990                 return; /* If this list is locked we wait till the next chance */
1991         
1992         now = time(NULL);
1993         
1994 #ifdef WITH_THREADLOG
1995         CtdlLogPrintf(CTDL_DEBUG, "Checking for scheduled threads to start.\n");
1996 #endif
1997
1998         this_thread = CtdlThreadSchedList;
1999         while(this_thread)
2000         {
2001                 that_thread = this_thread;
2002                 this_thread = this_thread->next;
2003                 
2004                 if (now > that_thread->when)
2005                 {
2006                         /* Unlink from schedule list */
2007                         if (that_thread->prev)
2008                                 that_thread->prev->next = that_thread->next;
2009                         else
2010                                 CtdlThreadSchedList = that_thread->next;
2011                         if (that_thread->next)
2012                                 that_thread->next->prev = that_thread->prev;
2013                                 
2014                         that_thread->next = that_thread->prev = NULL;
2015 #ifdef WITH_THREADLOG
2016                         CtdlLogPrintf(CTDL_DEBUG, "About to start scheduled thread \"%s\".\n", that_thread->name);
2017 #endif
2018                         begin_critical_section(S_THREAD_LIST);
2019                         if (CT->state > CTDL_THREAD_STOP_REQ)
2020                         {       /* Only start it if the system is not stopping */
2021                                 pthread_mutex_lock(&that_thread->ThreadMutex);
2022                                 if (ctdl_thread_internal_start_scheduled (that_thread) == NULL)
2023                                 {
2024 #ifdef WITH_THREADLOG
2025                         CtdlLogPrintf(CTDL_DEBUG, "Failed to start scheduled thread \"%s\".\n", that_thread->name);
2026 #endif
2027                                         pthread_mutex_unlock(&that_thread->ThreadMutex);
2028                                         pthread_mutex_destroy(&(that_thread->ThreadMutex));
2029                                         pthread_cond_destroy(&(that_thread->ThreadCond));
2030                                         pthread_mutex_destroy(&(that_thread->SleepMutex));
2031                                         pthread_cond_destroy(&(that_thread->SleepCond));
2032                                         pthread_attr_destroy(&that_thread->attr);
2033                                         free(that_thread);
2034                                 }
2035                                 else
2036                                 {
2037                                         CtdlLogPrintf(CTDL_INFO, "Thread system, Started a scheduled thread \"%s\" (%ld).\n",
2038                                                 that_thread->name, that_thread->tid);
2039                                         pthread_mutex_unlock(&that_thread->ThreadMutex);
2040                                         ctdl_thread_internal_calc_loadavg();
2041                                 }
2042                         }
2043                         end_critical_section(S_THREAD_LIST);
2044                 }
2045                 else
2046                 {
2047 #ifdef WITH_THREADLOG
2048                         CtdlLogPrintf(CTDL_DEBUG, "Thread \"%s\" will start in %ld seconds.\n", that_thread->name, that_thread->when - time(NULL));
2049 #endif
2050                 }
2051         }
2052         end_critical_section(S_SCHEDULE_LIST);
2053 }
2054
2055
2056 /*
2057  * A warapper function for select so we can show a thread as blocked
2058  */
2059 int CtdlThreadSelect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
2060 {
2061         int ret;
2062         
2063         ctdl_thread_internal_change_state(CT, CTDL_THREAD_BLOCKED);
2064         ret = select(n, readfds, writefds, exceptfds, timeout);
2065         ctdl_thread_internal_change_state(CT, CTDL_THREAD_RUNNING);
2066         return ret;
2067 }
2068
2069 /*
2070  * Purge all sessions which have the 'kill_me' flag set.
2071  * This function has code to prevent it from running more than once every
2072  * few seconds, because running it after every single unbind would waste a lot
2073  * of CPU time and keep the context list locked too much.  To force it to run
2074  * anyway, set "force" to nonzero.
2075  */
2076 void dead_session_purge(int force) {
2077         struct CitContext *ptr, *ptr2;          /* general-purpose utility pointer */
2078         struct CitContext *rem = NULL;  /* list of sessions to be destroyed */
2079         
2080         if (force == 0) {
2081                 if ( (time(NULL) - last_purge) < 5 ) {
2082                         return; /* Too soon, go away */
2083                 }
2084         }
2085         time(&last_purge);
2086
2087         if (try_critical_section(S_SESSION_TABLE))
2088                 return;
2089                 
2090         ptr = ContextList;
2091         while (ptr) {
2092                 ptr2 = ptr;
2093                 ptr = ptr->next;
2094                 
2095                 if ( (ptr2->state == CON_IDLE) && (ptr2->kill_me) ) {
2096                         /* Remove the session from the active list */
2097                         if (ptr2->prev) {
2098                                 ptr2->prev->next = ptr2->next;
2099                         }
2100                         else {
2101                                 ContextList = ptr2->next;
2102                         }
2103                         if (ptr2->next) {
2104                                 ptr2->next->prev = ptr2->prev;
2105                         }
2106
2107                         --num_sessions;
2108                         /* And put it on our to-be-destroyed list */
2109                         ptr2->next = rem;
2110                         rem = ptr2;
2111                 }
2112         }
2113         end_critical_section(S_SESSION_TABLE);
2114
2115         /* Now that we no longer have the session list locked, we can take
2116          * our time and destroy any sessions on the to-be-killed list, which
2117          * is allocated privately on this thread's stack.
2118          */
2119         while (rem != NULL) {
2120                 CtdlLogPrintf(CTDL_DEBUG, "Purging session %d\n", rem->cs_pid);
2121                 RemoveContext(rem);
2122                 ptr = rem;
2123                 rem = rem->next;
2124                 free(ptr);
2125         }
2126 }
2127
2128
2129
2130
2131
2132 /*
2133  * masterCC is the context we use when not attached to a session.  This
2134  * function initializes it.
2135  */
2136 void InitializeMasterCC(void) {
2137         memset(&masterCC, 0, sizeof(struct CitContext));
2138         masterCC.internal_pgm = 1;
2139         masterCC.cs_pid = 0;
2140 }
2141
2142
2143
2144
2145
2146
2147 /*
2148  * Bind a thread to a context.  (It's inline merely to speed things up.)
2149  */
2150 INLINE void become_session(struct CitContext *which_con) {
2151         pthread_setspecific(MyConKey, (void *)which_con );
2152 }
2153
2154
2155
2156 /* 
2157  * This loop just keeps going and going and going...
2158  */     
2159 void *worker_thread(void *arg) {
2160         int i;
2161         int highest;
2162         struct CitContext *ptr;
2163         struct CitContext *bind_me = NULL;
2164         fd_set readfds;
2165         int retval = 0;
2166         struct CitContext *con= NULL;   /* Temporary context pointer */
2167         struct ServiceFunctionHook *serviceptr;
2168         int ssock;                      /* Descriptor for client socket */
2169         struct timeval tv;
2170         int force_purge = 0;
2171         int m;
2172         
2173
2174         while (!CtdlThreadCheckStop()) {
2175
2176                 /* make doubly sure we're not holding any stale db handles
2177                  * which might cause a deadlock.
2178                  */
2179                 cdb_check_handles();
2180 do_select:      force_purge = 0;
2181                 bind_me = NULL;         /* Which session shall we handle? */
2182
2183                 /* Initialize the fdset. */
2184                 FD_ZERO(&readfds);
2185                 highest = 0;
2186
2187                 begin_critical_section(S_SESSION_TABLE);
2188                 for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
2189                         if (ptr->state == CON_IDLE) {
2190                                 FD_SET(ptr->client_socket, &readfds);
2191                                 if (ptr->client_socket > highest)
2192                                         highest = ptr->client_socket;
2193                         }
2194                         if ((bind_me == NULL) && (ptr->state == CON_READY)) {
2195                                 bind_me = ptr;
2196                                 ptr->state = CON_EXECUTING;
2197                         }
2198                 }
2199                 end_critical_section(S_SESSION_TABLE);
2200
2201                 if (bind_me) {
2202                         goto SKIP_SELECT;
2203                 }
2204
2205                 /* If we got this far, it means that there are no sessions
2206                  * which a previous thread marked for attention, so we go
2207                  * ahead and get ready to select().
2208                  */
2209
2210                 /* First, add the various master sockets to the fdset. */
2211                 for (serviceptr = ServiceHookTable; serviceptr != NULL;
2212                 serviceptr = serviceptr->next ) {
2213                         m = serviceptr->msock;
2214                         FD_SET(m, &readfds);
2215                         if (m > highest) {
2216                                 highest = m;
2217                         }
2218                 }
2219
2220                 if (!CtdlThreadCheckStop()) {
2221                         tv.tv_sec = 1;          /* wake up every second if no input */
2222                         tv.tv_usec = 0;
2223                         retval = CtdlThreadSelect(highest + 1, &readfds, NULL, NULL, &tv);
2224                 }
2225
2226                 if (CtdlThreadCheckStop()) return(NULL);
2227
2228                 /* Now figure out who made this select() unblock.
2229                  * First, check for an error or exit condition.
2230                  */
2231                 if (retval < 0) {
2232                         if (errno == EBADF) {
2233                                 CtdlLogPrintf(CTDL_NOTICE, "select() failed: (%s)\n",
2234                                         strerror(errno));
2235                                 goto do_select;
2236                         }
2237                         if (errno != EINTR) {
2238                                 CtdlLogPrintf(CTDL_EMERG, "Exiting (%s)\n", strerror(errno));
2239                                 CtdlThreadStopAll();
2240                         } else if (!CtdlThreadCheckStop()) {
2241                                 CtdlLogPrintf(CTDL_DEBUG, "Un handled select failure.\n");
2242                                 goto do_select;
2243                         }
2244                 }
2245                 else if(retval == 0) {
2246                         goto SKIP_SELECT;
2247                 }
2248                 /* Next, check to see if it's a new client connecting
2249                  * on a master socket.
2250                  */
2251                 else for (serviceptr = ServiceHookTable; serviceptr != NULL;
2252                      serviceptr = serviceptr->next ) {
2253
2254                         if (FD_ISSET(serviceptr->msock, &readfds)) {
2255                                 ssock = accept(serviceptr->msock, NULL, 0);
2256                                 if (ssock >= 0) {
2257                                         CtdlLogPrintf(CTDL_DEBUG,
2258                                                 "New client socket %d\n",
2259                                                 ssock);
2260
2261                                         /* The master socket is non-blocking but the client
2262                                          * sockets need to be blocking, otherwise certain
2263                                          * operations barf on FreeBSD.  Not a fatal error.
2264                                          */
2265                                         if (fcntl(ssock, F_SETFL, 0) < 0) {
2266                                                 CtdlLogPrintf(CTDL_EMERG,
2267                                                         "citserver: Can't set socket to blocking: %s\n",
2268                                                         strerror(errno));
2269                                         }
2270
2271                                         /* New context will be created already
2272                                          * set up in the CON_EXECUTING state.
2273                                          */
2274                                         con = CreateNewContext();
2275
2276                                         /* Assign our new socket number to it. */
2277                                         con->client_socket = ssock;
2278                                         con->h_command_function =
2279                                                 serviceptr->h_command_function;
2280                                         con->h_async_function =
2281                                                 serviceptr->h_async_function;
2282                                         con->ServiceName =
2283                                                 serviceptr->ServiceName;
2284                                         
2285                                         /* Determine whether it's a local socket */
2286                                         if (serviceptr->sockpath != NULL)
2287                                                 con->is_local_socket = 1;
2288         
2289                                         /* Set the SO_REUSEADDR socket option */
2290                                         i = 1;
2291                                         setsockopt(ssock, SOL_SOCKET,
2292                                                 SO_REUSEADDR,
2293                                                 &i, sizeof(i));
2294
2295                                         become_session(con);
2296                                         begin_session(con);
2297                                         serviceptr->h_greeting_function();
2298                                         become_session(NULL);
2299                                         con->state = CON_IDLE;
2300                                         goto do_select;
2301                                 }
2302                         }
2303                 }
2304
2305                 /* It must be a client socket.  Find a context that has data
2306                  * waiting on its socket *and* is in the CON_IDLE state.  Any
2307                  * active sockets other than our chosen one are marked as
2308                  * CON_READY so the next thread that comes around can just bind
2309                  * to one without having to select() again.
2310                  */
2311                 begin_critical_section(S_SESSION_TABLE);
2312                 for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
2313                         if ( (FD_ISSET(ptr->client_socket, &readfds))
2314                            && (ptr->state != CON_EXECUTING) ) {
2315                                 ptr->input_waiting = 1;
2316                                 if (!bind_me) {
2317                                         bind_me = ptr;  /* I choose you! */
2318                                         bind_me->state = CON_EXECUTING;
2319                                 }
2320                                 else {
2321                                         ptr->state = CON_READY;
2322                                 }
2323                         }
2324                 }
2325                 end_critical_section(S_SESSION_TABLE);
2326
2327 SKIP_SELECT:
2328                 /* We're bound to a session */
2329                 if (bind_me != NULL) {
2330                         become_session(bind_me);
2331
2332                         /* If the client has sent a command, execute it. */
2333                         if (CC->input_waiting) {
2334                                 CC->h_command_function();
2335                                 CC->input_waiting = 0;
2336                         }
2337
2338                         /* If there are asynchronous messages waiting and the
2339                          * client supports it, do those now */
2340                         if ((CC->is_async) && (CC->async_waiting)
2341                            && (CC->h_async_function != NULL)) {
2342                                 CC->h_async_function();
2343                                 CC->async_waiting = 0;
2344                         }
2345                         
2346                         force_purge = CC->kill_me;
2347                         become_session(NULL);
2348                         bind_me->state = CON_IDLE;
2349                 }
2350
2351                 dead_session_purge(force_purge);
2352                 do_housekeeping();
2353         }
2354         /* If control reaches this point, the server is shutting down */        
2355         return(NULL);
2356 }
2357
2358
2359
2360
2361 /*
2362  * SyslogFacility()
2363  * Translate text facility name to syslog.h defined value.
2364  */
2365 int SyslogFacility(char *name)
2366 {
2367         int i;
2368         struct
2369         {
2370                 int facility;
2371                 char *name;
2372         }   facTbl[] =
2373         {
2374                 {   LOG_KERN,   "kern"          },
2375                 {   LOG_USER,   "user"          },
2376                 {   LOG_MAIL,   "mail"          },
2377                 {   LOG_DAEMON, "daemon"        },
2378                 {   LOG_AUTH,   "auth"          },
2379                 {   LOG_SYSLOG, "syslog"        },
2380                 {   LOG_LPR,    "lpr"           },
2381                 {   LOG_NEWS,   "news"          },
2382                 {   LOG_UUCP,   "uucp"          },
2383                 {   LOG_LOCAL0, "local0"        },
2384                 {   LOG_LOCAL1, "local1"        },
2385                 {   LOG_LOCAL2, "local2"        },
2386                 {   LOG_LOCAL3, "local3"        },
2387                 {   LOG_LOCAL4, "local4"        },
2388                 {   LOG_LOCAL5, "local5"        },
2389                 {   LOG_LOCAL6, "local6"        },
2390                 {   LOG_LOCAL7, "local7"        },
2391                 {   0,            NULL          }
2392         };
2393         for(i = 0; facTbl[i].name != NULL; i++) {
2394                 if(!strcasecmp(name, facTbl[i].name))
2395                         return facTbl[i].facility;
2396         }
2397         enable_syslog = 0;
2398         return LOG_DAEMON;
2399 }
2400
2401
2402 /********** MEM CHEQQER ***********/
2403
2404 #ifdef DEBUG_MEMORY_LEAKS
2405
2406 #undef malloc
2407 #undef realloc
2408 #undef strdup
2409 #undef free
2410
2411 void *tracked_malloc(size_t size, char *file, int line) {
2412         struct igheap *thisheap;
2413         void *block;
2414
2415         block = malloc(size);
2416         if (block == NULL) return(block);
2417
2418         thisheap = malloc(sizeof(struct igheap));
2419         if (thisheap == NULL) {
2420                 free(block);
2421                 return(NULL);
2422         }
2423
2424         thisheap->block = block;
2425         strcpy(thisheap->file, file);
2426         thisheap->line = line;
2427         
2428         begin_critical_section(S_DEBUGMEMLEAKS);
2429         thisheap->next = igheap;
2430         igheap = thisheap;
2431         end_critical_section(S_DEBUGMEMLEAKS);
2432
2433         return(block);
2434 }
2435
2436
2437 void *tracked_realloc(void *ptr, size_t size, char *file, int line) {
2438         struct igheap *thisheap;
2439         void *block;
2440
2441         block = realloc(ptr, size);
2442         if (block == NULL) return(block);
2443
2444         thisheap = malloc(sizeof(struct igheap));
2445         if (thisheap == NULL) {
2446                 free(block);
2447                 return(NULL);
2448         }
2449
2450         thisheap->block = block;
2451         strcpy(thisheap->file, file);
2452         thisheap->line = line;
2453         
2454         begin_critical_section(S_DEBUGMEMLEAKS);
2455         thisheap->next = igheap;
2456         igheap = thisheap;
2457         end_critical_section(S_DEBUGMEMLEAKS);
2458
2459         return(block);
2460 }
2461
2462
2463
2464 void tracked_free(void *ptr) {
2465         struct igheap *thisheap;
2466         struct igheap *trash;
2467
2468         free(ptr);
2469
2470         if (igheap == NULL) return;
2471         begin_critical_section(S_DEBUGMEMLEAKS);
2472         for (thisheap = igheap; thisheap != NULL; thisheap = thisheap->next) {
2473                 if (thisheap->next != NULL) {
2474                         if (thisheap->next->block == ptr) {
2475                                 trash = thisheap->next;
2476                                 thisheap->next = thisheap->next->next;
2477                                 free(trash);
2478                         }
2479                 }
2480         }
2481         if (igheap->block == ptr) {
2482                 trash = igheap;
2483                 igheap = igheap->next;
2484                 free(trash);
2485         }
2486         end_critical_section(S_DEBUGMEMLEAKS);
2487 }
2488
2489 char *tracked_strdup(const char *s, char *file, int line) {
2490         char *ptr;
2491
2492         if (s == NULL) return(NULL);
2493         ptr = tracked_malloc(strlen(s) + 1, file, line);
2494         if (ptr == NULL) return(NULL);
2495         strncpy(ptr, s, strlen(s));
2496         return(ptr);
2497 }
2498
2499 void dump_heap(void) {
2500         struct igheap *thisheap;
2501
2502         for (thisheap = igheap; thisheap != NULL; thisheap = thisheap->next) {
2503                 CtdlLogPrintf(CTDL_CRIT, "UNFREED: %30s : %d\n",
2504                         thisheap->file, thisheap->line);
2505         }
2506 }
2507
2508 #endif /*  DEBUG_MEMORY_LEAKS */