Removed the DEBUG_MEMORY_LEAKS framework because we do this with Valgrind now.
[citadel.git] / citadel / sysdep.c
index 628e955b3e4577ad57f70803cccd1f93c970c5d1..e16c8a50b2228371d28a926b72fd17bb517ece86 100644 (file)
@@ -9,7 +9,7 @@
  *
  * Copyright (c) 1987-2011 by the citadel.org team
  *
- * This program is free software; you can redistribute it and/or modify
+ * This program is open source software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
@@ -21,7 +21,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
 #include "sysdep.h"
 #include "control.h"
 
 
-#ifdef DEBUG_MEMORY_LEAKS
-struct igheap {
-       struct igheap *next;
-       char file[32];
-       int line;
-       void *block;
-};
-
-struct igheap *igheap = NULL;
-#endif
-
-
 /*
  * Signal handler to shut down the server.
  */
@@ -168,22 +156,14 @@ void init_sysdep(void) {
         */
        sigemptyset(&set);
        sigaddset(&set, SIGINT);                // intr = shutdown
-       // sigaddset(&set, SIGQUIT);            // quit = force quit
        sigaddset(&set, SIGHUP);
        sigaddset(&set, SIGTERM);
-       // sigaddset(&set, SIGSEGV);            // we want core dumps
-       // sigaddset(&set, SIGILL);             // we want core dumps
-       // sigaddset(&set, SIGBUS);
        sigprocmask(SIG_UNBLOCK, &set, NULL);
 
        signal(SIGINT, signal_cleanup);         // intr = shutdown
-       // signal(SIGQUIT, signal_cleanup);     // quit = force quit
        signal(SIGHUP, signal_cleanup);
        signal(SIGTERM, signal_cleanup);
        signal(SIGUSR2, signal_exit);
-       // signal(SIGSEGV, signal_cleanup);     // we want coredumps
-       // signal(SIGILL, signal_cleanup);      // we want core dumps
-       // signal(SIGBUS, signal_cleanup);
 
        /*
         * Do not shut down the server on broken pipe signals, otherwise the
@@ -433,6 +413,25 @@ static void flush_client_inbuf(void)
 }
 */
 
+
+/*
+ * client_close()      ...     close the client socket
+ */
+void client_close(void) {
+       CitContext *CCC = CC;
+       int r;
+
+       if (!CCC) return;
+       if (CCC->client_socket <= 0) return;
+       syslog(LOG_DEBUG, "Closing socket %d\n", CCC->client_socket);
+       r = close(CCC->client_socket);
+       if (!r) syslog(LOG_INFO, "close() failed: %s\n", strerror(errno));
+       CCC->client_socket = -1 ;
+}
+
+
+
+
 /*
  * client_write()   ...    Send binary data to the client.
  */
@@ -506,22 +505,25 @@ int client_write(const char *buf, int nbytes)
                                        syslog(LOG_ERR,
                                                "client_write(%d bytes) select failed: %s (%d)\n",
                                                nbytes - bytes_written,
-                                               strerror(errno), errno);
+                                               strerror(errno), errno
+                                       );
                                        cit_backtrace();
+                                       client_close();
                                        Ctx->kill_me = KILLME_SELECT_FAILED;
                                        return -1;
                                }
                        }
                }
 
-               retval = write(Ctx->client_socket, &buf[bytes_written],
-                       nbytes - bytes_written);
+               retval = write(Ctx->client_socket, &buf[bytes_written], nbytes - bytes_written);
                if (retval < 1) {
                        syslog(LOG_ERR,
                                "client_write(%d bytes) failed: %s (%d)\n",
                                nbytes - bytes_written,
-                               strerror(errno), errno);
+                               strerror(errno), errno
+                       );
                        cit_backtrace();
+                       client_close();
                        // syslog(LOG_DEBUG, "Tried to send: %s",  &buf[bytes_written]);
                        Ctx->kill_me = KILLME_WRITE_FAILED;
                        return -1;
