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