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
522        sprintf(logbuf, "Received a CONNECT %s HTTP/%d.%d request",
523                doc, prot_major, prot_minor);
524        logmsg("%s", logbuf);
525
526        req->connect_request = TRUE;
527
528        if(req->prot_version == 10)
529          req->open = FALSE; /* HTTP 1.0 closes connection by default */
530
531        if(doc[0] == '[') {
532          char *p = &doc[1];
533          while(*p && (ISXDIGIT(*p) || (*p == ':') || (*p == '.')))
534            p++;
535          if(*p != ']')
536            logmsg("Invalid CONNECT IPv6 address format");
537          else if (*(p+1) != ':')
538            logmsg("Invalid CONNECT IPv6 port format");
539          else
540            portp = p+1;
541        }
542        else
543          portp = strchr(doc, ':');
544
545        if(portp && (*(portp+1) != '\0') && ISDIGIT(*(portp+1))) {
546          unsigned long ulnum = strtoul(portp+1, NULL, 10);
547          if(!ulnum || (ulnum > 65535UL))
548            logmsg("Invalid CONNECT port received");
549          else
550            req->connect_port = curlx_ultous(ulnum);
551        }
552      }
553    }
554
555    if(req->testno == DOCNUMBER_NOTHING) {
556      /* Still no test case number. Try to get the the number off the last dot
557         instead, IE we consider the TLD to be the test number. Test 123 can
558         then be written as "example.com.123". */
559
560      /* find the last dot */
561      ptr = strrchr(doc, '.');
562
563      /* get the number after it */
564      if(ptr) {
565        ptr++; /* skip the dot */
566
567        req->testno = strtol(ptr, &ptr, 10);
568
569        if(req->testno > 10000) {
570          req->partno = req->testno % 10000;
571          req->testno /= 10000;
572
573          logmsg("found test %d in requested host name", req->testno);
574
575        }
576        else
577          req->partno = 0;
578
579        sprintf(logbuf, "Requested test number %ld part %ld (from host name)",
580                req->testno, req->partno);
581        logmsg("%s", logbuf);
582
583      }
584
585      if(!req->testno) {
586        logmsg("Did not find test number in PATH");
587        req->testno = DOCNUMBER_404;
588      }
589      else
590        parse_servercmd(req);
591    }
592  }
593  else if((req->offset >= 3) && (req->testno == DOCNUMBER_NOTHING)) {
594    logmsg("** Unusual request. Starts with %02x %02x %02x",
595           line[0], line[1], line[2]);
596  }
597
598  if(!end) {
599    /* we don't have a complete request yet! */
600    logmsg("request not complete yet");
601    return 0; /* not complete yet */
602  }
603  logmsg("- request found to be complete");
604
605  if(use_gopher) {
606    /* when using gopher we cannot check the request until the entire
607       thing has been received */
608    char *ptr;
609
610    /* find the last slash in the line */
611    ptr = strrchr(line, '/');
612
613    if(ptr) {
614      ptr++; /* skip the slash */
615
616      /* skip all non-numericals following the slash */
617      while(*ptr && !ISDIGIT(*ptr))
618        ptr++;
619
620      req->testno = strtol(ptr, &ptr, 10);
621
622      if(req->testno > 10000) {
623        req->partno = req->testno % 10000;
624        req->testno /= 10000;
625      }
626      else
627        req->partno = 0;
628
629      sprintf(logbuf, "Requested GOPHER test number %ld part %ld",
630              req->testno, req->partno);
631      logmsg("%s", logbuf);
632    }
633  }
634
635  if(req->pipe)
636    /* we do have a full set, advance the checkindex to after the end of the
637       headers, for the pipelining case mostly */
638    req->checkindex += (end - line) + strlen(end_of_headers);
639
640  /* **** Persistence ****
641   *
642   * If the request is a HTTP/1.0 one, we close the connection unconditionally
643   * when we're done.
644   *
645   * If the request is a HTTP/1.1 one, we MUST check for a "Connection:"
646   * header that might say "close". If it does, we close a connection when
647   * this request is processed. Otherwise, we keep the connection alive for X
648   * seconds.
649   */
650
651  do {
652    if(got_exit_signal)
653      return 1; /* done */
654
655    if((req->cl==0) && curlx_strnequal("Content-Length:", line, 15)) {
656      /* If we don't ignore content-length, we read it and we read the whole
657         request including the body before we return. If we've been told to
658         ignore the content-length, we will return as soon as all headers
659         have been received */
660      char *endptr;
661      char *ptr = line + 15;
662      unsigned long clen = 0;
663      while(*ptr && ISSPACE(*ptr))
664        ptr++;
665      endptr = ptr;
666      errno = 0;
667      clen = strtoul(ptr, &endptr, 10);
668      if((ptr == endptr) || !ISSPACE(*endptr) || (ERANGE == errno)) {
669        /* this assumes that a zero Content-Length is valid */
670        logmsg("Found invalid Content-Length: (%s) in the request", ptr);
671        req->open = FALSE; /* closes connection */
672        return 1; /* done */
673      }
674      req->cl = clen - req->skip;
675
676      logmsg("Found Content-Length: %lu in the request", clen);
677      if(req->skip)
678        logmsg("... but will abort after %zu bytes", req->cl);
679      break;
680    }
681    else if(curlx_strnequal("Transfer-Encoding: chunked", line,
682                            strlen("Transfer-Encoding: chunked"))) {
683      /* chunked data coming in */
684      chunked = TRUE;
685    }
686
687    if(chunked) {
688      if(strstr(req->reqbuf, "\r\n0\r\n\r\n"))
689        /* end of chunks reached */
690        return 1; /* done */
691      else
692        return 0; /* not done */
693    }
694
695    line = strchr(line, '\n');
696    if(line)
697      line++;
698
699  } while(line);
700
701  if(!req->auth && strstr(req->reqbuf, "Authorization:")) {
702    req->auth = TRUE; /* Authorization: header present! */
703    if(req->auth_req)
704      logmsg("Authorization header found, as required");
705  }
706
707  if(!req->digest && strstr(req->reqbuf, "Authorization: Digest")) {
708    /* If the client is passing this Digest-header, we set the part number
709       to 1000. Not only to spice up the complexity of this, but to make
710       Digest stuff to work in the test suite. */
711    req->partno += 1000;
712    req->digest = TRUE; /* header found */
713    logmsg("Received Digest request, sending back data %ld", req->partno);
714  }
715  else if(!req->ntlm &&
716          strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAD")) {
717    /* If the client is passing this type-3 NTLM header */
718    req->partno += 1002;
719    req->ntlm = TRUE; /* NTLM found */
720    logmsg("Received NTLM type-3, sending back data %ld", req->partno);
721    if(req->cl) {
722      logmsg("  Expecting %zu POSTed bytes", req->cl);
723    }
724  }
725  else if(!req->ntlm &&
726          strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAB")) {
727    /* If the client is passing this type-1 NTLM header */
728    req->partno += 1001;
729    req->ntlm = TRUE; /* NTLM found */
730    logmsg("Received NTLM type-1, sending back data %ld", req->partno);
731  }
732  else if((req->partno >= 1000) &&
733          strstr(req->reqbuf, "Authorization: Basic")) {
734    /* If the client is passing this Basic-header and the part number is
735       already >=1000, we add 1 to the part number.  This allows simple Basic
736       authentication negotiation to work in the test suite. */
737    req->partno += 1;
738    logmsg("Received Basic request, sending back data %ld", req->partno);
739  }
740  if(strstr(req->reqbuf, "Connection: close"))
741    req->open = FALSE; /* close connection after this request */
742
743  if(!req->pipe &&
744     req->open &&
745     req->prot_version >= 11 &&
746     end &&
747     req->reqbuf + req->offset > end + strlen(end_of_headers) &&
748     !req->cl &&
749     (!strncmp(req->reqbuf, "GET", strlen("GET")) ||
750      !strncmp(req->reqbuf, "HEAD", strlen("HEAD")))) {
751    /* If we have a persistent connection, HTTP version >= 1.1
752       and GET/HEAD request, enable pipelining. */
753    req->checkindex = (end - req->reqbuf) + strlen(end_of_headers);
754    req->pipelining = TRUE;
755  }
756
757  while(req->pipe) {
758    if(got_exit_signal)
759      return 1; /* done */
760    /* scan for more header ends within this chunk */
761    line = &req->reqbuf[req->checkindex];
762    end = strstr(line, end_of_headers);
763    if(!end)
764      break;
765    req->checkindex += (end - line) + strlen(end_of_headers);
766    req->pipe--;
767  }
768
769  /* If authentication is required and no auth was provided, end now. This
770     makes the server NOT wait for PUT/POST data and you can then make the
771     test case send a rejection before any such data has been sent. Test case
772     154 uses this.*/
773  if(req->auth_req && !req->auth) {
774    logmsg("Return early due to auth requested by none provided");
775    return 1; /* done */
776  }
777
778  if(req->cl > 0) {
779    if(req->cl <= req->offset - (end - req->reqbuf) - strlen(end_of_headers))
780      return 1; /* done */
781    else
782      return 0; /* not complete yet */
783  }
784
785  return 1; /* done */
786}
787
788/* store the entire request in a file */
789static void storerequest(char *reqbuf, size_t totalsize)
790{
791  int res;
792  int error = 0;
793  size_t written;
794  size_t writeleft;
795  FILE *dump;
796  const char *dumpfile=is_proxy?REQUEST_PROXY_DUMP:REQUEST_DUMP;
797
798  if (reqbuf == NULL)
799    return;
800  if (totalsize == 0)
801    return;
802
803  do {
804    dump = fopen(dumpfile, "ab");
805  } while ((dump == NULL) && ((error = errno) == EINTR));
806  if (dump == NULL) {
807    logmsg("[2] Error opening file %s error: %d %s",
808           dumpfile, error, strerror(error));
809    logmsg("Failed to write request input ");
810    return;
811  }
812
813  writeleft = totalsize;
814  do {
815    written = fwrite(&reqbuf[totalsize-writeleft],
816                     1, writeleft, dump);
817    if(got_exit_signal)
818      goto storerequest_cleanup;
819    if(written > 0)
820      writeleft -= written;
821  } while ((writeleft > 0) && ((error = errno) == EINTR));
822
823  if(writeleft == 0)
824    logmsg("Wrote request (%zu bytes) input to %s", totalsize, dumpfile);
825  else if(writeleft > 0) {
826    logmsg("Error writing file %s error: %d %s",
827           dumpfile, error, strerror(error));
828    logmsg("Wrote only (%zu bytes) of (%zu bytes) request input to %s",
829           totalsize-writeleft, totalsize, dumpfile);
830  }
831
832storerequest_cleanup:
833
834  do {
835    res = fclose(dump);
836  } while(res && ((error = errno) == EINTR));
837  if(res)
838    logmsg("Error closing file %s error: %d %s",
839           dumpfile, error, strerror(error));
840}
841
842static void init_httprequest(struct httprequest *req)
843{
844  /* Pipelining is already set, so do not initialize it here. Only initialize
845     checkindex and offset if pipelining is not set, since in a pipeline they
846     need to be inherited from the previous request. */
847  if(!req->pipelining) {
848    req->checkindex = 0;
849    req->offset = 0;
850  }
851  req->testno = DOCNUMBER_NOTHING;
852  req->partno = 0;
853  req->connect_request = FALSE;
854  req->open = TRUE;
855  req->auth_req = FALSE;
856  req->auth = FALSE;
857  req->cl = 0;
858  req->digest = FALSE;
859  req->ntlm = FALSE;
860  req->pipe = 0;
861  req->skip = 0;
862  req->writedelay = 0;
863  req->rcmd = RCMD_NORMALREQ;
864  req->prot_version = 0;
865  req->callcount = 0;
866  req->connect_port = 0;
867  req->done_processing = 0;
868}
869
870/* returns 1 if the connection should be serviced again immediately, 0 if there
871   is no data waiting, or < 0 if it should be closed */
872static int get_request(curl_socket_t sock, struct httprequest *req)
873{
874  int error;
875  int fail = 0;
876  char *reqbuf = req->reqbuf;
877  ssize_t got = 0;
878  int overflow = 0;
879
880  char *pipereq = NULL;
881  size_t pipereq_length = 0;
882
883  if(req->pipelining) {
884    pipereq = reqbuf + req->checkindex;
885    pipereq_length = req->offset - req->checkindex;
886
887    /* Now that we've got the pipelining info we can reset the
888       pipelining-related vars which were skipped in init_httprequest */
889    req->pipelining = FALSE;
890    req->checkindex = 0;
891    req->offset = 0;
892  }
893
894  if(req->offset >= REQBUFSIZ-1) {
895    /* buffer is already full; do nothing */
896    overflow = 1;
897  }
898  else {
899    if(pipereq_length && pipereq) {
900      memmove(reqbuf, pipereq, pipereq_length);
901      got = curlx_uztosz(pipereq_length);
902      pipereq_length = 0;
903    }
904    else {
905      if(req->skip)
906        /* we are instructed to not read the entire thing, so we make sure to
907           only read what we're supposed to and NOT read the enire thing the
908           client wants to send! */
909        got = sread(sock, reqbuf + req->offset, req->cl);
910      else
911        got = sread(sock, reqbuf + req->offset, REQBUFSIZ-1 - req->offset);
912    }
913    if(got_exit_signal)
914      return -1;
915    if(got == 0) {
916      logmsg("Connection closed by client");
917      fail = 1;
918    }
919    else if(got < 0) {
920      error = SOCKERRNO;
921      if (EAGAIN == error || EWOULDBLOCK == error) {
922        /* nothing to read at the moment */
923        return 0;
924      }
925      logmsg("recv() returned error: (%d) %s", error, strerror(error));
926      fail = 1;
927    }
928    if(fail) {
929      /* dump the request received so far to the external file */
930      reqbuf[req->offset] = '\0';
931      storerequest(reqbuf, req->offset);
932      return -1;
933    }
934
935    logmsg("Read %zd bytes", got);
936
937    req->offset += (size_t)got;
938    reqbuf[req->offset] = '\0';
939
940    req->done_processing = ProcessRequest(req);
941    if(got_exit_signal)
942      return -1;
943    if(req->done_processing && req->pipe) {
944      logmsg("Waiting for another piped request");
945      req->done_processing = 0;
946      req->pipe--;
947    }
948  }
949
950  if(overflow || (req->offset == REQBUFSIZ-1 && got > 0)) {
951    logmsg("Request would overflow buffer, closing connection");
952    /* dump request received so far to external file anyway */
953    reqbuf[REQBUFSIZ-1] = '\0';
954    fail = 1;
955  }
956  else if(req->offset > REQBUFSIZ-1) {
957    logmsg("Request buffer overflow, closing connection");
958    /* dump request received so far to external file anyway */
959    reqbuf[REQBUFSIZ-1] = '\0';
960    fail = 1;
961  }
962  else
963    reqbuf[req->offset] = '\0';
964
965  /* at the end of a request dump it to an external file */
966  if (fail || req->done_processing)
967    storerequest(reqbuf, req->pipelining ? req->checkindex : req->offset);
968  if(got_exit_signal)
969    return -1;
970
971  return fail ? -1 : 1;
972}
973
974/* returns -1 on failure */
975static int send_doc(curl_socket_t sock, struct httprequest *req)
976{
977  ssize_t written;
978  size_t count;
979  const char *buffer;
980  char *ptr=NULL;
981  FILE *stream;
982  char *cmd=NULL;
983  size_t cmdsize=0;
984  FILE *dump;
985  bool persistant = TRUE;
986  bool sendfailure = FALSE;
987  size_t responsesize;
988  int error = 0;
989  int res;
990  const char *responsedump = is_proxy?RESPONSE_PROXY_DUMP:RESPONSE_DUMP;
991  static char weare[256];
992
993  switch(req->rcmd) {
994  default:
995  case RCMD_NORMALREQ:
996    break; /* continue with business as usual */
997  case RCMD_STREAM:
998#define STREAMTHIS "a string to stream 01234567890\n"
999    count = strlen(STREAMTHIS);
1000    for (;;) {
1001      written = swrite(sock, STREAMTHIS, count);
1002      if(got_exit_signal)
1003        return -1;
1004      if(written != (ssize_t)count) {
1005        logmsg("Stopped streaming");
1006        break;
1007      }
1008    }
1009    return -1;
1010  case RCMD_IDLE:
1011    /* Do nothing. Sit idle. Pretend it rains. */
1012    return 0;
1013  }
1014
1015  req->open = FALSE;
1016
1017  if(req->testno < 0) {
1018    size_t msglen;
1019    char msgbuf[64];
1020
1021    switch(req->testno) {
1022    case DOCNUMBER_QUIT:
1023      logmsg("Replying to QUIT");
1024      buffer = docquit;
1025      break;
1026    case DOCNUMBER_WERULEZ:
1027      /* we got a "friends?" question, reply back that we sure are */
1028      logmsg("Identifying ourselves as friends");
1029      sprintf(msgbuf, "WE ROOLZ: %ld\r\n", (long)getpid());
1030      msglen = strlen(msgbuf);
1031      if(use_gopher)
1032        sprintf(weare, "%s", msgbuf);
1033      else
1034        sprintf(weare, "HTTP/1.1 200 OK\r\nContent-Length: %zu\r\n\r\n%s",
1035                msglen, msgbuf);
1036      buffer = weare;
1037      break;
1038    case DOCNUMBER_404:
1039    default:
1040      logmsg("Replying to with a 404");
1041      buffer = doc404;
1042      break;
1043    }
1044
1045    count = strlen(buffer);
1046  }
1047  else {
1048    char partbuf[80];
1049    char *filename = test2file(req->testno);
1050
1051    /* select the <data> tag for "normal" requests and the <connect> one
1052       for CONNECT requests (within the <reply> section) */
1053    const char *section= req->connect_request?"connect":"data";
1054
1055    if(req->partno)
1056      sprintf(partbuf, "%s%ld", section, req->partno);
1057    else
1058      sprintf(partbuf, "%s", section);
1059
1060    logmsg("Send response test%ld section <%s>", req->testno, partbuf);
1061
1062    stream=fopen(filename, "rb");
1063    if(!stream) {
1064      error = errno;
1065      logmsg("fopen() failed with error: %d %s", error, strerror(error));
1066      logmsg("  [3] Error opening file: %s", filename);
1067      return 0;
1068    }
1069    else {
1070      error = getpart(&ptr, &count, "reply", partbuf, stream);
1071      fclose(stream);
1072      if(error) {
1073        logmsg("getpart() failed with error: %d", error);
1074        return 0;
1075      }
1076      buffer = ptr;
1077    }
1078
1079    if(got_exit_signal) {
1080      if(ptr)
1081        free(ptr);
1082      return -1;
1083    }
1084
1085    /* re-open the same file again */
1086    stream=fopen(filename, "rb");
1087    if(!stream) {
1088      error = errno;
1089      logmsg("fopen() failed with error: %d %s", error, strerror(error));
1090      logmsg("  [4] Error opening file: %s", filename);
1091      if(ptr)
1092        free(ptr);
1093      return 0;
1094    }
1095    else {
1096      /* get the custom server control "commands" */
1097      error = getpart(&cmd, &cmdsize, "reply", "postcmd", stream);
1098      fclose(stream);
1099      if(error) {
1100        logmsg("getpart() failed with error: %d", error);
1101        if(ptr)
1102          free(ptr);
1103        return 0;
1104      }
1105    }
1106  }
1107
1108  if(got_exit_signal) {
1109    if(ptr)
1110      free(ptr);
1111    if(cmd)
1112      free(cmd);
1113    return -1;
1114  }
1115
1116  /* If the word 'swsclose' is present anywhere in the reply chunk, the
1117     connection will be closed after the data has been sent to the requesting
1118     client... */
1119  if(strstr(buffer, "swsclose") || !count) {
1120    persistant = FALSE;
1121    logmsg("connection close instruction \"swsclose\" found in response");
1122  }
1123  if(strstr(buffer, "swsbounce")) {
1124    prevbounce = TRUE;
1125    logmsg("enable \"swsbounce\" in the next request");
1126  }
1127  else
1128    prevbounce = FALSE;
1129
1130  dump = fopen(responsedump, "ab");
1131  if(!dump) {
1132    error = errno;
1133    logmsg("fopen() failed with error: %d %s", error, strerror(error));
1134    logmsg("  [5] Error opening file: %s", responsedump);
1135    if(ptr)
1136      free(ptr);
1137    if(cmd)
1138      free(cmd);
1139    return -1;
1140  }
1141
1142  responsesize = count;
1143  do {
1144    /* Ok, we send no more than 200 bytes at a time, just to make sure that
1145       larger chunks are split up so that the client will need to do multiple
1146       recv() calls to get it and thus we exercise that code better */
1147    size_t num = count;
1148    if(num > 200)
1149      num = 200;
1150    written = swrite(sock, buffer, num);
1151    if (written < 0) {
1152      sendfailure = TRUE;
1153      break;
1154    }
1155    else {
1156      logmsg("Sent off %zd bytes", written);
1157    }
1158    /* write to file as well */
1159    fwrite(buffer, 1, (size_t)written, dump);
1160
1161    count -= written;
1162    buffer += written;
1163
1164    if(req->writedelay) {
1165      int quarters = req->writedelay * 4;
1166      logmsg("Pausing %d seconds", req->writedelay);
1167      while((quarters > 0) && !got_exit_signal) {
1168        quarters--;
1169        wait_ms(250);
1170      }
1171    }
1172  } while((count > 0) && !got_exit_signal);
1173
1174  do {
1175    res = fclose(dump);
1176  } while(res && ((error = errno) == EINTR));
1177  if(res)
1178    logmsg("Error closing file %s error: %d %s",
1179           responsedump, error, strerror(error));
1180
1181  if(got_exit_signal) {
1182    if(ptr)
1183      free(ptr);
1184    if(cmd)
1185      free(cmd);
1186    return -1;
1187  }
1188
1189  if(sendfailure) {
1190    logmsg("Sending response failed. Only (%zu bytes) of (%zu bytes) were sent",
1191           responsesize-count, responsesize);
1192    if(ptr)
1193      free(ptr);
1194    if(cmd)
1195      free(cmd);
1196    return -1;
1197  }
1198
1199  logmsg("Response sent (%zu bytes) and written to %s",
1200         responsesize, responsedump);
1201
1202  if(ptr)
1203    free(ptr);
1204
1205  if(cmdsize > 0 ) {
1206    char command[32];
1207    int quarters;
1208    int num;
1209    ptr=cmd;
1210    do {
1211      if(2 == sscanf(ptr, "%31s %d", command, &num)) {
1212        if(!strcmp("wait", command)) {
1213          logmsg("Told to sleep for %d seconds", num);
1214          quarters = num * 4;
1215          while((quarters > 0) && !got_exit_signal) {
1216            quarters--;
1217            res = wait_ms(250);
1218            if(res) {
1219              /* should not happen */
1220              error = errno;
1221              logmsg("wait_ms() failed with error: (%d) %s",
1222                     error, strerror(error));
1223              break;
1224            }
1225          }
1226          if(!quarters)
1227            logmsg("Continuing after sleeping %d seconds", num);
1228        }
1229        else
1230          logmsg("Unknown command in reply command section");
1231      }
1232      ptr = strchr(ptr, '\n');
1233      if(ptr)
1234        ptr++;
1235      else
1236        ptr = NULL;
1237    } while(ptr && *ptr);
1238  }
1239  if(cmd)
1240    free(cmd);
1241
1242  req->open = use_gopher?FALSE:persistant;
1243
1244  prevtestno = req->testno;
1245  prevpartno = req->partno;
1246
1247  return 0;
1248}
1249
1250static curl_socket_t connect_to(const char *ipaddr, unsigned short port)
1251{
1252  srvr_sockaddr_union_t serveraddr;
1253  curl_socket_t serverfd;
1254  int error;
1255  int rc;
1256  const char *op_br = "";
1257  const char *cl_br = "";
1258#ifdef TCP_NODELAY
1259  curl_socklen_t flag;
1260#endif
1261
1262#ifdef ENABLE_IPV6
1263  if(use_ipv6) {
1264    op_br = "[";
1265    cl_br = "]";
1266  }
1267#endif
1268
1269  if(!ipaddr)
1270    return CURL_SOCKET_BAD;
1271
1272  logmsg("about to connect to %s%s%s:%hu",
1273         op_br, ipaddr, cl_br, port);
1274
1275#ifdef ENABLE_IPV6
1276  if(!use_ipv6)
1277#endif
1278    serverfd = socket(AF_INET, SOCK_STREAM, 0);
1279#ifdef ENABLE_IPV6
1280  else
1281    serverfd = socket(AF_INET6, SOCK_STREAM, 0);
1282#endif
1283  if(CURL_SOCKET_BAD == serverfd) {
1284    error = SOCKERRNO;
1285    logmsg("Error creating socket for server conection: (%d) %s",
1286           error, strerror(error));
1287    return CURL_SOCKET_BAD;
1288  }
1289
1290#ifdef TCP_NODELAY
1291  /* Disable the Nagle algorithm */
1292  flag = 1;
1293  if(0 != setsockopt(serverfd, IPPROTO_TCP, TCP_NODELAY,
1294                     (void *)&flag, sizeof(flag)))
1295    logmsg("====> TCP_NODELAY for server conection failed");
1296  else
1297    logmsg("TCP_NODELAY set for server conection");
1298#endif
1299
1300#ifdef ENABLE_IPV6
1301  if(!use_ipv6) {
1302#endif
1303    memset(&serveraddr.sa4, 0, sizeof(serveraddr.sa4));
1304    serveraddr.sa4.sin_family = AF_INET;
1305    serveraddr.sa4.sin_port = htons(port);
1306    if(Curl_inet_pton(AF_INET, ipaddr, &serveraddr.sa4.sin_addr) < 1) {
1307      logmsg("Error inet_pton failed AF_INET conversion of '%s'", ipaddr);
1308      sclose(serverfd);
1309      return CURL_SOCKET_BAD;
1310    }
1311
1312    rc = connect(serverfd, &serveraddr.sa, sizeof(serveraddr.sa4));
1313#ifdef ENABLE_IPV6
1314  }
1315  else {
1316    memset(&serveraddr.sa6, 0, sizeof(serveraddr.sa6));
1317    serveraddr.sa6.sin6_family = AF_INET6;
1318    serveraddr.sa6.sin6_port = htons(port);
1319    if(Curl_inet_pton(AF_INET6, ipaddr, &serveraddr.sa6.sin6_addr) < 1) {
1320      logmsg("Error inet_pton failed AF_INET6 conversion of '%s'", ipaddr);
1321      sclose(serverfd);
1322      return CURL_SOCKET_BAD;
1323    }
1324
1325    rc = connect(serverfd, &serveraddr.sa, sizeof(serveraddr.sa6));
1326  }
1327#endif /* ENABLE_IPV6 */
1328
1329  if(got_exit_signal) {
1330    sclose(serverfd);
1331    return CURL_SOCKET_BAD;
1332  }
1333
1334  if(rc) {
1335    error = SOCKERRNO;
1336    logmsg("Error connecting to server port %hu: (%d) %s",
1337           port, error, strerror(error));
1338    sclose(serverfd);
1339    return CURL_SOCKET_BAD;
1340  }
1341
1342  logmsg("connected fine to %s%s%s:%hu, now tunnel",
1343         op_br, ipaddr, cl_br, port);
1344
1345  return serverfd;
1346}
1347
1348/*
1349 * A CONNECT has been received, a CONNECT response has been sent.
1350 *
1351 * This function needs to connect to the server, and then pass data between
1352 * the client and the server back and forth until the connection is closed by
1353 * either end.
1354 *
1355 * When doing FTP through a CONNECT proxy, we expect that the data connection
1356 * will be setup while the first connect is still being kept up. Therefor we
1357 * must accept a new connection and deal with it appropriately.
1358 */
1359
1360#define data_or_ctrl(x) ((x)?"DATA":"CTRL")
1361
1362#define CTRL  0
1363#define DATA  1
1364
1365static void http_connect(curl_socket_t *infdp,
1366                         curl_socket_t rootfd,
1367                         const char *ipaddr,
1368                         unsigned short ipport)
1369{
1370  curl_socket_t serverfd[2] = {CURL_SOCKET_BAD, CURL_SOCKET_BAD};
1371  curl_socket_t clientfd[2] = {CURL_SOCKET_BAD, CURL_SOCKET_BAD};
1372  ssize_t toc[2] = {0, 0}; /* number of bytes to client */
1373  ssize_t tos[2] = {0, 0}; /* number of bytes to server */
1374  char readclient[2][256];
1375  char readserver[2][256];
1376  bool poll_client_rd[2] = { TRUE, TRUE };
1377  bool poll_server_rd[2] = { TRUE, TRUE };
1378  bool poll_client_wr[2] = { TRUE, TRUE };
1379  bool poll_server_wr[2] = { TRUE, TRUE };
1380#ifdef TCP_NODELAY
1381  curl_socklen_t flag;
1382#endif
1383  bool primary = FALSE;
1384  bool secondary = FALSE;
1385  int max_tunnel_idx; /* CTRL or DATA */
1386  int loop;
1387  int i;
1388
1389  /* primary tunnel client endpoint already connected */
1390  clientfd[CTRL] = *infdp;
1391
1392  /* Sleep here to make sure the client reads CONNECT response's
1393     'end of headers' separate from the server data that follows.
1394     This is done to prevent triggering libcurl known bug #39. */
1395  for(loop = 2; (loop > 0) && !got_exit_signal; loop--)
1396    wait_ms(250);
1397  if(got_exit_signal)
1398    goto http_connect_cleanup;
1399
1400  serverfd[CTRL] = connect_to(ipaddr, ipport);
1401  if(serverfd[CTRL] == CURL_SOCKET_BAD)
1402    goto http_connect_cleanup;
1403
1404  /* Primary tunnel socket endpoints are now connected. Tunnel data back and
1405     forth over the primary tunnel until client or server breaks the primary
1406     tunnel, simultaneously allowing establishment, operation and teardown of
1407     a secondary tunnel that may be used for passive FTP data connection. */
1408
1409  max_tunnel_idx = CTRL;
1410  primary = TRUE;
1411
1412  while(!got_exit_signal) {
1413
1414    fd_set input;
1415    fd_set output;
1416    struct timeval timeout = {0, 250000L}; /* 250 ms */
1417    ssize_t rc;
1418    curl_socket_t maxfd = (curl_socket_t)-1;
1419
1420    FD_ZERO(&input);
1421    FD_ZERO(&output);
1422
1423    if((clientfd[DATA] == CURL_SOCKET_BAD) &&
1424       (serverfd[DATA] == CURL_SOCKET_BAD) &&
1425       poll_client_rd[CTRL] && poll_client_wr[CTRL] &&
1426       poll_server_rd[CTRL] && poll_server_wr[CTRL]) {
1427      /* listener socket is monitored to allow client to establish
1428         secondary tunnel only when this tunnel is not established
1429         and primary one is fully operational */
1430      FD_SET(rootfd, &input);
1431      maxfd = rootfd;
1432    }
1433
1434    /* set tunnel sockets to wait for */
1435    for(i = 0; i <= max_tunnel_idx; i++) {
1436      /* client side socket monitoring */
1437      if(clientfd[i] != CURL_SOCKET_BAD) {
1438        if(poll_client_rd[i]) {
1439          /* unless told not to do so, monitor readability */
1440          FD_SET(clientfd[i], &input);
1441          if(clientfd[i] > maxfd)
1442            maxfd = clientfd[i];
1443        }
1444        if(poll_client_wr[i] && toc[i]) {
1445          /* unless told not to do so, monitor writeability
1446             if there is data ready to be sent to client */
1447          FD_SET(clientfd[i], &output);
1448          if(clientfd[i] > maxfd)
1449            maxfd = clientfd[i];
1450        }
1451      }
1452      /* server side socket monitoring */
1453      if(serverfd[i] != CURL_SOCKET_BAD) {
1454        if(poll_server_rd[i]) {
1455          /* unless told not to do so, monitor readability */
1456          FD_SET(serverfd[i], &input);
1457          if(serverfd[i] > maxfd)
1458            maxfd = serverfd[i];
1459        }
1460        if(poll_server_wr[i] && tos[i]) {
1461          /* unless told not to do so, monitor writeability
1462             if there is data ready to be sent to server */
1463          FD_SET(serverfd[i], &output);
1464          if(serverfd[i] > maxfd)
1465            maxfd = serverfd[i];
1466        }
1467      }
1468    }
1469    if(got_exit_signal)
1470      break;
1471
1472    rc = select((int)maxfd + 1, &input, &output, NULL, &timeout);
1473
1474    if(rc > 0) {
1475      /* socket action */
1476      bool tcp_fin_wr;
1477
1478      if(got_exit_signal)
1479        break;
1480
1481      tcp_fin_wr = FALSE;
1482
1483      /* ---------------------------------------------------------- */
1484
1485      /* passive mode FTP may establish a secondary tunnel */
1486      if((clientfd[DATA] == CURL_SOCKET_BAD) &&
1487         (serverfd[DATA] == CURL_SOCKET_BAD) && FD_ISSET(rootfd, &input)) {
1488        /* a new connection on listener socket (most likely from client) */
1489        curl_socket_t datafd = accept(rootfd, NULL, NULL);
1490        if(datafd != CURL_SOCKET_BAD) {
1491          struct httprequest req2;
1492          int err = 0;
1493          memset(&req2, 0, sizeof(req2));
1494          logmsg("====> Client connect DATA");
1495#ifdef TCP_NODELAY
1496          /* Disable the Nagle algorithm */
1497          flag = 1;
1498          if(0 != setsockopt(datafd, IPPROTO_TCP, TCP_NODELAY,
1499                             (void *)&flag, sizeof(flag)))
1500            logmsg("====> TCP_NODELAY for client DATA conection failed");
1501          else
1502            logmsg("TCP_NODELAY set for client DATA conection");
1503#endif
1504          req2.pipelining = FALSE;
1505          init_httprequest(&req2);
1506          while(!req2.done_processing) {
1507            err = get_request(datafd, &req2);
1508            if(err < 0) {
1509              /* this socket must be closed, done or not */
1510              break;
1511            }
1512          }
1513
1514          /* skip this and close the socket if err < 0 */
1515          if(err >= 0) {
1516            err = send_doc(datafd, &req2);
1517            if(!err && req2.connect_request) {
1518              /* sleep to prevent triggering libcurl known bug #39. */
1519              for(loop = 2; (loop > 0) && !got_exit_signal; loop--)
1520                wait_ms(250);
1521              if(!got_exit_signal) {
1522                /* connect to the server */
1523                serverfd[DATA] = connect_to(ipaddr, req2.connect_port);
1524                if(serverfd[DATA] != CURL_SOCKET_BAD) {
1525                  /* secondary tunnel established, now we have two connections */
1526                  poll_client_rd[DATA] = TRUE;
1527                  poll_client_wr[DATA] = TRUE;
1528                  poll_server_rd[DATA] = TRUE;
1529                  poll_server_wr[DATA] = TRUE;
1530                  max_tunnel_idx = DATA;
1531                  secondary = TRUE;
1532                  toc[DATA] = 0;
1533                  tos[DATA] = 0;
1534                  clientfd[DATA] = datafd;
1535                  datafd = CURL_SOCKET_BAD;
1536                }
1537              }
1538            }
1539          }
1540          if(datafd != CURL_SOCKET_BAD) {
1541            /* secondary tunnel not established */
1542            shutdown(datafd, SHUT_RDWR);
1543            sclose(datafd);
1544          }
1545        }
1546        if(got_exit_signal)
1547          break;
1548      }
1549
1550      /* ---------------------------------------------------------- */
1551
1552      /* react to tunnel endpoint readable/writeable notifications */
1553      for(i = 0; i <= max_tunnel_idx; i++) {
1554        size_t len;
1555        if(clientfd[i] != CURL_SOCKET_BAD) {
1556          len = sizeof(readclient[i]) - tos[i];
1557          if(len && FD_ISSET(clientfd[i], &input)) {
1558            /* read from client */
1559            rc = sread(clientfd[i], &readclient[i][tos[i]], len);
1560            if(rc <= 0) {
1561              logmsg("[%s] got %zd, STOP READING client", data_or_ctrl(i), rc);
1562              shutdown(clientfd[i], SHUT_RD);
1563              poll_client_rd[i] = FALSE;
1564            }
1565            else {
1566              logmsg("[%s] READ %zd bytes from client", data_or_ctrl(i), rc);
1567              logmsg("[%s] READ \"%s\"", data_or_ctrl(i),
1568                     data_to_hex(&readclient[i][tos[i]], rc));
1569              tos[i] += rc;
1570            }
1571          }
1572        }
1573        if(serverfd[i] != CURL_SOCKET_BAD) {
1574          len = sizeof(readserver[i])-toc[i];
1575          if(len && FD_ISSET(serverfd[i], &input)) {
1576            /* read from server */
1577            rc = sread(serverfd[i], &readserver[i][toc[i]], len);
1578            if(rc <= 0) {
1579              logmsg("[%s] got %zd, STOP READING server", data_or_ctrl(i), rc);
1580              shutdown(serverfd[i], SHUT_RD);
1581              poll_server_rd[i] = FALSE;
1582            }
1583            else {
1584              logmsg("[%s] READ %zd bytes from server", data_or_ctrl(i), rc);
1585              logmsg("[%s] READ \"%s\"", data_or_ctrl(i),
1586                     data_to_hex(&readserver[i][toc[i]], rc));
1587              toc[i] += rc;
1588            }
1589          }
1590        }
1591        if(clientfd[i] != CURL_SOCKET_BAD) {
1592          if(toc[i] && FD_ISSET(clientfd[i], &output)) {
1593            /* write to client */
1594            rc = swrite(clientfd[i], readserver[i], toc[i]);
1595            if(rc <= 0) {
1596              logmsg("[%s] got %zd, STOP WRITING client", data_or_ctrl(i), rc);
1597              shutdown(clientfd[i], SHUT_WR);
1598              poll_client_wr[i] = FALSE;
1599              tcp_fin_wr = TRUE;
1600            }
1601            else {
1602              logmsg("[%s] SENT %zd bytes to client", data_or_ctrl(i), rc);
1603              logmsg("[%s] SENT \"%s\"", data_or_ctrl(i),
1604                     data_to_hex(readserver[i], rc));
1605              if(toc[i] - rc)
1606                memmove(&readserver[i][0], &readserver[i][rc], toc[i]-rc);
1607              toc[i] -= rc;
1608            }
1609          }
1610        }
1611        if(serverfd[i] != CURL_SOCKET_BAD) {
1612          if(tos[i] && FD_ISSET(serverfd[i], &output)) {
1613            /* write to server */
1614            rc = swrite(serverfd[i], readclient[i], tos[i]);
1615            if(rc <= 0) {
1616              logmsg("[%s] got %zd, STOP WRITING server", data_or_ctrl(i), rc);
1617              shutdown(serverfd[i], SHUT_WR);
1618              poll_server_wr[i] = FALSE;
1619              tcp_fin_wr = TRUE;
1620            }
1621            else {
1622              logmsg("[%s] SENT %zd bytes to server", data_or_ctrl(i), rc);
1623              logmsg("[%s] SENT \"%s\"", data_or_ctrl(i),
1624                     data_to_hex(readclient[i], rc));
1625              if(tos[i] - rc)
1626                memmove(&readclient[i][0], &readclient[i][rc], tos[i]-rc);
1627              tos[i] -= rc;
1628            }
1629          }
1630        }
1631      }
1632      if(got_exit_signal)
1633        break;
1634
1635      /* ---------------------------------------------------------- */
1636
1637      /* endpoint read/write disabling, endpoint closing and tunnel teardown */
1638      for(i = 0; i <= max_tunnel_idx; i++) {
1639        for(loop = 2; loop > 0; loop--) {
1640          /* loop twice to satisfy condition interdependencies without
1641             having to await select timeout or another socket event */
1642          if(clientfd[i] != CURL_SOCKET_BAD) {
1643            if(poll_client_rd[i] && !poll_server_wr[i]) {
1644              logmsg("[%s] DISABLED READING client", data_or_ctrl(i));
1645              shutdown(clientfd[i], SHUT_RD);
1646              poll_client_rd[i] = FALSE;
1647            }
1648            if(poll_client_wr[i] && !poll_server_rd[i] && !toc[i]) {
1649              logmsg("[%s] DISABLED WRITING client", data_or_ctrl(i));
1650              shutdown(clientfd[i], SHUT_WR);
1651              poll_client_wr[i] = FALSE;
1652              tcp_fin_wr = TRUE;
1653            }
1654          }
1655          if(serverfd[i] != CURL_SOCKET_BAD) {
1656            if(poll_server_rd[i] && !poll_client_wr[i]) {
1657              logmsg("[%s] DISABLED READING server", data_or_ctrl(i));
1658              shutdown(serverfd[i], SHUT_RD);
1659              poll_server_rd[i] = FALSE;
1660            }
1661            if(poll_server_wr[i] && !poll_client_rd[i] && !tos[i]) {
1662              logmsg("[%s] DISABLED WRITING server", data_or_ctrl(i));
1663              shutdown(serverfd[i], SHUT_WR);
1664              poll_server_wr[i] = FALSE;
1665              tcp_fin_wr = TRUE;
1666            }
1667          }
1668        }
1669      }
1670
1671      if(tcp_fin_wr)
1672        /* allow kernel to place FIN bit packet on the wire */
1673        wait_ms(250);
1674
1675      /* socket clearing */
1676      for(i = 0; i <= max_tunnel_idx; i++) {
1677        for(loop = 2; loop > 0; loop--) {
1678          if(clientfd[i] != CURL_SOCKET_BAD) {
1679            if(!poll_client_wr[i] && !poll_client_rd[i]) {
1680              logmsg("[%s] CLOSING client socket", data_or_ctrl(i));
1681              sclose(clientfd[i]);
1682              clientfd[i] = CURL_SOCKET_BAD;
1683              if(serverfd[i] == CURL_SOCKET_BAD) {
1684                logmsg("[%s] ENDING", data_or_ctrl(i));
1685                if(i == DATA)
1686                  secondary = FALSE;
1687                else
1688                  primary = FALSE;
1689              }
1690            }
1691          }
1692          if(serverfd[i] != CURL_SOCKET_BAD) {
1693            if(!poll_server_wr[i] && !poll_server_rd[i]) {
1694              logmsg("[%s] CLOSING server socket", data_or_ctrl(i));
1695              sclose(serverfd[i]);
1696              serverfd[i] = CURL_SOCKET_BAD;
1697              if(clientfd[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        }
1707      }
1708
1709      /* ---------------------------------------------------------- */
1710
1711      max_tunnel_idx = secondary ? DATA : CTRL;
1712
1713      if(!primary)
1714        /* exit loop upon primary tunnel teardown */
1715        break;
1716
1717    } /* (rc > 0) */
1718
1719  }
1720
1721http_connect_cleanup:
1722
1723  for(i = DATA; i >= CTRL; i--) {
1724    if(serverfd[i] != CURL_SOCKET_BAD) {
1725      logmsg("[%s] CLOSING server socket (cleanup)", data_or_ctrl(i));
1726      shutdown(serverfd[i], SHUT_RDWR);
1727      sclose(serverfd[i]);
1728    }
1729    if(clientfd[i] != CURL_SOCKET_BAD) {
1730      logmsg("[%s] CLOSING client socket (cleanup)", data_or_ctrl(i));
1731      shutdown(clientfd[i], SHUT_RDWR);
1732      sclose(clientfd[i]);
1733    }
1734    if((serverfd[i] != CURL_SOCKET_BAD) ||
1735       (clientfd[i] != CURL_SOCKET_BAD)) {
1736      logmsg("[%s] ABORTING", data_or_ctrl(i));
1737    }
1738  }
1739
1740  *infdp = CURL_SOCKET_BAD;
1741}
1742
1743/* returns a socket handle, or 0 if there are no more waiting sockets,
1744   or < 0 if there was an error */
1745static curl_socket_t accept_connection(curl_socket_t sock)
1746{
1747  curl_socket_t msgsock = CURL_SOCKET_BAD;
1748  int error;
1749  int flag = 1;
1750
1751  if(MAX_SOCKETS == num_sockets) {
1752    logmsg("Too many open sockets!");
1753    return CURL_SOCKET_BAD;
1754  }
1755
1756  msgsock = accept(sock, NULL, NULL);
1757
1758  if(got_exit_signal) {
1759    if(CURL_SOCKET_BAD != msgsock)
1760      sclose(msgsock);
1761    return CURL_SOCKET_BAD;
1762  }
1763
1764  if(CURL_SOCKET_BAD == msgsock) {
1765    error = SOCKERRNO;
1766    if(EAGAIN == error || EWOULDBLOCK == error) {
1767      /* nothing to accept */
1768      return 0;
1769    }
1770    logmsg("MAJOR ERROR: accept() failed with error: (%d) %s",
1771           error, strerror(error));
1772    return CURL_SOCKET_BAD;
1773  }
1774
1775  if(0 != curlx_nonblock(msgsock, TRUE)) {
1776    error = SOCKERRNO;
1777    logmsg("curlx_nonblock failed with error: (%d) %s",
1778           error, strerror(error));
1779    sclose(msgsock);
1780    return CURL_SOCKET_BAD;
1781  }
1782
1783  if(0 != setsockopt(msgsock, SOL_SOCKET, SO_KEEPALIVE,
1784                     (void *)&flag, sizeof(flag))) {
1785    error = SOCKERRNO;
1786    logmsg("setsockopt(SO_KEEPALIVE) failed with error: (%d) %s",
1787           error, strerror(error));
1788    sclose(msgsock);
1789    return CURL_SOCKET_BAD;
1790  }
1791
1792  /*
1793  ** As soon as this server accepts a connection from the test harness it
1794  ** must set the server logs advisor read lock to indicate that server
1795  ** logs should not be read until this lock is removed by this server.
1796  */
1797
1798  if(!serverlogslocked)
1799    set_advisor_read_lock(SERVERLOGS_LOCK);
1800  serverlogslocked += 1;
1801
1802  logmsg("====> Client connect");
1803
1804  all_sockets[num_sockets] = msgsock;
1805  num_sockets += 1;
1806
1807#ifdef TCP_NODELAY
1808  /*
1809   * Disable the Nagle algorithm to make it easier to send out a large
1810   * response in many small segments to torture the clients more.
1811   */
1812  if(0 != setsockopt(msgsock, IPPROTO_TCP, TCP_NODELAY,
1813                     (void *)&flag, sizeof(flag)))
1814    logmsg("====> TCP_NODELAY failed");
1815  else
1816    logmsg("TCP_NODELAY set");
1817#endif
1818
1819  return msgsock;
1820}
1821
1822/* returns 1 if the connection should be serviced again immediately, 0 if there
1823   is no data waiting, or < 0 if it should be closed */
1824static int service_connection(curl_socket_t msgsock, struct httprequest *req,
1825                              curl_socket_t listensock,
1826                              const char *connecthost)
1827{
1828  if(got_exit_signal)
1829    return -1;
1830
1831  while(!req->done_processing) {
1832    int rc = get_request(msgsock, req);
1833    if (rc <= 0) {
1834      /* Nothing further to read now (possibly because the socket was closed */
1835      return rc;
1836    }
1837  }
1838
1839  if(prevbounce) {
1840    /* bounce treatment requested */
1841    if((req->testno == prevtestno) &&
1842       (req->partno == prevpartno)) {
1843      req->partno++;
1844      logmsg("BOUNCE part number to %ld", req->partno);
1845    }
1846    else {
1847      prevbounce = FALSE;
1848      prevtestno = -1;
1849      prevpartno = -1;
1850    }
1851  }
1852
1853  send_doc(msgsock, req);
1854  if(got_exit_signal)
1855    return -1;
1856
1857  if(req->testno < 0) {
1858    logmsg("special request received, no persistency");
1859    return -1;
1860  }
1861  if(!req->open) {
1862    logmsg("instructed to close connection after server-reply");
1863    return -1;
1864  }
1865
1866  if(req->connect_request) {
1867    /* a CONNECT request, setup and talk the tunnel */
1868    if(!is_proxy) {
1869      logmsg("received CONNECT but isn't running as proxy!");
1870      return 1;
1871    }
1872    else {
1873      http_connect(&msgsock, listensock, connecthost, req->connect_port);
1874      return -1;
1875    }
1876  }
1877
1878  /* if we got a CONNECT, loop and get another request as well! */
1879
1880  if(req->open) {
1881    logmsg("=> persistant connection request ended, awaits new request\n");
1882    return 1;
1883  }
1884
1885  return -1;
1886}
1887
1888int main(int argc, char *argv[])
1889{
1890  srvr_sockaddr_union_t me;
1891  curl_socket_t sock = CURL_SOCKET_BAD;
1892  int wrotepidfile = 0;
1893  int flag;
1894  unsigned short port = DEFAULT_PORT;
1895  char *pidname= (char *)".http.pid";
1896  struct httprequest req;
1897  int rc;
1898  int error;
1899  int arg=1;
1900  long pid;
1901  const char *connecthost = "127.0.0.1";
1902
1903  /* a default CONNECT port is basically pointless but still ... */
1904  size_t socket_idx;
1905
1906  memset(&req, 0, sizeof(req));
1907
1908  while(argc>arg) {
1909    if(!strcmp("--version", argv[arg])) {
1910      printf("sws IPv4%s"
1911             "\n"
1912             ,
1913#ifdef ENABLE_IPV6
1914             "/IPv6"
1915#else
1916             ""
1917#endif
1918             );
1919      return 0;
1920    }
1921    else if(!strcmp("--pidfile", argv[arg])) {
1922      arg++;
1923      if(argc>arg)
1924        pidname = argv[arg++];
1925    }
1926    else if(!strcmp("--logfile", argv[arg])) {
1927      arg++;
1928      if(argc>arg)
1929        serverlogfile = argv[arg++];
1930    }
1931    else if(!strcmp("--gopher", argv[arg])) {
1932      arg++;
1933      use_gopher = TRUE;
1934      end_of_headers = "\r\n"; /* gopher style is much simpler */
1935    }
1936    else if(!strcmp("--ipv4", argv[arg])) {
1937#ifdef ENABLE_IPV6
1938      ipv_inuse = "IPv4";
1939      use_ipv6 = FALSE;
1940#endif
1941      arg++;
1942    }
1943    else if(!strcmp("--ipv6", argv[arg])) {
1944#ifdef ENABLE_IPV6
1945      ipv_inuse = "IPv6";
1946      use_ipv6 = TRUE;
1947#endif
1948      arg++;
1949    }
1950    else if(!strcmp("--port", argv[arg])) {
1951      arg++;
1952      if(argc>arg) {
1953        char *endptr;
1954        unsigned long ulnum = strtoul(argv[arg], &endptr, 10);
1955        if((endptr != argv[arg] + strlen(argv[arg])) ||
1956           (ulnum < 1025UL) || (ulnum > 65535UL)) {
1957          fprintf(stderr, "sws: invalid --port argument (%s)\n",
1958                  argv[arg]);
1959          return 0;
1960        }
1961        port = curlx_ultous(ulnum);
1962        arg++;
1963      }
1964    }
1965    else if(!strcmp("--srcdir", argv[arg])) {
1966      arg++;
1967      if(argc>arg) {
1968        path = argv[arg];
1969        arg++;
1970      }
1971    }
1972    else if(!strcmp("--connect", argv[arg])) {
1973      /* The connect host IP number that the proxy will connect to no matter
1974         what the client asks for, but also use this as a hint that we run as
1975         a proxy and do a few different internal choices */
1976      arg++;
1977      if(argc>arg) {
1978        connecthost = argv[arg];
1979        arg++;
1980        is_proxy = TRUE;
1981        logmsg("Run as proxy, CONNECT to host %s", connecthost);
1982      }
1983    }
1984    else {
1985      puts("Usage: sws [option]\n"
1986           " --version\n"
1987           " --logfile [file]\n"
1988           " --pidfile [file]\n"
1989           " --ipv4\n"
1990           " --ipv6\n"
1991           " --port [port]\n"
1992           " --srcdir [path]\n"
1993           " --connect [ip4-addr]\n"
1994           " --gopher");
1995      return 0;
1996    }
1997  }
1998
1999#ifdef WIN32
2000  win32_init();
2001  atexit(win32_cleanup);
2002#endif
2003
2004  install_signal_handlers();
2005
2006  pid = (long)getpid();
2007
2008#ifdef ENABLE_IPV6
2009  if(!use_ipv6)
2010#endif
2011    sock = socket(AF_INET, SOCK_STREAM, 0);
2012#ifdef ENABLE_IPV6
2013  else
2014    sock = socket(AF_INET6, SOCK_STREAM, 0);
2015#endif
2016
2017  all_sockets[0] = sock;
2018  num_sockets = 1;
2019
2020  if(CURL_SOCKET_BAD == sock) {
2021    error = SOCKERRNO;
2022    logmsg("Error creating socket: (%d) %s",
2023           error, strerror(error));
2024    goto sws_cleanup;
2025  }
2026
2027  flag = 1;
2028  if(0 != setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
2029                     (void *)&flag, sizeof(flag))) {
2030    error = SOCKERRNO;
2031    logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s",
2032           error, strerror(error));
2033    goto sws_cleanup;
2034  }
2035  if(0 != curlx_nonblock(sock, TRUE)) {
2036    error = SOCKERRNO;
2037    logmsg("curlx_nonblock failed with error: (%d) %s",
2038           error, strerror(error));
2039    goto sws_cleanup;
2040  }
2041
2042#ifdef ENABLE_IPV6
2043  if(!use_ipv6) {
2044#endif
2045    memset(&me.sa4, 0, sizeof(me.sa4));
2046    me.sa4.sin_family = AF_INET;
2047    me.sa4.sin_addr.s_addr = INADDR_ANY;
2048    me.sa4.sin_port = htons(port);
2049    rc = bind(sock, &me.sa, sizeof(me.sa4));
2050#ifdef ENABLE_IPV6
2051  }
2052  else {
2053    memset(&me.sa6, 0, sizeof(me.sa6));
2054    me.sa6.sin6_family = AF_INET6;
2055    me.sa6.sin6_addr = in6addr_any;
2056    me.sa6.sin6_port = htons(port);
2057    rc = bind(sock, &me.sa, sizeof(me.sa6));
2058  }
2059#endif /* ENABLE_IPV6 */
2060  if(0 != rc) {
2061    error = SOCKERRNO;
2062    logmsg("Error binding socket on port %hu: (%d) %s",
2063           port, error, strerror(error));
2064    goto sws_cleanup;
2065  }
2066
2067  logmsg("Running %s %s version on port %d",
2068         use_gopher?"GOPHER":"HTTP", ipv_inuse, (int)port);
2069
2070  /* start accepting connections */
2071  rc = listen(sock, 5);
2072  if(0 != rc) {
2073    error = SOCKERRNO;
2074    logmsg("listen() failed with error: (%d) %s",
2075           error, strerror(error));
2076    goto sws_cleanup;
2077  }
2078
2079  /*
2080  ** As soon as this server writes its pid file the test harness will
2081  ** attempt to connect to this server and initiate its verification.
2082  */
2083
2084  wrotepidfile = write_pidfile(pidname);
2085  if(!wrotepidfile)
2086    goto sws_cleanup;
2087
2088  /* initialization of httprequest struct is done before get_request(), but
2089     the pipelining struct field must be initialized previously to FALSE
2090     every time a new connection arrives. */
2091
2092  req.pipelining = FALSE;
2093  init_httprequest(&req);
2094
2095  for(;;) {
2096    fd_set input;
2097    fd_set output;
2098    struct timeval timeout = {0, 250000L}; /* 250 ms */
2099    curl_socket_t maxfd = (curl_socket_t)-1;
2100
2101    /* Clear out closed sockets */
2102    for (socket_idx = num_sockets - 1; socket_idx >= 1; --socket_idx) {
2103      if (CURL_SOCKET_BAD == all_sockets[socket_idx]) {
2104        char* dst = (char *) (all_sockets + socket_idx);
2105        char* src = (char *) (all_sockets + socket_idx + 1);
2106        char* end = (char *) (all_sockets + num_sockets);
2107        memmove(dst, src, end - src);
2108        num_sockets -= 1;
2109      }
2110    }
2111
2112    if(got_exit_signal)
2113      goto sws_cleanup;
2114
2115    /* Set up for select*/
2116    FD_ZERO(&input);
2117    FD_ZERO(&output);
2118
2119    for (socket_idx = 0; socket_idx < num_sockets; ++socket_idx) {
2120      /* Listen on all sockets */
2121      FD_SET(all_sockets[socket_idx], &input);
2122      if(all_sockets[socket_idx] > maxfd)
2123        maxfd = all_sockets[socket_idx];
2124    }
2125
2126    if(got_exit_signal)
2127      goto sws_cleanup;
2128
2129    rc = select((int)maxfd + 1, &input, &output, NULL, &timeout);
2130    if (rc < 0) {
2131      error = SOCKERRNO;
2132      logmsg("select() failed with error: (%d) %s",
2133             error, strerror(error));
2134      goto sws_cleanup;
2135    }
2136
2137    if(got_exit_signal)
2138      goto sws_cleanup;
2139
2140    if (rc == 0) {
2141      /* Timed out - try again*/
2142      continue;
2143    }
2144
2145    /* Check if the listening socket is ready to accept */
2146    if (FD_ISSET(all_sockets[0], &input)) {
2147      /* Service all queued connections */
2148      curl_socket_t msgsock;
2149      do {
2150        msgsock = accept_connection(sock);
2151        logmsg("accept_connection %d returned %d", sock, msgsock);
2152        if (CURL_SOCKET_BAD == msgsock)
2153          goto sws_cleanup;
2154      } while (msgsock > 0);
2155    }
2156
2157    /* Service all connections that are ready */
2158    for (socket_idx = 1; socket_idx < num_sockets; ++socket_idx) {
2159      if (FD_ISSET(all_sockets[socket_idx], &input)) {
2160        if(got_exit_signal)
2161          goto sws_cleanup;
2162
2163        /* Service this connection until it has nothing available */
2164        do {
2165          rc = service_connection(all_sockets[socket_idx], &req, sock,
2166                                  connecthost);
2167          if(got_exit_signal)
2168            goto sws_cleanup;
2169
2170          if (rc < 0) {
2171            logmsg("====> Client disconnect %d", req.connmon);
2172
2173            if(req.connmon) {
2174              const char *keepopen="[DISCONNECT]\n";
2175              storerequest((char *)keepopen, strlen(keepopen));
2176            }
2177
2178            if(!req.open)
2179              /* When instructed to close connection after server-reply we
2180                 wait a very small amount of time before doing so. If this
2181                 is not done client might get an ECONNRESET before reading
2182                 a single byte of server-reply. */
2183              wait_ms(50);
2184
2185            if(all_sockets[socket_idx] != CURL_SOCKET_BAD) {
2186              sclose(all_sockets[socket_idx]);
2187              all_sockets[socket_idx] = CURL_SOCKET_BAD;
2188            }
2189
2190            serverlogslocked -= 1;
2191            if(!serverlogslocked)
2192              clear_advisor_read_lock(SERVERLOGS_LOCK);
2193
2194            if (req.testno == DOCNUMBER_QUIT)
2195              goto sws_cleanup;
2196          }
2197
2198          /* Reset the request, unless we're still in the middle of reading */
2199          if (rc != 0)
2200            init_httprequest(&req);
2201        } while (rc > 0);
2202      }
2203    }
2204
2205    if(got_exit_signal)
2206      goto sws_cleanup;
2207  }
2208
2209sws_cleanup:
2210
2211  for (socket_idx = 1; socket_idx < num_sockets; ++socket_idx)
2212    if((all_sockets[socket_idx] != sock) &&
2213     (all_sockets[socket_idx] != CURL_SOCKET_BAD))
2214      sclose(all_sockets[socket_idx]);
2215
2216  if(sock != CURL_SOCKET_BAD)
2217    sclose(sock);
2218
2219  if(got_exit_signal)
2220    logmsg("signalled to die");
2221
2222  if(wrotepidfile)
2223    unlink(pidname);
2224
2225  if(serverlogslocked) {
2226    serverlogslocked = 0;
2227    clear_advisor_read_lock(SERVERLOGS_LOCK);
2228  }
2229
2230  restore_signal_handlers();
2231
2232  if(got_exit_signal) {
2233    logmsg("========> %s sws (port: %d pid: %ld) exits with signal (%d)",
2234           ipv_inuse, (int)port, pid, exit_signal);
2235    /*
2236     * To properly set the return status of the process we
2237     * must raise the same signal SIGINT or SIGTERM that we
2238     * caught and let the old handler take care of it.
2239     */
2240    raise(exit_signal);
2241  }
2242
2243  logmsg("========> sws quits");
2244  return 0;
2245}
2246
2247