1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2015, 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 http://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         sprintf(logbuf, "Got request: %s %s HTTP/%d.%d",
495                 request, doc, prot_major, prot_minor);
496       else
497         sprintf(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         sprintf(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         sprintf(logbuf, "Received a CONNECT %s HTTP/%d.%d request",
552                 doc, prot_major, prot_minor);
553         logmsg("%s", logbuf);
554 
555         req->connect_request = TRUE;
556 
557         if(req->prot_version == 10)
558           req->open = FALSE; /* HTTP 1.0 closes connection by default */
559 
560         if(doc[0] == '[') {
561           char *p = &doc[1];
562           /* scan through the hexgroups and store the value of the last group
563              in the 'part' variable and use as test case number!! */
564           while(*p && (ISXDIGIT(*p) || (*p == ':') || (*p == '.'))) {
565             char *endp;
566             part = strtoul(p, &endp, 16);
567             if(ISXDIGIT(*p))
568               p = endp;
569             else
570               p++;
571           }
572           if(*p != ']')
573             logmsg("Invalid CONNECT IPv6 address format");
574           else if (*(p+1) != ':')
575             logmsg("Invalid CONNECT IPv6 port format");
576           else
577             portp = p+1;
578 
579           req->testno = part;
580         }
581         else
582           portp = strchr(doc, ':');
583 
584         if(portp && (*(portp+1) != '\0') && ISDIGIT(*(portp+1))) {
585           unsigned long ulnum = strtoul(portp+1, NULL, 10);
586           if(!ulnum || (ulnum > 65535UL))
587             logmsg("Invalid CONNECT port received");
588           else
589             req->connect_port = curlx_ultous(ulnum);
590 
591         }
592         logmsg("Port number: %d, test case number: %ld",
593                req->connect_port, req->testno);
594       }
595     }
596 
597     if(req->testno == DOCNUMBER_NOTHING) {
598       /* Still no test case number. Try to get the the number off the last dot
599          instead, IE we consider the TLD to be the test number. Test 123 can
600          then be written as "example.com.123". */
601 
602       /* find the last dot */
603       ptr = strrchr(doc, '.');
604 
605       /* get the number after it */
606       if(ptr) {
607         ptr++; /* skip the dot */
608 
609         req->testno = strtol(ptr, &ptr, 10);
610 
611         if(req->testno > 10000) {
612           req->partno = req->testno % 10000;
613           req->testno /= 10000;
614 
615           logmsg("found test %d in requested host name", req->testno);
616 
617         }
618         else
619           req->partno = 0;
620 
621         sprintf(logbuf, "Requested test number %ld part %ld (from host name)",
622                 req->testno, req->partno);
623         logmsg("%s", logbuf);
624 
625       }
626 
627       if(!req->testno) {
628         logmsg("Did not find test number in PATH");
629         req->testno = DOCNUMBER_404;
630       }
631       else
632         parse_servercmd(req);
633     }
634   }
635   else if((req->offset >= 3) && (req->testno == DOCNUMBER_NOTHING)) {
636     logmsg("** Unusual request. Starts with %02x %02x %02x",
637            line[0], line[1], line[2]);
638   }
639 
640   if(!end) {
641     /* we don't have a complete request yet! */
642     logmsg("request not complete yet");
643     return 0; /* not complete yet */
644   }
645   logmsg("- request found to be complete");
646 
647   if(use_gopher) {
648     /* when using gopher we cannot check the request until the entire
649        thing has been received */
650     char *ptr;
651 
652     /* find the last slash in the line */
653     ptr = strrchr(line, '/');
654 
655     if(ptr) {
656       ptr++; /* skip the slash */
657 
658       /* skip all non-numericals following the slash */
659       while(*ptr && !ISDIGIT(*ptr))
660         ptr++;
661 
662       req->testno = strtol(ptr, &ptr, 10);
663 
664       if(req->testno > 10000) {
665         req->partno = req->testno % 10000;
666         req->testno /= 10000;
667       }
668       else
669         req->partno = 0;
670 
671       sprintf(logbuf, "Requested GOPHER test number %ld part %ld",
672               req->testno, req->partno);
673       logmsg("%s", logbuf);
674     }
675   }
676 
677   if(req->pipe)
678     /* we do have a full set, advance the checkindex to after the end of the
679        headers, for the pipelining case mostly */
680     req->checkindex += (end - line) + strlen(end_of_headers);
681 
682   /* **** Persistence ****
683    *
684    * If the request is a HTTP/1.0 one, we close the connection unconditionally
685    * when we're done.
686    *
687    * If the request is a HTTP/1.1 one, we MUST check for a "Connection:"
688    * header that might say "close". If it does, we close a connection when
689    * this request is processed. Otherwise, we keep the connection alive for X
690    * seconds.
691    */
692 
693   do {
694     if(got_exit_signal)
695       return 1; /* done */
696 
697     if((req->cl==0) && curlx_strnequal("Content-Length:", line, 15)) {
698       /* If we don't ignore content-length, we read it and we read the whole
699          request including the body before we return. If we've been told to
700          ignore the content-length, we will return as soon as all headers
701          have been received */
702       char *endptr;
703       char *ptr = line + 15;
704       unsigned long clen = 0;
705       while(*ptr && ISSPACE(*ptr))
706         ptr++;
707       endptr = ptr;
708       errno = 0;
709       clen = strtoul(ptr, &endptr, 10);
710       if((ptr == endptr) || !ISSPACE(*endptr) || (ERANGE == errno)) {
711         /* this assumes that a zero Content-Length is valid */
712         logmsg("Found invalid Content-Length: (%s) in the request", ptr);
713         req->open = FALSE; /* closes connection */
714         return 1; /* done */
715       }
716       req->cl = clen - req->skip;
717 
718       logmsg("Found Content-Length: %lu in the request", clen);
719       if(req->skip)
720         logmsg("... but will abort after %zu bytes", req->cl);
721       break;
722     }
723     else if(curlx_strnequal("Transfer-Encoding: chunked", line,
724                             strlen("Transfer-Encoding: chunked"))) {
725       /* chunked data coming in */
726       chunked = TRUE;
727     }
728 
729     if(chunked) {
730       if(strstr(req->reqbuf, "\r\n0\r\n\r\n"))
731         /* end of chunks reached */
732         return 1; /* done */
733       else
734         return 0; /* not done */
735     }
736 
737     line = strchr(line, '\n');
738     if(line)
739       line++;
740 
741   } while(line);
742 
743   if(!req->auth && strstr(req->reqbuf, "Authorization:")) {
744     req->auth = TRUE; /* Authorization: header present! */
745     if(req->auth_req)
746       logmsg("Authorization header found, as required");
747   }
748 
749   if(!req->digest && strstr(req->reqbuf, "Authorization: Digest")) {
750     /* If the client is passing this Digest-header, we set the part number
751        to 1000. Not only to spice up the complexity of this, but to make
752        Digest stuff to work in the test suite. */
753     req->partno += 1000;
754     req->digest = TRUE; /* header found */
755     logmsg("Received Digest request, sending back data %ld", req->partno);
756   }
757   else if(!req->ntlm &&
758           strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAD")) {
759     /* If the client is passing this type-3 NTLM header */
760     req->partno += 1002;
761     req->ntlm = TRUE; /* NTLM found */
762     logmsg("Received NTLM type-3, sending back data %ld", req->partno);
763     if(req->cl) {
764       logmsg("  Expecting %zu POSTed bytes", req->cl);
765     }
766   }
767   else if(!req->ntlm &&
768           strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAB")) {
769     /* If the client is passing this type-1 NTLM header */
770     req->partno += 1001;
771     req->ntlm = TRUE; /* NTLM found */
772     logmsg("Received NTLM type-1, sending back data %ld", req->partno);
773   }
774   else if((req->partno >= 1000) &&
775           strstr(req->reqbuf, "Authorization: Basic")) {
776     /* If the client is passing this Basic-header and the part number is
777        already >=1000, we add 1 to the part number.  This allows simple Basic
778        authentication negotiation to work in the test suite. */
779     req->partno += 1;
780     logmsg("Received Basic request, sending back data %ld", req->partno);
781   }
782   if(strstr(req->reqbuf, "Connection: close"))
783     req->open = FALSE; /* close connection after this request */
784 
785   if(!req->pipe &&
786      req->open &&
787      req->prot_version >= 11 &&
788      end &&
789      req->reqbuf + req->offset > end + strlen(end_of_headers) &&
790      !req->cl &&
791      (!strncmp(req->reqbuf, "GET", strlen("GET")) ||
792       !strncmp(req->reqbuf, "HEAD", strlen("HEAD")))) {
793     /* If we have a persistent connection, HTTP version >= 1.1
794        and GET/HEAD request, enable pipelining. */
795     req->checkindex = (end - req->reqbuf) + strlen(end_of_headers);
796     req->pipelining = TRUE;
797   }
798 
799   while(req->pipe) {
800     if(got_exit_signal)
801       return 1; /* done */
802     /* scan for more header ends within this chunk */
803     line = &req->reqbuf[req->checkindex];
804     end = strstr(line, end_of_headers);
805     if(!end)
806       break;
807     req->checkindex += (end - line) + strlen(end_of_headers);
808     req->pipe--;
809   }
810 
811   /* If authentication is required and no auth was provided, end now. This
812      makes the server NOT wait for PUT/POST data and you can then make the
813      test case send a rejection before any such data has been sent. Test case
814      154 uses this.*/
815   if(req->auth_req && !req->auth) {
816     logmsg("Return early due to auth requested by none provided");
817     return 1; /* done */
818   }
819 
820   if(req->upgrade && strstr(req->reqbuf, "Upgrade:")) {
821     /* we allow upgrade and there was one! */
822     logmsg("Found Upgrade: in request and allows it");
823     req->upgrade_request = TRUE;
824   }
825 
826   if(req->cl > 0) {
827     if(req->cl <= req->offset - (end - req->reqbuf) - strlen(end_of_headers))
828       return 1; /* done */
829     else
830       return 0; /* not complete yet */
831   }
832 
833   return 1; /* done */
834 }
835 
836 /* store the entire request in a file */
storerequest(char * reqbuf,size_t totalsize)837 static void storerequest(char *reqbuf, size_t totalsize)
838 {
839   int res;
840   int error = 0;
841   size_t written;
842   size_t writeleft;
843   FILE *dump;
844   const char *dumpfile=is_proxy?REQUEST_PROXY_DUMP:REQUEST_DUMP;
845 
846   if (reqbuf == NULL)
847     return;
848   if (totalsize == 0)
849     return;
850 
851   do {
852     dump = fopen(dumpfile, "ab");
853   } while ((dump == NULL) && ((error = errno) == EINTR));
854   if (dump == NULL) {
855     logmsg("[2] Error opening file %s error: %d %s",
856            dumpfile, error, strerror(error));
857     logmsg("Failed to write request input ");
858     return;
859   }
860 
861   writeleft = totalsize;
862   do {
863     written = fwrite(&reqbuf[totalsize-writeleft],
864                      1, writeleft, dump);
865     if(got_exit_signal)
866       goto storerequest_cleanup;
867     if(written > 0)
868       writeleft -= written;
869   } while ((writeleft > 0) && ((error = errno) == EINTR));
870 
871   if(writeleft == 0)
872     logmsg("Wrote request (%zu bytes) input to %s", totalsize, dumpfile);
873   else if(writeleft > 0) {
874     logmsg("Error writing file %s error: %d %s",
875            dumpfile, error, strerror(error));
876     logmsg("Wrote only (%zu bytes) of (%zu bytes) request input to %s",
877            totalsize-writeleft, totalsize, dumpfile);
878   }
879 
880 storerequest_cleanup:
881 
882   do {
883     res = fclose(dump);
884   } while(res && ((error = errno) == EINTR));
885   if(res)
886     logmsg("Error closing file %s error: %d %s",
887            dumpfile, error, strerror(error));
888 }
889 
init_httprequest(struct httprequest * req)890 static void init_httprequest(struct httprequest *req)
891 {
892   /* Pipelining is already set, so do not initialize it here. Only initialize
893      checkindex and offset if pipelining is not set, since in a pipeline they
894      need to be inherited from the previous request. */
895   if(!req->pipelining) {
896     req->checkindex = 0;
897     req->offset = 0;
898   }
899   req->testno = DOCNUMBER_NOTHING;
900   req->partno = 0;
901   req->connect_request = FALSE;
902   req->open = TRUE;
903   req->auth_req = FALSE;
904   req->auth = FALSE;
905   req->cl = 0;
906   req->digest = FALSE;
907   req->ntlm = FALSE;
908   req->pipe = 0;
909   req->skip = 0;
910   req->writedelay = 0;
911   req->rcmd = RCMD_NORMALREQ;
912   req->prot_version = 0;
913   req->callcount = 0;
914   req->connect_port = 0;
915   req->done_processing = 0;
916   req->upgrade = 0;
917   req->upgrade_request = 0;
918 }
919 
920 /* returns 1 if the connection should be serviced again immediately, 0 if there
921    is no data waiting, or < 0 if it should be closed */
get_request(curl_socket_t sock,struct httprequest * req)922 static int get_request(curl_socket_t sock, struct httprequest *req)
923 {
924   int error;
925   int fail = 0;
926   char *reqbuf = req->reqbuf;
927   ssize_t got = 0;
928   int overflow = 0;
929 
930   char *pipereq = NULL;
931   size_t pipereq_length = 0;
932 
933   if(req->pipelining) {
934     pipereq = reqbuf + req->checkindex;
935     pipereq_length = req->offset - req->checkindex;
936 
937     /* Now that we've got the pipelining info we can reset the
938        pipelining-related vars which were skipped in init_httprequest */
939     req->pipelining = FALSE;
940     req->checkindex = 0;
941     req->offset = 0;
942   }
943 
944   if(req->offset >= REQBUFSIZ-1) {
945     /* buffer is already full; do nothing */
946     overflow = 1;
947   }
948   else {
949     if(pipereq_length && pipereq) {
950       memmove(reqbuf, pipereq, pipereq_length);
951       got = curlx_uztosz(pipereq_length);
952       pipereq_length = 0;
953     }
954     else {
955       if(req->skip)
956         /* we are instructed to not read the entire thing, so we make sure to
957            only read what we're supposed to and NOT read the enire thing the
958            client wants to send! */
959         got = sread(sock, reqbuf + req->offset, req->cl);
960       else
961         got = sread(sock, reqbuf + req->offset, REQBUFSIZ-1 - req->offset);
962     }
963     if(got_exit_signal)
964       return -1;
965     if(got == 0) {
966       logmsg("Connection closed by client");
967       fail = 1;
968     }
969     else if(got < 0) {
970       error = SOCKERRNO;
971       if (EAGAIN == error || EWOULDBLOCK == error) {
972         /* nothing to read at the moment */
973         return 0;
974       }
975       logmsg("recv() returned error: (%d) %s", error, strerror(error));
976       fail = 1;
977     }
978     if(fail) {
979       /* dump the request received so far to the external file */
980       reqbuf[req->offset] = '\0';
981       storerequest(reqbuf, req->offset);
982       return -1;
983     }
984 
985     logmsg("Read %zd bytes", got);
986 
987     req->offset += (size_t)got;
988     reqbuf[req->offset] = '\0';
989 
990     req->done_processing = ProcessRequest(req);
991     if(got_exit_signal)
992       return -1;
993     if(req->done_processing && req->pipe) {
994       logmsg("Waiting for another piped request");
995       req->done_processing = 0;
996       req->pipe--;
997     }
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->pipelining ? req->checkindex : 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 persistant = 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       sprintf(msgbuf, "WE ROOLZ: %ld\r\n", (long)getpid());
1080       msglen = strlen(msgbuf);
1081       if(use_gopher)
1082         sprintf(weare, "%s", msgbuf);
1083       else
1084         sprintf(weare, "HTTP/1.1 200 OK\r\nContent-Length: %zu\r\n\r\n%s",
1085                 msglen, msgbuf);
1086       buffer = weare;
1087       break;
1088     case DOCNUMBER_404:
1089     default:
1090       logmsg("Replying to with a 404");
1091       buffer = doc404;
1092       break;
1093     }
1094 
1095     count = strlen(buffer);
1096   }
1097   else {
1098     char partbuf[80];
1099     char *filename = test2file(req->testno);
1100 
1101     /* select the <data> tag for "normal" requests and the <connect> one
1102        for CONNECT requests (within the <reply> section) */
1103     const char *section= req->connect_request?"connect":"data";
1104 
1105     if(req->partno)
1106       sprintf(partbuf, "%s%ld", section, req->partno);
1107     else
1108       sprintf(partbuf, "%s", section);
1109 
1110     logmsg("Send response test%ld section <%s>", req->testno, partbuf);
1111 
1112     stream=fopen(filename, "rb");
1113     if(!stream) {
1114       error = errno;
1115       logmsg("fopen() failed with error: %d %s", error, strerror(error));
1116       logmsg("  [3] Error opening file: %s", filename);
1117       return 0;
1118     }
1119     else {
1120       error = getpart(&ptr, &count, "reply", partbuf, stream);
1121       fclose(stream);
1122       if(error) {
1123         logmsg("getpart() failed with error: %d", error);
1124         return 0;
1125       }
1126       buffer = ptr;
1127     }
1128 
1129     if(got_exit_signal) {
1130       free(ptr);
1131       return -1;
1132     }
1133 
1134     /* re-open the same file again */
1135     stream=fopen(filename, "rb");
1136     if(!stream) {
1137       error = errno;
1138       logmsg("fopen() failed with error: %d %s", error, strerror(error));
1139       logmsg("  [4] Error opening file: %s", filename);
1140       free(ptr);
1141       return 0;
1142     }
1143     else {
1144       /* get the custom server control "commands" */
1145       error = getpart(&cmd, &cmdsize, "reply", "postcmd", stream);
1146       fclose(stream);
1147       if(error) {
1148         logmsg("getpart() failed with error: %d", error);
1149         free(ptr);
1150         return 0;
1151       }
1152     }
1153   }
1154 
1155   if(got_exit_signal) {
1156     free(ptr);
1157     free(cmd);
1158     return -1;
1159   }
1160 
1161   /* If the word 'swsclose' is present anywhere in the reply chunk, the
1162      connection will be closed after the data has been sent to the requesting
1163      client... */
1164   if(strstr(buffer, "swsclose") || !count) {
1165     persistant = FALSE;
1166     logmsg("connection close instruction \"swsclose\" found in response");
1167   }
1168   if(strstr(buffer, "swsbounce")) {
1169     prevbounce = TRUE;
1170     logmsg("enable \"swsbounce\" in the next request");
1171   }
1172   else
1173     prevbounce = FALSE;
1174 
1175   dump = fopen(responsedump, "ab");
1176   if(!dump) {
1177     error = errno;
1178     logmsg("fopen() failed with error: %d %s", error, strerror(error));
1179     logmsg("  [5] Error opening file: %s", responsedump);
1180     free(ptr);
1181     free(cmd);
1182     return -1;
1183   }
1184 
1185   responsesize = count;
1186   do {
1187     /* Ok, we send no more than 200 bytes at a time, just to make sure that
1188        larger chunks are split up so that the client will need to do multiple
1189        recv() calls to get it and thus we exercise that code better */
1190     size_t num = count;
1191     if(num > 200)
1192       num = 200;
1193     written = swrite(sock, buffer, num);
1194     if (written < 0) {
1195       sendfailure = TRUE;
1196       break;
1197     }
1198     else {
1199       logmsg("Sent off %zd bytes", written);
1200     }
1201     /* write to file as well */
1202     fwrite(buffer, 1, (size_t)written, dump);
1203 
1204     count -= written;
1205     buffer += written;
1206 
1207     if(req->writedelay) {
1208       int quarters = req->writedelay * 4;
1209       logmsg("Pausing %d seconds", req->writedelay);
1210       while((quarters > 0) && !got_exit_signal) {
1211         quarters--;
1212         wait_ms(250);
1213       }
1214     }
1215   } while((count > 0) && !got_exit_signal);
1216 
1217   do {
1218     res = fclose(dump);
1219   } while(res && ((error = errno) == EINTR));
1220   if(res)
1221     logmsg("Error closing file %s error: %d %s",
1222            responsedump, error, strerror(error));
1223 
1224   if(got_exit_signal) {
1225     free(ptr);
1226     free(cmd);
1227     return -1;
1228   }
1229 
1230   if(sendfailure) {
1231     logmsg("Sending response failed. Only (%zu bytes) of (%zu bytes) were sent",
1232            responsesize-count, responsesize);
1233     free(ptr);
1234     free(cmd);
1235     return -1;
1236   }
1237 
1238   logmsg("Response sent (%zu bytes) and written to %s",
1239          responsesize, responsedump);
1240   free(ptr);
1241 
1242   if(cmdsize > 0 ) {
1243     char command[32];
1244     int quarters;
1245     int num;
1246     ptr=cmd;
1247     do {
1248       if(2 == sscanf(ptr, "%31s %d", command, &num)) {
1249         if(!strcmp("wait", command)) {
1250           logmsg("Told to sleep for %d seconds", num);
1251           quarters = num * 4;
1252           while((quarters > 0) && !got_exit_signal) {
1253             quarters--;
1254             res = wait_ms(250);
1255             if(res) {
1256               /* should not happen */
1257               error = errno;
1258               logmsg("wait_ms() failed with error: (%d) %s",
1259                      error, strerror(error));
1260               break;
1261             }
1262           }
1263           if(!quarters)
1264             logmsg("Continuing after sleeping %d seconds", num);
1265         }
1266         else
1267           logmsg("Unknown command in reply command section");
1268       }
1269       ptr = strchr(ptr, '\n');
1270       if(ptr)
1271         ptr++;
1272       else
1273         ptr = NULL;
1274     } while(ptr && *ptr);
1275   }
1276   free(cmd);
1277   req->open = use_gopher?FALSE:persistant;
1278 
1279   prevtestno = req->testno;
1280   prevpartno = req->partno;
1281 
1282   return 0;
1283 }
1284 
connect_to(const char * ipaddr,unsigned short port)1285 static curl_socket_t connect_to(const char *ipaddr, unsigned short port)
1286 {
1287   srvr_sockaddr_union_t serveraddr;
1288   curl_socket_t serverfd;
1289   int error;
1290   int rc = 0;
1291   const char *op_br = "";
1292   const char *cl_br = "";
1293 
1294 #ifdef ENABLE_IPV6
1295   if(socket_domain == AF_INET6) {
1296     op_br = "[";
1297     cl_br = "]";
1298   }
1299 #endif
1300 
1301   if(!ipaddr)
1302     return CURL_SOCKET_BAD;
1303 
1304   logmsg("about to connect to %s%s%s:%hu",
1305          op_br, ipaddr, cl_br, port);
1306 
1307 
1308   serverfd = socket(socket_domain, SOCK_STREAM, 0);
1309   if(CURL_SOCKET_BAD == serverfd) {
1310     error = SOCKERRNO;
1311     logmsg("Error creating socket for server conection: (%d) %s",
1312            error, strerror(error));
1313     return CURL_SOCKET_BAD;
1314   }
1315 
1316 #ifdef TCP_NODELAY
1317   if(socket_domain_is_ip()) {
1318     /* Disable the Nagle algorithm */
1319     curl_socklen_t flag = 1;
1320     if(0 != setsockopt(serverfd, IPPROTO_TCP, TCP_NODELAY,
1321                        (void *)&flag, sizeof(flag)))
1322       logmsg("====> TCP_NODELAY for server conection failed");
1323   }
1324 #endif
1325 
1326   switch(socket_domain) {
1327   case AF_INET:
1328     memset(&serveraddr.sa4, 0, sizeof(serveraddr.sa4));
1329     serveraddr.sa4.sin_family = AF_INET;
1330     serveraddr.sa4.sin_port = htons(port);
1331     if(Curl_inet_pton(AF_INET, ipaddr, &serveraddr.sa4.sin_addr) < 1) {
1332       logmsg("Error inet_pton failed AF_INET conversion of '%s'", ipaddr);
1333       sclose(serverfd);
1334       return CURL_SOCKET_BAD;
1335     }
1336 
1337     rc = connect(serverfd, &serveraddr.sa, sizeof(serveraddr.sa4));
1338     break;
1339 #ifdef ENABLE_IPV6
1340   case AF_INET6:
1341     memset(&serveraddr.sa6, 0, sizeof(serveraddr.sa6));
1342     serveraddr.sa6.sin6_family = AF_INET6;
1343     serveraddr.sa6.sin6_port = htons(port);
1344     if(Curl_inet_pton(AF_INET6, ipaddr, &serveraddr.sa6.sin6_addr) < 1) {
1345       logmsg("Error inet_pton failed AF_INET6 conversion of '%s'", ipaddr);
1346       sclose(serverfd);
1347       return CURL_SOCKET_BAD;
1348     }
1349 
1350     rc = connect(serverfd, &serveraddr.sa, sizeof(serveraddr.sa6));
1351     break;
1352 #endif /* ENABLE_IPV6 */
1353 #ifdef USE_UNIX_SOCKETS
1354   case AF_UNIX:
1355     logmsg("Proxying through Unix socket is not (yet?) supported.");
1356     return CURL_SOCKET_BAD;
1357 #endif /* USE_UNIX_SOCKETS */
1358   }
1359 
1360   if(got_exit_signal) {
1361     sclose(serverfd);
1362     return CURL_SOCKET_BAD;
1363   }
1364 
1365   if(rc) {
1366     error = SOCKERRNO;
1367     logmsg("Error connecting to server port %hu: (%d) %s",
1368            port, error, strerror(error));
1369     sclose(serverfd);
1370     return CURL_SOCKET_BAD;
1371   }
1372 
1373   logmsg("connected fine to %s%s%s:%hu, now tunnel",
1374          op_br, ipaddr, cl_br, port);
1375 
1376   return serverfd;
1377 }
1378 
1379 /*
1380  * A CONNECT has been received, a CONNECT response has been sent.
1381  *
1382  * This function needs to connect to the server, and then pass data between
1383  * the client and the server back and forth until the connection is closed by
1384  * either end.
1385  *
1386  * When doing FTP through a CONNECT proxy, we expect that the data connection
1387  * will be setup while the first connect is still being kept up. Therefor we
1388  * must accept a new connection and deal with it appropriately.
1389  */
1390 
1391 #define data_or_ctrl(x) ((x)?"DATA":"CTRL")
1392 
1393 #define CTRL  0
1394 #define DATA  1
1395 
http_connect(curl_socket_t * infdp,curl_socket_t rootfd,const char * ipaddr,unsigned short ipport)1396 static void http_connect(curl_socket_t *infdp,
1397                          curl_socket_t rootfd,
1398                          const char *ipaddr,
1399                          unsigned short ipport)
1400 {
1401   curl_socket_t serverfd[2] = {CURL_SOCKET_BAD, CURL_SOCKET_BAD};
1402   curl_socket_t clientfd[2] = {CURL_SOCKET_BAD, CURL_SOCKET_BAD};
1403   ssize_t toc[2] = {0, 0}; /* number of bytes to client */
1404   ssize_t tos[2] = {0, 0}; /* number of bytes to server */
1405   char readclient[2][256];
1406   char readserver[2][256];
1407   bool poll_client_rd[2] = { TRUE, TRUE };
1408   bool poll_server_rd[2] = { TRUE, TRUE };
1409   bool poll_client_wr[2] = { TRUE, TRUE };
1410   bool poll_server_wr[2] = { TRUE, TRUE };
1411   bool primary = FALSE;
1412   bool secondary = FALSE;
1413   int max_tunnel_idx; /* CTRL or DATA */
1414   int loop;
1415   int i;
1416   int timeout_count=0;
1417 
1418   /* primary tunnel client endpoint already connected */
1419   clientfd[CTRL] = *infdp;
1420 
1421   /* Sleep here to make sure the client reads CONNECT response's
1422      'end of headers' separate from the server data that follows.
1423      This is done to prevent triggering libcurl known bug #39. */
1424   for(loop = 2; (loop > 0) && !got_exit_signal; loop--)
1425     wait_ms(250);
1426   if(got_exit_signal)
1427     goto http_connect_cleanup;
1428 
1429   serverfd[CTRL] = connect_to(ipaddr, ipport);
1430   if(serverfd[CTRL] == CURL_SOCKET_BAD)
1431     goto http_connect_cleanup;
1432 
1433   /* Primary tunnel socket endpoints are now connected. Tunnel data back and
1434      forth over the primary tunnel until client or server breaks the primary
1435      tunnel, simultaneously allowing establishment, operation and teardown of
1436      a secondary tunnel that may be used for passive FTP data connection. */
1437 
1438   max_tunnel_idx = CTRL;
1439   primary = TRUE;
1440 
1441   while(!got_exit_signal) {
1442 
1443     fd_set input;
1444     fd_set output;
1445     struct timeval timeout = {1, 0}; /* 1000 ms */
1446     ssize_t rc;
1447     curl_socket_t maxfd = (curl_socket_t)-1;
1448 
1449     FD_ZERO(&input);
1450     FD_ZERO(&output);
1451 
1452     if((clientfd[DATA] == CURL_SOCKET_BAD) &&
1453        (serverfd[DATA] == CURL_SOCKET_BAD) &&
1454        poll_client_rd[CTRL] && poll_client_wr[CTRL] &&
1455        poll_server_rd[CTRL] && poll_server_wr[CTRL]) {
1456       /* listener socket is monitored to allow client to establish
1457          secondary tunnel only when this tunnel is not established
1458          and primary one is fully operational */
1459       FD_SET(rootfd, &input);
1460       maxfd = rootfd;
1461     }
1462 
1463     /* set tunnel sockets to wait for */
1464     for(i = 0; i <= max_tunnel_idx; i++) {
1465       /* client side socket monitoring */
1466       if(clientfd[i] != CURL_SOCKET_BAD) {
1467         if(poll_client_rd[i]) {
1468           /* unless told not to do so, monitor readability */
1469           FD_SET(clientfd[i], &input);
1470           if(clientfd[i] > maxfd)
1471             maxfd = clientfd[i];
1472         }
1473         if(poll_client_wr[i] && toc[i]) {
1474           /* unless told not to do so, monitor writeability
1475              if there is data ready to be sent to client */
1476           FD_SET(clientfd[i], &output);
1477           if(clientfd[i] > maxfd)
1478             maxfd = clientfd[i];
1479         }
1480       }
1481       /* server side socket monitoring */
1482       if(serverfd[i] != CURL_SOCKET_BAD) {
1483         if(poll_server_rd[i]) {
1484           /* unless told not to do so, monitor readability */
1485           FD_SET(serverfd[i], &input);
1486           if(serverfd[i] > maxfd)
1487             maxfd = serverfd[i];
1488         }
1489         if(poll_server_wr[i] && tos[i]) {
1490           /* unless told not to do so, monitor writeability
1491              if there is data ready to be sent to server */
1492           FD_SET(serverfd[i], &output);
1493           if(serverfd[i] > maxfd)
1494             maxfd = serverfd[i];
1495         }
1496       }
1497     }
1498     if(got_exit_signal)
1499       break;
1500 
1501     rc = select((int)maxfd + 1, &input, &output, NULL, &timeout);
1502 
1503     if(rc > 0) {
1504       /* socket action */
1505       bool tcp_fin_wr;
1506       timeout_count=0;
1507 
1508       if(got_exit_signal)
1509         break;
1510 
1511       tcp_fin_wr = FALSE;
1512 
1513       /* ---------------------------------------------------------- */
1514 
1515       /* passive mode FTP may establish a secondary tunnel */
1516       if((clientfd[DATA] == CURL_SOCKET_BAD) &&
1517          (serverfd[DATA] == CURL_SOCKET_BAD) && FD_ISSET(rootfd, &input)) {
1518         /* a new connection on listener socket (most likely from client) */
1519         curl_socket_t datafd = accept(rootfd, NULL, NULL);
1520         if(datafd != CURL_SOCKET_BAD) {
1521           struct httprequest req2;
1522           int err = 0;
1523           memset(&req2, 0, sizeof(req2));
1524           logmsg("====> Client connect DATA");
1525 #ifdef TCP_NODELAY
1526           if(socket_domain_is_ip()) {
1527             /* Disable the Nagle algorithm */
1528             curl_socklen_t flag = 1;
1529             if(0 != setsockopt(datafd, IPPROTO_TCP, TCP_NODELAY,
1530                                (void *)&flag, sizeof(flag)))
1531               logmsg("====> TCP_NODELAY for client DATA conection failed");
1532           }
1533 #endif
1534           req2.pipelining = FALSE;
1535           init_httprequest(&req2);
1536           while(!req2.done_processing) {
1537             err = get_request(datafd, &req2);
1538             if(err < 0) {
1539               /* this socket must be closed, done or not */
1540               break;
1541             }
1542           }
1543 
1544           /* skip this and close the socket if err < 0 */
1545           if(err >= 0) {
1546             err = send_doc(datafd, &req2);
1547             if(!err && req2.connect_request) {
1548               /* sleep to prevent triggering libcurl known bug #39. */
1549               for(loop = 2; (loop > 0) && !got_exit_signal; loop--)
1550                 wait_ms(250);
1551               if(!got_exit_signal) {
1552                 /* connect to the server */
1553                 serverfd[DATA] = connect_to(ipaddr, req2.connect_port);
1554                 if(serverfd[DATA] != CURL_SOCKET_BAD) {
1555                   /* secondary tunnel established, now we have two connections */
1556                   poll_client_rd[DATA] = TRUE;
1557                   poll_client_wr[DATA] = TRUE;
1558                   poll_server_rd[DATA] = TRUE;
1559                   poll_server_wr[DATA] = TRUE;
1560                   max_tunnel_idx = DATA;
1561                   secondary = TRUE;
1562                   toc[DATA] = 0;
1563                   tos[DATA] = 0;
1564                   clientfd[DATA] = datafd;
1565                   datafd = CURL_SOCKET_BAD;
1566                 }
1567               }
1568             }
1569           }
1570           if(datafd != CURL_SOCKET_BAD) {
1571             /* secondary tunnel not established */
1572             shutdown(datafd, SHUT_RDWR);
1573             sclose(datafd);
1574           }
1575         }
1576         if(got_exit_signal)
1577           break;
1578       }
1579 
1580       /* ---------------------------------------------------------- */
1581 
1582       /* react to tunnel endpoint readable/writeable notifications */
1583       for(i = 0; i <= max_tunnel_idx; i++) {
1584         size_t len;
1585         if(clientfd[i] != CURL_SOCKET_BAD) {
1586           len = sizeof(readclient[i]) - tos[i];
1587           if(len && FD_ISSET(clientfd[i], &input)) {
1588             /* read from client */
1589             rc = sread(clientfd[i], &readclient[i][tos[i]], len);
1590             if(rc <= 0) {
1591               logmsg("[%s] got %zd, STOP READING client", data_or_ctrl(i), rc);
1592               shutdown(clientfd[i], SHUT_RD);
1593               poll_client_rd[i] = FALSE;
1594             }
1595             else {
1596               logmsg("[%s] READ %zd bytes from client", data_or_ctrl(i), rc);
1597               logmsg("[%s] READ \"%s\"", data_or_ctrl(i),
1598                      data_to_hex(&readclient[i][tos[i]], rc));
1599               tos[i] += rc;
1600             }
1601           }
1602         }
1603         if(serverfd[i] != CURL_SOCKET_BAD) {
1604           len = sizeof(readserver[i])-toc[i];
1605           if(len && FD_ISSET(serverfd[i], &input)) {
1606             /* read from server */
1607             rc = sread(serverfd[i], &readserver[i][toc[i]], len);
1608             if(rc <= 0) {
1609               logmsg("[%s] got %zd, STOP READING server", data_or_ctrl(i), rc);
1610               shutdown(serverfd[i], SHUT_RD);
1611               poll_server_rd[i] = FALSE;
1612             }
1613             else {
1614               logmsg("[%s] READ %zd bytes from server", data_or_ctrl(i), rc);
1615               logmsg("[%s] READ \"%s\"", data_or_ctrl(i),
1616                      data_to_hex(&readserver[i][toc[i]], rc));
1617               toc[i] += rc;
1618             }
1619           }
1620         }
1621         if(clientfd[i] != CURL_SOCKET_BAD) {
1622           if(toc[i] && FD_ISSET(clientfd[i], &output)) {
1623             /* write to client */
1624             rc = swrite(clientfd[i], readserver[i], toc[i]);
1625             if(rc <= 0) {
1626               logmsg("[%s] got %zd, STOP WRITING client", data_or_ctrl(i), rc);
1627               shutdown(clientfd[i], SHUT_WR);
1628               poll_client_wr[i] = FALSE;
1629               tcp_fin_wr = TRUE;
1630             }
1631             else {
1632               logmsg("[%s] SENT %zd bytes to client", data_or_ctrl(i), rc);
1633               logmsg("[%s] SENT \"%s\"", data_or_ctrl(i),
1634                      data_to_hex(readserver[i], rc));
1635               if(toc[i] - rc)
1636                 memmove(&readserver[i][0], &readserver[i][rc], toc[i]-rc);
1637               toc[i] -= rc;
1638             }
1639           }
1640         }
1641         if(serverfd[i] != CURL_SOCKET_BAD) {
1642           if(tos[i] && FD_ISSET(serverfd[i], &output)) {
1643             /* write to server */
1644             rc = swrite(serverfd[i], readclient[i], tos[i]);
1645             if(rc <= 0) {
1646               logmsg("[%s] got %zd, STOP WRITING server", data_or_ctrl(i), rc);
1647               shutdown(serverfd[i], SHUT_WR);
1648               poll_server_wr[i] = FALSE;
1649               tcp_fin_wr = TRUE;
1650             }
1651             else {
1652               logmsg("[%s] SENT %zd bytes to server", data_or_ctrl(i), rc);
1653               logmsg("[%s] SENT \"%s\"", data_or_ctrl(i),
1654                      data_to_hex(readclient[i], rc));
1655               if(tos[i] - rc)
1656                 memmove(&readclient[i][0], &readclient[i][rc], tos[i]-rc);
1657               tos[i] -= rc;
1658             }
1659           }
1660         }
1661       }
1662       if(got_exit_signal)
1663         break;
1664 
1665       /* ---------------------------------------------------------- */
1666 
1667       /* endpoint read/write disabling, endpoint closing and tunnel teardown */
1668       for(i = 0; i <= max_tunnel_idx; i++) {
1669         for(loop = 2; loop > 0; loop--) {
1670           /* loop twice to satisfy condition interdependencies without
1671              having to await select timeout or another socket event */
1672           if(clientfd[i] != CURL_SOCKET_BAD) {
1673             if(poll_client_rd[i] && !poll_server_wr[i]) {
1674               logmsg("[%s] DISABLED READING client", data_or_ctrl(i));
1675               shutdown(clientfd[i], SHUT_RD);
1676               poll_client_rd[i] = FALSE;
1677             }
1678             if(poll_client_wr[i] && !poll_server_rd[i] && !toc[i]) {
1679               logmsg("[%s] DISABLED WRITING client", data_or_ctrl(i));
1680               shutdown(clientfd[i], SHUT_WR);
1681               poll_client_wr[i] = FALSE;
1682               tcp_fin_wr = TRUE;
1683             }
1684           }
1685           if(serverfd[i] != CURL_SOCKET_BAD) {
1686             if(poll_server_rd[i] && !poll_client_wr[i]) {
1687               logmsg("[%s] DISABLED READING server", data_or_ctrl(i));
1688               shutdown(serverfd[i], SHUT_RD);
1689               poll_server_rd[i] = FALSE;
1690             }
1691             if(poll_server_wr[i] && !poll_client_rd[i] && !tos[i]) {
1692               logmsg("[%s] DISABLED WRITING server", data_or_ctrl(i));
1693               shutdown(serverfd[i], SHUT_WR);
1694               poll_server_wr[i] = FALSE;
1695               tcp_fin_wr = TRUE;
1696             }
1697           }
1698         }
1699       }
1700 
1701       if(tcp_fin_wr)
1702         /* allow kernel to place FIN bit packet on the wire */
1703         wait_ms(250);
1704 
1705       /* socket clearing */
1706       for(i = 0; i <= max_tunnel_idx; i++) {
1707         for(loop = 2; loop > 0; loop--) {
1708           if(clientfd[i] != CURL_SOCKET_BAD) {
1709             if(!poll_client_wr[i] && !poll_client_rd[i]) {
1710               logmsg("[%s] CLOSING client socket", data_or_ctrl(i));
1711               sclose(clientfd[i]);
1712               clientfd[i] = CURL_SOCKET_BAD;
1713               if(serverfd[i] == CURL_SOCKET_BAD) {
1714                 logmsg("[%s] ENDING", data_or_ctrl(i));
1715                 if(i == DATA)
1716                   secondary = FALSE;
1717                 else
1718                   primary = FALSE;
1719               }
1720             }
1721           }
1722           if(serverfd[i] != CURL_SOCKET_BAD) {
1723             if(!poll_server_wr[i] && !poll_server_rd[i]) {
1724               logmsg("[%s] CLOSING server socket", data_or_ctrl(i));
1725               sclose(serverfd[i]);
1726               serverfd[i] = CURL_SOCKET_BAD;
1727               if(clientfd[i] == CURL_SOCKET_BAD) {
1728                 logmsg("[%s] ENDING", data_or_ctrl(i));
1729                 if(i == DATA)
1730                   secondary = FALSE;
1731                 else
1732                   primary = FALSE;
1733               }
1734             }
1735           }
1736         }
1737       }
1738 
1739       /* ---------------------------------------------------------- */
1740 
1741       max_tunnel_idx = secondary ? DATA : CTRL;
1742 
1743       if(!primary)
1744         /* exit loop upon primary tunnel teardown */
1745         break;
1746 
1747     } /* (rc > 0) */
1748     else {
1749       timeout_count++;
1750       if(timeout_count > 5) {
1751         logmsg("CONNECT proxy timeout after %d idle seconds!", timeout_count);
1752         break;
1753       }
1754     }
1755   }
1756 
1757 http_connect_cleanup:
1758 
1759   for(i = DATA; i >= CTRL; i--) {
1760     if(serverfd[i] != CURL_SOCKET_BAD) {
1761       logmsg("[%s] CLOSING server socket (cleanup)", data_or_ctrl(i));
1762       shutdown(serverfd[i], SHUT_RDWR);
1763       sclose(serverfd[i]);
1764     }
1765     if(clientfd[i] != CURL_SOCKET_BAD) {
1766       logmsg("[%s] CLOSING client socket (cleanup)", data_or_ctrl(i));
1767       shutdown(clientfd[i], SHUT_RDWR);
1768       sclose(clientfd[i]);
1769     }
1770     if((serverfd[i] != CURL_SOCKET_BAD) ||
1771        (clientfd[i] != CURL_SOCKET_BAD)) {
1772       logmsg("[%s] ABORTING", data_or_ctrl(i));
1773     }
1774   }
1775 
1776   *infdp = CURL_SOCKET_BAD;
1777 }
1778 
http2(struct httprequest * req)1779 static void http2(struct httprequest *req)
1780 {
1781   (void)req;
1782   logmsg("switched to http2");
1783   /* left to implement */
1784 }
1785 
1786 
1787 /* returns a socket handle, or 0 if there are no more waiting sockets,
1788    or < 0 if there was an error */
accept_connection(curl_socket_t sock)1789 static curl_socket_t accept_connection(curl_socket_t sock)
1790 {
1791   curl_socket_t msgsock = CURL_SOCKET_BAD;
1792   int error;
1793   int flag = 1;
1794 
1795   if(MAX_SOCKETS == num_sockets) {
1796     logmsg("Too many open sockets!");
1797     return CURL_SOCKET_BAD;
1798   }
1799 
1800   msgsock = accept(sock, NULL, NULL);
1801 
1802   if(got_exit_signal) {
1803     if(CURL_SOCKET_BAD != msgsock)
1804       sclose(msgsock);
1805     return CURL_SOCKET_BAD;
1806   }
1807 
1808   if(CURL_SOCKET_BAD == msgsock) {
1809     error = SOCKERRNO;
1810     if(EAGAIN == error || EWOULDBLOCK == error) {
1811       /* nothing to accept */
1812       return 0;
1813     }
1814     logmsg("MAJOR ERROR: accept() failed with error: (%d) %s",
1815            error, strerror(error));
1816     return CURL_SOCKET_BAD;
1817   }
1818 
1819   if(0 != curlx_nonblock(msgsock, TRUE)) {
1820     error = SOCKERRNO;
1821     logmsg("curlx_nonblock failed with error: (%d) %s",
1822            error, strerror(error));
1823     sclose(msgsock);
1824     return CURL_SOCKET_BAD;
1825   }
1826 
1827   if(0 != setsockopt(msgsock, SOL_SOCKET, SO_KEEPALIVE,
1828                      (void *)&flag, sizeof(flag))) {
1829     error = SOCKERRNO;
1830     logmsg("setsockopt(SO_KEEPALIVE) failed with error: (%d) %s",
1831            error, strerror(error));
1832     sclose(msgsock);
1833     return CURL_SOCKET_BAD;
1834   }
1835 
1836   /*
1837   ** As soon as this server accepts a connection from the test harness it
1838   ** must set the server logs advisor read lock to indicate that server
1839   ** logs should not be read until this lock is removed by this server.
1840   */
1841 
1842   if(!serverlogslocked)
1843     set_advisor_read_lock(SERVERLOGS_LOCK);
1844   serverlogslocked += 1;
1845 
1846   logmsg("====> Client connect");
1847 
1848   all_sockets[num_sockets] = msgsock;
1849   num_sockets += 1;
1850 
1851 #ifdef TCP_NODELAY
1852   if(socket_domain_is_ip()) {
1853     /*
1854      * Disable the Nagle algorithm to make it easier to send out a large
1855      * response in many small segments to torture the clients more.
1856      */
1857     if(0 != setsockopt(msgsock, IPPROTO_TCP, TCP_NODELAY,
1858                        (void *)&flag, sizeof(flag)))
1859       logmsg("====> TCP_NODELAY failed");
1860   }
1861 #endif
1862 
1863   return msgsock;
1864 }
1865 
1866 /* returns 1 if the connection should be serviced again immediately, 0 if there
1867    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)1868 static int service_connection(curl_socket_t msgsock, struct httprequest *req,
1869                               curl_socket_t listensock,
1870                               const char *connecthost)
1871 {
1872   if(got_exit_signal)
1873     return -1;
1874 
1875   while(!req->done_processing) {
1876     int rc = get_request(msgsock, req);
1877     if (rc <= 0) {
1878       /* Nothing further to read now (possibly because the socket was closed */
1879       return rc;
1880     }
1881   }
1882 
1883   if(prevbounce) {
1884     /* bounce treatment requested */
1885     if((req->testno == prevtestno) &&
1886        (req->partno == prevpartno)) {
1887       req->partno++;
1888       logmsg("BOUNCE part number to %ld", req->partno);
1889     }
1890     else {
1891       prevbounce = FALSE;
1892       prevtestno = -1;
1893       prevpartno = -1;
1894     }
1895   }
1896 
1897   send_doc(msgsock, req);
1898   if(got_exit_signal)
1899     return -1;
1900 
1901   if(req->testno < 0) {
1902     logmsg("special request received, no persistency");
1903     return -1;
1904   }
1905   if(!req->open) {
1906     logmsg("instructed to close connection after server-reply");
1907     return -1;
1908   }
1909 
1910   if(req->connect_request) {
1911     /* a CONNECT request, setup and talk the tunnel */
1912     if(!is_proxy) {
1913       logmsg("received CONNECT but isn't running as proxy!");
1914       return 1;
1915     }
1916     else {
1917       http_connect(&msgsock, listensock, connecthost, req->connect_port);
1918       return -1;
1919     }
1920   }
1921 
1922   if(req->upgrade_request) {
1923     /* an upgrade request, switch to http2 here */
1924     http2(req);
1925     return -1;
1926   }
1927 
1928   /* if we got a CONNECT, loop and get another request as well! */
1929 
1930   if(req->open) {
1931     logmsg("=> persistant connection request ended, awaits new request\n");
1932     return 1;
1933   }
1934 
1935   return -1;
1936 }
1937 
main(int argc,char * argv[])1938 int main(int argc, char *argv[])
1939 {
1940   srvr_sockaddr_union_t me;
1941   curl_socket_t sock = CURL_SOCKET_BAD;
1942   int wrotepidfile = 0;
1943   int flag;
1944   unsigned short port = DEFAULT_PORT;
1945 #ifdef USE_UNIX_SOCKETS
1946   const char *unix_socket = NULL;
1947   bool unlink_socket = false;
1948 #endif
1949   char *pidname= (char *)".http.pid";
1950   struct httprequest req;
1951   int rc = 0;
1952   int error;
1953   int arg=1;
1954   long pid;
1955   const char *connecthost = "127.0.0.1";
1956   const char *socket_type = "IPv4";
1957   char port_str[11];
1958   const char *location_str = port_str;
1959 
1960   /* a default CONNECT port is basically pointless but still ... */
1961   size_t socket_idx;
1962 
1963   memset(&req, 0, sizeof(req));
1964 
1965   while(argc>arg) {
1966     if(!strcmp("--version", argv[arg])) {
1967       puts("sws IPv4"
1968 #ifdef ENABLE_IPV6
1969              "/IPv6"
1970 #endif
1971 #ifdef USE_UNIX_SOCKETS
1972              "/unix"
1973 #endif
1974           );
1975       return 0;
1976     }
1977     else if(!strcmp("--pidfile", argv[arg])) {
1978       arg++;
1979       if(argc>arg)
1980         pidname = argv[arg++];
1981     }
1982     else if(!strcmp("--logfile", argv[arg])) {
1983       arg++;
1984       if(argc>arg)
1985         serverlogfile = argv[arg++];
1986     }
1987     else if(!strcmp("--gopher", argv[arg])) {
1988       arg++;
1989       use_gopher = TRUE;
1990       end_of_headers = "\r\n"; /* gopher style is much simpler */
1991     }
1992     else if(!strcmp("--ipv4", argv[arg])) {
1993       socket_type = "IPv4";
1994       socket_domain = AF_INET;
1995       location_str = port_str;
1996       arg++;
1997     }
1998     else if(!strcmp("--ipv6", argv[arg])) {
1999 #ifdef ENABLE_IPV6
2000       socket_type = "IPv6";
2001       socket_domain = AF_INET6;
2002       location_str = port_str;
2003 #endif
2004       arg++;
2005     }
2006     else if(!strcmp("--unix-socket", argv[arg])) {
2007       arg++;
2008       if(argc>arg) {
2009 #ifdef USE_UNIX_SOCKETS
2010         unix_socket = argv[arg];
2011         if(strlen(unix_socket) >= sizeof(me.sau.sun_path)) {
2012           fprintf(stderr, "sws: socket path must be shorter than %zu chars\n",
2013                   sizeof(me.sau.sun_path));
2014           return 0;
2015         }
2016         socket_type = "unix";
2017         socket_domain = AF_UNIX;
2018         location_str = unix_socket;
2019 #endif
2020         arg++;
2021       }
2022     }
2023     else if(!strcmp("--port", argv[arg])) {
2024       arg++;
2025       if(argc>arg) {
2026         char *endptr;
2027         unsigned long ulnum = strtoul(argv[arg], &endptr, 10);
2028         if((endptr != argv[arg] + strlen(argv[arg])) ||
2029            (ulnum < 1025UL) || (ulnum > 65535UL)) {
2030           fprintf(stderr, "sws: invalid --port argument (%s)\n",
2031                   argv[arg]);
2032           return 0;
2033         }
2034         port = curlx_ultous(ulnum);
2035         arg++;
2036       }
2037     }
2038     else if(!strcmp("--srcdir", argv[arg])) {
2039       arg++;
2040       if(argc>arg) {
2041         path = argv[arg];
2042         arg++;
2043       }
2044     }
2045     else if(!strcmp("--connect", argv[arg])) {
2046       /* The connect host IP number that the proxy will connect to no matter
2047          what the client asks for, but also use this as a hint that we run as
2048          a proxy and do a few different internal choices */
2049       arg++;
2050       if(argc>arg) {
2051         connecthost = argv[arg];
2052         arg++;
2053         is_proxy = TRUE;
2054         logmsg("Run as proxy, CONNECT to host %s", connecthost);
2055       }
2056     }
2057     else {
2058       puts("Usage: sws [option]\n"
2059            " --version\n"
2060            " --logfile [file]\n"
2061            " --pidfile [file]\n"
2062            " --ipv4\n"
2063            " --ipv6\n"
2064            " --unix-socket [file]\n"
2065            " --port [port]\n"
2066            " --srcdir [path]\n"
2067            " --connect [ip4-addr]\n"
2068            " --gopher");
2069       return 0;
2070     }
2071   }
2072 
2073   snprintf(port_str, sizeof(port_str), "port %hu", port);
2074 
2075 #ifdef WIN32
2076   win32_init();
2077   atexit(win32_cleanup);
2078 #endif
2079 
2080   install_signal_handlers();
2081 
2082   pid = (long)getpid();
2083 
2084   sock = socket(socket_domain, SOCK_STREAM, 0);
2085 
2086   all_sockets[0] = sock;
2087   num_sockets = 1;
2088 
2089   if(CURL_SOCKET_BAD == sock) {
2090     error = SOCKERRNO;
2091     logmsg("Error creating socket: (%d) %s",
2092            error, strerror(error));
2093     goto sws_cleanup;
2094   }
2095 
2096   flag = 1;
2097   if(0 != setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
2098                      (void *)&flag, sizeof(flag))) {
2099     error = SOCKERRNO;
2100     logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s",
2101            error, strerror(error));
2102     goto sws_cleanup;
2103   }
2104   if(0 != curlx_nonblock(sock, TRUE)) {
2105     error = SOCKERRNO;
2106     logmsg("curlx_nonblock failed with error: (%d) %s",
2107            error, strerror(error));
2108     goto sws_cleanup;
2109   }
2110 
2111   switch(socket_domain) {
2112   case AF_INET:
2113     memset(&me.sa4, 0, sizeof(me.sa4));
2114     me.sa4.sin_family = AF_INET;
2115     me.sa4.sin_addr.s_addr = INADDR_ANY;
2116     me.sa4.sin_port = htons(port);
2117     rc = bind(sock, &me.sa, sizeof(me.sa4));
2118     break;
2119 #ifdef ENABLE_IPV6
2120   case AF_INET6:
2121     memset(&me.sa6, 0, sizeof(me.sa6));
2122     me.sa6.sin6_family = AF_INET6;
2123     me.sa6.sin6_addr = in6addr_any;
2124     me.sa6.sin6_port = htons(port);
2125     rc = bind(sock, &me.sa, sizeof(me.sa6));
2126     break;
2127 #endif /* ENABLE_IPV6 */
2128 #ifdef USE_UNIX_SOCKETS
2129   case AF_UNIX:
2130     memset(&me.sau, 0, sizeof(me.sau));
2131     me.sau.sun_family = AF_UNIX;
2132     strncpy(me.sau.sun_path, unix_socket, sizeof(me.sau.sun_path));
2133     rc = bind(sock, &me.sa, sizeof(me.sau));
2134     if(0 != rc && errno == EADDRINUSE) {
2135       struct stat statbuf;
2136       /* socket already exists. Perhaps it is stale? */
2137       int unixfd = socket(AF_UNIX, SOCK_STREAM, 0);
2138       if(CURL_SOCKET_BAD == unixfd) {
2139         error = SOCKERRNO;
2140         logmsg("Error binding socket, failed to create socket at %s: (%d) %s",
2141                unix_socket, error, strerror(error));
2142         goto sws_cleanup;
2143       }
2144       /* check whether the server is alive */
2145       rc = connect(unixfd, &me.sa, sizeof(me.sau));
2146       error = errno;
2147       close(unixfd);
2148       if(ECONNREFUSED != error) {
2149         logmsg("Error binding socket, failed to connect to %s: (%d) %s",
2150                unix_socket, error, strerror(error));
2151         goto sws_cleanup;
2152       }
2153       /* socket server is not alive, now check if it was actually a socket.
2154        * Systems which have Unix sockets will also have lstat */
2155       rc = lstat(unix_socket, &statbuf);
2156       if (0 != rc) {
2157         logmsg("Error binding socket, failed to stat %s: (%d) %s",
2158                unix_socket, errno, strerror(errno));
2159         goto sws_cleanup;
2160       }
2161       if((statbuf.st_mode & S_IFSOCK) != S_IFSOCK) {
2162         logmsg("Error binding socket, failed to stat %s: (%d) %s",
2163                unix_socket, error, strerror(error));
2164         goto sws_cleanup;
2165       }
2166       /* dead socket, cleanup and retry bind */
2167       rc = unlink(unix_socket);
2168       if(0 != rc) {
2169         logmsg("Error binding socket, failed to unlink %s: (%d) %s",
2170                unix_socket, errno, strerror(errno));
2171         goto sws_cleanup;
2172       }
2173       /* stale socket is gone, retry bind */
2174       rc = bind(sock, &me.sa, sizeof(me.sau));
2175     }
2176     break;
2177 #endif /* USE_UNIX_SOCKETS */
2178   }
2179   if(0 != rc) {
2180     error = SOCKERRNO;
2181     logmsg("Error binding socket on %s: (%d) %s",
2182            location_str, error, strerror(error));
2183     goto sws_cleanup;
2184   }
2185 
2186   logmsg("Running %s %s version on %s",
2187          use_gopher?"GOPHER":"HTTP", socket_type, location_str);
2188 
2189   /* start accepting connections */
2190   rc = listen(sock, 5);
2191   if(0 != rc) {
2192     error = SOCKERRNO;
2193     logmsg("listen() failed with error: (%d) %s",
2194            error, strerror(error));
2195     goto sws_cleanup;
2196   }
2197 
2198 #ifdef USE_UNIX_SOCKETS
2199   /* listen succeeds, so let's assume a valid listening Unix socket */
2200   unlink_socket = true;
2201 #endif
2202 
2203   /*
2204   ** As soon as this server writes its pid file the test harness will
2205   ** attempt to connect to this server and initiate its verification.
2206   */
2207 
2208   wrotepidfile = write_pidfile(pidname);
2209   if(!wrotepidfile)
2210     goto sws_cleanup;
2211 
2212   /* initialization of httprequest struct is done before get_request(), but
2213      the pipelining struct field must be initialized previously to FALSE
2214      every time a new connection arrives. */
2215 
2216   req.pipelining = FALSE;
2217   init_httprequest(&req);
2218 
2219   for(;;) {
2220     fd_set input;
2221     fd_set output;
2222     struct timeval timeout = {0, 250000L}; /* 250 ms */
2223     curl_socket_t maxfd = (curl_socket_t)-1;
2224 
2225     /* Clear out closed sockets */
2226     for (socket_idx = num_sockets - 1; socket_idx >= 1; --socket_idx) {
2227       if (CURL_SOCKET_BAD == all_sockets[socket_idx]) {
2228         char* dst = (char *) (all_sockets + socket_idx);
2229         char* src = (char *) (all_sockets + socket_idx + 1);
2230         char* end = (char *) (all_sockets + num_sockets);
2231         memmove(dst, src, end - src);
2232         num_sockets -= 1;
2233       }
2234     }
2235 
2236     if(got_exit_signal)
2237       goto sws_cleanup;
2238 
2239     /* Set up for select*/
2240     FD_ZERO(&input);
2241     FD_ZERO(&output);
2242 
2243     for (socket_idx = 0; socket_idx < num_sockets; ++socket_idx) {
2244       /* Listen on all sockets */
2245       FD_SET(all_sockets[socket_idx], &input);
2246       if(all_sockets[socket_idx] > maxfd)
2247         maxfd = all_sockets[socket_idx];
2248     }
2249 
2250     if(got_exit_signal)
2251       goto sws_cleanup;
2252 
2253     rc = select((int)maxfd + 1, &input, &output, NULL, &timeout);
2254     if (rc < 0) {
2255       error = SOCKERRNO;
2256       logmsg("select() failed with error: (%d) %s",
2257              error, strerror(error));
2258       goto sws_cleanup;
2259     }
2260 
2261     if(got_exit_signal)
2262       goto sws_cleanup;
2263 
2264     if (rc == 0) {
2265       /* Timed out - try again*/
2266       continue;
2267     }
2268 
2269     /* Check if the listening socket is ready to accept */
2270     if (FD_ISSET(all_sockets[0], &input)) {
2271       /* Service all queued connections */
2272       curl_socket_t msgsock;
2273       do {
2274         msgsock = accept_connection(sock);
2275         logmsg("accept_connection %d returned %d", sock, msgsock);
2276         if (CURL_SOCKET_BAD == msgsock)
2277           goto sws_cleanup;
2278       } while (msgsock > 0);
2279     }
2280 
2281     /* Service all connections that are ready */
2282     for (socket_idx = 1; socket_idx < num_sockets; ++socket_idx) {
2283       if (FD_ISSET(all_sockets[socket_idx], &input)) {
2284         if(got_exit_signal)
2285           goto sws_cleanup;
2286 
2287         /* Service this connection until it has nothing available */
2288         do {
2289           rc = service_connection(all_sockets[socket_idx], &req, sock,
2290                                   connecthost);
2291           if(got_exit_signal)
2292             goto sws_cleanup;
2293 
2294           if (rc < 0) {
2295             logmsg("====> Client disconnect %d", req.connmon);
2296 
2297             if(req.connmon) {
2298               const char *keepopen="[DISCONNECT]\n";
2299               storerequest((char *)keepopen, strlen(keepopen));
2300             }
2301 
2302             if(!req.open)
2303               /* When instructed to close connection after server-reply we
2304                  wait a very small amount of time before doing so. If this
2305                  is not done client might get an ECONNRESET before reading
2306                  a single byte of server-reply. */
2307               wait_ms(50);
2308 
2309             if(all_sockets[socket_idx] != CURL_SOCKET_BAD) {
2310               sclose(all_sockets[socket_idx]);
2311               all_sockets[socket_idx] = CURL_SOCKET_BAD;
2312             }
2313 
2314             serverlogslocked -= 1;
2315             if(!serverlogslocked)
2316               clear_advisor_read_lock(SERVERLOGS_LOCK);
2317 
2318             if (req.testno == DOCNUMBER_QUIT)
2319               goto sws_cleanup;
2320           }
2321 
2322           /* Reset the request, unless we're still in the middle of reading */
2323           if (rc != 0)
2324             init_httprequest(&req);
2325         } while (rc > 0);
2326       }
2327     }
2328 
2329     if(got_exit_signal)
2330       goto sws_cleanup;
2331   }
2332 
2333 sws_cleanup:
2334 
2335   for (socket_idx = 1; socket_idx < num_sockets; ++socket_idx)
2336     if((all_sockets[socket_idx] != sock) &&
2337      (all_sockets[socket_idx] != CURL_SOCKET_BAD))
2338       sclose(all_sockets[socket_idx]);
2339 
2340   if(sock != CURL_SOCKET_BAD)
2341     sclose(sock);
2342 
2343 #ifdef USE_UNIX_SOCKETS
2344   if(unlink_socket && socket_domain == AF_UNIX) {
2345     rc = unlink(unix_socket);
2346     logmsg("unlink(%s) = %d (%s)", unix_socket, rc, strerror(rc));
2347   }
2348 #endif
2349 
2350   if(got_exit_signal)
2351     logmsg("signalled to die");
2352 
2353   if(wrotepidfile)
2354     unlink(pidname);
2355 
2356   if(serverlogslocked) {
2357     serverlogslocked = 0;
2358     clear_advisor_read_lock(SERVERLOGS_LOCK);
2359   }
2360 
2361   restore_signal_handlers();
2362 
2363   if(got_exit_signal) {
2364     logmsg("========> %s sws (%s pid: %ld) exits with signal (%d)",
2365            socket_type, location_str, pid, exit_signal);
2366     /*
2367      * To properly set the return status of the process we
2368      * must raise the same signal SIGINT or SIGTERM that we
2369      * caught and let the old handler take care of it.
2370      */
2371     raise(exit_signal);
2372   }
2373 
2374   logmsg("========> sws quits");
2375   return 0;
2376 }
2377 
2378