New version made these changes necessary.
[privoxy.git] / jcc.c
diff --git a/jcc.c b/jcc.c
index 44f9398..0d52ac6 100644 (file)
--- a/jcc.c
+++ b/jcc.c
@@ -1,19 +1,19 @@
-const char jcc_rcs[] = "$Id: jcc.c,v 1.48 2001/10/10 19:56:46 jongfoster Exp $";
+const char jcc_rcs[] = "$Id: jcc.c,v 1.57 2001/11/16 00:47:43 jongfoster Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/jcc.c,v $
  *
- * Purpose     :  Main file.  Contains main() method, main loop, and 
+ * Purpose     :  Main file.  Contains main() method, main loop, and
  *                the main connection-handling function.
  *
  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
  *                IJBSWA team.  http://ijbswa.sourceforge.net
  *
  *                Based on the Internet Junkbuster originally written
- *                by and Copyright (C) 1997 Anonymous Coders and 
+ *                by and Copyright (C) 1997 Anonymous Coders and
  *                Junkbusters Corporation.  http://www.junkbusters.com
  *
- *                This program is free software; you can redistribute it 
+ *                This program is free 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 2 of the License, or (at
@@ -33,6 +33,44 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.48 2001/10/10 19:56:46 jongfoster Exp $";
  *
  * Revisions   :
  *    $Log: jcc.c,v $
+ *    Revision 1.57  2001/11/16 00:47:43  jongfoster
+ *    Changing the tty-disconnection code to use setsid().
+ *
+ *    Revision 1.56  2001/11/13 20:20:54  jongfoster
+ *    Tabs->spaces, fixing a bug with missing {} around an if()
+ *
+ *    Revision 1.55  2001/11/13 20:14:53  jongfoster
+ *    Patch for FreeBSD setpgrp() as suggested by Alexander Lazic
+ *
+ *    Revision 1.54  2001/11/07 00:03:14  steudten
+ *    Give reliable return value if an error
+ *    occurs not just 0 with new daemon mode.
+ *
+ *    Revision 1.53  2001/11/05 21:41:43  steudten
+ *    Add changes to be a real daemon just for unix os.
+ *    (change cwd to /, detach from controlling tty, set
+ *    process group and session leader to the own process.
+ *    Add DBG() Macro.
+ *    Add some fatal-error log message for failed malloc().
+ *    Add '-d' if compiled with 'configure --with-debug' to
+ *    enable debug output.
+ *
+ *    Revision 1.52  2001/10/26 20:11:20  jongfoster
+ *    Fixing type mismatch
+ *
+ *    Revision 1.51  2001/10/26 17:38:28  oes
+ *    Cosmetics
+ *
+ *    Revision 1.50  2001/10/25 03:40:48  david__schmidt
+ *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
+ *    threads to call select() simultaneously.  So, it's time to do a real, live,
+ *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
+ *    (native). Both versions will work, but using __OS2__ offers multi-threading.
+ *
+ *    Revision 1.49  2001/10/23 21:41:35  jongfoster
+ *    Added call to initialize the (statically-allocated of course)
+ *    "out of memory" CGI response.
+ *
  *    Revision 1.48  2001/10/10 19:56:46  jongfoster
  *    Moving some code that wasn't cookie-related out of an #ifdef
  *    FEATURE_COOKIE_JAR
@@ -360,10 +398,18 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.48 2001/10/10 19:56:46 jongfoster Exp $";
 
 #else /* ifndef _WIN32 */
 
+# if !defined (__OS2__)
 # include <unistd.h>
-# include <sys/time.h>
 # include <sys/wait.h>
+# endif /* ndef __OS2__ */
+# include <sys/time.h>
 # include <sys/stat.h>
+# include <sys/ioctl.h>
+
+#ifdef sun
+#include <sys/termios.h>
+#endif /* sun */
+
 # include <signal.h>
 
 # ifdef __BEOS__
@@ -371,9 +417,14 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.48 2001/10/10 19:56:46 jongfoster Exp $";
 #  include <OS.h>      /* declarations for threads and stuff. */
 # endif
 
-# ifdef __EMX__
+# if defined(__EMX__) || defined(__OS2__)
 #  include <sys/select.h>  /* OS/2/EMX needs a little help with select */
 # endif
+# ifdef __OS2__
+#define INCL_DOS
+# include <os2.h>
+#define bzero(B,N) memset(B,0x00,n)
+# endif
 
 # ifndef FD_ZERO
 #  include <select.h>
@@ -381,6 +432,10 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.48 2001/10/10 19:56:46 jongfoster Exp $";
 
 #endif
 
+#ifdef _DEBUG
+int ldebug = 0;
+#endif
+
 #include "project.h"
 #include "list.h"
 #include "jcc.h"
@@ -424,6 +479,13 @@ static int32 server_thread(void *data);
 #define sleep(N)  Sleep(((N) * 1000))
 #endif
 
+#ifdef __OS2__
+#define sleep(N)  DosSleep(((N) * 100))
+#endif
+
+#if defined(unix)
+const char *basedir;
+#endif /* defined unix */
 
 /* The vanilla wafer. */
 static const char VANILLA_WAFER[] =
@@ -442,7 +504,7 @@ static const char VANILLA_WAFER[] =
  *
  * Description :  Once a connection to the client has been accepted,
  *                this function is called (via serve()) to handle the
- *                main business of the communication.  When this 
+ *                main business of the communication.  When this
  *                function returns, the caller must close the client
  *                socket handle.
  *
@@ -461,7 +523,7 @@ static void chat(struct client_state *csp)
 {
 /*
  * This next lines are a little ugly, but they simplifies the if statements
- * below.  Basically if TOGGLE, then we want the if to test if the 
+ * below.  Basically if TOGGLE, then we want the if to test if the
  * CSP_FLAG_TOGGLED_ON flag ist set, else we don't.  And if FEATURE_FORCE_LOAD,
  * then we want the if to test for CSP_FLAG_FORCED , else we don't
  */
@@ -471,7 +533,7 @@ static void chat(struct client_state *csp)
 #   define IS_TOGGLED_ON_AND
 #endif /* ndef FEATURE_TOGGLE */
 #ifdef FEATURE_FORCE_LOAD
-#   define IS_NOT_FORCED_AND !(csp->flags & CSP_FLAG_FORCED) && 
+#   define IS_NOT_FORCED_AND !(csp->flags & CSP_FLAG_FORCED) &&
 #else /* ifndef FEATURE_FORCE_LOAD */
 #   define IS_NOT_FORCED_AND
 #endif /* def FEATURE_FORCE_LOAD */
@@ -495,7 +557,7 @@ static void chat(struct client_state *csp)
    int gif_deanimate;      /* bool, 1==will deanimate gifs */
 
    /* Function that does the content filtering for the current request */
-   char *(*content_filter)() = NULL; 
+   char *(*content_filter)() = NULL;
 
    /* Skeleton for HTTP response, if we should intercept the request */
    struct http_response *rsp;
@@ -526,7 +588,7 @@ static void chat(struct client_state *csp)
       {
          continue;   /* more to come! */
       }
+
 #ifdef FEATURE_FORCE_LOAD
       /* If this request contains the FORCE_PREFIX,
        * better get rid of it now and set the force flag --oes
@@ -537,7 +599,7 @@ static void chat(struct client_state *csp)
          strclean(req, FORCE_PREFIX);
          log_error(LOG_LEVEL_FORCE, "Enforcing request \"%s\".\n", req);
          csp->flags |= CSP_FLAG_FORCED;
-      } 
+      }
 
 #endif /* def FEATURE_FORCE_LOAD */
 
@@ -573,7 +635,7 @@ static void chat(struct client_state *csp)
     *          full orininal URL (w/url)
     *          Note that the path and/or the HTTP version may
     *          have been altered by now.
-    * 
+    *
     * connect = Open a socket to the host:port of the server
     *           and short-circuit server and client socket.
     *
@@ -585,7 +647,7 @@ static void chat(struct client_state *csp)
     *         parent's). After sending the request to the parent, we simply
     *         tunnel.
     *
-    * here's the matrix: 
+    * here's the matrix:
     *                        SSL
     *                    0        1
     *                +--------+--------+
@@ -600,7 +662,7 @@ static void chat(struct client_state *csp)
     *
     */
 
-   /* 
+   /*
     * Determine the actions for this URL
     */
 #ifdef FEATURE_TOGGLE
@@ -623,20 +685,20 @@ static void chat(struct client_state *csp)
     */
    if(http->ssl)
    {
-      if(  ( !(csp->action->flags & ACTION_LIMIT_CONNECT) && csp->http->port != 443) 
+      if(  ( !(csp->action->flags & ACTION_LIMIT_CONNECT) && csp->http->port != 443)
            || (csp->action->flags & ACTION_LIMIT_CONNECT
               && !match_portlist(csp->action->string[ACTION_STRING_LIMIT_CONNECT], csp->http->port)) )
       {
          strcpy(buf, CFORBIDDEN);
          write_socket(csp->cfd, buf, strlen(buf));
-         
+
          log_error(LOG_LEVEL_CONNECT, "Denying suspicious CONNECT request from %s", csp->ip_addr_str);
          log_error(LOG_LEVEL_CLF, "%s - - [%T] \" \" 403 0", csp->ip_addr_str);
 
          return;
       }
    }
-            
+
 
    /*
     * Downgrade http version from 1.1 to 1.0 if +downgrade
@@ -652,8 +714,8 @@ static void chat(struct client_state *csp)
     * (Re)build the HTTP request for non-SSL requests.
     * If forwarding, use the whole URL, else, use only the path.
     */
-   if (http->ssl == 0)  
-   {  
+   if (http->ssl == 0)
+   {
       freez(http->cmd);
 
       http->cmd = strsav(http->cmd, http->gpc);
@@ -720,23 +782,20 @@ static void chat(struct client_state *csp)
       enlist(csp->headers, p);
       freez(p);
    }
-
-   /* We have a request. */
-
-   /* 
-    * Now, check to see if we need to intercept it, i.e.
-    * If
+   /*
+    * We have a request. Now, check to see if we need to
+    * intercept it, i.e. If ..
     */
+
    if (
        /* a CGI call was detected and answered */
-        (NULL != (rsp = dispatch_cgi(csp))) 
+       (NULL != (rsp = dispatch_cgi(csp)))
 
        /* or we are enabled and... */
        || (IS_ENABLED_AND (
 
             /* ..the request was blocked */
-           ( NULL != (rsp = block_url(csp)))
+          ( NULL != (rsp = block_url(csp)))
 
           /* ..or untrusted */
 #ifdef FEATURE_TRUST
@@ -745,16 +804,16 @@ static void chat(struct client_state *csp)
 
           /* ..or a fast redirect kicked in */
 #ifdef FEATURE_FAST_REDIRECTS
-          || (((csp->action->flags & ACTION_FAST_REDIRECTS) != 0) && 
-                    (NULL != (rsp = redirect_url(csp))))
+          || (((csp->action->flags & ACTION_FAST_REDIRECTS) != 0) &&
+                (NULL != (rsp = redirect_url(csp))))
 #endif /* def FEATURE_FAST_REDIRECTS */
-                ))
-       )
+          ))
+      )
    {
       /* Write the answer to the client */
       if ((write_socket(csp->cfd, rsp->head, rsp->head_length) != rsp->head_length)
-            || (write_socket(csp->cfd, rsp->body, rsp->content_length) != rsp->content_length))
-      { 
+           || (write_socket(csp->cfd, rsp->body, rsp->content_length) != rsp->content_length))
+      {
          log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
       }
 
@@ -765,7 +824,7 @@ static void chat(struct client_state *csp)
 
       /* Log (FIXME: All intercept reasons apprear as "crunch" with Status 200) */
       log_error(LOG_LEVEL_GPC, "%s%s crunch!", http->hostport, http->path);
-      log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 3", csp->ip_addr_str, http->cmd); 
+      log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 3", csp->ip_addr_str, http->cmd);
 
       /* Clean up and return */
       free_http_response(rsp);
@@ -795,25 +854,25 @@ static void chat(struct client_state *csp)
 
       if (errno == EINVAL)
       {
-          rsp = error_response(csp, "no-such-domain", errno);
+         rsp = error_response(csp, "no-such-domain", errno);
 
-         log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 404 0", 
+         log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 404 0",
                    csp->ip_addr_str, http->cmd);
       }
       else
       {
-          rsp = error_response(csp, "connect-failed", errno);
+         rsp = error_response(csp, "connect-failed", errno);
 
-         log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 503 0", 
+         log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 503 0",
                    csp->ip_addr_str, http->cmd);
       }
 
       /* Write the answer to the client */
       if(rsp)
-       {
+      {
          if ((write_socket(csp->cfd, rsp->head, rsp->head_length) != rsp->head_length)
-               || (write_socket(csp->cfd, rsp->body, rsp->content_length) != rsp->content_length))
-         { 
+          || (write_socket(csp->cfd, rsp->body, rsp->content_length) != rsp->content_length))
+         {
             log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
          }
       }
@@ -841,16 +900,16 @@ static void chat(struct client_state *csp)
          log_error(LOG_LEVEL_CONNECT, "write header to: %s failed: %E",
                     http->hostport);
 
-         log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 503 0", 
-                   csp->ip_addr_str, http->cmd); 
+         log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 503 0",
+                   csp->ip_addr_str, http->cmd);
 
          rsp = error_response(csp, "connect-failed", errno);
 
          if(rsp)
          {
             if ((write_socket(csp->cfd, rsp->head, n) != n)
-               || (write_socket(csp->cfd, rsp->body, rsp->content_length) != rsp->content_length))
-            { 
+             || (write_socket(csp->cfd, rsp->body, rsp->content_length) != rsp->content_length))
+            {
                log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
             }
          }
