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