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