* do non-blocking accept()
authorWilfried Göesgens <willi@citadel.org>
Sun, 11 Nov 2007 16:09:45 +0000 (16:09 +0000)
committerWilfried Göesgens <willi@citadel.org>
Sun, 11 Nov 2007 16:09:45 +0000 (16:09 +0000)
* shut down on HUP instead of TERM; easier to debug.
* kill & free our running sessions on shutdown

webcit/Makefile.in
webcit/context_loop.c
webcit/debian/rules
webcit/sysdep.c [new file with mode: 0644]
webcit/webcit.h
webcit/webserver.c

index 559583afd9fb6c8b3f5b47f4e987a4891e8b3adf..44871bf2fbb2216aea571fd1f769fc49ae68700e 100644 (file)
@@ -51,7 +51,7 @@ webserver: webserver.o context_loop.o tools.o ical_dezonify.o \
        groupdav_main.o groupdav_get.o groupdav_propfind.o fmt_date.o \
        groupdav_options.o autocompletion.o gettext.o tabs.o sieve.o \
        groupdav_delete.o groupdav_put.o http_datestring.o setup_wizard.o \
-       downloads.o  addressbook_popup.o pushemail.o \
+       downloads.o  addressbook_popup.o pushemail.o sysdep.o \
        $(LIBOBJS)
        $(CC) webserver.o context_loop.o tools.o cookie_conversion.o \
        webcit.o auth.o tcp_sockets.o mainmenu.o serv_func.o who.o listsub.o \
@@ -63,7 +63,7 @@ webserver: webserver.o context_loop.o tools.o ical_dezonify.o \
        groupdav_main.o groupdav_get.o groupdav_propfind.o groupdav_delete.o \
        groupdav_options.o autocompletion.o tabs.o smtpqueue.o sieve.o \
        groupdav_put.o http_datestring.o setup_wizard.o fmt_date.o \
-       gettext.o downloads.o addressbook_popup.o pushemail.o \
+       gettext.o downloads.o addressbook_popup.o pushemail.o sysdep.o \
        $(LIBOBJS) $(LIBS) $(LDFLAGS) -o webserver
 
 .c.o:
index b693ff992676dd15632bdc45dcc9209fcfedf549..f37fa66762f0ba1c5f6a6fe0ba7352e67ab0681e 100644 (file)
@@ -37,6 +37,15 @@ void free_attachments(struct wcsession *sess) {
        }
 }
 
+
+void shutdown_sessions(void)
+{
+       struct wcsession *sptr;
+       
+       for (sptr = SessionList; sptr != NULL; sptr = sptr->next) {
+                       sptr->killthis = 1;
+       }
+}
 /**
  * \brief what??????
  */
index 1c5c346abf0e21970f96894d2f2d656f26ddb99e..c88c0403ec6f12c1184bf10978e73bec0c2a94b8 100755 (executable)
@@ -40,6 +40,7 @@ configure-stamp:
                 --with-ssldir=/etc/ssl/webcit/ \
                --with-zlib --with-ssl --with-libiconf \
                --with-newt --with-included-gettext \
+               --with-datadir=/var/run/citadel \
                --enable-debug $(EXTRA_ARGS) $(PROFILE_ARGS)
 
        touch configure-stamp
