- Jon's multiple AF patch:
[privoxy.git] / jcc.c
diff --git a/jcc.c b/jcc.c
index 88db8b7..54f190e 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.90 2002/04/02 14:57:28 oes Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/jcc.c,v $
@@ -7,7 +7,7 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.79 2002/03/09 20:03:52 jongfoster Exp $";
  *                the main connection-handling function.
  *
  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
- *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *                Privoxy team. http://www.privoxy.org/
  *
  *                Based on the Internet Junkbuster originally written
  *                by and Copyright (C) 1997 Anonymous Coders and
@@ -33,6 +33,46 @@ 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.90  2002/04/02 14:57:28  oes
+ *    Made sending wafers independent of FEATURE_COOKIE_JAR
+ *
+ *    Revision 1.89  2002/03/31 17:18:59  jongfoster
+ *    Win32 only: Enabling STRICT to fix a VC++ compile warning.
+ *
+ *    Revision 1.88  2002/03/27 14:32:43  david__schmidt
+ *    More compiler warning message maintenance
+ *
+ *    Revision 1.87  2002/03/26 22:29:54  swa
+ *    we have a new homepage!
+ *
+ *    Revision 1.86  2002/03/25 17:04:55  david__schmidt
+ *    Workaround for closing the jarfile before load_config() comes around again
+ *
+ *    Revision 1.85  2002/03/24 15:23:33  jongfoster
+ *    Name changes
+ *
+ *    Revision 1.84  2002/03/24 13:25:43  swa
+ *    name change related issues
+ *
+ *    Revision 1.83  2002/03/16 23:54:06  jongfoster
+ *    Adding graceful termination feature, to help look for memory leaks.
+ *    If you enable this (which, by design, has to be done by hand
+ *    editing config.h) and then go to http://i.j.b/die, then the program
+ *    will exit cleanly after the *next* request.  It should free all the
+ *    memory that was used.
+ *
+ *    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
@@ -496,6 +536,9 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.79 2002/03/09 20:03:52 jongfoster Exp $";
 
 #ifdef _WIN32
 # ifndef FEATURE_PTHREAD
+#  ifndef STRICT
+#   define STRICT
+#  endif
 #  include <windows.h>
 #  include <process.h>
 # endif /* ndef FEATURE_PTHREAD */
@@ -574,6 +617,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 +781,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));
 
@@ -924,19 +970,15 @@ static void chat(struct client_state *csp)
    enlist(csp->headers, http->cmd);
 
 
-#ifdef FEATURE_COOKIE_JAR
    /*
-    * If we're logging cookies in a cookie jar, and the user has not
-    * supplied any wafers, and the user has not told us to suppress the
-    * vanilla wafer, then send the vanilla wafer.
+    * If the user has not supplied any wafers, and the user has not
+    * told us to suppress the vanilla wafer, then send the vanilla wafer.
     */
