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