Annotation of embedaddon/curl/tests/server/sws.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>