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