Home | History | Annotate | Download | only in server
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel (at) haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.haxx.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  ***************************************************************************/
     22 #include "server_setup.h"
     23 
     24 /* sws.c: simple (silly?) web server
     25 
     26    This code was originally graciously donated to the project by Juergen
     27    Wilke. Thanks a bunch!
     28 
     29  */
     30 
     31 #ifdef HAVE_SIGNAL_H
     32 #include <signal.h>
     33 #endif
     34 #ifdef HAVE_NETINET_IN_H
     35 #include <netinet/in.h>
     36 #endif
     37 #ifdef HAVE_NETINET_IN6_H
     38 #include <netinet/in6.h>
     39 #endif
     40 #ifdef HAVE_ARPA_INET_H
     41 #include <arpa/inet.h>
     42 #endif
     43 #ifdef HAVE_NETDB_H
     44 #include <netdb.h>
     45 #endif
     46 #ifdef HAVE_NETINET_TCP_H
     47 #include <netinet/tcp.h> /* for TCP_NODELAY */
     48 #endif
     49 
     50 #define ENABLE_CURLX_PRINTF
     51 /* make the curlx header define all printf() functions to use the curlx_*
     52    versions instead */
     53 #include "curlx.h" /* from the private lib dir */
     54 #include "getpart.h"
     55 #include "inet_pton.h"
     56 #include "util.h"
     57 #include "server_sockaddr.h"
     58 
     59 /* include memdebug.h last */
     60 #include "memdebug.h"
     61 
     62 #ifdef USE_WINSOCK
     63 #undef  EINTR
     64 #define EINTR    4 /* errno.h value */
     65 #undef  EAGAIN
     66 #define EAGAIN  11 /* errno.h value */
     67 #undef  ERANGE
     68 #define ERANGE  34 /* errno.h value */
     69 #endif
     70 
     71 static enum {
     72   socket_domain_inet = AF_INET
     73 #ifdef ENABLE_IPV6
     74   , socket_domain_inet6 = AF_INET6
     75 #endif
     76 #ifdef USE_UNIX_SOCKETS
     77   , socket_domain_unix = AF_UNIX
     78 #endif
     79 } socket_domain = AF_INET;
     80 static bool use_gopher = FALSE;
     81 static int serverlogslocked = 0;
     82 static bool is_proxy = FALSE;
     83 
     84 #define REQBUFSIZ 150000
     85 #define REQBUFSIZ_TXT "149999"
     86 
     87 static long prevtestno = -1;    /* previous test number we served */
     88 static long prevpartno = -1;    /* previous part number we served */
     89 static bool prevbounce = FALSE; /* instructs the server to increase the part
     90                                    number for a test in case the identical
     91                                    testno+partno request shows up again */
     92 
     93 #define RCMD_NORMALREQ 0 /* default request, use the tests file normally */
     94 #define RCMD_IDLE      1 /* told to sit idle */
     95 #define RCMD_STREAM    2 /* told to stream */
     96 
     97 struct httprequest {
     98   char reqbuf[REQBUFSIZ]; /* buffer area for the incoming request */
     99   bool connect_request; /* if a CONNECT */
    100   unsigned short connect_port; /* the port number CONNECT used */
    101   size_t checkindex; /* where to start checking of the request */
    102   size_t offset;     /* size of the incoming request */
    103   long testno;       /* test number found in the request */
    104   long partno;       /* part number found in the request */
    105   bool open;      /* keep connection open info, as found in the request */
    106   bool auth_req;  /* authentication required, don't wait for body unless
    107                      there's an Authorization header */
    108   bool auth;      /* Authorization header present in the incoming request */
    109   size_t cl;      /* Content-Length of the incoming request */
    110   bool digest;    /* Authorization digest header found */
    111   bool ntlm;      /* Authorization ntlm header found */
    112   int writedelay; /* if non-zero, delay this number of seconds between
    113                      writes in the response */
    114   int pipe;       /* if non-zero, expect this many requests to do a "piped"
    115                      request/response */
    116   int skip;       /* if non-zero, the server is instructed to not read this
    117                      many bytes from a PUT/POST request. Ie the client sends N
    118                      bytes said in Content-Length, but the server only reads N
    119                      - skip bytes. */
    120   int rcmd;       /* doing a special command, see defines above */
    121   int prot_version;  /* HTTP version * 10 */
    122   bool pipelining;   /* true if request is pipelined */
    123   int callcount;  /* times ProcessRequest() gets called */
    124   bool connmon;   /* monitor the state of the connection, log disconnects */
    125   bool upgrade;   /* test case allows upgrade to http2 */
    126   bool upgrade_request; /* upgrade request found and allowed */
    127   int done_processing;
    128 };
    129 
    130 #define MAX_SOCKETS 1024
    131 
    132 static curl_socket_t all_sockets[MAX_SOCKETS];
    133 static size_t num_sockets = 0;
    134 
    135 static int ProcessRequest(struct httprequest *req);
    136 static void storerequest(const char *reqbuf, size_t totalsize);
    137 
    138 #define DEFAULT_PORT 8999
    139 
    140 #ifndef DEFAULT_LOGFILE
    141 #define DEFAULT_LOGFILE "log/sws.log"
    142 #endif
    143 
    144 const char *serverlogfile = DEFAULT_LOGFILE;
    145 
    146 #define SWSVERSION "curl test suite HTTP server/0.1"
    147 
    148 #define REQUEST_DUMP  "log/server.input"
    149 #define RESPONSE_DUMP "log/server.response"
    150 
    151 /* when told to run as proxy, we store the logs in different files so that
    152    they can co-exist with the same program running as a "server" */
    153 #define REQUEST_PROXY_DUMP  "log/proxy.input"
    154 #define RESPONSE_PROXY_DUMP "log/proxy.response"
    155 
    156 /* very-big-path support */
    157 #define MAXDOCNAMELEN 140000
    158 #define MAXDOCNAMELEN_TXT "139999"
    159 
    160 #define REQUEST_KEYWORD_SIZE 256
    161 #define REQUEST_KEYWORD_SIZE_TXT "255"
    162 
    163 #define CMD_AUTH_REQUIRED "auth_required"
    164 
    165 /* 'idle' means that it will accept the request fine but never respond
    166    any data. Just keep the connection alive. */
    167 #define CMD_IDLE "idle"
    168 
    169 /* 'stream' means to send a never-ending stream of data */
    170 #define CMD_STREAM "stream"
    171 
    172 /* 'connection-monitor' will output when a server/proxy connection gets
    173    disconnected as for some cases it is important that it gets done at the
    174    proper point - like with NTLM */
    175 #define CMD_CONNECTIONMONITOR "connection-monitor"
    176 
    177 /* upgrade to http2 */
    178 #define CMD_UPGRADE "upgrade"
    179 
    180 #define END_OF_HEADERS "\r\n\r\n"
    181 
    182 enum {
    183   DOCNUMBER_NOTHING = -4,
    184   DOCNUMBER_QUIT    = -3,
    185   DOCNUMBER_WERULEZ = -2,
    186   DOCNUMBER_404     = -1
    187 };
    188 
    189 static const char *end_of_headers = END_OF_HEADERS;
    190 
    191 /* sent as reply to a QUIT */
    192 static const char *docquit =
    193 "HTTP/1.1 200 Goodbye" END_OF_HEADERS;
    194 
    195 /* send back this on 404 file not found */
    196 static const char *doc404 = "HTTP/1.1 404 Not Found\r\n"
    197     "Server: " SWSVERSION "\r\n"
    198     "Connection: close\r\n"
    199     "Content-Type: text/html"
    200     END_OF_HEADERS
    201     "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
    202     "<HTML><HEAD>\n"
    203     "<TITLE>404 Not Found</TITLE>\n"
    204     "</HEAD><BODY>\n"
    205     "<H1>Not Found</H1>\n"
    206     "The requested URL was not found on this server.\n"
    207     "<P><HR><ADDRESS>" SWSVERSION "</ADDRESS>\n" "</BODY></HTML>\n";
    208 
    209 /* do-nothing macro replacement for systems which lack siginterrupt() */
    210 
    211 #ifndef HAVE_SIGINTERRUPT
    212 #define siginterrupt(x,y) do {} while(0)
    213 #endif
    214 
    215 /* vars used to keep around previous signal handlers */
    216 
    217 typedef RETSIGTYPE (*SIGHANDLER_T)(int);
    218 
    219 #ifdef SIGHUP
    220 static SIGHANDLER_T old_sighup_handler  = SIG_ERR;
    221 #endif
    222 
    223 #ifdef SIGPIPE
    224 static SIGHANDLER_T old_sigpipe_handler = SIG_ERR;
    225 #endif
    226 
    227 #ifdef SIGALRM
    228 static SIGHANDLER_T old_sigalrm_handler = SIG_ERR;
    229 #endif
    230 
    231 #ifdef SIGINT
    232 static SIGHANDLER_T old_sigint_handler  = SIG_ERR;
    233 #endif
    234 
    235 #ifdef SIGTERM
    236 static SIGHANDLER_T old_sigterm_handler = SIG_ERR;
    237 #endif
    238 
    239 #if defined(SIGBREAK) && defined(WIN32)
    240 static SIGHANDLER_T old_sigbreak_handler = SIG_ERR;
    241 #endif
    242 
    243 /* var which if set indicates that the program should finish execution */
    244 
    245 SIG_ATOMIC_T got_exit_signal = 0;
    246 
    247 /* if next is set indicates the first signal handled in exit_signal_handler */
    248 
    249 static volatile int exit_signal = 0;
    250 
    251 /* signal handler that will be triggered to indicate that the program
    252   should finish its execution in a controlled manner as soon as possible.
    253   The first time this is called it will set got_exit_signal to one and
    254   store in exit_signal the signal that triggered its execution. */
    255 
    256 static RETSIGTYPE exit_signal_handler(int signum)
    257 {
    258   int old_errno = errno;
    259   if(got_exit_signal == 0) {
    260     got_exit_signal = 1;
    261     exit_signal = signum;
    262   }
    263   (void)signal(signum, exit_signal_handler);
    264   errno = old_errno;
    265 }
    266 
    267 static void install_signal_handlers(void)
    268 {
    269 #ifdef SIGHUP
    270   /* ignore SIGHUP signal */
    271   old_sighup_handler = signal(SIGHUP, SIG_IGN);
    272   if(old_sighup_handler == SIG_ERR)
    273     logmsg("cannot install SIGHUP handler: %s", strerror(errno));
    274 #endif
    275 #ifdef SIGPIPE
    276   /* ignore SIGPIPE signal */
    277   old_sigpipe_handler = signal(SIGPIPE, SIG_IGN);
    278   if(old_sigpipe_handler == SIG_ERR)
    279     logmsg("cannot install SIGPIPE handler: %s", strerror(errno));
    280 #endif
    281 #ifdef SIGALRM
    282   /* ignore SIGALRM signal */
    283   old_sigalrm_handler = signal(SIGALRM, SIG_IGN);
    284   if(old_sigalrm_handler == SIG_ERR)
    285     logmsg("cannot install SIGALRM handler: %s", strerror(errno));
    286 #endif
    287 #ifdef SIGINT
    288   /* handle SIGINT signal with our exit_signal_handler */
    289   old_sigint_handler = signal(SIGINT, exit_signal_handler);
    290   if(old_sigint_handler == SIG_ERR)
    291     logmsg("cannot install SIGINT handler: %s", strerror(errno));
    292   else
    293     siginterrupt(SIGINT, 1);
    294 #endif
    295 #ifdef SIGTERM
    296   /* handle SIGTERM signal with our exit_signal_handler */
    297   old_sigterm_handler = signal(SIGTERM, exit_signal_handler);
    298   if(old_sigterm_handler == SIG_ERR)
    299     logmsg("cannot install SIGTERM handler: %s", strerror(errno));
    300   else
    301     siginterrupt(SIGTERM, 1);
    302 #endif
    303 #if defined(SIGBREAK) && defined(WIN32)
    304   /* handle SIGBREAK signal with our exit_signal_handler */
    305   old_sigbreak_handler = signal(SIGBREAK, exit_signal_handler);
    306   if(old_sigbreak_handler == SIG_ERR)
    307     logmsg("cannot install SIGBREAK handler: %s", strerror(errno));
    308   else
    309     siginterrupt(SIGBREAK, 1);
    310 #endif
    311 }
    312 
    313 static void restore_signal_handlers(void)
    314 {
    315 #ifdef SIGHUP
    316   if(SIG_ERR != old_sighup_handler)
    317     (void)signal(SIGHUP, old_sighup_handler);
    318 #endif
    319 #ifdef SIGPIPE
    320   if(SIG_ERR != old_sigpipe_handler)
    321     (void)signal(SIGPIPE, old_sigpipe_handler);
    322 #endif
    323 #ifdef SIGALRM
    324   if(SIG_ERR != old_sigalrm_handler)
    325     (void)signal(SIGALRM, old_sigalrm_handler);
    326 #endif
    327 #ifdef SIGINT
    328   if(SIG_ERR != old_sigint_handler)
    329     (void)signal(SIGINT, old_sigint_handler);
    330 #endif
    331 #ifdef SIGTERM
    332   if(SIG_ERR != old_sigterm_handler)
    333     (void)signal(SIGTERM, old_sigterm_handler);
    334 #endif
    335 #if defined(SIGBREAK) && defined(WIN32)
    336   if(SIG_ERR != old_sigbreak_handler)
    337     (void)signal(SIGBREAK, old_sigbreak_handler);
    338 #endif
    339 }
    340 
    341 /* returns true if the current socket is an IP one */
    342 static bool socket_domain_is_ip(void)
    343 {
    344   switch(socket_domain) {
    345   case AF_INET:
    346 #ifdef ENABLE_IPV6
    347   case AF_INET6:
    348 #endif
    349     return true;
    350   default:
    351   /* case AF_UNIX: */
    352     return false;
    353   }
    354 }
    355 
    356 /* based on the testno, parse the correct server commands */
    357 static int parse_servercmd(struct httprequest *req)
    358 {
    359   FILE *stream;
    360   char *filename;
    361   int error;
    362 
    363   filename = test2file(req->testno);
    364 
    365   stream = fopen(filename, "rb");
    366   if(!stream) {
    367     error = errno;
    368     logmsg("fopen() failed with error: %d %s", error, strerror(error));
    369     logmsg("  [1] Error opening file: %s", filename);
    370     logmsg("  Couldn't open test file %ld", req->testno);
    371     req->open = FALSE; /* closes connection */
    372     return 1; /* done */
    373   }
    374   else {
    375     char *orgcmd = NULL;
    376     char *cmd = NULL;
    377     size_t cmdsize = 0;
    378     int num = 0;
    379 
    380     /* get the custom server control "commands" */
    381     error = getpart(&orgcmd, &cmdsize, "reply", "servercmd", stream);
    382     fclose(stream);
    383     if(error) {
    384       logmsg("getpart() failed with error: %d", error);
    385       req->open = FALSE; /* closes connection */
    386       return 1; /* done */
    387     }
    388 
    389     req->connmon = FALSE;
    390 
    391     cmd = orgcmd;
    392     while(cmd && cmdsize) {
    393       char *check;
    394 
    395       if(!strncmp(CMD_AUTH_REQUIRED, cmd, strlen(CMD_AUTH_REQUIRED))) {
    396         logmsg("instructed to require authorization header");
    397         req->auth_req = TRUE;
    398       }
    399       else if(!strncmp(CMD_IDLE, cmd, strlen(CMD_IDLE))) {
    400         logmsg("instructed to idle");
    401         req->rcmd = RCMD_IDLE;
    402         req->open = TRUE;
    403       }
    404       else if(!strncmp(CMD_STREAM, cmd, strlen(CMD_STREAM))) {
    405         logmsg("instructed to stream");
    406         req->rcmd = RCMD_STREAM;
    407       }
    408       else if(!strncmp(CMD_CONNECTIONMONITOR, cmd,
    409                        strlen(CMD_CONNECTIONMONITOR))) {
    410         logmsg("enabled connection monitoring");
    411         req->connmon = TRUE;
    412       }
    413       else if(!strncmp(CMD_UPGRADE, cmd, strlen(CMD_UPGRADE))) {
    414         logmsg("enabled upgrade to http2");
    415         req->upgrade = TRUE;
    416       }
    417       else if(1 == sscanf(cmd, "pipe: %d", &num)) {
    418         logmsg("instructed to allow a pipe size of %d", num);
    419         if(num < 0)
    420           logmsg("negative pipe size ignored");
    421         else if(num > 0)
    422           req->pipe = num-1; /* decrease by one since we don't count the
    423                                 first request in this number */
    424       }
    425       else if(1 == sscanf(cmd, "skip: %d", &num)) {
    426         logmsg("instructed to skip this number of bytes %d", num);
    427         req->skip = num;
    428       }
    429       else if(1 == sscanf(cmd, "writedelay: %d", &num)) {
    430         logmsg("instructed to delay %d secs between packets", num);
    431         req->writedelay = num;
    432       }
    433       else {
    434         logmsg("Unknown <servercmd> instruction found: %s", cmd);
    435       }
    436       /* try to deal with CRLF or just LF */
    437       check = strchr(cmd, '\r');
    438       if(!check)
    439         check = strchr(cmd, '\n');
    440 
    441       if(check) {
    442         /* get to the letter following the newline */
    443         while((*check == '\r') || (*check == '\n'))
    444           check++;
    445 
    446         if(!*check)
    447           /* if we reached a zero, get out */
    448           break;
    449         cmd = check;
    450       }
    451       else
    452         break;
    453     }
    454     free(orgcmd);
    455   }
    456 
    457   return 0; /* OK! */
    458 }
    459 
    460 static int ProcessRequest(struct httprequest *req)
    461 {
    462   char *line = &req->reqbuf[req->checkindex];
    463   bool chunked = FALSE;
    464   static char request[REQUEST_KEYWORD_SIZE];
    465   static char doc[MAXDOCNAMELEN];
    466   char logbuf[456];
    467   int prot_major, prot_minor;
    468   char *end = strstr(line, end_of_headers);
    469 
    470   req->callcount++;
    471 
    472   logmsg("Process %d bytes request%s", req->offset,
    473          req->callcount > 1?" [CONTINUED]":"");
    474 
    475   /* try to figure out the request characteristics as soon as possible, but
    476      only once! */
    477 
    478   if(use_gopher &&
    479      (req->testno == DOCNUMBER_NOTHING) &&
    480      !strncmp("/verifiedserver", line, 15)) {
    481     logmsg("Are-we-friendly question received");
    482     req->testno = DOCNUMBER_WERULEZ;
    483     return 1; /* done */
    484   }
    485 
    486   else if((req->testno == DOCNUMBER_NOTHING) &&
    487      sscanf(line,
    488             "%" REQUEST_KEYWORD_SIZE_TXT"s %" MAXDOCNAMELEN_TXT "s HTTP/%d.%d",
    489             request,
    490             doc,
    491             &prot_major,
    492             &prot_minor) == 4) {
    493     char *ptr;
    494 
    495     req->prot_version = prot_major*10 + prot_minor;
    496 
    497     /* find the last slash */
    498     ptr = strrchr(doc, '/');
    499 
    500     /* get the number after it */
    501     if(ptr) {
    502       if((strlen(doc) + strlen(request)) < 400)
    503         snprintf(logbuf, sizeof(logbuf), "Got request: %s %s HTTP/%d.%d",
    504                  request, doc, prot_major, prot_minor);
    505       else
    506         snprintf(logbuf, sizeof(logbuf), "Got a *HUGE* request HTTP/%d.%d",
    507                  prot_major, prot_minor);
    508       logmsg("%s", logbuf);
    509 
    510       if(!strncmp("/verifiedserver", ptr, 15)) {
    511         logmsg("Are-we-friendly question received");
    512         req->testno = DOCNUMBER_WERULEZ;
    513         return 1; /* done */
    514       }
    515 
    516       if(!strncmp("/quit", ptr, 5)) {
    517         logmsg("Request-to-quit received");
    518         req->testno = DOCNUMBER_QUIT;
    519         return 1; /* done */
    520       }
    521 
    522       ptr++; /* skip the slash */
    523 
    524       /* skip all non-numericals following the slash */
    525       while(*ptr && !ISDIGIT(*ptr))
    526         ptr++;
    527 
    528       req->testno = strtol(ptr, &ptr, 10);
    529 
    530       if(req->testno > 10000) {
    531         req->partno = req->testno % 10000;
    532         req->testno /= 10000;
    533       }
    534       else
    535         req->partno = 0;
    536 
    537       if(req->testno) {
    538 
    539         snprintf(logbuf, sizeof(logbuf), "Requested test number %ld part %ld",
    540                  req->testno, req->partno);
    541         logmsg("%s", logbuf);
    542 
    543         /* find and parse <servercmd> for this test */
    544         parse_servercmd(req);
    545       }
    546       else
    547         req->testno = DOCNUMBER_NOTHING;
    548 
    549     }
    550 
    551     if(req->testno == DOCNUMBER_NOTHING) {
    552       /* didn't find any in the first scan, try alternative test case
    553          number placements */
    554 
    555       if(sscanf(req->reqbuf, "CONNECT %" MAXDOCNAMELEN_TXT "s HTTP/%d.%d",
    556                 doc, &prot_major, &prot_minor) == 3) {
    557         char *portp = NULL;
    558         unsigned long part = 0;
    559 
    560         snprintf(logbuf, sizeof(logbuf),
    561                  "Received a CONNECT %s HTTP/%d.%d request",
    562                  doc, prot_major, prot_minor);
    563         logmsg("%s", logbuf);
    564 
    565         req->connect_request = TRUE;
    566 
    567         if(req->prot_version == 10)
    568           req->open = FALSE; /* HTTP 1.0 closes connection by default */
    569 
    570         if(doc[0] == '[') {
    571           char *p = &doc[1];
    572           /* scan through the hexgroups and store the value of the last group
    573              in the 'part' variable and use as test case number!! */
    574           while(*p && (ISXDIGIT(*p) || (*p == ':') || (*p == '.'))) {
    575             char *endp;
    576             part = strtoul(p, &endp, 16);
    577             if(ISXDIGIT(*p))
    578               p = endp;
    579             else
    580               p++;
    581           }
    582           if(*p != ']')
    583             logmsg("Invalid CONNECT IPv6 address format");
    584           else if(*(p + 1) != ':')
    585             logmsg("Invalid CONNECT IPv6 port format");
    586           else
    587             portp = p + 1;
    588 
    589           req->testno = part;
    590         }
    591         else
    592           portp = strchr(doc, ':');
    593 
    594         if(portp && (*(portp + 1) != '\0') && ISDIGIT(*(portp + 1))) {
    595           unsigned long ulnum = strtoul(portp + 1, NULL, 10);
    596           if(!ulnum || (ulnum > 65535UL))
    597             logmsg("Invalid CONNECT port received");
    598           else
    599             req->connect_port = curlx_ultous(ulnum);
    600 
    601         }
    602         logmsg("Port number: %d, test case number: %ld",
    603                req->connect_port, req->testno);
    604       }
    605     }
    606 
    607     if(req->testno == DOCNUMBER_NOTHING) {
    608       /* check for a Testno: header with the test case number */
    609       char *testno = strstr(line, "\nTestno: ");
    610       if(testno) {
    611         req->testno = strtol(&testno[9], NULL, 10);
    612         logmsg("Found test number %d in Testno: header!", req->testno);
    613       }
    614     }
    615     if(req->testno == DOCNUMBER_NOTHING) {
    616       /* Still no test case number. Try to get the the number off the last dot
    617          instead, IE we consider the TLD to be the test number. Test 123 can
    618          then be written as "example.com.123". */
    619 
    620       /* find the last dot */
    621       ptr = strrchr(doc, '.');
    622 
    623       /* get the number after it */
    624       if(ptr) {
    625         ptr++; /* skip the dot */
    626 
    627         req->testno = strtol(ptr, &ptr, 10);
    628 
    629         if(req->testno > 10000) {
    630           req->partno = req->testno % 10000;
    631           req->testno /= 10000;
    632 
    633           logmsg("found test %d in requested host name", req->testno);
    634 
    635         }
    636         else
    637           req->partno = 0;
    638 
    639         snprintf(logbuf, sizeof(logbuf),
    640                  "Requested test number %ld part %ld (from host name)",
    641                  req->testno, req->partno);
    642         logmsg("%s", logbuf);
    643 
    644       }
    645 
    646       if(!req->testno) {
    647         logmsg("Did not find test number in PATH");
    648         req->testno = DOCNUMBER_404;
    649       }
    650       else
    651         parse_servercmd(req);
    652     }
    653   }
    654   else if((req->offset >= 3) && (req->testno == DOCNUMBER_NOTHING)) {
    655     logmsg("** Unusual request. Starts with %02x %02x %02x",
    656            line[0], line[1], line[2]);
    657   }
    658 
    659   if(!end) {
    660     /* we don't have a complete request yet! */
    661     logmsg("request not complete yet");
    662     return 0; /* not complete yet */
    663   }
    664   logmsg("- request found to be complete");
    665 
    666   if(use_gopher) {
    667     /* when using gopher we cannot check the request until the entire
    668        thing has been received */
    669     char *ptr;
    670 
    671     /* find the last slash in the line */
    672     ptr = strrchr(line, '/');
    673 
    674     if(ptr) {
    675       ptr++; /* skip the slash */
    676 
    677       /* skip all non-numericals following the slash */
    678       while(*ptr && !ISDIGIT(*ptr))
    679         ptr++;
    680 
    681       req->testno = strtol(ptr, &ptr, 10);
    682 
    683       if(req->testno > 10000) {
    684         req->partno = req->testno % 10000;
    685         req->testno /= 10000;
    686       }
    687       else
    688         req->partno = 0;
    689 
    690       snprintf(logbuf, sizeof(logbuf),
    691                "Requested GOPHER test number %ld part %ld",
    692                req->testno, req->partno);
    693       logmsg("%s", logbuf);
    694     }
    695   }
    696 
    697   if(req->pipe)
    698     /* we do have a full set, advance the checkindex to after the end of the
    699        headers, for the pipelining case mostly */
    700     req->checkindex += (end - line) + strlen(end_of_headers);
    701 
    702   /* **** Persistence ****
    703    *
    704    * If the request is a HTTP/1.0 one, we close the connection unconditionally
    705    * when we're done.
    706    *
    707    * If the request is a HTTP/1.1 one, we MUST check for a "Connection:"
    708    * header that might say "close". If it does, we close a connection when
    709    * this request is processed. Otherwise, we keep the connection alive for X
    710    * seconds.
    711    */
    712 
    713   do {
    714     if(got_exit_signal)
    715       return 1; /* done */
    716 
    717     if((req->cl == 0) && strncasecompare("Content-Length:", line, 15)) {
    718       /* If we don't ignore content-length, we read it and we read the whole
    719          request including the body before we return. If we've been told to
    720          ignore the content-length, we will return as soon as all headers
    721          have been received */
    722       char *endptr;
    723       char *ptr = line + 15;
    724       unsigned long clen = 0;
    725       while(*ptr && ISSPACE(*ptr))
    726         ptr++;
    727       endptr = ptr;
    728       errno = 0;
    729       clen = strtoul(ptr, &endptr, 10);
    730       if((ptr == endptr) || !ISSPACE(*endptr) || (ERANGE == errno)) {
    731         /* this assumes that a zero Content-Length is valid */
    732         logmsg("Found invalid Content-Length: (%s) in the request", ptr);
    733         req->open = FALSE; /* closes connection */
    734         return 1; /* done */
    735       }
    736       req->cl = clen - req->skip;
    737 
    738       logmsg("Found Content-Length: %lu in the request", clen);
    739       if(req->skip)
    740         logmsg("... but will abort after %zu bytes", req->cl);
    741       break;
    742     }
    743     else if(strncasecompare("Transfer-Encoding: chunked", line,
    744                             strlen("Transfer-Encoding: chunked"))) {
    745       /* chunked data coming in */
    746       chunked = TRUE;
    747     }
    748 
    749     if(chunked) {
    750       if(strstr(req->reqbuf, "\r\n0\r\n\r\n"))
    751         /* end of chunks reached */
    752         return 1; /* done */
    753       else
    754         return 0; /* not done */
    755     }
    756 
    757     line = strchr(line, '\n');
    758     if(line)
    759       line++;
    760 
    761   } while(line);
    762 
    763   if(!req->auth && strstr(req->reqbuf, "Authorization:")) {
    764     req->auth = TRUE; /* Authorization: header present! */
    765     if(req->auth_req)
    766       logmsg("Authorization header found, as required");
    767   }
    768 
    769   if(strstr(req->reqbuf, "Authorization: Negotiate")) {
    770     /* Negotiate iterations */
    771     static long prev_testno = -1;
    772     static long prev_partno = -1;
    773     logmsg("Negotiate: prev_testno: %d, prev_partno: %d",
    774             prev_testno, prev_partno);
    775     if(req->testno != prev_testno) {
    776       prev_testno = req->testno;
    777       prev_partno = req->partno;
    778     }
    779     prev_partno += 1;
    780     req->partno = prev_partno;
    781   }
    782   else if(!req->digest && strstr(req->reqbuf, "Authorization: Digest")) {
    783     /* If the client is passing this Digest-header, we set the part number
    784        to 1000. Not only to spice up the complexity of this, but to make
    785        Digest stuff to work in the test suite. */
    786     req->partno += 1000;
    787     req->digest = TRUE; /* header found */
    788     logmsg("Received Digest request, sending back data %ld", req->partno);
    789   }
    790   else if(!req->ntlm &&
    791           strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAD")) {
    792     /* If the client is passing this type-3 NTLM header */
    793     req->partno += 1002;
    794     req->ntlm = TRUE; /* NTLM found */
    795     logmsg("Received NTLM type-3, sending back data %ld", req->partno);
    796     if(req->cl) {
    797       logmsg("  Expecting %zu POSTed bytes", req->cl);
    798     }
    799   }
    800   else if(!req->ntlm &&
    801           strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAB")) {
    802     /* If the client is passing this type-1 NTLM header */
    803     req->partno += 1001;
    804     req->ntlm = TRUE; /* NTLM found */
    805     logmsg("Received NTLM type-1, sending back data %ld", req->partno);
    806   }
    807   else if((req->partno >= 1000) &&
    808           strstr(req->reqbuf, "Authorization: Basic")) {
    809     /* If the client is passing this Basic-header and the part number is
    810        already >=1000, we add 1 to the part number.  This allows simple Basic
    811        authentication negotiation to work in the test suite. */
    812     req->partno += 1;
    813     logmsg("Received Basic request, sending back data %ld", req->partno);
    814   }
    815   if(strstr(req->reqbuf, "Connection: close"))
    816     req->open = FALSE; /* close connection after this request */
    817 
    818   if(!req->pipe &&
    819      req->open &&
    820      req->prot_version >= 11 &&
    821      end &&
    822      req->reqbuf + req->offset > end + strlen(end_of_headers) &&
    823      !req->cl &&
    824      (!strncmp(req->reqbuf, "GET", strlen("GET")) ||
    825       !strncmp(req->reqbuf, "HEAD", strlen("HEAD")))) {
    826     /* If we have a persistent connection, HTTP version >= 1.1
    827        and GET/HEAD request, enable pipelining. */
    828     req->checkindex = (end - req->reqbuf) + strlen(end_of_headers);
    829     req->pipelining = TRUE;
    830   }
    831 
    832   while(req->pipe) {
    833     if(got_exit_signal)
    834       return 1; /* done */
    835     /* scan for more header ends within this chunk */
    836     line = &req->reqbuf[req->checkindex];
    837     end = strstr(line, end_of_headers);
    838     if(!end)
    839       break;
    840     req->checkindex += (end - line) + strlen(end_of_headers);
    841     req->pipe--;
    842   }
    843 
    844   /* If authentication is required and no auth was provided, end now. This
    845      makes the server NOT wait for PUT/POST data and you can then make the
    846      test case send a rejection before any such data has been sent. Test case
    847      154 uses this.*/
    848   if(req->auth_req && !req->auth) {
    849     logmsg("Return early due to auth requested by none provided");
    850     return 1; /* done */
    851   }
    852 
    853   if(req->upgrade && strstr(req->reqbuf, "Upgrade:")) {
    854     /* we allow upgrade and there was one! */
    855     logmsg("Found Upgrade: in request and allows it");
    856     req->upgrade_request = TRUE;
    857   }
    858 
    859   if(req->cl > 0) {
    860     if(req->cl <= req->offset - (end - req->reqbuf) - strlen(end_of_headers))
    861       return 1; /* done */
    862     else
    863       return 0; /* not complete yet */
    864   }
    865 
    866   return 1; /* done */
    867 }
    868 
    869 /* store the entire request in a file */
    870 static void storerequest(const char *reqbuf, size_t totalsize)
    871 {
    872   int res;
    873   int error = 0;
    874   size_t written;
    875   size_t writeleft;
    876   FILE *dump;
    877   const char *dumpfile = is_proxy?REQUEST_PROXY_DUMP:REQUEST_DUMP;
    878 
    879   if(reqbuf == NULL)
    880     return;
    881   if(totalsize == 0)
    882     return;
    883 
    884   do {
    885     dump = fopen(dumpfile, "ab");
    886   } while((dump == NULL) && ((error = errno) == EINTR));
    887   if(dump == NULL) {
    888     logmsg("[2] Error opening file %s error: %d %s",
    889            dumpfile, error, strerror(error));
    890     logmsg("Failed to write request input ");
    891     return;
    892   }
    893 
    894   writeleft = totalsize;
    895   do {
    896     written = fwrite(&reqbuf[totalsize-writeleft],
    897                      1, writeleft, dump);
    898     if(got_exit_signal)
    899       goto storerequest_cleanup;
    900     if(written > 0)
    901       writeleft -= written;
    902   } while((writeleft > 0) && ((error = errno) == EINTR));
    903 
    904   if(writeleft == 0)
    905     logmsg("Wrote request (%zu bytes) input to %s", totalsize, dumpfile);
    906   else if(writeleft > 0) {
    907     logmsg("Error writing file %s error: %d %s",
    908            dumpfile, error, strerror(error));
    909     logmsg("Wrote only (%zu bytes) of (%zu bytes) request input to %s",
    910            totalsize-writeleft, totalsize, dumpfile);
    911   }
    912 
    913 storerequest_cleanup:
    914 
    915   do {
    916     res = fclose(dump);
    917   } while(res && ((error = errno) == EINTR));
    918   if(res)
    919     logmsg("Error closing file %s error: %d %s",
    920            dumpfile, error, strerror(error));
    921 }
    922 
    923 static void init_httprequest(struct httprequest *req)
    924 {
    925   /* Pipelining is already set, so do not initialize it here. Only initialize
    926      checkindex and offset if pipelining is not set, since in a pipeline they
    927      need to be inherited from the previous request. */
    928   if(!req->pipelining) {
    929     req->checkindex = 0;
    930     req->offset = 0;
    931   }
    932   req->testno = DOCNUMBER_NOTHING;
    933   req->partno = 0;
    934   req->connect_request = FALSE;
    935   req->open = TRUE;
    936   req->auth_req = FALSE;
    937   req->auth = FALSE;
    938   req->cl = 0;
    939   req->digest = FALSE;
    940   req->ntlm = FALSE;
    941   req->pipe = 0;
    942   req->skip = 0;
    943   req->writedelay = 0;
    944   req->rcmd = RCMD_NORMALREQ;
    945   req->prot_version = 0;
    946   req->callcount = 0;
    947   req->connect_port = 0;
    948   req->done_processing = 0;
    949   req->upgrade = 0;
    950   req->upgrade_request = 0;
    951 }
    952 
    953 /* returns 1 if the connection should be serviced again immediately, 0 if there
    954    is no data waiting, or < 0 if it should be closed */
    955 static int get_request(curl_socket_t sock, struct httprequest *req)
    956 {
    957   int error;
    958   int fail = 0;
    959   char *reqbuf = req->reqbuf;
    960   ssize_t got = 0;
    961   int overflow = 0;
    962 
    963   char *pipereq = NULL;
    964   size_t pipereq_length = 0;
    965 
    966   if(req->pipelining) {
    967     pipereq = reqbuf + req->checkindex;
    968     pipereq_length = req->offset - req->checkindex;
    969 
    970     /* Now that we've got the pipelining info we can reset the
    971        pipelining-related vars which were skipped in init_httprequest */
    972     req->pipelining = FALSE;
    973     req->checkindex = 0;
    974     req->offset = 0;
    975   }
    976 
    977   if(req->offset >= REQBUFSIZ-1) {
    978     /* buffer is already full; do nothing */
    979     overflow = 1;
    980   }
    981   else {
    982     if(pipereq_length && pipereq) {
    983       memmove(reqbuf, pipereq, pipereq_length);
    984       got = curlx_uztosz(pipereq_length);
    985       pipereq_length = 0;
    986     }
    987     else {
    988       if(req->skip)
    989         /* we are instructed to not read the entire thing, so we make sure to
    990            only read what we're supposed to and NOT read the enire thing the
    991            client wants to send! */
    992         got = sread(sock, reqbuf + req->offset, req->cl);
    993       else
    994         got = sread(sock, reqbuf + req->offset, REQBUFSIZ-1 - req->offset);
    995     }
    996     if(got_exit_signal)
    997       return -1;
    998     if(got == 0) {
    999       logmsg("Connection closed by client");
   1000       fail = 1;
   1001     }
   1002     else if(got < 0) {
   1003       error = SOCKERRNO;
   1004       if(EAGAIN == error || EWOULDBLOCK == error) {
   1005         /* nothing to read at the moment */
   1006         return 0;
   1007       }
   1008       logmsg("recv() returned error: (%d) %s", error, strerror(error));
   1009       fail = 1;
   1010     }
   1011     if(fail) {
   1012       /* dump the request received so far to the external file */
   1013       reqbuf[req->offset] = '\0';
   1014       storerequest(reqbuf, req->offset);
   1015       return -1;
   1016     }
   1017 
   1018     logmsg("Read %zd bytes", got);
   1019 
   1020     req->offset += (size_t)got;
   1021     reqbuf[req->offset] = '\0';
   1022 
   1023     req->done_processing = ProcessRequest(req);
   1024     if(got_exit_signal)
   1025       return -1;
   1026     if(req->done_processing && req->pipe) {
   1027       logmsg("Waiting for another piped request");
   1028       req->done_processing = 0;
   1029       req->pipe--;
   1030     }
   1031   }
   1032 
   1033   if(overflow || (req->offset == REQBUFSIZ-1 && got > 0)) {
   1034     logmsg("Request would overflow buffer, closing connection");
   1035     /* dump request received so far to external file anyway */
   1036     reqbuf[REQBUFSIZ-1] = '\0';
   1037     fail = 1;
   1038   }
   1039   else if(req->offset > REQBUFSIZ-1) {
   1040     logmsg("Request buffer overflow, closing connection");
   1041     /* dump request received so far to external file anyway */
   1042     reqbuf[REQBUFSIZ-1] = '\0';
   1043     fail = 1;
   1044   }
   1045   else
   1046     reqbuf[req->offset] = '\0';
   1047 
   1048   /* at the end of a request dump it to an external file */
   1049   if(fail || req->done_processing)
   1050     storerequest(reqbuf, req->pipelining ? req->checkindex : req->offset);
   1051   if(got_exit_signal)
   1052     return -1;
   1053 
   1054   return fail ? -1 : 1;
   1055 }
   1056 
   1057 /* returns -1 on failure */
   1058 static int send_doc(curl_socket_t sock, struct httprequest *req)
   1059 {
   1060   ssize_t written;
   1061   size_t count;
   1062   const char *buffer;
   1063   char *ptr = NULL;
   1064   FILE *stream;
   1065   char *cmd = NULL;
   1066   size_t cmdsize = 0;
   1067   FILE *dump;
   1068   bool persistant = TRUE;
   1069   bool sendfailure = FALSE;
   1070   size_t responsesize;
   1071   int error = 0;
   1072   int res;
   1073   const char *responsedump = is_proxy?RESPONSE_PROXY_DUMP:RESPONSE_DUMP;
   1074   static char weare[256];
   1075 
   1076   switch(req->rcmd) {
   1077   default:
   1078   case RCMD_NORMALREQ:
   1079     break; /* continue with business as usual */
   1080   case RCMD_STREAM:
   1081 #define STREAMTHIS "a string to stream 01234567890\n"
   1082     count = strlen(STREAMTHIS);
   1083     for(;;) {
   1084       written = swrite(sock, STREAMTHIS, count);
   1085       if(got_exit_signal)
   1086         return -1;
   1087       if(written != (ssize_t)count) {
   1088         logmsg("Stopped streaming");
   1089         break;
   1090       }
   1091     }
   1092     return -1;
   1093   case RCMD_IDLE:
   1094     /* Do nothing. Sit idle. Pretend it rains. */
   1095     return 0;
   1096   }
   1097 
   1098   req->open = FALSE;
   1099 
   1100   if(req->testno < 0) {
   1101     size_t msglen;
   1102     char msgbuf[64];
   1103 
   1104     switch(req->testno) {
   1105     case DOCNUMBER_QUIT:
   1106       logmsg("Replying to QUIT");
   1107       buffer = docquit;
   1108       break;
   1109     case DOCNUMBER_WERULEZ:
   1110       /* we got a "friends?" question, reply back that we sure are */
   1111       logmsg("Identifying ourselves as friends");
   1112       snprintf(msgbuf, sizeof(msgbuf), "WE ROOLZ: %ld\r\n", (long)getpid());
   1113       msglen = strlen(msgbuf);
   1114       if(use_gopher)
   1115         snprintf(weare, sizeof(weare), "%s", msgbuf);
   1116       else
   1117         snprintf(weare, sizeof(weare),
   1118                  "HTTP/1.1 200 OK\r\nContent-Length: %zu\r\n\r\n%s",
   1119                  msglen, msgbuf);
   1120       buffer = weare;
   1121       break;
   1122     case DOCNUMBER_404:
   1123     default:
   1124       logmsg("Replying to with a 404");
   1125       buffer = doc404;
   1126       break;
   1127     }
   1128 
   1129     count = strlen(buffer);
   1130   }
   1131   else {
   1132     char partbuf[80];
   1133     char *filename = test2file(req->testno);
   1134 
   1135     /* select the <data> tag for "normal" requests and the <connect> one
   1136        for CONNECT requests (within the <reply> section) */
   1137     const char *section = req->connect_request?"connect":"data";
   1138 
   1139     if(req->partno)
   1140       snprintf(partbuf, sizeof(partbuf), "%s%ld", section, req->partno);
   1141     else
   1142       snprintf(partbuf, sizeof(partbuf), "%s", section);
   1143 
   1144     logmsg("Send response test%ld section <%s>", req->testno, partbuf);
   1145 
   1146     stream = fopen(filename, "rb");
   1147     if(!stream) {
   1148       error = errno;
   1149       logmsg("fopen() failed with error: %d %s", error, strerror(error));
   1150       logmsg("  [3] Error opening file: %s", filename);
   1151       return 0;
   1152     }
   1153     else {
   1154       error = getpart(&ptr, &count, "reply", partbuf, stream);
   1155       fclose(stream);
   1156       if(error) {
   1157         logmsg("getpart() failed with error: %d", error);
   1158         return 0;
   1159       }
   1160       buffer = ptr;
   1161     }
   1162 
   1163     if(got_exit_signal) {
   1164       free(ptr);
   1165       return -1;
   1166     }
   1167 
   1168     /* re-open the same file again */
   1169     stream = fopen(filename, "rb");
   1170     if(!stream) {
   1171       error = errno;
   1172       logmsg("fopen() failed with error: %d %s", error, strerror(error));
   1173       logmsg("  [4] Error opening file: %s", filename);
   1174       free(ptr);
   1175       return 0;
   1176     }
   1177     else {
   1178       /* get the custom server control "commands" */
   1179       error = getpart(&cmd, &cmdsize, "reply", "postcmd", stream);
   1180       fclose(stream);
   1181       if(error) {
   1182         logmsg("getpart() failed with error: %d", error);
   1183         free(ptr);
   1184         return 0;
   1185       }
   1186     }
   1187   }
   1188 
   1189   if(got_exit_signal) {
   1190     free(ptr);
   1191     free(cmd);
   1192     return -1;
   1193   }
   1194 
   1195   /* If the word 'swsclose' is present anywhere in the reply chunk, the
   1196      connection will be closed after the data has been sent to the requesting
   1197      client... */
   1198   if(strstr(buffer, "swsclose") || !count) {
   1199     persistant = FALSE;
   1200     logmsg("connection close instruction \"swsclose\" found in response");
   1201   }
   1202   if(strstr(buffer, "swsbounce")) {
   1203     prevbounce = TRUE;
   1204     logmsg("enable \"swsbounce\" in the next request");
   1205   }
   1206   else
   1207     prevbounce = FALSE;
   1208 
   1209   dump = fopen(responsedump, "ab");
   1210   if(!dump) {
   1211     error = errno;
   1212     logmsg("fopen() failed with error: %d %s", error, strerror(error));
   1213     logmsg("  [5] Error opening file: %s", responsedump);
   1214     free(ptr);
   1215     free(cmd);
   1216     return -1;
   1217   }
   1218 
   1219   responsesize = count;
   1220   do {
   1221     /* Ok, we send no more than N bytes at a time, just to make sure that
   1222        larger chunks are split up so that the client will need to do multiple
   1223        recv() calls to get it and thus we exercise that code better */
   1224     size_t num = count;
   1225     if(num > 20)
   1226       num = 20;
   1227 
   1228     retry:
   1229     written = swrite(sock, buffer, num);
   1230     if(written < 0) {
   1231       if((EWOULDBLOCK == SOCKERRNO) || (EAGAIN == SOCKERRNO)) {
   1232         wait_ms(10);
   1233         goto retry;
   1234       }
   1235       sendfailure = TRUE;
   1236       break;
   1237     }
   1238 
   1239     /* write to file as well */
   1240     fwrite(buffer, 1, (size_t)written, dump);
   1241 
   1242     count -= written;
   1243     buffer += written;
   1244 
   1245     if(req->writedelay) {
   1246       int quarters = req->writedelay * 4;
   1247       logmsg("Pausing %d seconds", req->writedelay);
   1248       while((quarters > 0) && !got_exit_signal) {
   1249         quarters--;
   1250         wait_ms(250);
   1251       }
   1252     }
   1253   } while((count > 0) && !got_exit_signal);
   1254 
   1255   do {
   1256     res = fclose(dump);
   1257   } while(res && ((error = errno) == EINTR));
   1258   if(res)
   1259     logmsg("Error closing file %s error: %d %s",
   1260            responsedump, error, strerror(error));
   1261 
   1262   if(got_exit_signal) {
   1263     free(ptr);
   1264     free(cmd);
   1265     return -1;
   1266   }
   1267 
   1268   if(sendfailure) {
   1269     logmsg("Sending response failed. Only (%zu bytes) of (%zu bytes) "
   1270            "were sent",
   1271            responsesize-count, responsesize);
   1272     free(ptr);
   1273     free(cmd);
   1274     return -1;
   1275   }
   1276 
   1277   logmsg("Response sent (%zu bytes) and written to %s",
   1278          responsesize, responsedump);
   1279   free(ptr);
   1280 
   1281   if(cmdsize > 0) {
   1282     char command[32];
   1283     int quarters;
   1284     int num;
   1285     ptr = cmd;
   1286     do {
   1287       if(2 == sscanf(ptr, "%31s %d", command, &num)) {
   1288         if(!strcmp("wait", command)) {
   1289           logmsg("Told to sleep for %d seconds", num);
   1290           quarters = num * 4;
   1291           while((quarters > 0) && !got_exit_signal) {
   1292             quarters--;
   1293             res = wait_ms(250);
   1294             if(res) {
   1295               /* should not happen */
   1296               error = errno;
   1297               logmsg("wait_ms() failed with error: (%d) %s",
   1298                      error, strerror(error));
   1299               break;
   1300             }
   1301           }
   1302           if(!quarters)
   1303             logmsg("Continuing after sleeping %d seconds", num);
   1304         }
   1305         else
   1306           logmsg("Unknown command in reply command section");
   1307       }
   1308       ptr = strchr(ptr, '\n');
   1309       if(ptr)
   1310         ptr++;
   1311       else
   1312         ptr = NULL;
   1313     } while(ptr && *ptr);
   1314   }
   1315   free(cmd);
   1316   req->open = use_gopher?FALSE:persistant;
   1317 
   1318   prevtestno = req->testno;
   1319   prevpartno = req->partno;
   1320 
   1321   return 0;
   1322 }
   1323 
   1324 static curl_socket_t connect_to(const char *ipaddr, unsigned short port)
   1325 {
   1326   srvr_sockaddr_union_t serveraddr;
   1327   curl_socket_t serverfd;
   1328   int error;
   1329   int rc = 0;
   1330   const char *op_br = "";
   1331   const char *cl_br = "";
   1332 
   1333 #ifdef ENABLE_IPV6
   1334   if(socket_domain == AF_INET6) {
   1335     op_br = "[";
   1336     cl_br = "]";
   1337   }
   1338 #endif
   1339 
   1340   if(!ipaddr)
   1341     return CURL_SOCKET_BAD;
   1342 
   1343   logmsg("about to connect to %s%s%s:%hu",
   1344          op_br, ipaddr, cl_br, port);
   1345 
   1346 
   1347   serverfd = socket(socket_domain, SOCK_STREAM, 0);
   1348   if(CURL_SOCKET_BAD == serverfd) {
   1349     error = SOCKERRNO;
   1350     logmsg("Error creating socket for server conection: (%d) %s",
   1351            error, strerror(error));
   1352     return CURL_SOCKET_BAD;
   1353   }
   1354 
   1355 #ifdef TCP_NODELAY
   1356   if(socket_domain_is_ip()) {
   1357     /* Disable the Nagle algorithm */
   1358     curl_socklen_t flag = 1;
   1359     if(0 != setsockopt(serverfd, IPPROTO_TCP, TCP_NODELAY,
   1360                        (void *)&flag, sizeof(flag)))
   1361       logmsg("====> TCP_NODELAY for server conection failed");
   1362   }
   1363 #endif
   1364 
   1365   switch(socket_domain) {
   1366   case AF_INET:
   1367     memset(&serveraddr.sa4, 0, sizeof(serveraddr.sa4));
   1368     serveraddr.sa4.sin_family = AF_INET;
   1369     serveraddr.sa4.sin_port = htons(port);
   1370     if(Curl_inet_pton(AF_INET, ipaddr, &serveraddr.sa4.sin_addr) < 1) {
   1371       logmsg("Error inet_pton failed AF_INET conversion of '%s'", ipaddr);
   1372       sclose(serverfd);
   1373       return CURL_SOCKET_BAD;
   1374     }
   1375 
   1376     rc = connect(serverfd, &serveraddr.sa, sizeof(serveraddr.sa4));
   1377     break;
   1378 #ifdef ENABLE_IPV6
   1379   case AF_INET6:
   1380     memset(&serveraddr.sa6, 0, sizeof(serveraddr.sa6));
   1381     serveraddr.sa6.sin6_family = AF_INET6;
   1382     serveraddr.sa6.sin6_port = htons(port);
   1383     if(Curl_inet_pton(AF_INET6, ipaddr, &serveraddr.sa6.sin6_addr) < 1) {
   1384       logmsg("Error inet_pton failed AF_INET6 conversion of '%s'", ipaddr);
   1385       sclose(serverfd);
   1386       return CURL_SOCKET_BAD;
   1387     }
   1388 
   1389     rc = connect(serverfd, &serveraddr.sa, sizeof(serveraddr.sa6));
   1390     break;
   1391 #endif /* ENABLE_IPV6 */
   1392 #ifdef USE_UNIX_SOCKETS
   1393   case AF_UNIX:
   1394     logmsg("Proxying through Unix socket is not (yet?) supported.");
   1395     return CURL_SOCKET_BAD;
   1396 #endif /* USE_UNIX_SOCKETS */
   1397   }
   1398 
   1399   if(got_exit_signal) {
   1400     sclose(serverfd);
   1401     return CURL_SOCKET_BAD;
   1402   }
   1403 
   1404   if(rc) {
   1405     error = SOCKERRNO;
   1406     logmsg("Error connecting to server port %hu: (%d) %s",
   1407            port, error, strerror(error));
   1408     sclose(serverfd);
   1409     return CURL_SOCKET_BAD;
   1410   }
   1411 
   1412   logmsg("connected fine to %s%s%s:%hu, now tunnel",
   1413          op_br, ipaddr, cl_br, port);
   1414 
   1415   return serverfd;
   1416 }
   1417 
   1418 /*
   1419  * A CONNECT has been received, a CONNECT response has been sent.
   1420  *
   1421  * This function needs to connect to the server, and then pass data between
   1422  * the client and the server back and forth until the connection is closed by
   1423  * either end.
   1424  *
   1425  * When doing FTP through a CONNECT proxy, we expect that the data connection
   1426  * will be setup while the first connect is still being kept up. Therefor we
   1427  * must accept a new connection and deal with it appropriately.
   1428  */
   1429 
   1430 #define data_or_ctrl(x) ((x)?"DATA":"CTRL")
   1431 
   1432 #define CTRL  0
   1433 #define DATA  1
   1434 
   1435 static void http_connect(curl_socket_t *infdp,
   1436                          curl_socket_t rootfd,
   1437                          const char *ipaddr,
   1438                          unsigned short ipport)
   1439 {
   1440   curl_socket_t serverfd[2] = {CURL_SOCKET_BAD, CURL_SOCKET_BAD};
   1441   curl_socket_t clientfd[2] = {CURL_SOCKET_BAD, CURL_SOCKET_BAD};
   1442   ssize_t toc[2] = {0, 0}; /* number of bytes to client */
   1443   ssize_t tos[2] = {0, 0}; /* number of bytes to server */
   1444   char readclient[2][256];
   1445   char readserver[2][256];
   1446   bool poll_client_rd[2] = { TRUE, TRUE };
   1447   bool poll_server_rd[2] = { TRUE, TRUE };
   1448   bool poll_client_wr[2] = { TRUE, TRUE };
   1449   bool poll_server_wr[2] = { TRUE, TRUE };
   1450   bool primary = FALSE;
   1451   bool secondary = FALSE;
   1452   int max_tunnel_idx; /* CTRL or DATA */
   1453   int loop;
   1454   int i;
   1455   int timeout_count = 0;
   1456 
   1457   /* primary tunnel client endpoint already connected */
   1458   clientfd[CTRL] = *infdp;
   1459 
   1460   /* Sleep here to make sure the client reads CONNECT response's
   1461      'end of headers' separate from the server data that follows.
   1462      This is done to prevent triggering libcurl known bug #39. */
   1463   for(loop = 2; (loop > 0) && !got_exit_signal; loop--)
   1464     wait_ms(250);
   1465   if(got_exit_signal)
   1466     goto http_connect_cleanup;
   1467 
   1468   serverfd[CTRL] = connect_to(ipaddr, ipport);
   1469   if(serverfd[CTRL] == CURL_SOCKET_BAD)
   1470     goto http_connect_cleanup;
   1471 
   1472   /* Primary tunnel socket endpoints are now connected. Tunnel data back and
   1473      forth over the primary tunnel until client or server breaks the primary
   1474      tunnel, simultaneously allowing establishment, operation and teardown of
   1475      a secondary tunnel that may be used for passive FTP data connection. */
   1476 
   1477   max_tunnel_idx = CTRL;
   1478   primary = TRUE;
   1479 
   1480   while(!got_exit_signal) {
   1481 
   1482     fd_set input;
   1483     fd_set output;
   1484     struct timeval timeout = {1, 0}; /* 1000 ms */
   1485     ssize_t rc;
   1486     curl_socket_t maxfd = (curl_socket_t)-1;
   1487 
   1488     FD_ZERO(&input);
   1489     FD_ZERO(&output);
   1490 
   1491     if((clientfd[DATA] == CURL_SOCKET_BAD) &&
   1492        (serverfd[DATA] == CURL_SOCKET_BAD) &&
   1493        poll_client_rd[CTRL] && poll_client_wr[CTRL] &&
   1494        poll_server_rd[CTRL] && poll_server_wr[CTRL]) {
   1495       /* listener socket is monitored to allow client to establish
   1496          secondary tunnel only when this tunnel is not established
   1497          and primary one is fully operational */
   1498       FD_SET(rootfd, &input);
   1499       maxfd = rootfd;
   1500     }
   1501 
   1502     /* set tunnel sockets to wait for */
   1503     for(i = 0; i <= max_tunnel_idx; i++) {
   1504       /* client side socket monitoring */
   1505       if(clientfd[i] != CURL_SOCKET_BAD) {
   1506         if(poll_client_rd[i]) {
   1507           /* unless told not to do so, monitor readability */
   1508           FD_SET(clientfd[i], &input);
   1509           if(clientfd[i] > maxfd)
   1510             maxfd = clientfd[i];
   1511         }
   1512         if(poll_client_wr[i] && toc[i]) {
   1513           /* unless told not to do so, monitor writability
   1514              if there is data ready to be sent to client */
   1515           FD_SET(clientfd[i], &output);
   1516           if(clientfd[i] > maxfd)
   1517             maxfd = clientfd[i];
   1518         }
   1519       }
   1520       /* server side socket monitoring */
   1521       if(serverfd[i] != CURL_SOCKET_BAD) {
   1522         if(poll_server_rd[i]) {
   1523           /* unless told not to do so, monitor readability */
   1524           FD_SET(serverfd[i], &input);
   1525           if(serverfd[i] > maxfd)
   1526             maxfd = serverfd[i];
   1527         }
   1528         if(poll_server_wr[i] && tos[i]) {
   1529           /* unless told not to do so, monitor writability
   1530              if there is data ready to be sent to server */
   1531           FD_SET(serverfd[i], &output);
   1532           if(serverfd[i] > maxfd)
   1533             maxfd = serverfd[i];
   1534         }
   1535       }
   1536     }
   1537     if(got_exit_signal)
   1538       break;
   1539 
   1540     rc = select((int)maxfd + 1, &input, &output, NULL, &timeout);
   1541 
   1542     if(rc > 0) {
   1543       /* socket action */
   1544       bool tcp_fin_wr;
   1545       timeout_count = 0;
   1546 
   1547       if(got_exit_signal)
   1548         break;
   1549 
   1550       tcp_fin_wr = FALSE;
   1551 
   1552       /* ---------------------------------------------------------- */
   1553 
   1554       /* passive mode FTP may establish a secondary tunnel */
   1555       if((clientfd[DATA] == CURL_SOCKET_BAD) &&
   1556          (serverfd[DATA] == CURL_SOCKET_BAD) && FD_ISSET(rootfd, &input)) {
   1557         /* a new connection on listener socket (most likely from client) */
   1558         curl_socket_t datafd = accept(rootfd, NULL, NULL);
   1559         if(datafd != CURL_SOCKET_BAD) {
   1560           struct httprequest req2;
   1561           int err = 0;
   1562           memset(&req2, 0, sizeof(req2));
   1563           logmsg("====> Client connect DATA");
   1564 #ifdef TCP_NODELAY
   1565           if(socket_domain_is_ip()) {
   1566             /* Disable the Nagle algorithm */
   1567             curl_socklen_t flag = 1;
   1568             if(0 != setsockopt(datafd, IPPROTO_TCP, TCP_NODELAY,
   1569                                (void *)&flag, sizeof(flag)))
   1570               logmsg("====> TCP_NODELAY for client DATA conection failed");
   1571           }
   1572 #endif
   1573           req2.pipelining = FALSE;
   1574           init_httprequest(&req2);
   1575           while(!req2.done_processing) {
   1576             err = get_request(datafd, &req2);
   1577             if(err < 0) {
   1578               /* this socket must be closed, done or not */
   1579               break;
   1580             }
   1581           }
   1582 
   1583           /* skip this and close the socket if err < 0 */
   1584           if(err >= 0) {
   1585             err = send_doc(datafd, &req2);
   1586             if(!err && req2.connect_request) {
   1587               /* sleep to prevent triggering libcurl known bug #39. */
   1588               for(loop = 2; (loop > 0) && !got_exit_signal; loop--)
   1589                 wait_ms(250);
   1590               if(!got_exit_signal) {
   1591                 /* connect to the server */
   1592                 serverfd[DATA] = connect_to(ipaddr, req2.connect_port);
   1593                 if(serverfd[DATA] != CURL_SOCKET_BAD) {
   1594                   /* secondary tunnel established, now we have two
   1595                      connections */
   1596                   poll_client_rd[DATA] = TRUE;
   1597                   poll_client_wr[DATA] = TRUE;
   1598                   poll_server_rd[DATA] = TRUE;
   1599                   poll_server_wr[DATA] = TRUE;
   1600                   max_tunnel_idx = DATA;
   1601                   secondary = TRUE;
   1602                   toc[DATA] = 0;
   1603                   tos[DATA] = 0;
   1604                   clientfd[DATA] = datafd;
   1605                   datafd = CURL_SOCKET_BAD;
   1606                 }
   1607               }
   1608             }
   1609           }
   1610           if(datafd != CURL_SOCKET_BAD) {
   1611             /* secondary tunnel not established */
   1612             shutdown(datafd, SHUT_RDWR);
   1613             sclose(datafd);
   1614           }
   1615         }
   1616         if(got_exit_signal)
   1617           break;
   1618       }
   1619 
   1620       /* ---------------------------------------------------------- */
   1621 
   1622       /* react to tunnel endpoint readable/writable notifications */
   1623       for(i = 0; i <= max_tunnel_idx; i++) {
   1624         size_t len;
   1625         if(clientfd[i] != CURL_SOCKET_BAD) {
   1626           len = sizeof(readclient[i]) - tos[i];
   1627           if(len && FD_ISSET(clientfd[i], &input)) {
   1628             /* read from client */
   1629             rc = sread(clientfd[i], &readclient[i][tos[i]], len);
   1630             if(rc <= 0) {
   1631               logmsg("[%s] got %zd, STOP READING client", data_or_ctrl(i), rc);
   1632               shutdown(clientfd[i], SHUT_RD);
   1633               poll_client_rd[i] = FALSE;
   1634             }
   1635             else {
   1636               logmsg("[%s] READ %zd bytes from client", data_or_ctrl(i), rc);
   1637               logmsg("[%s] READ \"%s\"", data_or_ctrl(i),
   1638                      data_to_hex(&readclient[i][tos[i]], rc));
   1639               tos[i] += rc;
   1640             }
   1641           }
   1642         }
   1643         if(serverfd[i] != CURL_SOCKET_BAD) {
   1644           len = sizeof(readserver[i])-toc[i];
   1645           if(len && FD_ISSET(serverfd[i], &input)) {
   1646             /* read from server */
   1647             rc = sread(serverfd[i], &readserver[i][toc[i]], len);
   1648             if(rc <= 0) {
   1649               logmsg("[%s] got %zd, STOP READING server", data_or_ctrl(i), rc);
   1650               shutdown(serverfd[i], SHUT_RD);
   1651               poll_server_rd[i] = FALSE;
   1652             }
   1653             else {
   1654               logmsg("[%s] READ %zd bytes from server", data_or_ctrl(i), rc);
   1655               logmsg("[%s] READ \"%s\"", data_or_ctrl(i),
   1656                      data_to_hex(&readserver[i][toc[i]], rc));
   1657               toc[i] += rc;
   1658             }
   1659           }
   1660         }
   1661         if(clientfd[i] != CURL_SOCKET_BAD) {
   1662           if(toc[i] && FD_ISSET(clientfd[i], &output)) {
   1663             /* write to client */
   1664             rc = swrite(clientfd[i], readserver[i], toc[i]);
   1665             if(rc <= 0) {
   1666               logmsg("[%s] got %zd, STOP WRITING client", data_or_ctrl(i), rc);
   1667               shutdown(clientfd[i], SHUT_WR);
   1668               poll_client_wr[i] = FALSE;
   1669               tcp_fin_wr = TRUE;
   1670             }
   1671             else {
   1672               logmsg("[%s] SENT %zd bytes to client", data_or_ctrl(i), rc);
   1673               logmsg("[%s] SENT \"%s\"", data_or_ctrl(i),
   1674                      data_to_hex(readserver[i], rc));
   1675               if(toc[i] - rc)
   1676                 memmove(&readserver[i][0], &readserver[i][rc], toc[i]-rc);
   1677               toc[i] -= rc;
   1678             }
   1679           }
   1680         }
   1681         if(serverfd[i] != CURL_SOCKET_BAD) {
   1682           if(tos[i] && FD_ISSET(serverfd[i], &output)) {
   1683             /* write to server */
   1684             rc = swrite(serverfd[i], readclient[i], tos[i]);
   1685             if(rc <= 0) {
   1686               logmsg("[%s] got %zd, STOP WRITING server", data_or_ctrl(i), rc);
   1687               shutdown(serverfd[i], SHUT_WR);
   1688               poll_server_wr[i] = FALSE;
   1689               tcp_fin_wr = TRUE;
   1690             }
   1691             else {
   1692               logmsg("[%s] SENT %zd bytes to server", data_or_ctrl(i), rc);
   1693               logmsg("[%s] SENT \"%s\"", data_or_ctrl(i),
   1694                      data_to_hex(readclient[i], rc));
   1695               if(tos[i] - rc)
   1696                 memmove(&readclient[i][0], &readclient[i][rc], tos[i]-rc);
   1697               tos[i] -= rc;
   1698             }
   1699           }
   1700         }
   1701       }
   1702       if(got_exit_signal)
   1703         break;
   1704 
   1705       /* ---------------------------------------------------------- */
   1706 
   1707       /* endpoint read/write disabling, endpoint closing and tunnel teardown */
   1708       for(i = 0; i <= max_tunnel_idx; i++) {
   1709         for(loop = 2; loop > 0; loop--) {
   1710           /* loop twice to satisfy condition interdependencies without
   1711              having to await select timeout or another socket event */
   1712           if(clientfd[i] != CURL_SOCKET_BAD) {
   1713             if(poll_client_rd[i] && !poll_server_wr[i]) {
   1714               logmsg("[%s] DISABLED READING client", data_or_ctrl(i));
   1715               shutdown(clientfd[i], SHUT_RD);
   1716               poll_client_rd[i] = FALSE;
   1717             }
   1718             if(poll_client_wr[i] && !poll_server_rd[i] && !toc[i]) {
   1719               logmsg("[%s] DISABLED WRITING client", data_or_ctrl(i));
   1720               shutdown(clientfd[i], SHUT_WR);
   1721               poll_client_wr[i] = FALSE;
   1722               tcp_fin_wr = TRUE;
   1723             }
   1724           }
   1725           if(serverfd[i] != CURL_SOCKET_BAD) {
   1726             if(poll_server_rd[i] && !poll_client_wr[i]) {
   1727               logmsg("[%s] DISABLED READING server", data_or_ctrl(i));
   1728               shutdown(serverfd[i], SHUT_RD);
   1729               poll_server_rd[i] = FALSE;
   1730             }
   1731             if(poll_server_wr[i] && !poll_client_rd[i] && !tos[i]) {
   1732               logmsg("[%s] DISABLED WRITING server", data_or_ctrl(i));
   1733               shutdown(serverfd[i], SHUT_WR);
   1734               poll_server_wr[i] = FALSE;
   1735               tcp_fin_wr = TRUE;
   1736             }
   1737           }
   1738         }
   1739       }
   1740 
   1741       if(tcp_fin_wr)
   1742         /* allow kernel to place FIN bit packet on the wire */
   1743         wait_ms(250);
   1744 
   1745       /* socket clearing */
   1746       for(i = 0; i <= max_tunnel_idx; i++) {
   1747         for(loop = 2; loop > 0; loop--) {
   1748           if(clientfd[i] != CURL_SOCKET_BAD) {
   1749             if(!poll_client_wr[i] && !poll_client_rd[i]) {
   1750               logmsg("[%s] CLOSING client socket", data_or_ctrl(i));
   1751               sclose(clientfd[i]);
   1752               clientfd[i] = CURL_SOCKET_BAD;
   1753               if(serverfd[i] == CURL_SOCKET_BAD) {
   1754                 logmsg("[%s] ENDING", data_or_ctrl(i));
   1755                 if(i == DATA)
   1756                   secondary = FALSE;
   1757                 else
   1758                   primary = FALSE;
   1759               }
   1760             }
   1761           }
   1762           if(serverfd[i] != CURL_SOCKET_BAD) {
   1763             if(!poll_server_wr[i] && !poll_server_rd[i]) {
   1764               logmsg("[%s] CLOSING server socket", data_or_ctrl(i));
   1765               sclose(serverfd[i]);
   1766               serverfd[i] = CURL_SOCKET_BAD;
   1767               if(clientfd[i] == CURL_SOCKET_BAD) {
   1768                 logmsg("[%s] ENDING", data_or_ctrl(i));
   1769                 if(i == DATA)
   1770                   secondary = FALSE;
   1771                 else
   1772                   primary = FALSE;
   1773               }
   1774             }
   1775           }
   1776         }
   1777       }
   1778 
   1779       /* ---------------------------------------------------------- */
   1780 
   1781       max_tunnel_idx = secondary ? DATA : CTRL;
   1782 
   1783       if(!primary)
   1784         /* exit loop upon primary tunnel teardown */
   1785         break;
   1786 
   1787     } /* (rc > 0) */
   1788     else {
   1789       timeout_count++;
   1790       if(timeout_count > 5) {
   1791         logmsg("CONNECT proxy timeout after %d idle seconds!", timeout_count);
   1792         break;
   1793       }
   1794     }
   1795   }
   1796 
   1797 http_connect_cleanup:
   1798 
   1799   for(i = DATA; i >= CTRL; i--) {
   1800     if(serverfd[i] != CURL_SOCKET_BAD) {
   1801       logmsg("[%s] CLOSING server socket (cleanup)", data_or_ctrl(i));
   1802       shutdown(serverfd[i], SHUT_RDWR);
   1803       sclose(serverfd[i]);
   1804     }
   1805     if(clientfd[i] != CURL_SOCKET_BAD) {
   1806       logmsg("[%s] CLOSING client socket (cleanup)", data_or_ctrl(i));
   1807       shutdown(clientfd[i], SHUT_RDWR);
   1808       sclose(clientfd[i]);
   1809     }
   1810     if((serverfd[i] != CURL_SOCKET_BAD) ||
   1811        (clientfd[i] != CURL_SOCKET_BAD)) {
   1812       logmsg("[%s] ABORTING", data_or_ctrl(i));
   1813     }
   1814   }
   1815 
   1816   *infdp = CURL_SOCKET_BAD;
   1817 }
   1818 
   1819 static void http2(struct httprequest *req)
   1820 {
   1821   (void)req;
   1822   logmsg("switched to http2");
   1823   /* left to implement */
   1824 }
   1825 
   1826 
   1827 /* returns a socket handle, or 0 if there are no more waiting sockets,
   1828    or < 0 if there was an error */
   1829 static curl_socket_t accept_connection(curl_socket_t sock)
   1830 {
   1831   curl_socket_t msgsock = CURL_SOCKET_BAD;
   1832   int error;
   1833   int flag = 1;
   1834 
   1835   if(MAX_SOCKETS == num_sockets) {
   1836     logmsg("Too many open sockets!");
   1837     return CURL_SOCKET_BAD;
   1838   }
   1839 
   1840   msgsock = accept(sock, NULL, NULL);
   1841 
   1842   if(got_exit_signal) {
   1843     if(CURL_SOCKET_BAD != msgsock)
   1844       sclose(msgsock);
   1845     return CURL_SOCKET_BAD;
   1846   }
   1847 
   1848   if(CURL_SOCKET_BAD == msgsock) {
   1849     error = SOCKERRNO;
   1850     if(EAGAIN == error || EWOULDBLOCK == error) {
   1851       /* nothing to accept */
   1852       return 0;
   1853     }
   1854     logmsg("MAJOR ERROR: accept() failed with error: (%d) %s",
   1855            error, strerror(error));
   1856     return CURL_SOCKET_BAD;
   1857   }
   1858 
   1859   if(0 != curlx_nonblock(msgsock, TRUE)) {
   1860     error = SOCKERRNO;
   1861     logmsg("curlx_nonblock failed with error: (%d) %s",
   1862            error, strerror(error));
   1863     sclose(msgsock);
   1864     return CURL_SOCKET_BAD;
   1865   }
   1866 
   1867   if(0 != setsockopt(msgsock, SOL_SOCKET, SO_KEEPALIVE,
   1868                      (void *)&flag, sizeof(flag))) {
   1869     error = SOCKERRNO;
   1870     logmsg("setsockopt(SO_KEEPALIVE) failed with error: (%d) %s",
   1871            error, strerror(error));
   1872     sclose(msgsock);
   1873     return CURL_SOCKET_BAD;
   1874   }
   1875 
   1876   /*
   1877   ** As soon as this server accepts a connection from the test harness it
   1878   ** must set the server logs advisor read lock to indicate that server
   1879   ** logs should not be read until this lock is removed by this server.
   1880   */
   1881 
   1882   if(!serverlogslocked)
   1883     set_advisor_read_lock(SERVERLOGS_LOCK);
   1884   serverlogslocked += 1;
   1885 
   1886   logmsg("====> Client connect");
   1887 
   1888   all_sockets[num_sockets] = msgsock;
   1889   num_sockets += 1;
   1890 
   1891 #ifdef TCP_NODELAY
   1892   if(socket_domain_is_ip()) {
   1893     /*
   1894      * Disable the Nagle algorithm to make it easier to send out a large
   1895      * response in many small segments to torture the clients more.
   1896      */
   1897     if(0 != setsockopt(msgsock, IPPROTO_TCP, TCP_NODELAY,
   1898                        (void *)&flag, sizeof(flag)))
   1899       logmsg("====> TCP_NODELAY failed");
   1900   }
   1901 #endif
   1902 
   1903   return msgsock;
   1904 }
   1905 
   1906 /* returns 1 if the connection should be serviced again immediately, 0 if there
   1907    is no data waiting, or < 0 if it should be closed */
   1908 static int service_connection(curl_socket_t msgsock, struct httprequest *req,
   1909                               curl_socket_t listensock,
   1910                               const char *connecthost)
   1911 {
   1912   if(got_exit_signal)
   1913     return -1;
   1914 
   1915   while(!req->done_processing) {
   1916     int rc = get_request(msgsock, req);
   1917     if(rc <= 0) {
   1918       /* Nothing further to read now, possibly because the socket was closed */
   1919       return rc;
   1920     }
   1921   }
   1922 
   1923   if(prevbounce) {
   1924     /* bounce treatment requested */
   1925     if((req->testno == prevtestno) &&
   1926        (req->partno == prevpartno)) {
   1927       req->partno++;
   1928       logmsg("BOUNCE part number to %ld", req->partno);
   1929     }
   1930     else {
   1931       prevbounce = FALSE;
   1932       prevtestno = -1;
   1933       prevpartno = -1;
   1934     }
   1935   }
   1936 
   1937   send_doc(msgsock, req);
   1938   if(got_exit_signal)
   1939     return -1;
   1940 
   1941   if(req->testno < 0) {
   1942     logmsg("special request received, no persistency");
   1943     return -1;
   1944   }
   1945   if(!req->open) {
   1946     logmsg("instructed to close connection after server-reply");
   1947     return -1;
   1948   }
   1949 
   1950   if(req->connect_request) {
   1951     /* a CONNECT request, setup and talk the tunnel */
   1952     if(!is_proxy) {
   1953       logmsg("received CONNECT but isn't running as proxy!");
   1954       return 1;
   1955     }
   1956     else {
   1957       http_connect(&msgsock, listensock, connecthost, req->connect_port);
   1958       return -1;
   1959     }
   1960   }
   1961 
   1962   if(req->upgrade_request) {
   1963     /* an upgrade request, switch to http2 here */
   1964     http2(req);
   1965     return -1;
   1966   }
   1967 
   1968   /* if we got a CONNECT, loop and get another request as well! */
   1969 
   1970   if(req->open) {
   1971     logmsg("=> persistant connection request ended, awaits new request\n");
   1972     return 1;
   1973   }
   1974 
   1975   return -1;
   1976 }
   1977 
   1978 int main(int argc, char *argv[])
   1979 {
   1980   srvr_sockaddr_union_t me;
   1981   curl_socket_t sock = CURL_SOCKET_BAD;
   1982   int wrotepidfile = 0;
   1983   int flag;
   1984   unsigned short port = DEFAULT_PORT;
   1985 #ifdef USE_UNIX_SOCKETS
   1986   const char *unix_socket = NULL;
   1987   bool unlink_socket = false;
   1988 #endif
   1989   const char *pidname = ".http.pid";
   1990   struct httprequest req;
   1991   int rc = 0;
   1992   int error;
   1993   int arg = 1;
   1994   long pid;
   1995   const char *connecthost = "127.0.0.1";
   1996   const char *socket_type = "IPv4";
   1997   char port_str[11];
   1998   const char *location_str = port_str;
   1999 
   2000   /* a default CONNECT port is basically pointless but still ... */
   2001   size_t socket_idx;
   2002 
   2003   memset(&req, 0, sizeof(req));
   2004 
   2005   while(argc>arg) {
   2006     if(!strcmp("--version", argv[arg])) {
   2007       puts("sws IPv4"
   2008 #ifdef ENABLE_IPV6
   2009              "/IPv6"
   2010 #endif
   2011 #ifdef USE_UNIX_SOCKETS
   2012              "/unix"
   2013 #endif
   2014           );
   2015       return 0;
   2016     }
   2017     else if(!strcmp("--pidfile", argv[arg])) {
   2018       arg++;
   2019       if(argc>arg)
   2020         pidname = argv[arg++];
   2021     }
   2022     else if(!strcmp("--logfile", argv[arg])) {
   2023       arg++;
   2024       if(argc>arg)
   2025         serverlogfile = argv[arg++];
   2026     }
   2027     else if(!strcmp("--gopher", argv[arg])) {
   2028       arg++;
   2029       use_gopher = TRUE;
   2030       end_of_headers = "\r\n"; /* gopher style is much simpler */
   2031     }
   2032     else if(!strcmp("--ipv4", argv[arg])) {
   2033       socket_type = "IPv4";
   2034       socket_domain = AF_INET;
   2035       location_str = port_str;
   2036       arg++;
   2037     }
   2038     else if(!strcmp("--ipv6", argv[arg])) {
   2039 #ifdef ENABLE_IPV6
   2040       socket_type = "IPv6";
   2041       socket_domain = AF_INET6;
   2042       location_str = port_str;
   2043 #endif
   2044       arg++;
   2045     }
   2046     else if(!strcmp("--unix-socket", argv[arg])) {
   2047       arg++;
   2048       if(argc>arg) {
   2049 #ifdef USE_UNIX_SOCKETS
   2050         unix_socket = argv[arg];
   2051         if(strlen(unix_socket) >= sizeof(me.sau.sun_path)) {
   2052           fprintf(stderr, "sws: socket path must be shorter than %zu chars\n",
   2053                   sizeof(me.sau.sun_path));
   2054           return 0;
   2055         }
   2056         socket_type = "unix";
   2057         socket_domain = AF_UNIX;
   2058         location_str = unix_socket;
   2059 #endif
   2060         arg++;
   2061       }
   2062     }
   2063     else if(!strcmp("--port", argv[arg])) {
   2064       arg++;
   2065       if(argc>arg) {
   2066         char *endptr;
   2067         unsigned long ulnum = strtoul(argv[arg], &endptr, 10);
   2068         if((endptr != argv[arg] + strlen(argv[arg])) ||
   2069            (ulnum < 1025UL) || (ulnum > 65535UL)) {
   2070           fprintf(stderr, "sws: invalid --port argument (%s)\n",
   2071                   argv[arg]);
   2072           return 0;
   2073         }
   2074         port = curlx_ultous(ulnum);
   2075         arg++;
   2076       }
   2077     }
   2078     else if(!strcmp("--srcdir", argv[arg])) {
   2079       arg++;
   2080       if(argc>arg) {
   2081         path = argv[arg];
   2082         arg++;
   2083       }
   2084     }
   2085     else if(!strcmp("--connect", argv[arg])) {
   2086       /* The connect host IP number that the proxy will connect to no matter
   2087          what the client asks for, but also use this as a hint that we run as
   2088          a proxy and do a few different internal choices */
   2089       arg++;
   2090       if(argc>arg) {
   2091         connecthost = argv[arg];
   2092         arg++;
   2093         is_proxy = TRUE;
   2094         logmsg("Run as proxy, CONNECT to host %s", connecthost);
   2095       }
   2096     }
   2097     else {
   2098       puts("Usage: sws [option]\n"
   2099            " --version\n"
   2100            " --logfile [file]\n"
   2101            " --pidfile [file]\n"
   2102            " --ipv4\n"
   2103            " --ipv6\n"
   2104            " --unix-socket [file]\n"
   2105            " --port [port]\n"
   2106            " --srcdir [path]\n"
   2107            " --connect [ip4-addr]\n"
   2108            " --gopher");
   2109       return 0;
   2110     }
   2111   }
   2112 
   2113   snprintf(port_str, sizeof(port_str), "port %hu", port);
   2114 
   2115 #ifdef WIN32
   2116   win32_init();
   2117   atexit(win32_cleanup);
   2118 #endif
   2119 
   2120   install_signal_handlers();
   2121 
   2122   pid = (long)getpid();
   2123 
   2124   sock = socket(socket_domain, SOCK_STREAM, 0);
   2125 
   2126   all_sockets[0] = sock;
   2127   num_sockets = 1;
   2128 
   2129   if(CURL_SOCKET_BAD == sock) {
   2130     error = SOCKERRNO;
   2131     logmsg("Error creating socket: (%d) %s",
   2132            error, strerror(error));
   2133     goto sws_cleanup;
   2134   }
   2135 
   2136   flag = 1;
   2137   if(0 != setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
   2138                      (void *)&flag, sizeof(flag))) {
   2139     error = SOCKERRNO;
   2140     logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s",
   2141            error, strerror(error));
   2142     goto sws_cleanup;
   2143   }
   2144   if(0 != curlx_nonblock(sock, TRUE)) {
   2145     error = SOCKERRNO;
   2146     logmsg("curlx_nonblock failed with error: (%d) %s",
   2147            error, strerror(error));
   2148     goto sws_cleanup;
   2149   }
   2150 
   2151   switch(socket_domain) {
   2152   case AF_INET:
   2153     memset(&me.sa4, 0, sizeof(me.sa4));
   2154     me.sa4.sin_family = AF_INET;
   2155     me.sa4.sin_addr.s_addr = INADDR_ANY;
   2156     me.sa4.sin_port = htons(port);
   2157     rc = bind(sock, &me.sa, sizeof(me.sa4));
   2158     break;
   2159 #ifdef ENABLE_IPV6
   2160   case AF_INET6:
   2161     memset(&me.sa6, 0, sizeof(me.sa6));
   2162     me.sa6.sin6_family = AF_INET6;
   2163     me.sa6.sin6_addr = in6addr_any;
   2164     me.sa6.sin6_port = htons(port);
   2165     rc = bind(sock, &me.sa, sizeof(me.sa6));
   2166     break;
   2167 #endif /* ENABLE_IPV6 */
   2168 #ifdef USE_UNIX_SOCKETS
   2169   case AF_UNIX:
   2170     memset(&me.sau, 0, sizeof(me.sau));
   2171     me.sau.sun_family = AF_UNIX;
   2172     strncpy(me.sau.sun_path, unix_socket, sizeof(me.sau.sun_path));
   2173     rc = bind(sock, &me.sa, sizeof(me.sau));
   2174     if(0 != rc && errno == EADDRINUSE) {
   2175       struct stat statbuf;
   2176       /* socket already exists. Perhaps it is stale? */
   2177       int unixfd = socket(AF_UNIX, SOCK_STREAM, 0);
   2178       if(CURL_SOCKET_BAD == unixfd) {
   2179         error = SOCKERRNO;
   2180         logmsg("Error binding socket, failed to create socket at %s: (%d) %s",
   2181                unix_socket, error, strerror(error));
   2182         goto sws_cleanup;
   2183       }
   2184       /* check whether the server is alive */
   2185       rc = connect(unixfd, &me.sa, sizeof(me.sau));
   2186       error = errno;
   2187       close(unixfd);
   2188       if(ECONNREFUSED != error) {
   2189         logmsg("Error binding socket, failed to connect to %s: (%d) %s",
   2190                unix_socket, error, strerror(error));
   2191         goto sws_cleanup;
   2192       }
   2193       /* socket server is not alive, now check if it was actually a socket.
   2194        * Systems which have Unix sockets will also have lstat */
   2195       rc = lstat(unix_socket, &statbuf);
   2196       if(0 != rc) {
   2197         logmsg("Error binding socket, failed to stat %s: (%d) %s",
   2198                unix_socket, errno, strerror(errno));
   2199         goto sws_cleanup;
   2200       }
   2201       if((statbuf.st_mode & S_IFSOCK) != S_IFSOCK) {
   2202         logmsg("Error binding socket, failed to stat %s: (%d) %s",
   2203                unix_socket, error, strerror(error));
   2204         goto sws_cleanup;
   2205       }
   2206       /* dead socket, cleanup and retry bind */
   2207       rc = unlink(unix_socket);
   2208       if(0 != rc) {
   2209         logmsg("Error binding socket, failed to unlink %s: (%d) %s",
   2210                unix_socket, errno, strerror(errno));
   2211         goto sws_cleanup;
   2212       }
   2213       /* stale socket is gone, retry bind */
   2214       rc = bind(sock, &me.sa, sizeof(me.sau));
   2215     }
   2216     break;
   2217 #endif /* USE_UNIX_SOCKETS */
   2218   }
   2219   if(0 != rc) {
   2220     error = SOCKERRNO;
   2221     logmsg("Error binding socket on %s: (%d) %s",
   2222            location_str, error, strerror(error));
   2223     goto sws_cleanup;
   2224   }
   2225 
   2226   logmsg("Running %s %s version on %s",
   2227          use_gopher?"GOPHER":"HTTP", socket_type, location_str);
   2228 
   2229   /* start accepting connections */
   2230   rc = listen(sock, 5);
   2231   if(0 != rc) {
   2232     error = SOCKERRNO;
   2233     logmsg("listen() failed with error: (%d) %s",
   2234            error, strerror(error));
   2235     goto sws_cleanup;
   2236   }
   2237 
   2238 #ifdef USE_UNIX_SOCKETS
   2239   /* listen succeeds, so let's assume a valid listening Unix socket */
   2240   unlink_socket = true;
   2241 #endif
   2242 
   2243   /*
   2244   ** As soon as this server writes its pid file the test harness will
   2245   ** attempt to connect to this server and initiate its verification.
   2246   */
   2247 
   2248   wrotepidfile = write_pidfile(pidname);
   2249   if(!wrotepidfile)
   2250     goto sws_cleanup;
   2251 
   2252   /* initialization of httprequest struct is done before get_request(), but
   2253      the pipelining struct field must be initialized previously to FALSE
   2254      every time a new connection arrives. */
   2255 
   2256   req.pipelining = FALSE;
   2257   init_httprequest(&req);
   2258 
   2259   for(;;) {
   2260     fd_set input;
   2261     fd_set output;
   2262     struct timeval timeout = {0, 250000L}; /* 250 ms */
   2263     curl_socket_t maxfd = (curl_socket_t)-1;
   2264 
   2265     /* Clear out closed sockets */
   2266     for(socket_idx = num_sockets - 1; socket_idx >= 1; --socket_idx) {
   2267       if(CURL_SOCKET_BAD == all_sockets[socket_idx]) {
   2268         char *dst = (char *) (all_sockets + socket_idx);
   2269         char *src = (char *) (all_sockets + socket_idx + 1);
   2270         char *end = (char *) (all_sockets + num_sockets);
   2271         memmove(dst, src, end - src);
   2272         num_sockets -= 1;
   2273       }
   2274     }
   2275 
   2276     if(got_exit_signal)
   2277       goto sws_cleanup;
   2278 
   2279     /* Set up for select */
   2280     FD_ZERO(&input);
   2281     FD_ZERO(&output);
   2282 
   2283     for(socket_idx = 0; socket_idx < num_sockets; ++socket_idx) {
   2284       /* Listen on all sockets */
   2285       FD_SET(all_sockets[socket_idx], &input);
   2286       if(all_sockets[socket_idx] > maxfd)
   2287         maxfd = all_sockets[socket_idx];
   2288     }
   2289 
   2290     if(got_exit_signal)
   2291       goto sws_cleanup;
   2292 
   2293     rc = select((int)maxfd + 1, &input, &output, NULL, &timeout);
   2294     if(rc < 0) {
   2295       error = SOCKERRNO;
   2296       logmsg("select() failed with error: (%d) %s",
   2297              error, strerror(error));
   2298       goto sws_cleanup;
   2299     }
   2300 
   2301     if(got_exit_signal)
   2302       goto sws_cleanup;
   2303 
   2304     if(rc == 0) {
   2305       /* Timed out - try again */
   2306       continue;
   2307     }
   2308 
   2309     /* Check if the listening socket is ready to accept */
   2310     if(FD_ISSET(all_sockets[0], &input)) {
   2311       /* Service all queued connections */
   2312       curl_socket_t msgsock;
   2313       do {
   2314         msgsock = accept_connection(sock);
   2315         logmsg("accept_connection %d returned %d", sock, msgsock);
   2316         if(CURL_SOCKET_BAD == msgsock)
   2317           goto sws_cleanup;
   2318       } while(msgsock > 0);
   2319     }
   2320 
   2321     /* Service all connections that are ready */
   2322     for(socket_idx = 1; socket_idx < num_sockets; ++socket_idx) {
   2323       if(FD_ISSET(all_sockets[socket_idx], &input)) {
   2324         if(got_exit_signal)
   2325           goto sws_cleanup;
   2326 
   2327         /* Service this connection until it has nothing available */
   2328         do {
   2329           rc = service_connection(all_sockets[socket_idx], &req, sock,
   2330                                   connecthost);
   2331           if(got_exit_signal)
   2332             goto sws_cleanup;
   2333 
   2334           if(rc < 0) {
   2335             logmsg("====> Client disconnect %d", req.connmon);
   2336 
   2337             if(req.connmon) {
   2338               const char *keepopen = "[DISCONNECT]\n";
   2339               storerequest(keepopen, strlen(keepopen));
   2340             }
   2341 
   2342             if(!req.open)
   2343               /* When instructed to close connection after server-reply we
   2344                  wait a very small amount of time before doing so. If this
   2345                  is not done client might get an ECONNRESET before reading
   2346                  a single byte of server-reply. */
   2347               wait_ms(50);
   2348 
   2349             if(all_sockets[socket_idx] != CURL_SOCKET_BAD) {
   2350               sclose(all_sockets[socket_idx]);
   2351               all_sockets[socket_idx] = CURL_SOCKET_BAD;
   2352             }
   2353 
   2354             serverlogslocked -= 1;
   2355             if(!serverlogslocked)
   2356               clear_advisor_read_lock(SERVERLOGS_LOCK);
   2357 
   2358             if(req.testno == DOCNUMBER_QUIT)
   2359               goto sws_cleanup;
   2360           }
   2361 
   2362           /* Reset the request, unless we're still in the middle of reading */
   2363           if(rc != 0)
   2364             init_httprequest(&req);
   2365         } while(rc > 0);
   2366       }
   2367     }
   2368 
   2369     if(got_exit_signal)
   2370       goto sws_cleanup;
   2371   }
   2372 
   2373 sws_cleanup:
   2374 
   2375   for(socket_idx = 1; socket_idx < num_sockets; ++socket_idx)
   2376     if((all_sockets[socket_idx] != sock) &&
   2377      (all_sockets[socket_idx] != CURL_SOCKET_BAD))
   2378       sclose(all_sockets[socket_idx]);
   2379 
   2380   if(sock != CURL_SOCKET_BAD)
   2381     sclose(sock);
   2382 
   2383 #ifdef USE_UNIX_SOCKETS
   2384   if(unlink_socket && socket_domain == AF_UNIX) {
   2385     rc = unlink(unix_socket);
   2386     logmsg("unlink(%s) = %d (%s)", unix_socket, rc, strerror(rc));
   2387   }
   2388 #endif
   2389 
   2390   if(got_exit_signal)
   2391     logmsg("signalled to die");
   2392 
   2393   if(wrotepidfile)
   2394     unlink(pidname);
   2395 
   2396   if(serverlogslocked) {
   2397     serverlogslocked = 0;
   2398     clear_advisor_read_lock(SERVERLOGS_LOCK);
   2399   }
   2400 
   2401   restore_signal_handlers();
   2402 
   2403   if(got_exit_signal) {
   2404     logmsg("========> %s sws (%s pid: %ld) exits with signal (%d)",
   2405            socket_type, location_str, pid, exit_signal);
   2406     /*
   2407      * To properly set the return status of the process we
   2408      * must raise the same signal SIGINT or SIGTERM that we
   2409      * caught and let the old handler take care of it.
   2410      */
   2411     raise(exit_signal);
   2412   }
   2413 
   2414   logmsg("========> sws quits");
   2415   return 0;
   2416 }
   2417 
   2418