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