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