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