-   if ((csp->config->jarfile != NULL)
-       && list_is_empty(csp->action->multi[ACTION_MULTI_WAFER])
+   if (list_is_empty(csp->action->multi[ACTION_MULTI_WAFER])
        && ((csp->action->flags & ACTION_VANILLA_WAFER) != 0))
    {
       enlist(csp->action->multi[ACTION_MULTI_WAFER], VANILLA_WAFER);
    }
-#endif /* def FEATURE_COOKIE_JAR */
 
 
 #ifdef FEATURE_KILL_POPUPS
@@ -944,15 +986,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 +1182,7 @@ static void chat(struct client_state *csp)
 
    server_body = 0;
 
-   while (FOREVER)
+   for (;;)
    {
 #ifdef __OS2__
       /*
@@ -1154,7 +1196,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 +1217,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 +1368,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 +1379,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 +1401,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 +1422,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 +1518,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");
 
@@ -1585,7 +1627,7 @@ static int32 server_thread(void *data)
  *********************************************************************/
 void usage(const char *myname)
 {
-   printf("JunkBuster proxy version " VERSION " (" HOME_PAGE_URL ")\n"
+   printf("Privoxy version " VERSION " (" HOME_PAGE_URL ")\n"
            "Usage: %s [--help] [--version] [--no-daemon] [--pidfile pidfile] [--user user[.group]] [configfile]\n"
            "Aborting.\n", myname);
  
@@ -1655,7 +1697,7 @@ int main(int argc, const char *argv[])
 
       else if(strcmp(argv[argc_pos], "--version") == 0)
       {
-         printf("Junkbuster version " VERSION " (" HOME_PAGE_URL ")\n");
+         printf("Privoxy version " VERSION " (" HOME_PAGE_URL ")\n");
          exit(0);
       }
 
@@ -1880,7 +1922,7 @@ int main(int argc, const char *argv[])
  *                on failure.
  *
  * Parameters  :
- *          1  :  config = Junkbuster configuration.  Specifies port
+ *          1  :  config = Privoxy configuration.  Specifies port
  *                         to bind to.
  *
  * Returns     :  Port that was opened.
@@ -1919,7 +1961,7 @@ static jb_socket bind_port_helper(struct configuration_spec * config)
       {
          case -3 :
             log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: "
-               "There may be another junkbuster or some other "
+               "There may be another Privoxy or some other "
                "proxy running on port %d",
                (NULL != config->haddr) ? config->haddr : "INADDR_ANY",
                       config->hport, config->hport);
@@ -1965,7 +2007,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)
@@ -1990,6 +2036,23 @@ static void listen_loop(void)
       }
 #endif
 
+#ifdef __OS2__
+#ifdef FEATURE_COOKIE_JAR
+      /*
+       * Need a workaround here: we have to fclose() the jarfile, or we die because it's
+       * already open.  I think unload_configfile() is not being run, which should do
+       * this work.  Until that can get resolved, we'll use this workaround.
+       */
+       if (csp)
+         if(csp->config)
+           if (csp->config->jar)
+           {
+             fclose(csp->config->jar);
+             csp->config->jar = NULL;
+           }
+#endif /* FEATURE_COOKIE_JAR */
+#endif /* __OS2__ */
+
       if ( NULL == (csp = (struct client_state *) zalloc(sizeof(*csp))) )
       {
          log_error(LOG_LEVEL_FATAL, "malloc(%d) for csp failed: %E", sizeof(*csp));
@@ -2093,7 +2156,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
@@ -2101,7 +2164,7 @@ static void listen_loop(void)
 #if defined(__OS2__) && !defined(SELECTED_ONE_OPTION)
 #define SELECTED_ONE_OPTION
          child_id = _beginthread(
-            serve,
+            (void(* _Optlink)(void*))serve,
             NULL,
             64 * 1024,
             csp);
@@ -2131,7 +2194,7 @@ static void listen_loop(void)
             NP_Entry, (ULONG)server_thread,
             NP_Output, Output(),
             NP_CloseOutput, FALSE,
-            NP_Name, (ULONG)"junkbuster child",
+            NP_Name, (ULONG)"privoxy child",
             NP_StackSize, 200*1024,
             TAG_DONE)))
          {
@@ -2179,7 +2242,7 @@ static void listen_loop(void)
 
             log_error(LOG_LEVEL_ERROR, "can't fork: %E");
 
-            sprintf(buf , "JunkBuster: can't fork: errno = %d", errno);
+            sprintf(buf , "Privoxy: can't fork: errno = %d", errno);
 
             write_socket(csp->cfd, buf, strlen(buf));
             close_socket(csp->cfd);
@@ -2193,7 +2256,48 @@ 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(unix)
+   free(basedir);
+#endif
+#if defined(_WIN32) && !defined(_WIN_CONSOLE)
+   /* Cleanup - remove taskbar icon etc. */
+   TermLogWindow();
+#endif
+
+   exit(0);
+#endif /* FEATURE_GRACEFUL_TERMINATION */
 
 }