@@ -867,8 +926,8 @@ static void chat(struct client_state *csp)
        * so just send the "connect succeeded" message to the
        * client, flush the rest, and get out of the way.
        */
-      log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 2\n", 
-                csp->ip_addr_str, http->cmd); 
+      log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 2\n",
+                csp->ip_addr_str, http->cmd);
 
       if (write_socket(csp->cfd, CSUCCEED, sizeof(CSUCCEED)-1) < 0)
       {
@@ -941,19 +1000,19 @@ static void chat(struct client_state *csp)
          {
             log_error(LOG_LEVEL_ERROR, "read from: %s failed: %E", http->host);
 
-            log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 503 0", 
-                      csp->ip_addr_str, http->cmd); 
+            log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 503 0",
+                      csp->ip_addr_str, http->cmd);
 
             rsp = error_response(csp, "connect-failed", errno);
 
             if(rsp)
             {
                if ((write_socket(csp->cfd, rsp->head, rsp->head_length) != rsp->head_length)
-                   || (write_socket(csp->cfd, rsp->body, rsp->content_length) != rsp->content_length))
-               { 
+                || (write_socket(csp->cfd, rsp->body, rsp->content_length) != rsp->content_length))
+               {
                   log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
-                          }
-                       }
+               }
+            }
 
             free_http_response(rsp);
             return;
