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