]> code.citadel.org Git - citadel.git/blobdiff - citadel/sysdep.c
* Removed userspace buffering. Everyone has TCP_CORK or TCP_NOPUSH nowadays.
[citadel.git] / citadel / sysdep.c
index 3f90a79d288833cc121c351dd3ceafc01d054f01..995742b40d834cb379c886740128f965579126cb 100644 (file)
@@ -2,7 +2,7 @@
  * $Id$
  *
  * Citadel "system dependent" stuff.
- * See copyright.txt for copyright information.
+ * See COPYING 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.
@@ -71,6 +71,9 @@
 
 #include "ctdl_module.h"
 #include "threads.h"
+#include "user_ops.h"
+#include "control.h"
+
 
 #ifdef DEBUG_MEMORY_LEAKS
 struct igheap {
@@ -96,31 +99,63 @@ int syslog_facility = LOG_DAEMON;
 int enable_syslog = 0;
 
 
-/*
- * 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, ...)
+/* Flag for single user mode */
+static int want_single_user = 0;
+
+/* Try to go single user */
+
+int CtdlTrySingleUser(void)
 {
-       va_list arg_ptr;
-       va_start(arg_ptr, format);
-       vlprintf(loglevel, format, arg_ptr);
-       va_end(arg_ptr);
+       int can_do = 0;
+       
+       begin_critical_section(S_SINGLE_USER);
+       if (want_single_user)
+               can_do = 0;
+       else
+       {
+               can_do = 1;
+               want_single_user = 1;
+       }
+       end_critical_section(S_SINGLE_USER);
+       return can_do;
+}
+
+void CtdlEndSingleUser(void)
+{
+       begin_critical_section(S_SINGLE_USER);
+       want_single_user = 0;
+       end_critical_section(S_SINGLE_USER);
+}
+
+
+int CtdlWantSingleUser(void)
+{
+       return want_single_user;
+}
+
+int CtdlIsSingleUser(void)
+{
+       if (want_single_user)
+       {
+               /* check for only one context here */
+               if (num_sessions == 1)
+                       return TRUE;
+       }
+       return FALSE;
 }
 
 
 /*
- * lprintf()  ...   Write logging information
+ * CtdlLogPrintf()  ...   Write logging information
  */
-void lprintf(enum LogLevel loglevel, const char *format, ...) {   
+void CtdlLogPrintf(enum LogLevel loglevel, const char *format, ...) {   
        va_list arg_ptr;
        va_start(arg_ptr, format);
-       vlprintf(loglevel, format, arg_ptr);
+       vCtdlLogPrintf(loglevel, format, arg_ptr);
        va_end(arg_ptr);
 }
 
-void vlprintf(enum LogLevel loglevel, const char *format, va_list arg_ptr)
+void vCtdlLogPrintf(enum LogLevel loglevel, const char *format, va_list arg_ptr)
 {
        char buf[SIZ], buf2[SIZ];
 
@@ -174,16 +209,15 @@ volatile int restart_server = 0;
 volatile int running_as_daemon = 0;
 
 static RETSIGTYPE signal_cleanup(int signum) {
-       CtdlLogPrintf(CTDL_DEBUG, "Caught signal %d; shutting down.\n", signum);
 #ifdef THREADS_USESIGNALS
        if (CT)
-       {
-               CtdlLogPrintf(CTDL_DEBUG, "Thread \"%s\" caught signal %d.\n", CT->name, signum);
                CT->signal = signum;
-       }
        else
 #endif
+       {
+               CtdlLogPrintf(CTDL_DEBUG, "Caught signal %d; shutting down.\n", signum);
                exit_signal = signum;
+       }
 }
 
 
@@ -346,7 +380,7 @@ int ig_uds_server(char *sockpath, int queue_len, char **errormessage)
        if (actual_queue_len < 5) actual_queue_len = 5;
 
        i = unlink(sockpath);
-       if (i != 0) if (errno != ENOENT) {
+       if ((i != 0) && (errno != ENOENT)) {
                *errormessage = (char*) malloc(SIZ + 1);
                snprintf(*errormessage, SIZ, "citserver: can't unlink %s: %s",
                        sockpath, strerror(errno));
@@ -435,8 +469,12 @@ struct CitContext *CreateNewContext(void) {
                CtdlLogPrintf(CTDL_ALERT, "citserver: can't allocate memory!!\n");
                return NULL;
        }
-       memset(me, 0, sizeof(struct CitContext));
 
+       memset(me, 0, sizeof(struct CitContext));
+       
+       /* Give the contaxt a name. Hopefully makes it easier to track */
+       strcpy (me->user.fullname, "SYS_notauth");
+       
        /* The new context will be created already in the CON_EXECUTING state
         * in order to prevent another thread from grabbing it while it's
         * being set up.
@@ -478,10 +516,40 @@ struct CitContext *CtdlGetContextArray(int *count)
        return nptr;
 }
 
+
+
+/**
+ * This function fills in a context and its user field correctly
+ * Then creates/loads that user
+ */
+void CtdlFillSystemContext(struct CitContext *context, char *name)
+{
+       char sysname[USERNAME_SIZE];
+
+       memset(context, 0, sizeof(struct CitContext));
+       context->internal_pgm = 1;
+       context->cs_pid = 0;
+       strcpy (sysname, "SYS_");
+       strcat (sysname, name);
+       /* internal_create_user has the side effect of loading the user regardless of wether they
+        * already existed or needed to be created
+        */
+       internal_create_user (sysname, &(context->user), -1) ;
+       
+       /* Check to see if the system user needs upgrading */
+       if (context->user.usernum == 0)
+       {       /* old system user with number 0, upgrade it */
+               context->user.usernum = get_new_user_number();
+               CtdlLogPrintf(CTDL_DEBUG, "Upgrading system user \"%s\" from user number 0 to user number %d\n", context->user.fullname, context->user.usernum);
+               /* add user to the database */
+               putuser(&(context->user));
+               cdb_store(CDB_USERSBYNUMBER, &(context->user.usernum), sizeof(long), context->user.fullname, strlen(context->user.fullname)+1);
+       }
+}
+
 /*
- * The following functions implement output buffering. If the kernel supplies
- * native TCP buffering (Linux & *BSD), use that; otherwise, emulate it with
- * user-space buffering.
+ * The following functions implement output buffering on operating systems which
+ * support it (such as Linux and various BSD flavors).
  */
 #ifndef HAVE_DARWIN
 #ifdef TCP_CORK
@@ -494,71 +562,34 @@ struct CitContext *CtdlGetContextArray(int *count)
 #endif /* TCP_CORK */
 #endif /* HAVE_DARWIN */
 
-#ifdef HAVE_TCP_BUFFERING
 static unsigned on = 1, off = 0;
-void buffer_output(void) {
-       struct CitContext *ctx = MyContext();
-       setsockopt(ctx->client_socket, IPPROTO_TCP, TCP_CORK, &on, 4);
-       ctx->buffering = 1;
-}
 
-void unbuffer_output(void) {
-       struct CitContext *ctx = MyContext();
-       setsockopt(ctx->client_socket, IPPROTO_TCP, TCP_CORK, &off, 4);
-       ctx->buffering = 0;
-}
-
-void flush_output(void) {
-       struct CitContext *ctx = MyContext();
-       setsockopt(ctx->client_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;
+#ifdef HAVE_TCP_BUFFERING
+       setsockopt(CC->client_socket, IPPROTO_TCP, TCP_CORK, &on, 4);
+#endif
 }
+
 void unbuffer_output(void) {
-       CC->buffering = 0;
-}
-void flush_output(void) {
-}
-#else
-void buffer_output(void) {
-       if (CC->buffering == 0) {
-               CC->buffering = 1;
-               CC->buffer_len = 0;
-               CC->output_buffer = malloc(SIZ);
-       }
+#ifdef HAVE_TCP_BUFFERING
+       setsockopt(CC->client_socket, IPPROTO_TCP, TCP_CORK, &off, 4);
+#endif
 }
 
 void flush_output(void) {
-       if (CC->buffering == 1) {
-               client_write(CC->output_buffer, CC->buffer_len);
-               CC->buffer_len = 0;
-       }
-}
-
-void unbuffer_output(void) {
-       if (CC->buffering == 1) {
-               CC->buffering = 0;
-               /* We don't call flush_output because we can't. */
-               client_write(CC->output_buffer, CC->buffer_len);
-               CC->buffer_len = 0;
-               free(CC->output_buffer);
-               CC->output_buffer = NULL;
-       }
+#ifdef HAVE_TCP_BUFFERING
+       struct CitContext *CCC = CC;
+       setsockopt(CCC->client_socket, IPPROTO_TCP, TCP_CORK, &off, 4);
+       setsockopt(CCC->client_socket, IPPROTO_TCP, TCP_CORK, &on, 4);
+#endif
 }
-#endif /* HAVE_DARWIN */
-#endif /* HAVE_TCP_BUFFERING */
 
 
 
 /*
  * client_write()   ...    Send binary data to the client.
  */
-void client_write(char *buf, int nbytes)
+int client_write(char *buf, int nbytes)
 {
        int bytes_written = 0;
        int retval;
@@ -579,26 +610,13 @@ void client_write(char *buf, int nbytes)
                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 (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;
+               return 0;
        }
-#endif
-
-       /* Ok, at this point we're not buffering.  Go ahead and write. */
 
 #ifdef HAVE_OPENSSL
        if (Ctx->redirect_ssl) {
                client_write_ssl(buf, nbytes);
-               return;
+               return 0;
        }
 #endif
 
@@ -615,7 +633,7 @@ void client_write(char *buf, int nbytes)
                                        strerror(errno), errno);
                                cit_backtrace();
                                Ctx->kill_me = 1;
-                               return;
+                               return -1;
                        }
                }
 
@@ -629,21 +647,21 @@ void client_write(char *buf, int nbytes)
                        cit_backtrace();
                        // CtdlLogPrintf(CTDL_DEBUG, "Tried to send: %s",  &buf[bytes_written]);
                        Ctx->kill_me = 1;
-                       return;
+                       return -1;
                }
                bytes_written = bytes_written + retval;
        }
+       return 0;
 }
 
 
 /*
- * cprintf()  ...   Send formatted printable data to the client.   It is
- *               implemented in terms of client_write() but remains in
- *               sysdep.c in case we port to somewhere without va_args...
+ * cprintf()   Send formatted printable data to the client.
+ *             Implemented in terms of client_write() so it's technically not sysdep...
  */
 void cprintf(const char *format, ...) {   
        va_list arg_ptr;   
-       char buf[1024];   
+       char buf[1024];
    
        va_start(arg_ptr, format);   
        if (vsnprintf(buf, sizeof buf, format, arg_ptr) == -1)
@@ -684,6 +702,15 @@ int client_read_to(char *buf, int bytes, int timeout)
 
                retval = select( (fd)+1, 
                                 &rfds, NULL, NULL, &tv);
+               if (retval < 0)
+               {
+                       if (errno == EINTR)
+                       {
+                               CtdlLogPrintf(CTDL_DEBUG, "Interrupted select().\n");
+                               CC->kill_me = 1;
+                               return (-1);
+                       }
+               }
 
                if (FD_ISSET(fd, &rfds) == 0) {
                        return(0);
@@ -774,7 +801,7 @@ void context_cleanup(void)
                rem = ptr->next;
                --num_sessions;
                
-               lprintf(CTDL_DEBUG, "Purging session %d\n", ptr->cs_pid);
+               CtdlLogPrintf(CTDL_DEBUG, "Purging session %d\n", ptr->cs_pid);
                RemoveContext(ptr);
                free (ptr);
                ptr = rem;
@@ -1056,8 +1083,6 @@ void InitializeMasterCC(void) {
 
 
 
-
-
 /*
  * Bind a thread to a context.  (It's inline merely to speed things up.)
  */
@@ -1176,8 +1201,9 @@ do_select:        force_purge = 0;
                        if (errno != EINTR) {
                                CtdlLogPrintf(CTDL_EMERG, "Exiting (%s)\n", strerror(errno));
                                CtdlThreadStopAll();
-                       } else if (!CtdlThreadCheckStop()) {
-                               CtdlLogPrintf(CTDL_DEBUG, "Interrupted select.\n");
+                       } else {
+                               CtdlLogPrintf(CTDL_DEBUG, "Interrupted CtdlThreadSelect.\n");
+                               if (CtdlThreadCheckStop()) return(NULL);
                                goto do_select;
                        }
                }