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