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