Adding graceful termination feature, to help look for memory leaks.
[privoxy.git] / jcc.c
diff --git a/jcc.c b/jcc.c
index 88db8b7..4e28e4f 100644 (file)
--- a/jcc.c
+++ b/jcc.c
@@ -1,4 +1,4 @@
-const char jcc_rcs[] = "$Id: jcc.c,v 1.79 2002/03/09 20:03:52 jongfoster Exp $";
+const char jcc_rcs[] = "$Id: jcc.c,v 1.82 2002/03/13 00:27:05 jongfoster Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/jcc.c,v $
@@ -33,6 +33,18 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.79 2002/03/09 20:03:52 jongfoster Exp $";
  *
  * Revisions   :
  *    $Log: jcc.c,v $
+ *    Revision 1.82  2002/03/13 00:27:05  jongfoster
+ *    Killing warnings
+ *
+ *    Revision 1.81  2002/03/12 01:42:50  oes
+ *    Introduced modular filters
+ *
+ *    Revision 1.80  2002/03/11 22:07:05  david__schmidt
+ *    OS/2 port maintenance:
+ *    - Fixed EMX build - it had decayed a little
+ *    - Fixed inexplicable crash during FD_ZERO - must be due to a bad macro.
+ *      substituted a memset for now.
+ *
  *    Revision 1.79  2002/03/09 20:03:52  jongfoster
  *    - Making various functions return int rather than size_t.
  *      (Undoing a recent change).  Since size_t is unsigned on
@@ -574,6 +586,9 @@ int urls_read     = 0;     /* total nr of urls read inc rejected */
 int urls_rejected = 0;     /* total nr of urls rejected */
 #endif /* def FEATURE_STATISTICS */
 
+#ifdef FEATURE_GRACEFUL_TERMINATION
+int g_terminate = 0;
+#endif
 
 static void listen_loop(void);
 static void chat(struct client_state *csp);
@@ -735,7 +750,7 @@ static void chat(struct client_state *csp)
     * could get blocked here if a client connected, then didn't say anything!
     */
 
