X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fsysdep.c;h=182c0df7d1b0795b098eb566d092025ca9d95f53;hb=c1cf1c8630e59eab79e4eea45ed82a5f71edd0d4;hp=f4e20d72ebb3c6bda71acff9ecad6fce5d95f1e9;hpb=11219dbc3e638e7ee47feffbbb7d63588d7dd77f;p=citadel.git diff --git a/citadel/sysdep.c b/citadel/sysdep.c index f4e20d72e..182c0df7d 100644 --- a/citadel/sysdep.c +++ b/citadel/sysdep.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #if TIME_WITH_SYS_TIME @@ -53,7 +54,6 @@ #endif #include "citadel.h" #include "server.h" -#include "serv_extensions.h" #include "sysdep_decls.h" #include "citserver.h" #include "support.h" @@ -61,8 +61,8 @@ #include "database.h" #include "housekeeping.h" #include "tools.h" -#include "serv_crypto.h" -#include "serv_fulltext.h" +#include "modules/crypto/serv_crypto.h" /* Needed for init_ssl, client_write_ssl, client_read_ssl, destruct_ssl */ +#include "ecrash.h" #ifdef HAVE_SYS_SELECT_H #include @@ -94,23 +94,43 @@ struct CitContext masterCC; time_t last_purge = 0; /* Last dead session purge */ static int num_threads = 0; /* Current number of threads */ int num_sessions = 0; /* Current number of sessions */ -pthread_t indexer_thread_tid; -pthread_t checkpoint_thread_tid; int syslog_facility = LOG_DAEMON; int enable_syslog = 0; -extern int running_as_daemon; + +void DestroyWorkerList(void); + + +/* + * Create an interface to lprintf that follows the coding convention. + * This is here until such time as we have replaced all calls to lprintf with CtdlLogPrintf + */ + +void CtdlLogPrintf(enum LogLevel loglevel, const char *format, ...) +{ + va_list arg_ptr; + va_start(arg_ptr, format); + vlprintf(loglevel, format, arg_ptr); + va_end(arg_ptr); +} + /* * lprintf() ... Write logging information */ void lprintf(enum LogLevel loglevel, const char *format, ...) { va_list arg_ptr; + va_start(arg_ptr, format); + vlprintf(loglevel, format, arg_ptr); + va_end(arg_ptr); +} + +void vlprintf(enum LogLevel loglevel, const char *format, va_list arg_ptr) +{ + char buf[SIZ], buf2[SIZ]; if (enable_syslog) { - va_start(arg_ptr, format); - vsyslog((syslog_facility | loglevel), format, arg_ptr); - va_end(arg_ptr); + vsyslog((syslog_facility | loglevel), format, arg_ptr); } /* stderr output code */ @@ -127,22 +147,22 @@ void lprintf(enum LogLevel loglevel, const char *format, ...) { unixtime = tv.tv_sec; localtime_r(&unixtime, &tim); if (CC->cs_pid != 0) { - fprintf(stderr, + sprintf(buf, "%04d/%02d/%02d %2d:%02d:%02d.%06ld [%3d] ", tim.tm_year + 1900, tim.tm_mon + 1, tim.tm_mday, tim.tm_hour, tim.tm_min, tim.tm_sec, (long)tv.tv_usec, CC->cs_pid); } else { - fprintf(stderr, + sprintf(buf, "%04d/%02d/%02d %2d:%02d:%02d.%06ld ", tim.tm_year + 1900, tim.tm_mon + 1, tim.tm_mday, tim.tm_hour, tim.tm_min, tim.tm_sec, (long)tv.tv_usec); } - va_start(arg_ptr, format); - vfprintf(stderr, format, arg_ptr); - va_end(arg_ptr); + vsprintf(buf2, format, arg_ptr); + + fprintf(stderr, "%s%s", buf, buf2); fflush(stderr); } } @@ -155,6 +175,8 @@ void lprintf(enum LogLevel loglevel, const char *format, ...) { volatile int time_to_die = 0; volatile int shutdown_and_halt = 0; +volatile int restart_server = 0; +volatile int running_as_daemon = 0; static RETSIGTYPE signal_cleanup(int signum) { lprintf(CTDL_DEBUG, "Caught signal %d; shutting down.\n", signum); @@ -163,11 +185,24 @@ static RETSIGTYPE signal_cleanup(int signum) { } + + +void InitialiseSemaphores(void) +{ + int i; + + /* Set up a bunch of semaphores to be used for critical sections */ + for (i=0; iclient_socket, IPPROTO_TCP, TCP_CORK, &off, 4); setsockopt(ctx->client_socket, IPPROTO_TCP, TCP_CORK, &on, 4); } +#else +#ifdef HAVE_DARWIN +/* Stub functions for Darwin/OS X where TCP buffering isn't liked at all */ +void buffer_output(void) { + CC->buffering = 0; +} +void unbuffer_output(void) { + CC->buffering = 0; +} +void flush_output(void) { +} #else void buffer_output(void) { if (CC->buffering == 0) { @@ -532,7 +574,8 @@ void unbuffer_output(void) { CC->output_buffer = NULL; } } -#endif +#endif /* HAVE_DARWIN */ +#endif /* HAVE_TCP_BUFFERING */ @@ -546,26 +589,28 @@ void client_write(char *buf, int nbytes) #ifndef HAVE_TCP_BUFFERING int old_buffer_len = 0; #endif - - if (CC->redirect_buffer != NULL) { - if ((CC->redirect_len + nbytes + 2) >= CC->redirect_alloc) { - CC->redirect_alloc = (CC->redirect_alloc * 2) + nbytes; - CC->redirect_buffer = realloc(CC->redirect_buffer, - CC->redirect_alloc); + t_context *Ctx; + + Ctx = CC; + if (Ctx->redirect_buffer != NULL) { + if ((Ctx->redirect_len + nbytes + 2) >= Ctx->redirect_alloc) { + Ctx->redirect_alloc = (Ctx->redirect_alloc * 2) + nbytes; + Ctx->redirect_buffer = realloc(Ctx->redirect_buffer, + Ctx->redirect_alloc); } - memcpy(&CC->redirect_buffer[CC->redirect_len], buf, nbytes); - CC->redirect_len += nbytes; - CC->redirect_buffer[CC->redirect_len] = 0; + memcpy(&Ctx->redirect_buffer[Ctx->redirect_len], buf, nbytes); + Ctx->redirect_len += nbytes; + Ctx->redirect_buffer[Ctx->redirect_len] = 0; return; } #ifndef HAVE_TCP_BUFFERING /* If we're buffering for later, do that now. */ - if (CC->buffering) { - old_buffer_len = CC->buffer_len; - CC->buffer_len += nbytes; - CC->output_buffer = realloc(CC->output_buffer, CC->buffer_len); - memcpy(&CC->output_buffer[old_buffer_len], buf, nbytes); + if (Ctx->buffering) { + old_buffer_len = Ctx->buffer_len; + Ctx->buffer_len += nbytes; + Ctx->output_buffer = realloc(Ctx->output_buffer, Ctx->buffer_len); + memcpy(&Ctx->output_buffer[old_buffer_len], buf, nbytes); return; } #endif @@ -573,21 +618,23 @@ void client_write(char *buf, int nbytes) /* Ok, at this point we're not buffering. Go ahead and write. */ #ifdef HAVE_OPENSSL - if (CC->redirect_ssl) { + if (Ctx->redirect_ssl) { client_write_ssl(buf, nbytes); return; } #endif while (bytes_written < nbytes) { - retval = write(CC->client_socket, &buf[bytes_written], + retval = write(Ctx->client_socket, &buf[bytes_written], nbytes - bytes_written); if (retval < 1) { lprintf(CTDL_ERR, "client_write(%d bytes) failed: %s (%d)\n", nbytes - bytes_written, strerror(errno), errno); - CC->kill_me = 1; + cit_backtrace(); + // lprintf(CTDL_DEBUG, "Tried to send: %s", &buf[bytes_written]); + Ctx->kill_me = 1; return; } bytes_written = bytes_written + retval; @@ -624,6 +671,7 @@ int client_read_to(char *buf, int bytes, int timeout) { int len,rlen; fd_set rfds; + int fd; struct timeval tv; int retval; @@ -633,20 +681,21 @@ int client_read_to(char *buf, int bytes, int timeout) } #endif len = 0; + fd = CC->client_socket; while(lenclient_socket, &rfds); + FD_SET(fd, &rfds); tv.tv_sec = timeout; tv.tv_usec = 0; - retval = select( (CC->client_socket)+1, - &rfds, NULL, NULL, &tv); + retval = select( (fd)+1, + &rfds, NULL, NULL, &tv); - if (FD_ISSET(CC->client_socket, &rfds) == 0) { + if (FD_ISSET(fd, &rfds) == 0) { return(0); } - rlen = read(CC->client_socket, &buf[len], bytes-len); + rlen = read(fd, &buf[len], bytes-len); if (rlen<1) { /* The socket has been disconnected! */ CC->kill_me = 1; @@ -694,10 +743,13 @@ int client_getln(char *buf, int bufsize) /* Strip the trailing LF, and the trailing CR if present. */ buf[i] = 0; - while ( (strlen(buf) > 0) && ((buf[strlen(buf)-1]==10) || (buf[strlen(buf)-1] == 13)) ) { - buf[strlen(buf)-1] = 0; + while ( (i > 0) + && ( (buf[i - 1]==13) + || ( buf[i - 1]==10)) ) { + i--; + buf[i] = 0; } - if (retval < 0) safestrncpy(buf, "000", bufsize); + if (retval < 0) safestrncpy(&buf[i], "000", bufsize - i); return(retval); } @@ -709,6 +761,7 @@ int client_getln(char *buf, int bufsize) void sysdep_master_cleanup(void) { struct ServiceFunctionHook *serviceptr; +///// DestroyWorkerList(); /* * close all protocol master sockets */ @@ -730,9 +783,28 @@ void sysdep_master_cleanup(void) { unlink(serviceptr->sockpath); } } +#ifdef HAVE_OPENSSL + destruct_ssl(); +#endif + serv_calendar_destroy(); + CtdlDestroyProtoHooks(); + CtdlDestroyDeleteHooks(); + CtdlDestroyXmsgHooks(); + CtdlDestroyNetprocHooks(); + CtdlDestroyUserHooks(); + CtdlDestroyMessageHook(); + CtdlDestroyCleanupHooks(); + CtdlDestroyFixedOutputHooks(); + CtdlDestroySessionHooks(); + CtdlDestroyServiceHook(); + #ifdef HAVE_BACKTRACE + eCrash_Uninit(); + #endif } + + /* * Terminate another session. * (This could justifiably be moved out of sysdep.c because it @@ -750,19 +822,103 @@ void kill_session(int session_to_kill) { end_critical_section(S_SESSION_TABLE); } - +pid_t current_child; +void graceful_shutdown(int signum) { + kill(current_child, signum); + unlink(file_pid_file); + exit(0); +} /* * Start running as a daemon. */ void start_daemon(int unused) { - close(0); close(1); close(2); - if (fork()) exit(0); + int status = 0; + pid_t child = 0; + FILE *fp; + int do_restart = 0; + + current_child = 0; + + /* Close stdin/stdout/stderr and replace them with /dev/null. + * We don't just call close() because we don't want these fd's + * to be reused for other files. + */ + chdir(ctdl_run_dir); + + child = fork(); + if (child != 0) { + exit(0); + } + + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + setsid(); - signal(SIGHUP,SIG_IGN); - signal(SIGINT,SIG_IGN); - signal(SIGQUIT,SIG_IGN); + umask(0); + freopen("/dev/null", "r", stdin); + freopen("/dev/null", "w", stdout); + freopen("/dev/null", "w", stderr); + + do { + current_child = fork(); + + signal(SIGTERM, graceful_shutdown); + + if (current_child < 0) { + perror("fork"); + exit(errno); + } + + else if (current_child == 0) { + return; /* continue starting citadel. */ + } + + else { + fp = fopen(file_pid_file, "w"); + if (fp != NULL) { + /* + * NB.. The pid file contains the pid of the actual server. + * This is not the pid of the watcher process + */ + fprintf(fp, ""F_PID_T"\n", current_child); + fclose(fp); + } + waitpid(current_child, &status, 0); + } + + do_restart = 0; + + /* Did the main process exit with an actual exit code? */ + if (WIFEXITED(status)) { + + /* Exit code 0 means the watcher should exit */ + if (WEXITSTATUS(status) == 0) { + do_restart = 0; + } + + /* Exit code 101-109 means the watcher should exit */ + else if ( (WEXITSTATUS(status) >= 101) && (WEXITSTATUS(status) <= 109) ) { + do_restart = 0; + } + + /* Any other exit code means we should restart. */ + else { + do_restart = 1; + } + } + + /* Any other type of termination (signals, etc.) should also restart. */ + else { + do_restart = 1; + } + + } while (do_restart); + + unlink(file_pid_file); + exit(WEXITSTATUS(status)); } @@ -837,10 +993,40 @@ void create_worker(void) { pthread_attr_destroy(&attr); } +void DestroyWorkerList(void) +{ + struct CitContext *ptr; /* general-purpose utility pointer */ + struct CitContext *rem = NULL; /* list of sessions to be destroyed */ + + begin_critical_section(S_SESSION_TABLE); + ptr = ContextList; + while (ptr != NULL){ + /* Remove the session from the active list */ + rem = ptr->next; + --num_sessions; + + lprintf(CTDL_DEBUG, "Purging session %d\n", rem->cs_pid); + end_critical_section(S_SESSION_TABLE); + RemoveContext(ptr); + begin_critical_section(S_SESSION_TABLE); + free (ptr); + ptr = rem; + } + end_critical_section(S_SESSION_TABLE); + + struct worker_node *cur, *p; + cur = worker_list; + while (cur != NULL) + { + p = cur->next; + free (cur); + cur = p; + } + worker_list = NULL; +} /* - * Create the indexer thread and begin its operation. - * Then create the checkpoint thread and begin its operation. + * Create the maintenance threads and begin their operation. */ void create_maintenance_threads(void) { int ret; @@ -863,15 +1049,23 @@ void create_maintenance_threads(void) { pthread_attr_destroy(&attr); return; } + + struct MaintenanceThreadHook *fcn; - if ((ret = pthread_create(&indexer_thread_tid, &attr, indexer_thread, NULL) != 0)) { - lprintf(CTDL_ALERT, "Can't create thread: %s\n", strerror(ret)); - } + lprintf(CTDL_DEBUG, "Performing startup of maintenance thread hooks\n"); - if ((ret = pthread_create(&checkpoint_thread_tid, &attr, checkpoint_thread, NULL) != 0)) { - lprintf(CTDL_ALERT, "Can't create thread: %s\n", strerror(ret)); + for (fcn = MaintenanceThreadHookTable; fcn != NULL; fcn = fcn->next) { + if ((ret = pthread_create(&(fcn->MaintenanceThread_tid), &attr, fcn->fcn_ptr, NULL) != 0)) { + lprintf(CTDL_ALERT, "Can't create thread: %s\n", strerror(ret)); + } + else + { + lprintf(CTDL_NOTICE, "Spawned a new maintenance thread \"%s\" (%ld). \n", fcn->name, + fcn->MaintenanceThread_tid); + } } + pthread_attr_destroy(&attr); } @@ -994,6 +1188,10 @@ void *worker_thread(void *arg) { cdb_allocate_tsd(); + // Register for tracing + #ifdef HAVE_BACKTRACE + eCrash_RegisterThread("WorkerThread", 0); + #endif while (!time_to_die) { /* make doubly sure we're not holding any stale db handles @@ -1098,7 +1296,9 @@ do_select: force_purge = 0; serviceptr->h_command_function; con->h_async_function = serviceptr->h_async_function; - + con->ServiceName = + serviceptr->ServiceName; + /* Determine whether it's a local socket */ if (serviceptr->sockpath != NULL) con->is_local_socket = 1; @@ -1169,8 +1369,11 @@ SKIP_SELECT: do_housekeeping(); check_sched_shutdown(); } - + if (con != NULL) free (con);//// TODO: could this harm other threads? /* If control reaches this point, the server is shutting down */ + #ifdef HAVE_BACKTRACE + eCrash_UnregisterThread(); + #endif return(NULL); }