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