• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22 #include "server_setup.h"
23 
24 /* sws.c: simple (silly?) web server
25 
26    This code was originally graciously donated to the project by Juergen
27    Wilke. Thanks a bunch!
28 
29  */
30 
31 #ifdef HAVE_SIGNAL_H
32 #include <signal.h>
33 #endif
34 #ifdef HAVE_NETINET_IN_H
35 #include <netinet/in.h>
36 #endif
37 #ifdef HAVE_ARPA_INET_H
38 #include <arpa/inet.h>
39 #endif
40 #ifdef HAVE_NETDB_H
41 #include <netdb.h>
42 #endif
43 #ifdef HAVE_NETINET_TCP_H
44 #include <netinet/tcp.h> /* for TCP_NODELAY */
45 #endif
46 
47 #define ENABLE_CURLX_PRINTF
48 /* make the curlx header define all printf() functions to use the curlx_*
49    versions instead */
50 #include "curlx.h" /* from the private lib dir */
51 #include "getpart.h"
52 #include "inet_pton.h"
53 #include "util.h"
54 #include "server_sockaddr.h"
55 
56 /* include memdebug.h last */
57 #include "memdebug.h"
58 
59 #ifdef USE_WINSOCK
60 #undef  EINTR
61 #define EINTR    4 /* errno.h value */
62 #undef  EAGAIN
63 #define EAGAIN  11 /* errno.h value */
64 #undef  ERANGE
65 #define ERANGE  34 /* errno.h value */
66 #endif
67 
68 static enum {
69   socket_domain_inet = AF_INET
70 #ifdef ENABLE_IPV6
71   , socket_domain_inet6 = AF_INET6
72 #endif
73 #ifdef USE_UNIX_SOCKETS
74   , socket_domain_unix = AF_UNIX
75 #endif
76 } socket_domain = AF_INET;
77 static bool use_gopher = FALSE;
78 static int serverlogslocked = 0;
79 static bool is_proxy = FALSE;
80 
81 #define REQBUFSIZ 150000
82 #define REQBUFSIZ_TXT "149999"
83 
84 static long prevtestno=-1;    /* previous test number we served */
85 static long prevpartno=-1;    /* previous part number we served */
86 static bool prevbounce=FALSE; /* instructs the server to increase the part
87                                  number for a test in case the identical
88                                  testno+partno request shows up again */
89 
90 #define RCMD_NORMALREQ 0 /* default request, use the tests file normally */
91 #define RCMD_IDLE      1 /* told to sit idle */
92 #define RCMD_STREAM    2 /* told to stream */
93 
94 struct httprequest {
95   char reqbuf[REQBUFSIZ]; /* buffer area for the incoming request */
96   bool connect_request; /* if a CONNECT */
97   unsigned short connect_port; /* the port number CONNECT used */
98   size_t checkindex; /* where to start checking of the request */
99   size_t offset;     /* size of the incoming request */
100   long testno;       /* test number found in the request */
101   long partno;       /* part number found in the request */
102   bool open;      /* keep connection open info, as found in the request */
103   bool auth_req;  /* authentication required, don't wait for body unless
104                      there's an Authorization header */
105   bool auth;      /* Authorization header present in the incoming request */
106   size_t cl;      /* Content-Length of the incoming request */
107   bool digest;    /* Authorization digest header found */
108   bool ntlm;      /* Authorization ntlm header found */
109   int writedelay; /* if non-zero, delay this number of seconds between
110                      writes in the response */
111   int pipe;       /* if non-zero, expect this many requests to do a "piped"
112                      request/response */
113   int skip;       /* if non-zero, the server is instructed to not read this
114                      many bytes from a PUT/POST request. Ie the client sends N
115                      bytes said in Content-Length, but the server only reads N
116                      - skip bytes. */
117   int rcmd;       /* doing a special command, see defines above */
118   int prot_version;  /* HTTP version * 10 */
119   bool pipelining;   /* true if request is pipelined */
120   int callcount;  /* times ProcessRequest() gets called */
121   bool connmon;   /* monitor the state of the connection, log disconnects */
122   bool upgrade;   /* test case allows upgrade to http2 */
123   bool upgrade_request; /* upgrade request found and allowed */
124   int done_processing;
125 };
126 
127 #define MAX_SOCKETS 1024
128 
129 static curl_socket_t all_sockets[MAX_SOCKETS];
130 static size_t num_sockets = 0;
131 
132 static int ProcessRequest(struct httprequest *req);
133 static void storerequest(char *reqbuf, size_t totalsize);
134 
135 #define DEFAULT_PORT 8999
136 
137 #ifndef DEFAULT_LOGFILE
138 #define DEFAULT_LOGFILE "log/sws.log"
139 #endif
140 
141 const char *serverlogfile = DEFAULT_LOGFILE;
142 
143 #define SWSVERSION "curl test suite HTTP server/0.1"
144 
145 #define REQUEST_DUMP  "log/server.input"
146 #define RESPONSE_DUMP "log/server.response"
147 
148 /* when told to run as proxy, we store the logs in different files so that
149    they can co-exist with the same program running as a "server" */
150 #define REQUEST_PROXY_DUMP  "log/proxy.input"
151 #define RESPONSE_PROXY_DUMP "log/proxy.response"
152 
153 /* very-big-path support */
154 #define MAXDOCNAMELEN 140000
155 #define MAXDOCNAMELEN_TXT "139999"
156 
157 #define REQUEST_KEYWORD_SIZE 256
158 #define REQUEST_KEYWORD_SIZE_TXT "255"
159 
160 #define CMD_AUTH_REQUIRED "auth_required"
161 
162 /* 'idle' means that it will accept the request fine but never respond
163    any data. Just keep the connection alive. */
164 #define CMD_IDLE "idle"
165 
166 /* 'stream' means to send a never-ending stream of data */
167 #define CMD_STREAM "stream"
168 
169 /* 'connection-monitor' will output when a server/proxy connection gets
170    disconnected as for some cases it is important that it gets done at the
171    proper point - like with NTLM */
172 #define CMD_CONNECTIONMONITOR "connection-monitor"
173 
174 /* upgrade to http2 */
175 #define CMD_UPGRADE "upgrade"
176 
177 #define END_OF_HEADERS "\r\n\r\n"
178 
179 enum {
180   DOCNUMBER_NOTHING = -4,
181   DOCNUMBER_QUIT    = -3,
182   DOCNUMBER_WERULEZ = -2,
183   DOCNUMBER_404     = -1
184 };
185 
186 static const char *end_of_headers = END_OF_HEADERS;
187 
188 /* sent as reply to a QUIT */
189 static const char *docquit =
190 "HTTP/1.1 200 Goodbye" END_OF_HEADERS;
191 
192 /* send back this on 404 file not found */
193 static const char *doc404 = "HTTP/1.1 404 Not Found\r\n"
194     "Server: " SWSVERSION "\r\n"
195     "Connection: close\r\n"
196     "Content-Type: text/html"
197     END_OF_HEADERS
198     "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
199     "<HTML><HEAD>\n"
200     "<TITLE>404 Not Found</TITLE>\n"
201     "</HEAD><BODY>\n"
202     "<H1>Not Found</H1>\n"
203     "The requested URL was not found on this server.\n"
204     "<P><HR><ADDRESS>" SWSVERSION "</ADDRESS>\n" "</BODY></HTML>\n";
205 
206 /* do-nothing macro replacement for systems which lack siginterrupt() */
207 
208 #ifndef HAVE_SIGINTERRUPT
209 #define siginterrupt(x,y) do {} while(0)
210 #endif
211 
212 /* vars used to keep around previous signal handlers */
213 
214 typedef RETSIGTYPE (*SIGHANDLER_T)(int);
215 
216 #ifdef SIGHUP
217 static SIGHANDLER_T old_sighup_handler  = SIG_ERR;
218 #endif
219 
220 #ifdef SIGPIPE
221 static SIGHANDLER_T old_sigpipe_handler = SIG_ERR;
222 #endif
223 
224 #ifdef SIGALRM
225 static SIGHANDLER_T old_sigalrm_handler = SIG_ERR;
226 #endif
227 
228 #ifdef SIGINT
229 static SIGHANDLER_T old_sigint_handler  = SIG_ERR;
230 #endif
231 
232 #ifdef SIGTERM
233 static SIGHANDLER_T old_sigterm_handler = SIG_ERR;
234 #endif
235 
236 #if defined(SIGBREAK) && defined(WIN32)
237 static SIGHANDLER_T old_sigbreak_handler = SIG_ERR;
238 #endif
239 
240 /* var which if set indicates that the program should finish execution */
241 
242 SIG_ATOMIC_T got_exit_signal = 0;
243 
244 /* if next is set indicates the first signal handled in exit_signal_handler */
245 
246 static volatile int exit_signal = 0;
247 
248 /* signal handler that will be triggered to indicate that the program
249   should finish its execution in a controlled manner as soon as possible.
250   The first time this is called it will set got_exit_signal to one and
251   store in exit_signal the signal that triggered its execution. */
252 
exit_signal_handler(int signum)253 static RETSIGTYPE exit_signal_handler(int signum)
254 {
255   int old_errno = errno;
256   if(got_exit_signal == 0) {
257     got_exit_signal = 1;
258     exit_signal = signum;
259   }
260   (void)signal(signum, exit_signal_handler);
261   errno = old_errno;
262 }
263 
install_signal_handlers(void)264 static void install_signal_handlers(void)
265 {
266 #ifdef SIGHUP
267   /* ignore SIGHUP signal */
268   if((old_sighup_handler = signal(SIGHUP, SIG_IGN)) == SIG_ERR)
269     logmsg("cannot install SIGHUP handler: %s", strerror(errno));
270 #endif
271 #ifdef SIGPIPE
272   /* ignore SIGPIPE signal */
273   if((old_sigpipe_handler = signal(SIGPIPE, SIG_IGN)) == SIG_ERR)
274     logmsg("cannot install SIGPIPE handler: %s", strerror(errno));
275 #endif
276 #ifdef SIGALRM
277   /* ignore SIGALRM signal */
278   if((old_sigalrm_handler = signal(SIGALRM, SIG_IGN)) == SIG_ERR)
279     logmsg("cannot install SIGALRM handler: %s", strerror(errno));
280 #endif
281 #ifdef SIGINT
282   /* handle SIGINT signal with our exit_signal_handler */
283   if((old_sigint_handler = signal(SIGINT, exit_signal_handler)) == SIG_ERR)
284     logmsg("cannot install SIGINT handler: %s", strerror(errno));
285   else
286     siginterrupt(SIGINT, 1);
287 #endif
288 #ifdef SIGTERM
289   /* handle SIGTERM signal with our exit_signal_handler */
290   if((old_sigterm_handler = signal(SIGTERM, exit_signal_handler)) == SIG_ERR)
291     logmsg("cannot install SIGTERM handler: %s", strerror(errno));
292   else
293     siginterrupt(SIGTERM, 1);
294 #endif
295 #if defined(SIGBREAK) && defined(WIN32)
296   /* handle SIGBREAK signal with our exit_signal_handler */
297   if((old_sigbreak_handler = signal(SIGBREAK, exit_signal_handler)) == SIG_ERR)
298     logmsg("cannot install SIGBREAK handler: %s", strerror(errno));
299   else
300     siginterrupt(SIGBREAK, 1);
301 #endif
302 }
303 
restore_signal_handlers(void)304 static void restore_signal_handlers(void)
305 {
306 #ifdef SIGHUP
307   if(SIG_ERR != old_sighup_handler)
308     (void)signal(SIGHUP, old_sighup_handler);
309 #endif
310 #ifdef SIGPIPE
311   if(SIG_ERR != old_sigpipe_handler)
312     (void)signal(SIGPIPE, old_sigpipe_handler);
313 #endif
314 #ifdef SIGALRM
315   if(SIG_ERR != old_sigalrm_handler)
316     (void)signal(SIGALRM, old_sigalrm_handler);
317 #endif
318 #ifdef SIGINT
319   if(SIG_ERR != old_sigint_handler)
320     (void)signal(SIGINT, old_sigint_handler);
321 #endif
322 #ifdef SIGTERM
323   if(SIG_ERR != old_sigterm_handler)
324     (void)signal(SIGTERM, old_sigterm_handler);
325 #endif
326 #if defined(SIGBREAK) && defined(WIN32)
327   if(SIG_ERR != old_sigbreak_handler)
328     (void)signal(SIGBREAK, old_sigbreak_handler);
329 #endif
330 }
331 
332 /* returns true if the current socket is an IP one */
socket_domain_is_ip(void)333 static bool socket_domain_is_ip(void)
334 {
335   switch(socket_domain) {
336   case AF_INET:
337 #ifdef ENABLE_IPV6
338   case AF_INET6:
339 #endif
340     return true;
341   default:
342   /* case AF_UNIX: */
343     return false;
344   }
345 }
346 
347 /* based on the testno, parse the correct server commands */
parse_servercmd(struct httprequest * req)348 static int parse_servercmd(struct httprequest *req)
349 {
350   FILE *stream;
351   char *filename;
352   int error;
353 
354   filename = test2file(req->testno);
355 
356   stream=fopen(filename, "rb");
357   if(!stream) {
358     error = errno;
359     logmsg("fopen() failed with error: %d %s", error, strerror(error));
360     logmsg("  [1] Error opening file: %s", filename);
361     logmsg("  Couldn't open test file %ld", req->testno);
362     req->open = FALSE; /* closes connection */
363     return 1; /* done */
364   }
365   else {
366     char *orgcmd = NULL;
367     char *cmd = NULL;
368     size_t cmdsize = 0;
369     int num=0;
370 
371     /* get the custom server control "commands" */
372     error = getpart(&orgcmd, &cmdsize, "reply", "servercmd", stream);
373     fclose(stream);
374     if(error) {
375       logmsg("getpart() failed with error: %d", error);
376       req->open = FALSE; /* closes connection */
377       return 1; /* done */
378     }
379 
380     req->connmon = FALSE;
381 
382     cmd = orgcmd;
383     while(cmd && cmdsize) {
384       char *check;
385 
386       if(!strncmp(CMD_AUTH_REQUIRED, cmd, strlen(CMD_AUTH_REQUIRED))) {
387         logmsg("instructed to require authorization header");
388         req->auth_req = TRUE;
389       }
390       else if(!strncmp(CMD_IDLE, cmd, strlen(CMD_IDLE))) {
391         logmsg("instructed to idle");
392         req->rcmd = RCMD_IDLE;
393         req->open = TRUE;
394       }
395       else if(!strncmp(CMD_STREAM, cmd, strlen(CMD_STREAM))) {
396         logmsg("instructed to stream");
397         req->rcmd = RCMD_STREAM;
398       }
399       else if(!strncmp(CMD_CONNECTIONMONITOR, cmd,
400                        strlen(CMD_CONNECTIONMONITOR))) {
401         logmsg("enabled connection monitoring");
402         req->connmon = TRUE;
403       }
404       else if(!strncmp(CMD_UPGRADE, cmd, strlen(CMD_UPGRADE))) {
405         logmsg("enabled upgrade to http2");
406         req->upgrade = TRUE;
407       }
408       else if(1 == sscanf(cmd, "pipe: %d", &num)) {
409         logmsg("instructed to allow a pipe size of %d", num);
410         if(num < 0)
411           logmsg("negative pipe size ignored");
412         else if(num > 0)
413           req->pipe = num-1; /* decrease by one since we don't count the
414                                 first request in this number */
415       }
416       else if(1 == sscanf(cmd, "skip: %d", &num)) {
417         logmsg("instructed to skip this number of bytes %d", num);
418         req->skip = num;
419       }
420       else if(1 == sscanf(cmd, "writedelay: %d", &num)) {
421         logmsg("instructed to delay %d secs between packets", num);
422         req->writedelay = num;
423       }
424       else {
425         logmsg("Unknown <servercmd> instruction found: %s", cmd);
426       }
427       /* try to deal with CRLF or just LF */
428       check = strchr(cmd, '\r');
429       if(!check)
430         check = strchr(cmd, '\n');
431 
432       if(check) {
433         /* get to the letter following the newline */
434         while((*check == '\r') || (*check == '\n'))
435           check++;
436 
437         if(!*check)
438           /* if we reached a zero, get out */
439           break;
440         cmd = check;
441       }
442       else
443         break;
444     }
445     free(orgcmd);
446   }
447 
448   return 0; /* OK! */
449 }
450 
ProcessRequest(struct httprequest * req)451 static int ProcessRequest(struct httprequest *req)
452 {
453   char *line=&req->reqbuf[req->checkindex];
454   bool chunked = FALSE;
455   static char request[REQUEST_KEYWORD_SIZE];
456   static char doc[MAXDOCNAMELEN];
457   char logbuf[456];
458   int prot_major, prot_minor;
459   char *end = strstr(line, end_of_headers);
460 
461   req->callcount++;
462 
463   logmsg("Process %d bytes request%s", req->offset,
464          req->callcount > 1?" [CONTINUED]":"");
465 
466   /* try to figure out the request characteristics as soon as possible, but
467      only once! */
468 
469   if(use_gopher &&
470      (req->testno == DOCNUMBER_NOTHING) &&
471      !strncmp("/verifiedserver", line, 15)) {
472     logmsg("Are-we-friendly question received");
473     req->testno = DOCNUMBER_WERULEZ;
474     return 1; /* done */
475   }
476 
477   else if((req->testno == DOCNUMBER_NOTHING) &&
478      sscanf(line,
479             "%" REQUEST_KEYWORD_SIZE_TXT"s %" MAXDOCNAMELEN_TXT "s HTTP/%d.%d",
480             request,
481             doc,
482             &prot_major,
483             &prot_minor) == 4) {
484     char *ptr;
485 
486     req->prot_version = prot_major*10 + prot_minor;
487 
488     /* find the last slash */
489     ptr = strrchr(doc, '/');
490 
491     /* get the number after it */
492     if(ptr) {
493       if((strlen(doc) + strlen(request)) < 400)
494         snprintf(logbuf, sizeof(logbuf), "Got request: %s %s HTTP/%d.%d",
495                  request, doc, prot_major, prot_minor);
496       else
497         snprintf(logbuf, sizeof(logbuf), "Got a *HUGE* request HTTP/%d.%d",
498                  prot_major, prot_minor);
499       logmsg("%s", logbuf);
500 
501       if(!strncmp("/verifiedserver", ptr, 15)) {
502         logmsg("Are-we-friendly question received");
503         req->testno = DOCNUMBER_WERULEZ;
504         return 1; /* done */
505       }
506 
507       if(!strncmp("/quit", ptr, 5)) {
508         logmsg("Request-to-quit received");
509         req->testno = DOCNUMBER_QUIT;
510         return 1; /* done */
511       }
512 
513       ptr++; /* skip the slash */
514 
515       /* skip all non-numericals following the slash */
516       while(*ptr && !ISDIGIT(*ptr))
517         ptr++;
518 
519       req->testno = strtol(ptr, &ptr, 10);
520 
521       if(req->testno > 10000) {
522         req->partno = req->testno % 10000;
523         req->testno /= 10000;
524       }
525       else
526         req->partno = 0;
527 
528       if(req->testno) {
529 
530         snprintf(logbuf, sizeof(logbuf), "Requested test number %ld part %ld",
531                  req->testno, req->partno);
532         logmsg("%s", logbuf);
533 
534         /* find and parse <servercmd> for this test */
535         parse_servercmd(req);
536       }
537       else
538         req->testno = DOCNUMBER_NOTHING;
539 
540     }
541 
542     if(req->testno == DOCNUMBER_NOTHING) {
543       /* didn't find any in the first scan, try alternative test case
544          number placements */
545 
546       if(sscanf(req->reqbuf, "CONNECT %" MAXDOCNAMELEN_TXT "s HTTP/%d.%d",
547                 doc, &prot_major, &prot_minor) == 3) {
548         char *portp = NULL;
549         unsigned long part=0;
550 
551         snprintf(logbuf, sizeof(logbuf),
552                  "Received a CONNECT %s HTTP/%d.%d request",
553                  doc, prot_major, prot_minor);
554         logmsg("%s", logbuf);
555 
556         req->connect_request = TRUE;
557 
558         if(req->prot_version == 10)
559           req->open = FALSE; /* HTTP 1.0 closes connection by default */
560 
561         if(doc[0] == '[') {
562           char *p = &doc[1];
563           /* scan through the hexgroups and store the value of the last group
564              in the 'part' variable and use as test case number!! */
565           while(*p && (ISXDIGIT(*p) || (*p == ':') || (*p == '.'))) {
566             char *endp;
567             part = strtoul(p, &endp, 16);
568             if(ISXDIGIT(*p))
569               p = endp;
570             else
571               p++;
572           }
573           if(*p != ']')
574             logmsg("Invalid CONNECT IPv6 address format");
575           else if(*(p+1) != ':')
576             logmsg("Invalid CONNECT IPv6 port format");
577           else
578             portp = p+1;
579 
580           req->testno = part;
581         }
582         else
583           portp = strchr(doc, ':');
584 
585         if(portp && (*(portp+1) != '\0') && ISDIGIT(*(portp+1))) {
586           unsigned long ulnum = strtoul(portp+1, NULL, 10);
587           if(!ulnum || (ulnum > 65535UL))
588             logmsg("Invalid CONNECT port received");
589           else
590             req->connect_port = curlx_ultous(ulnum);
591 
592         }
593         logmsg("Port number: %d, test case number: %ld",
594                req->connect_port, req->testno);
595       }
596     }
597 
598     if(req->testno == DOCNUMBER_NOTHING) {
599       /* Still no test case number. Try to get the the number off the last dot
600          instead, IE we consider the TLD to be the test number. Test 123 can
601          then be written as "example.com.123". */
602 
603       /* find the last dot */
604       ptr = strrchr(doc, '.');
605 
606       /* get the number after it */
607       if(ptr) {
608         ptr++; /* skip the dot */
609 
610         req->testno = strtol(ptr, &ptr, 10);
611 
612         if(req->testno > 10000) {
613           req->partno = req->testno % 10000;
614           req->testno /= 10000;
615 
616           logmsg("found test %d in requested host name", req->testno);
617 
618         }
619         else
620           req->partno = 0;
621 
622         snprintf(logbuf, sizeof(logbuf),
623                  "Requested test number %ld part %ld (from host name)",
624                  req->testno, req->partno);
625         logmsg("%s", logbuf);
626 
627       }
628 
629       if(!req->testno) {
630         logmsg("Did not find test number in PATH");
631         req->testno = DOCNUMBER_404;
632       }
633       else
634         parse_servercmd(req);
635     }
636   }
637   else if((req->offset >= 3) && (req->testno == DOCNUMBER_NOTHING)) {
638     logmsg("** Unusual request. Starts with %02x %02x %02x",
639            line[0], line[1], line[2]);
640   }
641 
642   if(!end) {
643     /* we don't have a complete request yet! */
644     logmsg("request not complete yet");
645     return 0; /* not complete yet */
646   }
647   logmsg("- request found to be complete");
648 
649   if(use_gopher) {
650     /* when using gopher we cannot check the request until the entire
651        thing has been received */
652     char *ptr;
653 
654     /* find the last slash in the line */
655     ptr = strrchr(line, '/');
656 
657     if(ptr) {
658       ptr++; /* skip the slash */
659 
660       /* skip all non-numericals following the slash */
661       while(*ptr && !ISDIGIT(*ptr))
662         ptr++;
663 
664       req->testno = strtol(ptr, &ptr, 10);
665 
666       if(req->testno > 10000) {
667         req->partno = req->testno % 10000;
668         req->testno /= 10000;
669       }
670       else
671         req->partno = 0;
672 
673       snprintf(logbuf, sizeof(logbuf),
674                "Requested GOPHER test number %ld part %ld",
675                req->testno, req->partno);
676       logmsg("%s", logbuf);
677     }
678   }
679 
680   if(req->pipe)
681     /* we do have a full set, advance the checkindex to after the end of the
682        headers, for the pipelining case mostly */
683     req->checkindex += (end - line) + strlen(end_of_headers);
684 
685   /* **** Persistence ****
686    *
687    * If the request is a HTTP/1.0 one, we close the connection unconditionally
688    * when we're done.
689    *
690    * If the request is a HTTP/1.1 one, we MUST check for a "Connection:"
691    * header that might say "close". If it does, we close a connection when
692    * this request is processed. Otherwise, we keep the connection alive for X
693    * seconds.
694    */
695 
696   do {
697     if(got_exit_signal)
698       return 1; /* done */
699 
700     if((req->cl==0) && strncasecompare("Content-Length:", line, 15)) {
701       /* If we don't ignore content-length, we read it and we read the whole
702          request including the body before we return. If we've been told to
703          ignore the content-length, we will return as soon as all headers
704          have been received */
705       char *endptr;
706       char *ptr = line + 15;
707       unsigned long clen = 0;
708       while(*ptr && ISSPACE(*ptr))
709         ptr++;
710       endptr = ptr;
711       errno = 0;
712       clen = strtoul(ptr, &endptr, 10);
713       if((ptr == endptr) || !ISSPACE(*endptr) || (ERANGE == errno)) {
714         /* this assumes that a zero Content-Length is valid */
715         logmsg("Found invalid Content-Length: (%s) in the request", ptr);
716         req->open = FALSE; /* closes connection */
717         return 1; /* done */
718       }
719       req->cl = clen - req->skip;
720 
721       logmsg("Found Content-Length: %lu in the request", clen);
722       if(req->skip)
723         logmsg("... but will abort after %zu bytes", req->cl);
724       break;
725     }
726     else if(strncasecompare("Transfer-Encoding: chunked", line,
727                             strlen("Transfer-Encoding: chunked"))) {
728       /* chunked data coming in */
729       chunked = TRUE;
730     }
731 
732     if(chunked) {
733       if(strstr(req->reqbuf, "\r\n0\r\n\r\n"))
734         /* end of chunks reached */
735         return 1; /* done */
736       else
737         return 0; /* not done */
738     }
739 
740     line = strchr(line, '\n');
741     if(line)
742       line++;
743 
744   } while(line);
745 
746   if(!req->auth && strstr(req->reqbuf, "Authorization:")) {
747     req->auth = TRUE; /* Authorization: header present! */
748     if(req->auth_req)
749       logmsg("Authorization header found, as required");
750   }
751 
752   if(!req->digest && strstr(req->reqbuf, "Authorization: Digest")) {
753     /* If the client is passing this Digest-header, we set the part number
754        to 1000. Not only to spice up the complexity of this, but to make
755        Digest stuff to work in the test suite. */
756     req->partno += 1000;
757     req->digest = TRUE; /* header found */
758     logmsg("Received Digest request, sending back data %ld", req->partno);
759   }
760   else if(!req->ntlm &&
761           strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAD")) {
762     /* If the client is passing this type-3 NTLM header */
763     req->partno += 1002;
764     req->ntlm = TRUE; /* NTLM found */
765     logmsg("Received NTLM type-3, sending back data %ld", req->partno);
766     if(req->cl) {
767       logmsg("  Expecting %zu POSTed bytes", req->cl);
768     }
769   }
770   else if(!req->ntlm &&
771           strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAB")) {
772     /* If the client is passing this type-1 NTLM header */
773     req->partno += 1001;
774     req->ntlm = TRUE; /* NTLM found */
775     logmsg("Received NTLM type-1, sending back data %ld", req->partno);
776   }
777   else if((req->partno >= 1000) &&
778           strstr(req->reqbuf, "Authorization: Basic")) {
779     /* If the client is passing this Basic-header and the part number is
780        already >=1000, we add 1 to the part number.  This allows simple Basic
781        authentication negotiation to work in the test suite. */
782     req->partno += 1;
783     logmsg("Received Basic request, sending back data %ld", req->partno);
784   }
785   if(strstr(req->reqbuf, "Connection: close"))
786     req->open = FALSE; /* close connection after this request */
787 
788   if(!req->pipe &&
789      req->open &&
790      req->prot_version >= 11 &&
791      end &&
792      req->reqbuf + req->offset > end + strlen(end_of_headers) &&
793      !req->cl &&
794      (!strncmp(req->reqbuf, "GET", strlen("GET")) ||
795       !strncmp(req->reqbuf, "HEAD", strlen("HEAD")))) {
796     /* If we have a persistent connection, HTTP version >= 1.1
797        and GET/HEAD request, enable pipelining. */
798     req->checkindex = (end - req->reqbuf) + strlen(end_of_headers);
799     req->pipelining = TRUE;
800   }
801 
802   while(req->pipe) {
803     if(got_exit_signal)
804       return 1; /* done */
805     /* scan for more header ends within this chunk */
806     line = &req->reqbuf[req->checkindex];
807     end = strstr(line, end_of_headers);
808     if(!end)
809       break;
810     req->checkindex += (end - line) + strlen(end_of_headers);
811     req->pipe--;
812   }
813 
814   /* If authentication is required and no auth was provided, end now. This
815      makes the server NOT wait for PUT/POST data and you can then make the
816      test case send a rejection before any such data has been sent. Test case
817      154 uses this.*/
818   if(req->auth_req && !req->auth) {
819     logmsg("Return early due to auth requested by none provided");
820     return 1; /* done */
821   }
822 
823   if(req->upgrade && strstr(req->reqbuf, "Upgrade:")) {
824     /* we allow upgrade and there was one! */
825     logmsg("Found Upgrade: in request and allows it");
826     req->upgrade_request = TRUE;
827   }
828 
829   if(req->cl > 0) {
830     if(req->cl <= req->offset - (end - req->reqbuf) - strlen(end_of_headers))
831       return 1; /* done */
832     else
833       return 0; /* not complete yet */
834   }
835 
836   return 1; /* done */
837 }
838 
839 /* store the entire request in a file */
storerequest(char * reqbuf,size_t totalsize)840 static void storerequest(char *reqbuf, size_t totalsize)
841 {
842   int res;
843   int error = 0;
844   size_t written;
845   size_t writeleft;
846   FILE *dump;
847   const char *dumpfile=is_proxy?REQUEST_PROXY_DUMP:REQUEST_DUMP;
848 
849   if(reqbuf == NULL)
850     return;
851   if(totalsize == 0)
852     return;
853 
854   do {
855     dump = fopen(dumpfile, "ab");
856   } while((dump == NULL) && ((error = errno) == EINTR));
857   if(dump == NULL) {
858     logmsg("[2] Error opening file %s error: %d %s",
859            dumpfile, error, strerror(error));
860     logmsg("Failed to write request input ");
861     return;
862   }
863 
864   writeleft = totalsize;
865   do {
866     written = fwrite(&reqbuf[totalsize-writeleft],
867                      1, writeleft, dump);
868     if(got_exit_signal)
869       goto storerequest_cleanup;
870     if(written > 0)
871       writeleft -= written;
872   } while((writeleft > 0) && ((error = errno) == EINTR));
873 
874   if(writeleft == 0)
875     logmsg("Wrote request (%zu bytes) input to %s", totalsize, dumpfile);
876   else if(writeleft > 0) {
877     logmsg("Error writing file %s error: %d %s",
878            dumpfile, error, strerror(error));
879     logmsg("Wrote only (%zu bytes) of (%zu bytes) request input to %s",
880            totalsize-writeleft, totalsize, dumpfile);
881   }
882 
883 storerequest_cleanup:
884 
885   do {
886     res = fclose(dump);
887   } while(res && ((error = errno) == EINTR));
888   if(res)
889     logmsg("Error closing file %s error: %d %s",
890            dumpfile, error, strerror(error));
891 }
892 
init_httprequest(struct httprequest * req)893 static void init_httprequest(struct httprequest *req)
894 {
895   /* Pipelining is already set, so do not initialize it here. Only initialize
896      checkindex and offset if pipelining is not set, since in a pipeline they
897      need to be inherited from the previous request. */
898   if(!req->pipelining) {
899     req->checkindex = 0;
900     req->offset = 0;
901   }
902   req->testno = DOCNUMBER_NOTHING;
903   req->partno = 0;
904   req->connect_request = FALSE;
905   req->open = TRUE;
906   req->auth_req = FALSE;
907   req->auth = FALSE;
908   req->cl = 0;
909   req->digest = FALSE;
910   req->ntlm = FALSE;
911   req->pipe = 0;
912   req->skip = 0;
913   req->writedelay = 0;
914   req->rcmd = RCMD_NORMALREQ;
915   req->prot_version = 0;
916   req->callcount = 0;
917   req->connect_port = 0;
918   req->done_processing = 0;
919   req->upgrade = 0;
920   req->upgrade_request = 0;
921 }
922 
923 /* returns 1 if the connection should be serviced again immediately, 0 if there
924    is no data waiting, or < 0 if it should be closed */
get_request(curl_socket_t sock,struct httprequest * req)925 static int get_request(curl_socket_t sock, struct httprequest *req)
926 {
927   int error;
928   int fail = 0;
929   char *reqbuf = req->reqbuf;
930   ssize_t got = 0;
931   int overflow = 0;
932 
933   char *pipereq = NULL;
934   size_t pipereq_length = 0;
935 
936   if(req->pipelining) {
937     pipereq = reqbuf + req->checkindex;
938     pipereq_length = req->offset - req->checkindex;
939 
940     /* Now that we've got the pipelining info we can reset the
941        pipelining-related vars which were skipped in init_httprequest */
942     req->pipelining = FALSE;
943     req->checkindex = 0;
944     req->offset = 0;
945   }
946 
947   if(req->offset >= REQBUFSIZ-1) {
948     /* buffer is already full; do nothing */
949     overflow = 1;
950   }
951   else {
952     if(pipereq_length && pipereq) {
953       memmove(reqbuf, pipereq, pipereq_length);
954       got = curlx_uztosz(pipereq_length);
955       pipereq_length = 0;
956     }
957     else {
958       if(req->skip)
959         /* we are instructed to not read the entire thing, so we make sure to
960            only read what we're supposed to and NOT read the enire thing the
961            client wants to send! */
962         got = sread(sock, reqbuf + req->offset, req->cl);
963       else
964         got = sread(sock, reqbuf + req->offset, REQBUFSIZ-1 - req->offset);
965     }
966     if(got_exit_signal)
967       return -1;
968     if(got == 0) {
969       logmsg("Connection closed by client");
970       fail = 1;
971     }
972     else if(got < 0) {
973       error = SOCKERRNO;
974       if(EAGAIN == error || EWOULDBLOCK == error) {
975         /* nothing to read at the moment */
976         return 0;
977       }
978       logmsg("recv() returned error: (%d) %s", error, strerror(error));
979       fail = 1;
980     }
981     if(fail) {
982       /* dump the request received so far to the external file */
983       reqbuf[req->offset] = '\0';
984       storerequest(reqbuf, req->offset);
985       return -1;
986     }
987 
988     logmsg("Read %zd bytes", got);
989 
990     req->offset += (size_t)got;
991     reqbuf[req->offset] = '\0';
992 
993     req->done_processing = ProcessRequest(req);
994     if(got_exit_signal)
995       return -1;
996     if(req->done_processing && req->pipe) {
997       logmsg("Waiting for another piped request");
998       req->done_processing = 0;
999       req->pipe--;
1000     }
1001   }
1002 
1003   if(overflow || (req->offset == REQBUFSIZ-1 && got > 0)) {
1004     logmsg("Request would overflow buffer, closing connection");
1005     /* dump request received so far to external file anyway */
1006     reqbuf[REQBUFSIZ-1] = '\0';
1007     fail = 1;
1008   }
1009   else if(req->offset > REQBUFSIZ-1) {
1010     logmsg("Request buffer overflow, closing connection");
1011     /* dump request received so far to external file anyway */
1012     reqbuf[REQBUFSIZ-1] = '\0';
1013     fail = 1;
1014   }
1015   else
1016     reqbuf[req->offset] = '\0';
1017 
1018   /* at the end of a request dump it to an external file */
1019   if(fail || req->done_processing)
1020     storerequest(reqbuf, req->pipelining ? req->checkindex : req->offset);
1021   if(got_exit_signal)
1022     return -1;
1023 
1024   return fail ? -1 : 1;
1025 }
1026 
1027 /* returns -1 on failure */
send_doc(curl_socket_t sock,struct httprequest * req)1028 static int send_doc(curl_socket_t sock, struct httprequest *req)
1029 {
1030   ssize_t written;
1031   size_t count;
1032   const char *buffer;
1033   char *ptr=NULL;
1034   FILE *stream;
1035   char *cmd=NULL;
1036   size_t cmdsize=0;
1037   FILE *dump;
1038   bool persistant = TRUE;
1039   bool sendfailure = FALSE;
1040   size_t responsesize;
1041   int error = 0;
1042   int res;
1043   const char *responsedump = is_proxy?RESPONSE_PROXY_DUMP:RESPONSE_DUMP;
1044   static char weare[256];
1045 
1046   switch(req->rcmd) {
1047   default:
1048   case RCMD_NORMALREQ:
1049     break; /* continue with business as usual */
1050   case RCMD_STREAM:
1051 #define STREAMTHIS "a string to stream 01234567890\n"
1052     count = strlen(STREAMTHIS);
1053     for(;;) {
1054       written = swrite(sock, STREAMTHIS, count);
1055       if(got_exit_signal)
1056         return -1;
1057       if(written != (ssize_t)count) {
1058         logmsg("Stopped streaming");
1059         break;
1060       }
1061     }
1062     return -1;
1063   case RCMD_IDLE:
1064     /* Do nothing. Sit idle. Pretend it rains. */
1065     return 0;
1066   }
1067 
1068   req->open = FALSE;
1069 
1070   if(req->testno < 0) {
1071     size_t msglen;
1072     char msgbuf[64];
1073 
1074     switch(req->testno) {
1075     case DOCNUMBER_QUIT:
1076       logmsg("Replying to QUIT");
1077       buffer = docquit;
1078       break;
1079     case DOCNUMBER_WERULEZ:
1080       /* we got a "friends?" question, reply back that we sure are */
1081       logmsg("Identifying ourselves as friends");
1082       snprintf(msgbuf, sizeof(msgbuf), "WE ROOLZ: %ld\r\n", (long)getpid());
1083       msglen = strlen(msgbuf);
1084       if(use_gopher)
1085         snprintf(weare, sizeof(weare), "%s", msgbuf);
1086       else
1087         snprintf(weare, sizeof(weare),
1088                  "HTTP/1.1 200 OK\r\nContent-Length: %zu\r\n\r\n%s",
1089                  msglen, msgbuf);
1090       buffer = weare;
1091       break;
1092     case DOCNUMBER_404:
1093     default:
1094       logmsg("Replying to with a 404");
1095       buffer = doc404;
1096       break;
1097     }
1098 
1099     count = strlen(buffer);
1100   }
1101   else {
1102     char partbuf[80];
1103     char *filename = test2file(req->testno);
1104 
1105     /* select the <data> tag for "normal" requests and the <connect> one
1106        for CONNECT requests (within the <reply> section) */
1107     const char *section= req->connect_request?"connect":"data";
1108 
1109     if(req->partno)
1110       snprintf(partbuf, sizeof(partbuf), "%s%ld", section, req->partno);
1111     else
1112       snprintf(partbuf, sizeof(partbuf), "%s", section);
1113 
1114     logmsg("Send response test%ld section <%s>", req->testno, partbuf);
1115 
1116     stream=fopen(filename, "rb");
1117     if(!stream) {
1118       error = errno;
1119       logmsg("fopen() failed with error: %d %s", error, strerror(error));
1120       logmsg("  [3] Error opening file: %s", filename);
1121       return 0;
1122     }
1123     else {
1124       error = getpart(&ptr, &count, "reply", partbuf, stream);
1125       fclose(stream);
1126       if(error) {
1127         logmsg("getpart() failed with error: %d", error);
1128         return 0;
1129       }
1130       buffer = ptr;
1131     }
1132 
1133     if(got_exit_signal) {
1134       free(ptr);
1135       return -1;
1136     }
1137 
1138     /* re-open the same file again */
1139     stream=fopen(filename, "rb");
1140     if(!stream) {
1141       error = errno;
1142       logmsg("fopen() failed with error: %d %s", error, strerror(error));
1143       logmsg("  [4] Error opening file: %s", filename);
1144       free(ptr);
1145       return 0;
1146     }
1147     else {
1148       /* get the custom server control "commands" */
1149       error = getpart(&cmd, &cmdsize, "reply", "postcmd", stream);
1150       fclose(stream);
1151       if(error) {
1152         logmsg("getpart() failed with error: %d", error);
1153         free(ptr);
1154         return 0;
1155       }
1156     }
1157   }
1158 
1159   if(got_exit_signal) {
1160     free(ptr);
1161     free(cmd);
1162     return -1;
1163   }
1164 
1165   /* If the word 'swsclose' is present anywhere in the reply chunk, the
1166      connection will be closed after the data has been sent to the requesting
1167      client... */
1168   if(strstr(buffer, "swsclose") || !count) {
1169     persistant = FALSE;
1170     logmsg("connection close instruction \"swsclose\" found in response");
1171   }
1172   if(strstr(buffer, "swsbounce")) {
1173     prevbounce = TRUE;
1174     logmsg("enable \"swsbounce\" in the next request");
1175   }
1176   else
1177     prevbounce = FALSE;
1178 
1179   dump = fopen(responsedump, "ab");
1180   if(!dump) {
1181     error = errno;
1182     logmsg("fopen() failed with error: %d %s", error, strerror(error));
1183     logmsg("  [5] Error opening file: %s", responsedump);
1184     free(ptr);
1185     free(cmd);
1186     return -1;
1187   }
1188 
1189   responsesize = count;
1190   do {
1191     /* Ok, we send no more than 200 bytes at a time, just to make sure that
1192        larger chunks are split up so that the client will need to do multiple
1193        recv() calls to get it and thus we exercise that code better */
1194     size_t num = count;
1195     if(num > 200)
1196       num = 200;
1197     written = swrite(sock, buffer, num);
1198     if(written < 0) {
1199       sendfailure = TRUE;
1200       break;
1201     }
1202     else {
1203       logmsg("Sent off %zd bytes", written);
1204     }
1205     /* write to file as well */
1206     fwrite(buffer, 1, (size_t)written, dump);
1207 
1208     count -= written;
1209     buffer += written;
1210 
1211     if(req->writedelay) {
1212       int quarters = req->writedelay * 4;
1213       logmsg("Pausing %d seconds", req->writedelay);
1214       while((quarters > 0) && !got_exit_signal) {
1215         quarters--;
1216         wait_ms(250);
1217       }
1218     }
1219   } while((count > 0) && !got_exit_signal);
1220 
1221   do {
1222     res = fclose(dump);
1223   } while(res && ((error = errno) == EINTR));
1224   if(res)
1225     logmsg("Error closing file %s error: %d %s",
1226            responsedump, error, strerror(error));
1227 
1228   if(got_exit_signal) {
1229     free(ptr);
1230     free(cmd);
1231     return -1;
1232   }
1233 
1234   if(sendfailure) {
1235     logmsg("Sending response failed. Only (%zu bytes) of (%zu bytes) "
1236            "were sent",
1237            responsesize-count, responsesize);
1238     free(ptr);
1239     free(cmd);
1240     return -1;
1241   }
1242 
1243   logmsg("Response sent (%zu bytes) and written to %s",
1244          responsesize, responsedump);
1245   free(ptr);
1246 
1247   if(cmdsize > 0) {
1248     char command[32];
1249     int quarters;
1250     int num;
1251     ptr=cmd;
1252     do {
1253       if(2 == sscanf(ptr, "%31s %d", command, &num)) {
1254         if(!strcmp("wait", command)) {
1255           logmsg("Told to sleep for %d seconds", num);
1256           quarters = num * 4;
1257           while((quarters > 0) && !got_exit_signal) {
1258             quarters--;
1259             res = wait_ms(250);
1260             if(res) {
1261               /* should not happen */
1262               error = errno;
1263               logmsg("wait_ms() failed with error: (%d) %s",
1264                      error, strerror(error));
1265               break;
1266             }
1267           }
1268           if(!quarters)
1269             logmsg("Continuing after sleeping %d seconds", num);
1270         }
1271         else
1272           logmsg("Unknown command in reply command section");
1273       }
1274       ptr = strchr(ptr, '\n');
1275       if(ptr)
1276         ptr++;
1277       else
1278         ptr = NULL;
1279     } while(ptr && *ptr);
1280   }
1281   free(cmd);
1282   req->open = use_gopher?FALSE:persistant;
1283 
1284   prevtestno = req->testno;
1285   prevpartno = req->partno;
1286 
1287   return 0;
1288 }
1289 
connect_to(const char * ipaddr,unsigned short port)1290 static curl_socket_t connect_to(const char *ipaddr, unsigned short port)
1291 {
1292   srvr_sockaddr_union_t serveraddr;
1293   curl_socket_t serverfd;
1294   int error;
1295   int rc = 0;
1296   const char *op_br = "";
1297   const char *cl_br = "";
1298 
1299 #ifdef ENABLE_IPV6
1300   if(socket_domain == AF_INET6) {
1301     op_br = "[";
1302     cl_br = "]";
1303   }
1304 #endif
1305 
1306   if(!ipaddr)
1307     return CURL_SOCKET_BAD;
1308 
1309   logmsg("about to connect to %s%s%s:%hu",
1310          op_br, ipaddr, cl_br, port);
1311 
1312 
1313   serverfd = socket(socket_domain, SOCK_STREAM, 0);
1314   if(CURL_SOCKET_BAD == serverfd) {
1315     error = SOCKERRNO;
1316     logmsg("Error creating socket for server conection: (%d) %s",
1317            error, strerror(error));
1318     return CURL_SOCKET_BAD;
1319   }
1320 
1321 #ifdef TCP_NODELAY
1322   if(socket_domain_is_ip()) {
1323     /* Disable the Nagle algorithm */
1324     curl_socklen_t flag = 1;
1325     if(0 != setsockopt(serverfd, IPPROTO_TCP, TCP_NODELAY,
1326                        (void *)&flag, sizeof(flag)))
1327       logmsg("====> TCP_NODELAY for server conection failed");
1328   }
1329 #endif
1330 
1331   switch(socket_domain) {
1332   case AF_INET:
1333     memset(&serveraddr.sa4, 0, sizeof(serveraddr.sa4));
1334     serveraddr.sa4.sin_family = AF_INET;
1335     serveraddr.sa4.sin_port = htons(port);
1336     if(Curl_inet_pton(AF_INET, ipaddr, &serveraddr.sa4.sin_addr) < 1) {
1337       logmsg("Error inet_pton failed AF_INET conversion of '%s'", ipaddr);
1338       sclose(serverfd);
1339       return CURL_SOCKET_BAD;
1340     }
1341 
1342     rc = connect(serverfd, &serveraddr.sa, sizeof(serveraddr.sa4));
1343     break;
1344 #ifdef ENABLE_IPV6
1345   case AF_INET6:
1346     memset(&serveraddr.sa6, 0, sizeof(serveraddr.sa6));
1347     serveraddr.sa6.sin6_family = AF_INET6;
1348     serveraddr.sa6.sin6_port = htons(port);
1349     if(Curl_inet_pton(AF_INET6, ipaddr, &serveraddr.sa6.sin6_addr) < 1) {
1350       logmsg("Error inet_pton failed AF_INET6 conversion of '%s'", ipaddr);
1351       sclose(serverfd);
1352       return CURL_SOCKET_BAD;
1353     }
1354 
1355     rc = connect(serverfd, &serveraddr.sa, sizeof(serveraddr.sa6));
1356     break;
1357 #endif /* ENABLE_IPV6 */
1358 #ifdef USE_UNIX_SOCKETS
1359   case AF_UNIX:
1360     logmsg("Proxying through Unix socket is not (yet?) supported.");
1361     return CURL_SOCKET_BAD;
1362 #endif /* USE_UNIX_SOCKETS */
1363   }
1364 
1365   if(got_exit_signal) {
1366     sclose(serverfd);
1367     return CURL_SOCKET_BAD;
1368   }
1369 
1370   if(rc) {
1371     error = SOCKERRNO;
1372     logmsg("Error connecting to server port %hu: (%d) %s",
1373            port, error, strerror(error));
1374     sclose(serverfd);
1375     return CURL_SOCKET_BAD;
1376   }
1377 
1378   logmsg("connected fine to %s%s%s:%hu, now tunnel",
1379          op_br, ipaddr, cl_br, port);
1380 
1381   return serverfd;
1382 }
1383 
1384 /*
1385  * A CONNECT has been received, a CONNECT response has been sent.
1386  *
1387  * This function needs to connect to the server, and then pass data between
1388  * the client and the server back and forth until the connection is closed by
1389  * either end.
1390  *
1391  * When doing FTP through a CONNECT proxy, we expect that the data connection
1392  * will be setup while the first connect is still being kept up. Therefor we
1393  * must accept a new connection and deal with it appropriately.
1394  */
1395 
1396 #define data_or_ctrl(x) ((x)?"DATA":"CTRL")
1397 
1398 #define CTRL  0
1399 #define DATA  1
1400 
http_connect(curl_socket_t * infdp,curl_socket_t rootfd,const char * ipaddr,unsigned short ipport)1401 static void http_connect(curl_socket_t *infdp,
1402                          curl_socket_t rootfd,
1403                          const char *ipaddr,
1404                          unsigned short ipport)
1405 {
1406   curl_socket_t serverfd[2] = {CURL_SOCKET_BAD, CURL_SOCKET_BAD};
1407   curl_socket_t clientfd[2] = {CURL_SOCKET_BAD, CURL_SOCKET_BAD};
1408   ssize_t toc[2] = {0, 0}; /* number of bytes to client */
1409   ssize_t tos[2] = {0, 0}; /* number of bytes to server */
1410   char readclient[2][256];
1411   char readserver[2][256];
1412   bool poll_client_rd[2] = { TRUE, TRUE };
1413   bool poll_server_rd[2] = { TRUE, TRUE };
1414   bool poll_client_wr[2] = { TRUE, TRUE };
1415   bool poll_server_wr[2] = { TRUE, TRUE };
1416   bool primary = FALSE;
1417   bool secondary = FALSE;
1418   int max_tunnel_idx; /* CTRL or DATA */
1419   int loop;
1420   int i;
1421   int timeout_count=0;
1422 
1423   /* primary tunnel client endpoint already connected */
1424   clientfd[CTRL] = *infdp;
1425 
1426   /* Sleep here to make sure the client reads CONNECT response's
1427      'end of headers' separate from the server data that follows.
1428      This is done to prevent triggering libcurl known bug #39. */
1429   for(loop = 2; (loop > 0) && !got_exit_signal; loop--)
1430     wait_ms(250);
1431   if(got_exit_signal)
1432     goto http_connect_cleanup;
1433 
1434   serverfd[CTRL] = connect_to(ipaddr, ipport);
1435   if(serverfd[CTRL] == CURL_SOCKET_BAD)
1436     goto http_connect_cleanup;
1437 
1438   /* Primary tunnel socket endpoints are now connected. Tunnel data back and
1439      forth over the primary tunnel until client or server breaks the primary
1440      tunnel, simultaneously allowing establishment, operation and teardown of
1441      a secondary tunnel that may be used for passive FTP data connection. */
1442 
1443   max_tunnel_idx = CTRL;
1444   primary = TRUE;
1445 
1446   while(!got_exit_signal) {
1447 
1448     fd_set input;
1449     fd_set output;
1450     struct timeval timeout = {1, 0}; /* 1000 ms */
1451     ssize_t rc;
1452     curl_socket_t maxfd = (curl_socket_t)-1;
1453 
1454     FD_ZERO(&input);
1455     FD_ZERO(&output);
1456 
1457     if((clientfd[DATA] == CURL_SOCKET_BAD) &&
1458        (serverfd[DATA] == CURL_SOCKET_BAD) &&
1459        poll_client_rd[CTRL] && poll_client_wr[CTRL] &&
1460        poll_server_rd[CTRL] && poll_server_wr[CTRL]) {
1461       /* listener socket is monitored to allow client to establish
1462          secondary tunnel only when this tunnel is not established
1463          and primary one is fully operational */
1464       FD_SET(rootfd, &input);
1465       maxfd = rootfd;
1466     }
1467 
1468     /* set tunnel sockets to wait for */
1469     for(i = 0; i <= max_tunnel_idx; i++) {
1470       /* client side socket monitoring */
1471       if(clientfd[i] != CURL_SOCKET_BAD) {
1472         if(poll_client_rd[i]) {
1473           /* unless told not to do so, monitor readability */
1474           FD_SET(clientfd[i], &input);
1475           if(clientfd[i] > maxfd)
1476             maxfd = clientfd[i];
1477         }
1478         if(poll_client_wr[i] && toc[i]) {
1479           /* unless told not to do so, monitor writeability
1480              if there is data ready to be sent to client */
1481           FD_SET(clientfd[i], &output);
1482           if(clientfd[i] > maxfd)
1483             maxfd = clientfd[i];
1484         }
1485       }
1486       /* server side socket monitoring */
1487       if(serverfd[i] != CURL_SOCKET_BAD) {
1488         if(poll_server_rd[i]) {
1489           /* unless told not to do so, monitor readability */
1490           FD_SET(serverfd[i], &input);
1491           if(serverfd[i] > maxfd)
1492             maxfd = serverfd[i];
1493         }
1494         if(poll_server_wr[i] && tos[i]) {
1495           /* unless told not to do so, monitor writeability
1496              if there is data ready to be sent to server */
1497           FD_SET(serverfd[i], &output);
1498           if(serverfd[i] > maxfd)
1499             maxfd = serverfd[i];
1500         }
1501       }
1502     }
1503     if(got_exit_signal)
1504       break;
1505 
1506     rc = select((int)maxfd + 1, &input, &output, NULL, &timeout);
1507 
1508     if(rc > 0) {
1509       /* socket action */
1510       bool tcp_fin_wr;
1511       timeout_count=0;
1512 
1513       if(got_exit_signal)
1514         break;
1515 
1516       tcp_fin_wr = FALSE;
1517 
1518       /* ---------------------------------------------------------- */
1519 
1520       /* passive mode FTP may establish a secondary tunnel */
1521       if((clientfd[DATA] == CURL_SOCKET_BAD) &&
1522          (serverfd[DATA] == CURL_SOCKET_BAD) && FD_ISSET(rootfd, &input)) {
1523         /* a new connection on listener socket (most likely from client) */
1524         curl_socket_t datafd = accept(rootfd, NULL, NULL);
1525         if(datafd != CURL_SOCKET_BAD) {
1526           struct httprequest req2;
1527           int err = 0;
1528           memset(&req2, 0, sizeof(req2));
1529           logmsg("====> Client connect DATA");
1530 #ifdef TCP_NODELAY
1531           if(socket_domain_is_ip()) {
1532             /* Disable the Nagle algorithm */
1533             curl_socklen_t flag = 1;
1534             if(0 != setsockopt(datafd, IPPROTO_TCP, TCP_NODELAY,
1535                                (void *)&flag, sizeof(flag)))
1536               logmsg("====> TCP_NODELAY for client DATA conection failed");
1537           }
1538 #endif
1539           req2.pipelining = FALSE;
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/writeable 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("=> persistant 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   char *pidname= (char *)".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   snprintf(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   req.pipelining = FALSE;
2223   init_httprequest(&req);
2224 
2225   for(;;) {
2226     fd_set input;
2227     fd_set output;
2228     struct timeval timeout = {0, 250000L}; /* 250 ms */
2229     curl_socket_t maxfd = (curl_socket_t)-1;
2230 
2231     /* Clear out closed sockets */
2232     for(socket_idx = num_sockets - 1; socket_idx >= 1; --socket_idx) {
2233       if(CURL_SOCKET_BAD == all_sockets[socket_idx]) {
2234         char *dst = (char *) (all_sockets + socket_idx);
2235         char *src = (char *) (all_sockets + socket_idx + 1);
2236         char *end = (char *) (all_sockets + num_sockets);
2237         memmove(dst, src, end - src);
2238         num_sockets -= 1;
2239       }
2240     }
2241 
2242     if(got_exit_signal)
2243       goto sws_cleanup;
2244 
2245     /* Set up for select*/
2246     FD_ZERO(&input);
2247     FD_ZERO(&output);
2248 
2249     for(socket_idx = 0; socket_idx < num_sockets; ++socket_idx) {
2250       /* Listen on all sockets */
2251       FD_SET(all_sockets[socket_idx], &input);
2252       if(all_sockets[socket_idx] > maxfd)
2253         maxfd = all_sockets[socket_idx];
2254     }
2255 
2256     if(got_exit_signal)
2257       goto sws_cleanup;
2258 
2259     rc = select((int)maxfd + 1, &input, &output, NULL, &timeout);
2260     if(rc < 0) {
2261       error = SOCKERRNO;
2262       logmsg("select() failed with error: (%d) %s",
2263              error, strerror(error));
2264       goto sws_cleanup;
2265     }
2266 
2267     if(got_exit_signal)
2268       goto sws_cleanup;
2269 
2270     if(rc == 0) {
2271       /* Timed out - try again*/
2272       continue;
2273     }
2274 
2275     /* Check if the listening socket is ready to accept */
2276     if(FD_ISSET(all_sockets[0], &input)) {
2277       /* Service all queued connections */
2278       curl_socket_t msgsock;
2279       do {
2280         msgsock = accept_connection(sock);
2281         logmsg("accept_connection %d returned %d", sock, msgsock);
2282         if(CURL_SOCKET_BAD == msgsock)
2283           goto sws_cleanup;
2284       } while(msgsock > 0);
2285     }
2286 
2287     /* Service all connections that are ready */
2288     for(socket_idx = 1; socket_idx < num_sockets; ++socket_idx) {
2289       if(FD_ISSET(all_sockets[socket_idx], &input)) {
2290         if(got_exit_signal)
2291           goto sws_cleanup;
2292 
2293         /* Service this connection until it has nothing available */
2294         do {
2295           rc = service_connection(all_sockets[socket_idx], &req, sock,
2296                                   connecthost);
2297           if(got_exit_signal)
2298             goto sws_cleanup;
2299 
2300           if(rc < 0) {
2301             logmsg("====> Client disconnect %d", req.connmon);
2302 
2303             if(req.connmon) {
2304               const char *keepopen="[DISCONNECT]\n";
2305               storerequest((char *)keepopen, strlen(keepopen));
2306             }
2307 
2308             if(!req.open)
2309               /* When instructed to close connection after server-reply we
2310                  wait a very small amount of time before doing so. If this
2311                  is not done client might get an ECONNRESET before reading
2312                  a single byte of server-reply. */
2313               wait_ms(50);
2314 
2315             if(all_sockets[socket_idx] != CURL_SOCKET_BAD) {
2316               sclose(all_sockets[socket_idx]);
2317               all_sockets[socket_idx] = CURL_SOCKET_BAD;
2318             }
2319 
2320             serverlogslocked -= 1;
2321             if(!serverlogslocked)
2322               clear_advisor_read_lock(SERVERLOGS_LOCK);
2323 
2324             if(req.testno == DOCNUMBER_QUIT)
2325               goto sws_cleanup;
2326           }
2327 
2328           /* Reset the request, unless we're still in the middle of reading */
2329           if(rc != 0)
2330             init_httprequest(&req);
2331         } while(rc > 0);
2332       }
2333     }
2334 
2335     if(got_exit_signal)
2336       goto sws_cleanup;
2337   }
2338 
2339 sws_cleanup:
2340 
2341   for(socket_idx = 1; socket_idx < num_sockets; ++socket_idx)
2342     if((all_sockets[socket_idx] != sock) &&
2343      (all_sockets[socket_idx] != CURL_SOCKET_BAD))
2344       sclose(all_sockets[socket_idx]);
2345 
2346   if(sock != CURL_SOCKET_BAD)
2347     sclose(sock);
2348 
2349 #ifdef USE_UNIX_SOCKETS
2350   if(unlink_socket && socket_domain == AF_UNIX) {
2351     rc = unlink(unix_socket);
2352     logmsg("unlink(%s) = %d (%s)", unix_socket, rc, strerror(rc));
2353   }
2354 #endif
2355 
2356   if(got_exit_signal)
2357     logmsg("signalled to die");
2358 
2359   if(wrotepidfile)
2360     unlink(pidname);
2361 
2362   if(serverlogslocked) {
2363     serverlogslocked = 0;
2364     clear_advisor_read_lock(SERVERLOGS_LOCK);
2365   }
2366 
2367   restore_signal_handlers();
2368 
2369   if(got_exit_signal) {
2370     logmsg("========> %s sws (%s pid: %ld) exits with signal (%d)",
2371            socket_type, location_str, pid, exit_signal);
2372     /*
2373      * To properly set the return status of the process we
2374      * must raise the same signal SIGINT or SIGTERM that we
2375      * caught and let the old handler take care of it.
2376      */
2377     raise(exit_signal);
2378   }
2379 
2380   logmsg("========> sws quits");
2381   return 0;
2382 }
2383 
2384