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