diff --git a/webcit/sysdep.c b/webcit/sysdep.c
new file mode 100644 (file)
index 0000000..cbe4171
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * $Id: sysdep.c 5691 2007-11-04 23:19:17Z dothebart $
+ *
+ * Citadel "system dependent" stuff.
+ * See copyright.txt for copyright information.
+ *
+ * Here's where we (hopefully) have most parts of the Citadel server that
+ * would need to be altered to run the server in a non-POSIX environment.
+ * 
+ * If we ever port to a different platform and either have multiple
+ * variants of this file or simply load it up with #ifdefs.
+ *
+ */
+
+#include "sysdep.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <syslog.h>
+#include <sys/syslog.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#include <limits.h>
+#include <sys/resource.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/un.h>
+#include <string.h>
+#include <pwd.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <grp.h>
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
+#include "webcit.h"
+#include "sysdep.h"
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifndef HAVE_SNPRINTF
+#include "snprintf.h"
+#endif
+
+pthread_mutex_t Critters[MAX_SEMAPHORES];      /* Things needing locking */
+pthread_key_t MyConKey;                                /* TSD key for MyContext() */
+
+void InitialiseSemaphores(void)
+{
+       int i;
+
+       /* Set up a bunch of semaphores to be used for critical sections */
+       for (i=0; i<MAX_SEMAPHORES; ++i) {
+               pthread_mutex_init(&Critters[i], NULL);
+       }
+}
+
+/*
+ * Obtain a semaphore lock to begin a critical section.
+ */
+void begin_critical_section(int which_one)
+{
+       /* lprintf(CTDL_DEBUG, "begin_critical_section(%d)\n", which_one); */
+       pthread_mutex_lock(&Critters[which_one]);
+}
+
+/*
+ * Release a semaphore lock to end a critical section.
+ */
+void end_critical_section(int which_one)
+{
+       pthread_mutex_unlock(&Critters[which_one]);
+}
+
index 49fed8dc7ef9a39b67d659a4f0fba39520977699..f9b05e119f68afec620b29a211b54acd27b4d25e 100644 (file)
@@ -2,6 +2,9 @@
 
 #include "sysdep.h"
 
+
+#include <sys/select.h>
+
 #include <ctype.h>
 #include <stdlib.h>
 #ifdef HAVE_UNISTD_H
@@ -404,7 +407,11 @@ enum {
        current_iconbar_menu,     /**< view the icon menue */
        current_iconbar_roomlist  /**< view the roomtree */
 };
-
+enum {
+       S_SELECT,
+       S_SHUTDOWN,
+       MAX_SEMAPHORES
+};
 
 #define num_parms(source)              num_tokens(source, '|') 
 
@@ -435,6 +442,12 @@ extern time_t if_modified_since;
 extern int follow_xff;
 void do_setup_wizard(void);
 