@@ -992,7 +1051,7 @@ static void chat(struct client_state *csp)
           */
          if (n == 0)
          {
-            
+
             if (server_body || http->ssl)
             {
                /*
@@ -1032,7 +1091,7 @@ static void chat(struct client_state *csp)
             }
 
             /*
-             * This is NOT the body, so 
+             * This is NOT the body, so
              * Let's pretend the server just sent us a blank line.
              */
             n = sprintf(buf, "\r\n");
@@ -1055,17 +1114,17 @@ static void chat(struct client_state *csp)
          {
             if (content_filter)
             {
-               add_to_iob(csp, buf, n); 
+               add_to_iob(csp, buf, n);
 
                /*
                 * If the buffer limit will be reached on the next read,
                 * switch to non-filtering mode, i.e. make & write the
                 * header, flush the socket and get out of the way.
                 */
-               if (csp->iob->eod - csp->iob->buf + BUFFER_SIZE > csp->config->buffer_limit)
+               if (((size_t)(csp->iob->eod - csp->iob->buf)) + (size_t)BUFFER_SIZE > csp->config->buffer_limit)
                {
                   log_error(LOG_LEVEL_ERROR, "Buffer size limit reached! Flushing and stepping back.");
-                  
+
                   hdr = sed(server_patterns, add_server_headers, csp);
                   n   = strlen(hdr);
                   byte_count += n;
@@ -1237,8 +1296,8 @@ static void chat(struct client_state *csp)
       return; /* huh? we should never get here */
    }
 
-   log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 %d", 
-             csp->ip_addr_str, http->cmd, byte_count); 
+   log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 %d",
+             csp->ip_addr_str, http->cmd, byte_count);
 }
 
 
@@ -1315,7 +1374,7 @@ static int32 server_thread(void *data)
  *                any load fails, and can't bind port.
  *
  *                Else main never returns, the process must be signaled
- *                to terminate execution.  Or, on Windows, use the 
+ *                to terminate execution.  Or, on Windows, use the
  *                "File", "Exit" menu option.
  *
  *********************************************************************/
@@ -1325,13 +1384,15 @@ int real_main(int argc, const char *argv[])
 int main(int argc, const char *argv[])
 #endif
 {
+   int argc_pos = 1;
+
    configfile =
 #ifdef AMIGA
    "AmiTCP:db/junkbuster/config"
 #elif !defined(_WIN32)
    "config"
 #else
-   "junkbstr.txt"
+   "config.txt"
 #endif
       ;
 
@@ -1350,15 +1411,51 @@ int main(int argc, const char *argv[])
       printf(VERSION "\n");
       exit(2);
    }
+#ifdef _DEBUG
+   if ((argc >= 2) && (strcmp(argv[1], "-d")==0))
+   {
+      ldebug++;
+      argc_pos++;
+      fprintf(stderr,"debugging enabled..\n");
+   }
+#endif /* _DEBUG */
 #endif /* !defined(_WIN32) || defined(_WIN_CONSOLE) */
 
    Argc = argc;
    Argv = argv;
 
-   if (argc > 1)
+   if (argc > argc_pos )
+   {
+      configfile = argv[argc_pos];
+   }
+
+#if defined(unix)
+   if ( *configfile != '/' )
    {
-      configfile = argv[1];
+      char *abs_file;
+
+      DBG(1, ("configfile before '%s'\n",configfile) );
+
+      /* make config-filename absolute here */
+      if ( !(basedir = getcwd( NULL, 1024 )))
+      {
+         perror("get working dir failed");
+         exit( 1 );
+      }
+      DBG(1, ("working dir '%s'\n",basedir) );
+      if ( !(abs_file = malloc( strlen( basedir ) + strlen( configfile ) + 5 )))
+      {
+         perror("malloc failed");
+         exit( 1 );
+      }
+      strcpy( abs_file, basedir );
+      strcat( abs_file, "/" );
+      strcat( abs_file, configfile );
+      configfile = abs_file;
+      DBG(1, ("configfile after '%s'\n",configfile) );
    }
+#endif /* defined unix */
+
 
    files->next = NULL;
 
@@ -1369,7 +1466,7 @@ int main(int argc, const char *argv[])
 #endif
 
 
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(__OS2__)
    signal(SIGPIPE, SIG_IGN);
    signal(SIGCHLD, SIG_IGN);
 
@@ -1387,6 +1484,79 @@ int main(int argc, const char *argv[])
    /* Initialize the CGI subsystem */
    cgi_init_error_messages();
 
+#if defined(unix)
+{
+   pid_t pid = 0;
+#if 0
+   int   fd;
+#endif
+
+   /*
+    * we make us a real daemon
+    */
+#ifdef _DEBUG
+   if ( !ldebug)
+#endif
+   pid  = fork();
+   if ( pid < 0 ) /* error */
+   {
+      perror("fork");
+      exit( 3 );
+   }
+   else if ( pid != 0 ) /* parent */
+   {
+      int status;
+      pid_t wpid;
+      /*
+       * must check for errors
+       * child died due to missing files aso
+       */
+      sleep( 1 );
+      wpid = waitpid( pid, &status, WNOHANG );
+      if ( wpid != 0 )
+      {
+         exit( 1 );
+      }
+      exit( 0 );
+   }
+   /* child */
+#if 1
+   /* Should be more portable, but not as well tested */
+   setsid();
+#else /* !1 */
+#ifdef __FreeBSD__
+   setpgrp(0,0);
+#else /* ndef __FreeBSD__ */
+   setpgrp();
+#endif /* ndef __FreeBSD__ */
+   fd = open("/dev/tty", O_RDONLY);
+   if ( fd )
+   {
+      /* no error check here */
+      ioctl( fd, TIOCNOTTY,0 );
+      close ( fd );
+   }
+#endif /* !1 */
+   /* should close stderr (fd 2) here too, but the test for existence
+   ** and load config file is done in listen_loop() and puts
+   ** some messages on stderr there.
+   */
+#ifdef _DEBUG
+   if ( !ldebug )
+   {
+      close( 0 );
+      close( 1 );
+   }
+#else
+   close( 0 );
+   close( 1 );
+#endif /* _DEBUG */
+   chdir("/");
+
+}
+#endif /* defined unix */
+
+   DBG(1, ("call listen_loop() \n") );
    listen_loop();
 
    /* NOTREACHED */
@@ -1423,8 +1593,8 @@ static void listen_loop(void)
    {
       log_error(LOG_LEVEL_FATAL, "can't bind %s:%d: %E "
          "- There may be another junkbuster or some other "
-         "proxy running on port %d", 
-         (NULL != config->haddr) ? config->haddr : "INADDR_ANY", 
+         "proxy running on port %d",
+         (NULL != config->haddr) ? config->haddr : "INADDR_ANY",
          config->hport, config->hport
       );
       /* shouldn't get here */
@@ -1433,10 +1603,9 @@ static void listen_loop(void)
 
    config->need_bind = 0;
 
-
    while (FOREVER)
    {
-#if !defined(FEATURE_PTHREAD) && !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
+#if !defined(FEATURE_PTHREAD) && !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
       while (waitpid(-1, NULL, WNOHANG) > 0)
       {
          /* zombie children */
@@ -1480,8 +1649,8 @@ static void listen_loop(void)
          {
             log_error(LOG_LEVEL_FATAL, "can't bind %s:%d: %E "
                "- There may be another junkbuster or some other "
-               "proxy running on port %d", 
-               (NULL != config->haddr) ? config->haddr : "INADDR_ANY", 
+               "proxy running on port %d",
+               (NULL != config->haddr) ? config->haddr : "INADDR_ANY",
                config->hport, config->hport
             );
             /* shouldn't get here */
@@ -1500,7 +1669,7 @@ static void listen_loop(void)
 #ifdef AMIGA
          if(!childs)
          {
-            exit(1); 
+            exit(1);
          }
 #endif
          freez(csp);
@@ -1568,6 +1737,15 @@ static void listen_loop(void)
             csp);
 #endif
 
+#if defined(__OS2__) && !defined(SELECTED_ONE_OPTION)
+#define SELECTED_ONE_OPTION
+         child_id = _beginthread(
+            serve,
+            NULL,
+            64 * 1024,
+            csp);
+#endif
+
 #if defined(__BEOS__) && !defined(SELECTED_ONE_OPTION)
 #define SELECTED_ONE_OPTION
          {