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