+
+void InitialiseSemaphores(void);
+void begin_critical_section(int which_one);
+void end_critical_section(int which_one);
+
+
 void stuff_to_cookie(char *cookie, int session,
                        char *user, char *pass, char *room);
 void cookie_to_stuff(char *cookie, int *session,
@@ -556,6 +569,8 @@ void display_confirm_delete_node(void);
 void delete_node(void);
 void display_add_node(void);
 void terminate_session(void);
+void shutdown_sessions(void);
+void do_housekeeping(void);
 void edit_me(void);
 void display_siteconfig(void);
 void siteconfig(void);
index 55439dc6907ec594849b225d1ea7b62127ea494a..89238741a1dce03151bff511c862d8ad83be2ae0 100644 (file)
@@ -109,6 +109,8 @@ int ig_tcp_server(char *ip_addr, int port_number, int queue_len)
        i = 1;
        setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
 
+       fcntl(s, F_SETFL, O_NONBLOCK);/// TODO
+       
        if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
                lprintf(1, "Can't bind: %s\n", strerror(errno));
                exit(WC_EXIT_BIND);
@@ -474,10 +476,17 @@ pid_t current_child;
 void graceful_shutdown(int signum) {
 //     kill(current_child, signum);
        char wd[SIZ];
+       FILE *FD;
+       int fd;
        getcwd(wd, SIZ);
-       lprintf (1, "bye going down gracefull.[%s]\n", wd);
+       lprintf (1, "bye going down gracefull.[%d][%s]\n", signum, wd);
+       fd = msock;
+       msock = -1;
        time_to_die = 1;
-       exit(0);
+       FD=fdopen(fd, "a+");
+       fflush (FD);
+       fclose (FD);
+       close(fd);
 }
 
 
@@ -519,7 +528,8 @@ void start_daemon(char *pid_file)
        freopen("/dev/null", "r", stdin);
        freopen("/dev/null", "w", stdout);
        freopen("/dev/null", "w", stderr);
-       signal(SIGTERM, graceful_shutdown_watcher);
+///    signal(SIGTERM, graceful_shutdown_watcher);
+       signal(SIGHUP, graceful_shutdown_watcher);
 
        do {
                current_child = fork();
@@ -531,12 +541,15 @@ void start_daemon(char *pid_file)
                }
        
                else if (current_child == 0) {
-                       signal(SIGTERM, graceful_shutdown);
+////                   signal(SIGTERM, graceful_shutdown);
+                       signal(SIGHUP, graceful_shutdown);
+
                        return; /* continue starting webcit. */
                }
        
                else {
-                       signal(SIGTERM, SIG_IGN);
+////                   signal(SIGTERM, SIG_IGN);
+                       signal(SIGHUP, SIG_IGN);
                        if (pid_file) {
                                fp = fopen(pid_file, "w");
                                if (fp != NULL) {
@@ -735,7 +748,8 @@ int main(int argc, char **argv)
                start_daemon(pidfile);
        }
        else {
-               signal(SIGTERM, graceful_shutdown);
+///            signal(SIGTERM, graceful_shutdown);
+               signal(SIGHUP, graceful_shutdown);
        }
 
        /** Tell 'em who's in da house */
@@ -806,6 +820,7 @@ int main(int argc, char **argv)
        if (pthread_key_create(&MyConKey, NULL) != 0) {
                lprintf(1, "Can't create TSD key: %s\n", strerror(errno));
        }
+       InitialiseSemaphores ();
 
        /**
         * Set up a place to put thread-specific SSL data.
@@ -876,15 +891,76 @@ void worker_entry(void)
        int ssock;
        int i = 0;
        int fail_this_transaction = 0;
+       int ret;
+       struct timeval tv;
+       fd_set readset, tempset;
+
+       tv.tv_sec = 0;
+       tv.tv_usec = 10000;
+       FD_ZERO(&readset);
+       FD_SET(msock, &readset);
 
        do {
                /** Only one thread can accept at a time */
                fail_this_transaction = 0;
-               ssock = accept(msock, NULL, 0);
-               if (ssock < 0) {
-                       lprintf(2, "accept() failed: %s\n",
-                               strerror(errno));
-               } else {
+               ssock = -1; 
+               errno = EAGAIN;
+               do {
+                       ret = -1; /* just one at once should select... */
+                       begin_critical_section(S_SELECT);
+
+                       FD_ZERO(&tempset);
+                       if (msock > 0) FD_SET(msock, &tempset);
+                       tv.tv_sec = 0;
+                       tv.tv_usec = 10000;
+                       if (msock > 0)  ret = select(msock+1, &tempset, NULL, NULL,  &tv);
+                       end_critical_section(S_SELECT);
+                       if ((ret < 0) && (errno != EINTR) && (errno != EAGAIN))
+                       {// EINTR and EAGAIN are thrown but not of interest.
+                               lprintf(2, "accept() failed:%d %s\n",
+                                       errno, strerror(errno));
+                       }
+                       else if ((ret > 0) && (msock > 0) && FD_ISSET(msock, &tempset))
+                       {// Successfully selected, and still not shutting down? Accept!
+                               ssock = accept(msock, NULL, 0);
+                       }
+                       
+               } while ((msock > 0) && (ssock < 0)  && (time_to_die == 0));
+
+               if ((msock == -1)||(time_to_die))
+               {// ok, we're going down.
+                       int shutdown = 0;
+
+                       /* the first to come here will have to do the cleanup.
+                        * make shure its realy just one.
+                        */
+                       begin_critical_section(S_SHUTDOWN);
+                       if (msock == -1)
+                       {
+                               msock = -2;
+                               shutdown = 1;
+                       }
+                       end_critical_section(S_SHUTDOWN);
+                       if (shutdown == 1)
+                       {// we're the one to cleanup the mess.
+                               lprintf(2, "I'm master shutdown: tagging sessions to be killed.\n");
+                               shutdown_sessions();
+                               lprintf(2, "master shutdown: waiting for others\n");
+                               sleeeeeeeeeep(1); // wait so some others might finish...
+                               lprintf(2, "master shutdown: cleaning up sessions\n");
+                               do_housekeeping();
+                               lprintf(2, "master shutdown exiting!.\n");                              
+                               exit(0);
+                       }
+                       break;
+               }
+               if (ssock < 0 ) continue;
+
+               if (msock < 0) {
+                       if (ssock > 0) close (ssock);
+                       lprintf(2, "inbetween.");
+                       pthread_exit(NULL);
+               } else { // Got it? do some real work!
                        /** Set the SO_REUSEADDR socket option */
                        i = 1;
                        setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR,
@@ -920,7 +996,7 @@ void worker_entry(void)
 
        } while (!time_to_die);
 
-       lprintf (1, "bye");
+       lprintf (1, "bye\n");
        pthread_exit(NULL);
 }