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