-   while (FOREVER)
+   for (;;)
    {
       len = read_socket(csp->cfd, buf, sizeof(buf));
 
@@ -944,15 +959,15 @@ static void chat(struct client_state *csp)
 #endif /* def FEATURE_KILL_POPUPS */
 
    pcrs_filter                = (csp->rlist != NULL) &&  /* There are expressions to be used */
-                                ((csp->action->flags & ACTION_FILTER) != 0);
+                                (!list_is_empty(csp->action->multi[ACTION_MULTI_FILTER]));
 
    gif_deanimate              = ((csp->action->flags & ACTION_DEANIMATE) != 0);
 
    /* grab the rest of the client's headers */
 
-   while (FOREVER)
+   for (;;)
    {
-      if ( ( p = get_header(csp) ) && ( *p == '\0' ) )
+      if ( ( ( p = get_header(csp) ) != NULL) && ( *p == '\0' ) )
       {
          len = read_socket(csp->cfd, buf, sizeof(buf));
          if (len <= 0)
@@ -1140,7 +1155,7 @@ static void chat(struct client_state *csp)
 
    server_body = 0;
 
-   while (FOREVER)
+   for (;;)
    {
 #ifdef __OS2__
       /*
@@ -1154,7 +1169,7 @@ static void chat(struct client_state *csp)
       FD_SET(csp->cfd, &rfds);
       FD_SET(csp->sfd, &rfds);
 
-      n = select(maxfd+1, &rfds, NULL, NULL, NULL);
+      n = select((int)maxfd+1, &rfds, NULL, NULL, NULL);
 
       if (n < 0)
       {
@@ -1175,7 +1190,7 @@ static void chat(struct client_state *csp)
             break; /* "game over, man" */
          }
 
-         if (write_socket(csp->sfd, buf, len))
+         if (write_socket(csp->sfd, buf, (size_t)len))
          {
             log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
             return;
@@ -1326,6 +1341,8 @@ static void chat(struct client_state *csp)
                 */
                if (((size_t)(csp->iob->eod - csp->iob->buf)) + (size_t)BUFFER_SIZE > csp->config->buffer_limit)
                {
+                  size_t hdrlen;
+
                   log_error(LOG_LEVEL_ERROR, "Buffer size limit reached! Flushing and stepping back.");
 
                   hdr = sed(server_patterns, add_server_headers, csp);
@@ -1335,11 +1352,11 @@ static void chat(struct client_state *csp)
                      log_error(LOG_LEVEL_FATAL, "Out of memory parsing server header");
                   }
 
-                  len = strlen(hdr);
-                  byte_count += len;
+                  hdrlen = strlen(hdr);
+                  byte_count += hdrlen;
 
-                  if (write_socket(csp->cfd, hdr, len)
-                   || (len = flush_socket(csp->cfd, csp) < 0))
+                  if (write_socket(csp->cfd, hdr, hdrlen)
+                   || ((len = flush_socket(csp->cfd, csp)) < 0))
                   {
                      log_error(LOG_LEVEL_CONNECT, "write header to client failed: %E");
 
@@ -1357,7 +1374,7 @@ static void chat(struct client_state *csp)
             }
             else
             {
-               if (write_socket(csp->cfd, buf, len))
+               if (write_socket(csp->cfd, buf, (size_t)len))
                {
                   log_error(LOG_LEVEL_ERROR, "write to client failed: %E");
                   return;
@@ -1378,7 +1395,7 @@ static void chat(struct client_state *csp)
 
             /* get header lines from the iob */
 
-            while ((p = get_header(csp)))
+            while ((p = get_header(csp)) != NULL)
             {
                if (*p == '\0')
                {
@@ -1474,10 +1491,8 @@ static void chat(struct client_state *csp)
                 * may be in the buffer)
                 */
 
-               len = strlen(hdr);
-
-               if (write_socket(csp->cfd, hdr, len)
-                || (len = flush_socket(csp->cfd, csp) < 0))
+               if (write_socket(csp->cfd, hdr, strlen(hdr))
+                || ((len = flush_socket(csp->cfd, csp)) < 0))
                {
                   log_error(LOG_LEVEL_CONNECT, "write header to client failed: %E");
 
@@ -1965,7 +1980,11 @@ static void listen_loop(void)
 
    bfd = bind_port_helper(config);
 
-   while (FOREVER)
+#ifdef FEATURE_GRACEFUL_TERMINATION
+   while (!g_terminate)
+#else
+   for (;;)
+#endif
    {
 #if !defined(FEATURE_PTHREAD) && !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
       while (waitpid(-1, NULL, WNOHANG) > 0)
@@ -2093,7 +2112,7 @@ static void listen_loop(void)
 #if defined(_WIN32) && !defined(_CYGWIN) && !defined(SELECTED_ONE_OPTION)
 #define SELECTED_ONE_OPTION
          child_id = _beginthread(
-            (void*)serve,
+            (void (*)(void *))serve,
             64 * 1024,
             csp);
 #endif
@@ -2193,7 +2212,45 @@ static void listen_loop(void)
          serve(csp);
       }
    }
-   /* NOTREACHED */
+
+   /* NOTREACHED unless FEATURE_GRACEFUL_TERMINATION is defined */
+
+   /* Clean up.  Aim: free all memory (no leaks) */
+#ifdef FEATURE_GRACEFUL_TERMINATION
+
+   log_error(LOG_LEVEL_ERROR, "Graceful termination requested");
+
+   unload_current_config_file();
+   unload_current_actions_file();
+   unload_current_re_filterfile();
+#ifdef FEATURE_TRUST
+   unload_current_trust_file();
+#endif
+
+   if (config->multi_threaded)
+   {
+      int i = 60;
+      do
+      {
+         sleep(1);
+         sweep();
+      } while ((clients->next != NULL) && (--i > 0));
+
+      if (i <= 0)
+      {
+         log_error(LOG_LEVEL_ERROR, "Graceful termination failed - still some live clients after 1 minute wait.");
+      }
+   }
+   sweep();
+   sweep();
+
+#if defined(_WIN32) && !defined(_WIN_CONSOLE)
+   /* Cleanup - remove taskbar icon etc. */
+   TermLogWindow();
+#endif
+
+   exit(0);
+#endif /* FEATURE_GRACEFUL_TERMINATION */
 
 }