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