@@ -636,10 +638,8 @@ int client_read_blob(StrBuf *Target, int bytes, int timeout)
                                                O_TERM,
                                                &Error);
                if (retval < 0) {
-                       syslog(LOG_CRIT, 
-                                     "%s failed: %s\n",
-                                     __FUNCTION__, 
-                                     Error);
+                       syslog(LOG_CRIT, "%s failed: %s\n", __FUNCTION__, Error);
+                       client_close();
                        return retval;
                }
 #ifdef BIGBAD_IODBG
@@ -650,8 +650,6 @@ int client_read_blob(StrBuf *Target, int bytes, int timeout)
                        StrLength(Target));
                rv = fwrite(ChrPtr(Target), StrLength(Target), 1, fd);
                fprintf(fd, "]\n");
-               
-               
                fclose(fd);
 #endif
        }
@@ -1148,31 +1146,6 @@ int convert_login(char NameToConvert[]) {
 /* 
  * This loop just keeps going and going and going...
  */
-/*
- * FIXME:
- * This current implimentation of worker_thread creates a bottle neck in several situations
- * The first thing to remember is that a single thread can handle more than one connection at a time.
- * More threads mean less memory for the system to run in.
- * So for efficiency we want every thread to be doing something useful or waiting in the main loop for
- * something to happen anywhere.
- * This current implimentation requires worker threads to wait in other locations, after it has
- * been committed to a single connection which is very wasteful.
- * As an extreme case consider this:
- * A slow client connects and this slow client sends only one character each second.
- * With this current implimentation a single worker thread is dispatched to handle that connection
- * until such times as the client timeout expires, an error occurs on the socket or the client
- * completes its transmission.
- * THIS IS VERY BAD since that thread could have handled a read from many more clients in each one
- * second interval between chars.
- *
- * It is my intention to re-write this code and the associated client_getln, client_read functions
- * to allow any thread to read data on behalf of any connection (context).
- * To do this I intend to have this main loop read chars into a buffer stored in the context.
- * Once the correct criteria for a full buffer is met then we will dispatch a thread to 
- * process it.
- * This worker thread loop also needs to be able to handle binary data.
- */
 void *worker_thread(void *arg) {
        int highest;
        CitContext *ptr;
@@ -1198,18 +1171,17 @@ do_select:      force_purge = 0;
 
                begin_critical_section(S_SESSION_TABLE);
                for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
-                       int client_socket;
                        if ((ptr->state == CON_SYS) && (ptr->client_socket == 0))
                            continue;
-                       client_socket = ptr->client_socket;
-                       /* Dont select on dead sessions only truly idle ones */
-                       if ((ptr->state == CON_IDLE) && 
-                           (CC->kill_me == 0) &&
-                           (client_socket > 0))
-                       {
-                               FD_SET(client_socket, &readfds);
-                               if (client_socket > highest)
-                                       highest = client_socket;
+
+                       /* Don't select on dead sessions, only truly idle ones */
+                       if (    (ptr->state == CON_IDLE)
+                               && (ptr->kill_me == 0)
+                               && (ptr->client_socket > 0)
+                       {
+                               FD_SET(ptr->client_socket, &readfds);
+                               if (ptr->client_socket > highest)
+                                       highest = ptr->client_socket;
                        }
                        if ((bind_me == NULL) && (ptr->state == CON_READY)) {
                                bind_me = ptr;
@@ -1418,9 +1390,7 @@ void *select_on_master (void *arg)
                        if (FD_ISSET(serviceptr->msock, &master_fds)) {
                                ssock = accept(serviceptr->msock, NULL, 0);
                                if (ssock >= 0) {
-                                       syslog(LOG_DEBUG,
-                                               "New client socket %d\n",
-                                               ssock);
+                                       syslog(LOG_DEBUG, "New client socket %d\n", ssock);
 
                                        /* The master socket is non-blocking but the client
                                         * sockets need to be blocking, otherwise certain
@@ -1439,26 +1409,20 @@ void *select_on_master (void *arg)
 
                                        /* Assign our new socket number to it. */
                                        con->client_socket = ssock;
-                                       con->h_command_function =
-                                               serviceptr->h_command_function;
-                                       con->h_async_function =
-                                               serviceptr->h_async_function;
+                                       con->h_command_function = serviceptr->h_command_function;
+                                       con->h_async_function = serviceptr->h_async_function;
                                        con->h_greeting_function = serviceptr->h_greeting_function;
-                                       con->ServiceName =
-                                               serviceptr->ServiceName;
+                                       con->ServiceName = serviceptr->ServiceName;
                                        
                                        /* Determine whether it's a local socket */
-                                       if (serviceptr->sockpath != NULL)
+                                       if (serviceptr->sockpath != NULL) {
                                                con->is_local_socket = 1;
+                                       }
        
                                        /* Set the SO_REUSEADDR socket option */
                                        i = 1;
-                                       setsockopt(ssock, SOL_SOCKET,
-                                               SO_REUSEADDR,
-                                               &i, sizeof(i));
-
+                                       setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
                                        con->state = CON_GREETING;
-
                                        retval--;
                                        if (retval == 0)
                                                break;
@@ -1511,112 +1475,3 @@ int SyslogFacility(char *name)
        }
        return LOG_DAEMON;
 }
-
-
-/********** MEM CHEQQER ***********/
-
-#ifdef DEBUG_MEMORY_LEAKS
-
-#undef malloc
-#undef realloc
-#undef strdup
-#undef free
-
-void *tracked_malloc(size_t size, char *file, int line) {
-       struct igheap *thisheap;
-       void *block;
-
-       block = malloc(size);
-       if (block == NULL) return(block);
-
-       thisheap = malloc(sizeof(struct igheap));
-       if (thisheap == NULL) {
-               free(block);
-               return(NULL);
-       }
-
-       thisheap->block = block;
-       strcpy(thisheap->file, file);
-       thisheap->line = line;
-       
-       begin_critical_section(S_DEBUGMEMLEAKS);
-       thisheap->next = igheap;
-       igheap = thisheap;
-       end_critical_section(S_DEBUGMEMLEAKS);
-
-       return(block);
-}
-
-
-void *tracked_realloc(void *ptr, size_t size, char *file, int line) {
-       struct igheap *thisheap;
-       void *block;
-
-       block = realloc(ptr, size);
-       if (block == NULL) return(block);
-
-       thisheap = malloc(sizeof(struct igheap));
-       if (thisheap == NULL) {
-               free(block);
-               return(NULL);
-       }
-
-       thisheap->block = block;
-       strcpy(thisheap->file, file);
-       thisheap->line = line;
-       
-       begin_critical_section(S_DEBUGMEMLEAKS);
-       thisheap->next = igheap;
-       igheap = thisheap;
-       end_critical_section(S_DEBUGMEMLEAKS);
-
-       return(block);
-}
-
-
-
-void tracked_free(void *ptr) {
-       struct igheap *thisheap;
-       struct igheap *trash;
-
-       free(ptr);
-
-       if (igheap == NULL) return;
-       begin_critical_section(S_DEBUGMEMLEAKS);
-       for (thisheap = igheap; thisheap != NULL; thisheap = thisheap->next) {
-               if (thisheap->next != NULL) {
-                       if (thisheap->next->block == ptr) {
-                               trash = thisheap->next;
-                               thisheap->next = thisheap->next->next;
-                               free(trash);
-                       }
-               }
-       }
-       if (igheap->block == ptr) {
-               trash = igheap;
-               igheap = igheap->next;
-               free(trash);
-       }
-       end_critical_section(S_DEBUGMEMLEAKS);
-}
-
-char *tracked_strdup(const char *s, char *file, int line) {
-       char *ptr;
-
-       if (s == NULL) return(NULL);
-       ptr = tracked_malloc(strlen(s) + 1, file, line);
-       if (ptr == NULL) return(NULL);
-       strncpy(ptr, s, strlen(s));
-       return(ptr);
-}
-
-void dump_heap(void) {
-       struct igheap *thisheap;
-
-       for (thisheap = igheap; thisheap != NULL; thisheap = thisheap->next) {
-               syslog(LOG_CRIT, "UNFREED: %30s : %d\n",
-                       thisheap->file, thisheap->line);
-       }
-}
-
-#endif /*  DEBUG_MEMORY_LEAKS */