1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
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.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
22 #include "server_setup.h"
24 /* sws.c: simple (silly?) web server
26 This code was originally graciously donated to the project by Juergen
27 Wilke. Thanks a bunch!
34 #ifdef HAVE_NETINET_IN_H
35 #include <netinet/in.h>
37 #ifdef HAVE_NETINET_IN6_H
38 #include <netinet/in6.h>
40 #ifdef HAVE_ARPA_INET_H
41 #include <arpa/inet.h>
46 #ifdef HAVE_NETINET_TCP_H
47 #include <netinet/tcp.h> /* for TCP_NODELAY */
50 #define ENABLE_CURLX_PRINTF
51 /* make the curlx header define all printf() functions to use the curlx_*
53 #include "curlx.h" /* from the private lib dir */
55 #include "inet_pton.h"
57 #include "server_sockaddr.h"
59 /* include memdebug.h last */
64 #define EINTR 4 /* errno.h value */
66 #define EAGAIN 11 /* errno.h value */
68 #define ERANGE 34 /* errno.h value */
72 socket_domain_inet = AF_INET
74 , socket_domain_inet6 = AF_INET6
76 #ifdef USE_UNIX_SOCKETS
77 , socket_domain_unix = AF_UNIX
79 } socket_domain = AF_INET;
80 static bool use_gopher = FALSE;
81 static int serverlogslocked = 0;
82 static bool is_proxy = FALSE;
84 #define REQBUFSIZ 150000
85 #define REQBUFSIZ_TXT "149999"
87 static long prevtestno = -1; /* previous test number we served */
88 static long prevpartno = -1; /* previous part number we served */
89 static bool prevbounce = FALSE; /* instructs the server to increase the part
90 number for a test in case the identical
91 testno+partno request shows up again */
93 #define RCMD_NORMALREQ 0 /* default request, use the tests file normally */
94 #define RCMD_IDLE 1 /* told to sit idle */
95 #define RCMD_STREAM 2 /* told to stream */
98 char reqbuf[REQBUFSIZ]; /* buffer area for the incoming request */
99 bool connect_request; /* if a CONNECT */
100 unsigned short connect_port; /* the port number CONNECT used */
101 size_t checkindex; /* where to start checking of the request */
102 size_t offset; /* size of the incoming request */
103 long testno; /* test number found in the request */
104 long partno; /* part number found in the request */
105 bool open; /* keep connection open info, as found in the request */
106 bool auth_req; /* authentication required, don't wait for body unless
107 there's an Authorization header */
108 bool auth; /* Authorization header present in the incoming request */
109 size_t cl; /* Content-Length of the incoming request */
110 bool digest; /* Authorization digest header found */
111 bool ntlm; /* Authorization ntlm header found */
112 int writedelay; /* if non-zero, delay this number of seconds between
113 writes in the response */
114 int pipe; /* if non-zero, expect this many requests to do a "piped"
116 int skip; /* if non-zero, the server is instructed to not read this
117 many bytes from a PUT/POST request. Ie the client sends N
118 bytes said in Content-Length, but the server only reads N
120 int rcmd; /* doing a special command, see defines above */
121 int prot_version; /* HTTP version * 10 */
122 bool pipelining; /* true if request is pipelined */
123 int callcount; /* times ProcessRequest() gets called */
124 bool connmon; /* monitor the state of the connection, log disconnects */
125 bool upgrade; /* test case allows upgrade to http2 */
126 bool upgrade_request; /* upgrade request found and allowed */
130 #define MAX_SOCKETS 1024
132 static curl_socket_t all_sockets[MAX_SOCKETS];
133 static size_t num_sockets = 0;
135 static int ProcessRequest(struct httprequest *req);
136 static void storerequest(const char *reqbuf, size_t totalsize);
138 #define DEFAULT_PORT 8999
140 #ifndef DEFAULT_LOGFILE
141 #define DEFAULT_LOGFILE "log/sws.log"
144 const char *serverlogfile = DEFAULT_LOGFILE;
146 #define SWSVERSION "curl test suite HTTP server/0.1"
148 #define REQUEST_DUMP "log/server.input"
149 #define RESPONSE_DUMP "log/server.response"
151 /* when told to run as proxy, we store the logs in different files so that
152 they can co-exist with the same program running as a "server" */
153 #define REQUEST_PROXY_DUMP "log/proxy.input"
154 #define RESPONSE_PROXY_DUMP "log/proxy.response"
156 /* very-big-path support */
157 #define MAXDOCNAMELEN 140000
158 #define MAXDOCNAMELEN_TXT "139999"
160 #define REQUEST_KEYWORD_SIZE 256
161 #define REQUEST_KEYWORD_SIZE_TXT "255"
163 #define CMD_AUTH_REQUIRED "auth_required"
165 /* 'idle' means that it will accept the request fine but never respond
166 any data. Just keep the connection alive. */
167 #define CMD_IDLE "idle"
169 /* 'stream' means to send a never-ending stream of data */
170 #define CMD_STREAM "stream"
172 /* 'connection-monitor' will output when a server/proxy connection gets
173 disconnected as for some cases it is important that it gets done at the
174 proper point - like with NTLM */
175 #define CMD_CONNECTIONMONITOR "connection-monitor"
177 /* upgrade to http2 */
178 #define CMD_UPGRADE "upgrade"
180 #define END_OF_HEADERS "\r\n\r\n"
183 DOCNUMBER_NOTHING = -4,
185 DOCNUMBER_WERULEZ = -2,
189 static const char *end_of_headers = END_OF_HEADERS;
191 /* sent as reply to a QUIT */
192 static const char *docquit =
193 "HTTP/1.1 200 Goodbye" END_OF_HEADERS;
195 /* send back this on 404 file not found */
196 static const char *doc404 = "HTTP/1.1 404 Not Found\r\n"
197 "Server: " SWSVERSION "\r\n"
198 "Connection: close\r\n"
199 "Content-Type: text/html"
201 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
203 "<TITLE>404 Not Found</TITLE>\n"
205 "<H1>Not Found</H1>\n"
206 "The requested URL was not found on this server.\n"
207 "<P><HR><ADDRESS>" SWSVERSION "</ADDRESS>\n" "</BODY></HTML>\n";
209 /* do-nothing macro replacement for systems which lack siginterrupt() */
211 #ifndef HAVE_SIGINTERRUPT
212 #define siginterrupt(x,y) do {} while(0)
215 /* vars used to keep around previous signal handlers */
217 typedef RETSIGTYPE (*SIGHANDLER_T)(int);
220 static SIGHANDLER_T old_sighup_handler = SIG_ERR;
224 static SIGHANDLER_T old_sigpipe_handler = SIG_ERR;
228 static SIGHANDLER_T old_sigalrm_handler = SIG_ERR;
232 static SIGHANDLER_T old_sigint_handler = SIG_ERR;
236 static SIGHANDLER_T old_sigterm_handler = SIG_ERR;
239 #if defined(SIGBREAK) && defined(WIN32)
240 static SIGHANDLER_T old_sigbreak_handler = SIG_ERR;
243 /* var which if set indicates that the program should finish execution */
245 SIG_ATOMIC_T got_exit_signal = 0;
247 /* if next is set indicates the first signal handled in exit_signal_handler */
249 static volatile int exit_signal = 0;
251 /* signal handler that will be triggered to indicate that the program
252 should finish its execution in a controlled manner as soon as possible.
253 The first time this is called it will set got_exit_signal to one and
254 store in exit_signal the signal that triggered its execution. */
256 static RETSIGTYPE exit_signal_handler(int signum)
258 int old_errno = errno;
259 if(got_exit_signal == 0) {
261 exit_signal = signum;
263 (void)signal(signum, exit_signal_handler);
267 static void install_signal_handlers(void)
270 /* ignore SIGHUP signal */
271 old_sighup_handler = signal(SIGHUP, SIG_IGN);
272 if(old_sighup_handler == SIG_ERR)
273 logmsg("cannot install SIGHUP handler: %s", strerror(errno));
276 /* ignore SIGPIPE signal */
277 old_sigpipe_handler = signal(SIGPIPE, SIG_IGN);
278 if(old_sigpipe_handler == SIG_ERR)
279 logmsg("cannot install SIGPIPE handler: %s", strerror(errno));
282 /* ignore SIGALRM signal */
283 old_sigalrm_handler = signal(SIGALRM, SIG_IGN);
284 if(old_sigalrm_handler == SIG_ERR)
285 logmsg("cannot install SIGALRM handler: %s", strerror(errno));
288 /* handle SIGINT signal with our exit_signal_handler */
289 old_sigint_handler = signal(SIGINT, exit_signal_handler);
290 if(old_sigint_handler == SIG_ERR)
291 logmsg("cannot install SIGINT handler: %s", strerror(errno));
293 siginterrupt(SIGINT, 1);
296 /* handle SIGTERM signal with our exit_signal_handler */
297 old_sigterm_handler = signal(SIGTERM, exit_signal_handler);
298 if(old_sigterm_handler == SIG_ERR)
299 logmsg("cannot install SIGTERM handler: %s", strerror(errno));
301 siginterrupt(SIGTERM, 1);
303 #if defined(SIGBREAK) && defined(WIN32)
304 /* handle SIGBREAK signal with our exit_signal_handler */
305 old_sigbreak_handler = signal(SIGBREAK, exit_signal_handler);
306 if(old_sigbreak_handler == SIG_ERR)
307 logmsg("cannot install SIGBREAK handler: %s", strerror(errno));
309 siginterrupt(SIGBREAK, 1);
313 static void restore_signal_handlers(void)
316 if(SIG_ERR != old_sighup_handler)
317 (void)signal(SIGHUP, old_sighup_handler);
320 if(SIG_ERR != old_sigpipe_handler)
321 (void)signal(SIGPIPE, old_sigpipe_handler);
324 if(SIG_ERR != old_sigalrm_handler)
325 (void)signal(SIGALRM, old_sigalrm_handler);
328 if(SIG_ERR != old_sigint_handler)
329 (void)signal(SIGINT, old_sigint_handler);
332 if(SIG_ERR != old_sigterm_handler)
333 (void)signal(SIGTERM, old_sigterm_handler);
335 #if defined(SIGBREAK) && defined(WIN32)
336 if(SIG_ERR != old_sigbreak_handler)
337 (void)signal(SIGBREAK, old_sigbreak_handler);
341 /* returns true if the current socket is an IP one */
342 static bool socket_domain_is_ip(void)
344 switch(socket_domain) {
356 /* based on the testno, parse the correct server commands */
357 static int parse_servercmd(struct httprequest *req)
363 filename = test2file(req->testno);
365 stream = fopen(filename, "rb");
368 logmsg("fopen() failed with error: %d %s", error, strerror(error));
369 logmsg(" [1] Error opening file: %s", filename);
370 logmsg(" Couldn't open test file %ld", req->testno);
371 req->open = FALSE; /* closes connection */
380 /* get the custom server control "commands" */
381 error = getpart(&orgcmd, &cmdsize, "reply", "servercmd", stream);
384 logmsg("getpart() failed with error: %d", error);
385 req->open = FALSE; /* closes connection */
389 req->connmon = FALSE;
392 while(cmd && cmdsize) {
395 if(!strncmp(CMD_AUTH_REQUIRED, cmd, strlen(CMD_AUTH_REQUIRED))) {
396 logmsg("instructed to require authorization header");
397 req->auth_req = TRUE;
399 else if(!strncmp(CMD_IDLE, cmd, strlen(CMD_IDLE))) {
400 logmsg("instructed to idle");
401 req->rcmd = RCMD_IDLE;
404 else if(!strncmp(CMD_STREAM, cmd, strlen(CMD_STREAM))) {
405 logmsg("instructed to stream");
406 req->rcmd = RCMD_STREAM;
408 else if(!strncmp(CMD_CONNECTIONMONITOR, cmd,
409 strlen(CMD_CONNECTIONMONITOR))) {
410 logmsg("enabled connection monitoring");
413 else if(!strncmp(CMD_UPGRADE, cmd, strlen(CMD_UPGRADE))) {
414 logmsg("enabled upgrade to http2");
417 else if(1 == sscanf(cmd, "pipe: %d", &num)) {
418 logmsg("instructed to allow a pipe size of %d", num);
420 logmsg("negative pipe size ignored");
422 req->pipe = num-1; /* decrease by one since we don't count the
423 first request in this number */
425 else if(1 == sscanf(cmd, "skip: %d", &num)) {
426 logmsg("instructed to skip this number of bytes %d", num);
429 else if(1 == sscanf(cmd, "writedelay: %d", &num)) {
430 logmsg("instructed to delay %d secs between packets", num);
431 req->writedelay = num;
434 logmsg("Unknown <servercmd> instruction found: %s", cmd);
436 /* try to deal with CRLF or just LF */
437 check = strchr(cmd, '\r');
439 check = strchr(cmd, '\n');
442 /* get to the letter following the newline */
443 while((*check == '\r') || (*check == '\n'))
447 /* if we reached a zero, get out */
460 static int ProcessRequest(struct httprequest *req)
462 char *line = &req->reqbuf[req->checkindex];
463 bool chunked = FALSE;
464 static char request[REQUEST_KEYWORD_SIZE];
465 static char doc[MAXDOCNAMELEN];
467 int prot_major, prot_minor;
468 char *end = strstr(line, end_of_headers);
472 logmsg("Process %d bytes request%s", req->offset,
473 req->callcount > 1?" [CONTINUED]":"");
475 /* try to figure out the request characteristics as soon as possible, but
479 (req->testno == DOCNUMBER_NOTHING) &&
480 !strncmp("/verifiedserver", line, 15)) {
481 logmsg("Are-we-friendly question received");
482 req->testno = DOCNUMBER_WERULEZ;
486 else if((req->testno == DOCNUMBER_NOTHING) &&
488 "%" REQUEST_KEYWORD_SIZE_TXT"s %" MAXDOCNAMELEN_TXT "s HTTP/%d.%d",
495 req->prot_version = prot_major*10 + prot_minor;
497 /* find the last slash */
498 ptr = strrchr(doc, '/');
500 /* get the number after it */
502 if((strlen(doc) + strlen(request)) < 400)
503 snprintf(logbuf, sizeof(logbuf), "Got request: %s %s HTTP/%d.%d",
504 request, doc, prot_major, prot_minor);
506 snprintf(logbuf, sizeof(logbuf), "Got a *HUGE* request HTTP/%d.%d",
507 prot_major, prot_minor);
508 logmsg("%s", logbuf);
510 if(!strncmp("/verifiedserver", ptr, 15)) {
511 logmsg("Are-we-friendly question received");
512 req->testno = DOCNUMBER_WERULEZ;
516 if(!strncmp("/quit", ptr, 5)) {
517 logmsg("Request-to-quit received");
518 req->testno = DOCNUMBER_QUIT;
522 ptr++; /* skip the slash */
524 /* skip all non-numericals following the slash */
525 while(*ptr && !ISDIGIT(*ptr))
528 req->testno = strtol(ptr, &ptr, 10);
530 if(req->testno > 10000) {
531 req->partno = req->testno % 10000;
532 req->testno /= 10000;
539 snprintf(logbuf, sizeof(logbuf), "Requested test number %ld part %ld",
540 req->testno, req->partno);
541 logmsg("%s", logbuf);
543 /* find and parse <servercmd> for this test */
544 parse_servercmd(req);
547 req->testno = DOCNUMBER_NOTHING;
551 if(req->testno == DOCNUMBER_NOTHING) {
552 /* didn't find any in the first scan, try alternative test case
555 if(sscanf(req->reqbuf, "CONNECT %" MAXDOCNAMELEN_TXT "s HTTP/%d.%d",
556 doc, &prot_major, &prot_minor) == 3) {
558 unsigned long part = 0;
560 snprintf(logbuf, sizeof(logbuf),
561 "Received a CONNECT %s HTTP/%d.%d request",
562 doc, prot_major, prot_minor);
563 logmsg("%s", logbuf);
565 req->connect_request = TRUE;
567 if(req->prot_version == 10)
568 req->open = FALSE; /* HTTP 1.0 closes connection by default */
572 /* scan through the hexgroups and store the value of the last group
573 in the 'part' variable and use as test case number!! */
574 while(*p && (ISXDIGIT(*p) || (*p == ':') || (*p == '.'))) {
576 part = strtoul(p, &endp, 16);
583 logmsg("Invalid CONNECT IPv6 address format");
584 else if(*(p + 1) != ':')
585 logmsg("Invalid CONNECT IPv6 port format");
592 portp = strchr(doc, ':');
594 if(portp && (*(portp + 1) != '\0') && ISDIGIT(*(portp + 1))) {
595 unsigned long ulnum = strtoul(portp + 1, NULL, 10);
596 if(!ulnum || (ulnum > 65535UL))
597 logmsg("Invalid CONNECT port received");
599 req->connect_port = curlx_ultous(ulnum);
602 logmsg("Port number: %d, test case number: %ld",
603 req->connect_port, req->testno);
607 if(req->testno == DOCNUMBER_NOTHING) {
608 /* check for a Testno: header with the test case number */
609 char *testno = strstr(line, "\nTestno: ");
611 req->testno = strtol(&testno[9], NULL, 10);
612 logmsg("Found test number %d in Testno: header!", req->testno);
615 if(req->testno == DOCNUMBER_NOTHING) {
616 /* Still no test case number. Try to get the the number off the last dot
617 instead, IE we consider the TLD to be the test number. Test 123 can
618 then be written as "example.com.123". */
620 /* find the last dot */
621 ptr = strrchr(doc, '.');
623 /* get the number after it */
625 ptr++; /* skip the dot */
627 req->testno = strtol(ptr, &ptr, 10);
629 if(req->testno > 10000) {
630 req->partno = req->testno % 10000;
631 req->testno /= 10000;
633 logmsg("found test %d in requested host name", req->testno);
639 snprintf(logbuf, sizeof(logbuf),
640 "Requested test number %ld part %ld (from host name)",
641 req->testno, req->partno);
642 logmsg("%s", logbuf);
647 logmsg("Did not find test number in PATH");
648 req->testno = DOCNUMBER_404;
651 parse_servercmd(req);
654 else if((req->offset >= 3) && (req->testno == DOCNUMBER_NOTHING)) {
655 logmsg("** Unusual request. Starts with %02x %02x %02x",
656 line[0], line[1], line[2]);
660 /* we don't have a complete request yet! */
661 logmsg("request not complete yet");
662 return 0; /* not complete yet */
664 logmsg("- request found to be complete");
667 /* when using gopher we cannot check the request until the entire
668 thing has been received */
671 /* find the last slash in the line */
672 ptr = strrchr(line, '/');
675 ptr++; /* skip the slash */
677 /* skip all non-numericals following the slash */
678 while(*ptr && !ISDIGIT(*ptr))
681 req->testno = strtol(ptr, &ptr, 10);
683 if(req->testno > 10000) {
684 req->partno = req->testno % 10000;
685 req->testno /= 10000;
690 snprintf(logbuf, sizeof(logbuf),
691 "Requested GOPHER test number %ld part %ld",
692 req->testno, req->partno);
693 logmsg("%s", logbuf);
698 /* we do have a full set, advance the checkindex to after the end of the
699 headers, for the pipelining case mostly */
700 req->checkindex += (end - line) + strlen(end_of_headers);
702 /* **** Persistence ****
704 * If the request is a HTTP/1.0 one, we close the connection unconditionally
707 * If the request is a HTTP/1.1 one, we MUST check for a "Connection:"
708 * header that might say "close". If it does, we close a connection when
709 * this request is processed. Otherwise, we keep the connection alive for X
717 if((req->cl == 0) && strncasecompare("Content-Length:", line, 15)) {
718 /* If we don't ignore content-length, we read it and we read the whole
719 request including the body before we return. If we've been told to
720 ignore the content-length, we will return as soon as all headers
721 have been received */
723 char *ptr = line + 15;
724 unsigned long clen = 0;
725 while(*ptr && ISSPACE(*ptr))
729 clen = strtoul(ptr, &endptr, 10);
730 if((ptr == endptr) || !ISSPACE(*endptr) || (ERANGE == errno)) {
731 /* this assumes that a zero Content-Length is valid */
732 logmsg("Found invalid Content-Length: (%s) in the request", ptr);
733 req->open = FALSE; /* closes connection */
736 req->cl = clen - req->skip;
738 logmsg("Found Content-Length: %lu in the request", clen);
740 logmsg("... but will abort after %zu bytes", req->cl);
743 else if(strncasecompare("Transfer-Encoding: chunked", line,
744 strlen("Transfer-Encoding: chunked"))) {
745 /* chunked data coming in */
750 if(strstr(req->reqbuf, "\r\n0\r\n\r\n"))
751 /* end of chunks reached */
754 return 0; /* not done */
757 line = strchr(line, '\n');
763 if(!req->auth && strstr(req->reqbuf, "Authorization:")) {
764 req->auth = TRUE; /* Authorization: header present! */
766 logmsg("Authorization header found, as required");
769 if(strstr(req->reqbuf, "Authorization: Negotiate")) {
770 /* Negotiate iterations */
771 static long prev_testno = -1;
772 static long prev_partno = -1;
773 logmsg("Negotiate: prev_testno: %d, prev_partno: %d",
774 prev_testno, prev_partno);
775 if(req->testno != prev_testno) {
776 prev_testno = req->testno;
777 prev_partno = req->partno;
780 req->partno = prev_partno;
782 else if(!req->digest && strstr(req->reqbuf, "Authorization: Digest")) {
783 /* If the client is passing this Digest-header, we set the part number
784 to 1000. Not only to spice up the complexity of this, but to make
785 Digest stuff to work in the test suite. */
787 req->digest = TRUE; /* header found */
788 logmsg("Received Digest request, sending back data %ld", req->partno);
790 else if(!req->ntlm &&
791 strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAD")) {
792 /* If the client is passing this type-3 NTLM header */
794 req->ntlm = TRUE; /* NTLM found */
795 logmsg("Received NTLM type-3, sending back data %ld", req->partno);
797 logmsg(" Expecting %zu POSTed bytes", req->cl);
800 else if(!req->ntlm &&
801 strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAB")) {
802 /* If the client is passing this type-1 NTLM header */
804 req->ntlm = TRUE; /* NTLM found */
805 logmsg("Received NTLM type-1, sending back data %ld", req->partno);
807 else if((req->partno >= 1000) &&
808 strstr(req->reqbuf, "Authorization: Basic")) {
809 /* If the client is passing this Basic-header and the part number is
810 already >=1000, we add 1 to the part number. This allows simple Basic
811 authentication negotiation to work in the test suite. */
813 logmsg("Received Basic request, sending back data %ld", req->partno);
815 if(strstr(req->reqbuf, "Connection: close"))
816 req->open = FALSE; /* close connection after this request */
820 req->prot_version >= 11 &&
822 req->reqbuf + req->offset > end + strlen(end_of_headers) &&
824 (!strncmp(req->reqbuf, "GET", strlen("GET")) ||
825 !strncmp(req->reqbuf, "HEAD", strlen("HEAD")))) {
826 /* If we have a persistent connection, HTTP version >= 1.1
827 and GET/HEAD request, enable pipelining. */
828 req->checkindex = (end - req->reqbuf) + strlen(end_of_headers);
829 req->pipelining = TRUE;
835 /* scan for more header ends within this chunk */
836 line = &req->reqbuf[req->checkindex];
837 end = strstr(line, end_of_headers);
840 req->checkindex += (end - line) + strlen(end_of_headers);
844 /* If authentication is required and no auth was provided, end now. This
845 makes the server NOT wait for PUT/POST data and you can then make the
846 test case send a rejection before any such data has been sent. Test case
848 if(req->auth_req && !req->auth) {
849 logmsg("Return early due to auth requested by none provided");
853 if(req->upgrade && strstr(req->reqbuf, "Upgrade:")) {
854 /* we allow upgrade and there was one! */
855 logmsg("Found Upgrade: in request and allows it");
856 req->upgrade_request = TRUE;
860 if(req->cl <= req->offset - (end - req->reqbuf) - strlen(end_of_headers))
863 return 0; /* not complete yet */
869 /* store the entire request in a file */
870 static void storerequest(const char *reqbuf, size_t totalsize)
877 const char *dumpfile = is_proxy?REQUEST_PROXY_DUMP:REQUEST_DUMP;
885 dump = fopen(dumpfile, "ab");
886 } while((dump == NULL) && ((error = errno) == EINTR));
888 logmsg("[2] Error opening file %s error: %d %s",
889 dumpfile, error, strerror(error));
890 logmsg("Failed to write request input ");
894 writeleft = totalsize;
896 written = fwrite(&reqbuf[totalsize-writeleft],
899 goto storerequest_cleanup;
901 writeleft -= written;
902 } while((writeleft > 0) && ((error = errno) == EINTR));
905 logmsg("Wrote request (%zu bytes) input to %s", totalsize, dumpfile);
906 else if(writeleft > 0) {
907 logmsg("Error writing file %s error: %d %s",
908 dumpfile, error, strerror(error));
909 logmsg("Wrote only (%zu bytes) of (%zu bytes) request input to %s",
910 totalsize-writeleft, totalsize, dumpfile);
913 storerequest_cleanup:
917 } while(res && ((error = errno) == EINTR));
919 logmsg("Error closing file %s error: %d %s",
920 dumpfile, error, strerror(error));
923 static void init_httprequest(struct httprequest *req)
925 /* Pipelining is already set, so do not initialize it here. Only initialize
926 checkindex and offset if pipelining is not set, since in a pipeline they
927 need to be inherited from the previous request. */
928 if(!req->pipelining) {
932 req->testno = DOCNUMBER_NOTHING;
934 req->connect_request = FALSE;
936 req->auth_req = FALSE;
944 req->rcmd = RCMD_NORMALREQ;
945 req->prot_version = 0;
947 req->connect_port = 0;
948 req->done_processing = 0;
950 req->upgrade_request = 0;
953 /* returns 1 if the connection should be serviced again immediately, 0 if there
954 is no data waiting, or < 0 if it should be closed */
955 static int get_request(curl_socket_t sock, struct httprequest *req)
959 char *reqbuf = req->reqbuf;
963 char *pipereq = NULL;
964 size_t pipereq_length = 0;
966 if(req->pipelining) {
967 pipereq = reqbuf + req->checkindex;
968 pipereq_length = req->offset - req->checkindex;
970 /* Now that we've got the pipelining info we can reset the
971 pipelining-related vars which were skipped in init_httprequest */
972 req->pipelining = FALSE;
977 if(req->offset >= REQBUFSIZ-1) {
978 /* buffer is already full; do nothing */
982 if(pipereq_length && pipereq) {
983 memmove(reqbuf, pipereq, pipereq_length);
984 got = curlx_uztosz(pipereq_length);
989 /* we are instructed to not read the entire thing, so we make sure to
990 only read what we're supposed to and NOT read the enire thing the
991 client wants to send! */
992 got = sread(sock, reqbuf + req->offset, req->cl);
994 got = sread(sock, reqbuf + req->offset, REQBUFSIZ-1 - req->offset);
999 logmsg("Connection closed by client");
1004 if(EAGAIN == error || EWOULDBLOCK == error) {
1005 /* nothing to read at the moment */
1008 logmsg("recv() returned error: (%d) %s", error, strerror(error));
1012 /* dump the request received so far to the external file */
1013 reqbuf[req->offset] = '\0';
1014 storerequest(reqbuf, req->offset);
1018 logmsg("Read %zd bytes", got);
1020 req->offset += (size_t)got;
1021 reqbuf[req->offset] = '\0';
1023 req->done_processing = ProcessRequest(req);
1026 if(req->done_processing && req->pipe) {
1027 logmsg("Waiting for another piped request");
1028 req->done_processing = 0;
1033 if(overflow || (req->offset == REQBUFSIZ-1 && got > 0)) {
1034 logmsg("Request would overflow buffer, closing connection");
1035 /* dump request received so far to external file anyway */
1036 reqbuf[REQBUFSIZ-1] = '\0';
1039 else if(req->offset > REQBUFSIZ-1) {
1040 logmsg("Request buffer overflow, closing connection");
1041 /* dump request received so far to external file anyway */
1042 reqbuf[REQBUFSIZ-1] = '\0';
1046 reqbuf[req->offset] = '\0';
1048 /* at the end of a request dump it to an external file */
1049 if(fail || req->done_processing)
1050 storerequest(reqbuf, req->pipelining ? req->checkindex : req->offset);
1054 return fail ? -1 : 1;
1057 /* returns -1 on failure */
1058 static int send_doc(curl_socket_t sock, struct httprequest *req)
1068 bool persistant = TRUE;
1069 bool sendfailure = FALSE;
1070 size_t responsesize;
1073 const char *responsedump = is_proxy?RESPONSE_PROXY_DUMP:RESPONSE_DUMP;
1074 static char weare[256];
1078 case RCMD_NORMALREQ:
1079 break; /* continue with business as usual */
1081 #define STREAMTHIS "a string to stream 01234567890\n"
1082 count = strlen(STREAMTHIS);
1084 written = swrite(sock, STREAMTHIS, count);
1087 if(written != (ssize_t)count) {
1088 logmsg("Stopped streaming");
1094 /* Do nothing. Sit idle. Pretend it rains. */
1100 if(req->testno < 0) {
1104 switch(req->testno) {
1105 case DOCNUMBER_QUIT:
1106 logmsg("Replying to QUIT");
1109 case DOCNUMBER_WERULEZ:
1110 /* we got a "friends?" question, reply back that we sure are */
1111 logmsg("Identifying ourselves as friends");
1112 snprintf(msgbuf, sizeof(msgbuf), "WE ROOLZ: %ld\r\n", (long)getpid());
1113 msglen = strlen(msgbuf);
1115 snprintf(weare, sizeof(weare), "%s", msgbuf);
1117 snprintf(weare, sizeof(weare),
1118 "HTTP/1.1 200 OK\r\nContent-Length: %zu\r\n\r\n%s",
1124 logmsg("Replying to with a 404");
1129 count = strlen(buffer);
1133 char *filename = test2file(req->testno);
1135 /* select the <data> tag for "normal" requests and the <connect> one
1136 for CONNECT requests (within the <reply> section) */
1137 const char *section = req->connect_request?"connect":"data";
1140 snprintf(partbuf, sizeof(partbuf), "%s%ld", section, req->partno);
1142 snprintf(partbuf, sizeof(partbuf), "%s", section);
1144 logmsg("Send response test%ld section <%s>", req->testno, partbuf);
1146 stream = fopen(filename, "rb");
1149 logmsg("fopen() failed with error: %d %s", error, strerror(error));
1150 logmsg(" [3] Error opening file: %s", filename);
1154 error = getpart(&ptr, &count, "reply", partbuf, stream);
1157 logmsg("getpart() failed with error: %d", error);
1163 if(got_exit_signal) {
1168 /* re-open the same file again */
1169 stream = fopen(filename, "rb");
1172 logmsg("fopen() failed with error: %d %s", error, strerror(error));
1173 logmsg(" [4] Error opening file: %s", filename);
1178 /* get the custom server control "commands" */
1179 error = getpart(&cmd, &cmdsize, "reply", "postcmd", stream);
1182 logmsg("getpart() failed with error: %d", error);
1189 if(got_exit_signal) {
1195 /* If the word 'swsclose' is present anywhere in the reply chunk, the
1196 connection will be closed after the data has been sent to the requesting
1198 if(strstr(buffer, "swsclose") || !count) {
1200 logmsg("connection close instruction \"swsclose\" found in response");
1202 if(strstr(buffer, "swsbounce")) {
1204 logmsg("enable \"swsbounce\" in the next request");
1209 dump = fopen(responsedump, "ab");
1212 logmsg("fopen() failed with error: %d %s", error, strerror(error));
1213 logmsg(" [5] Error opening file: %s", responsedump);
1219 responsesize = count;
1221 /* Ok, we send no more than N bytes at a time, just to make sure that
1222 larger chunks are split up so that the client will need to do multiple
1223 recv() calls to get it and thus we exercise that code better */
1229 written = swrite(sock, buffer, num);
1231 if((EWOULDBLOCK == SOCKERRNO) || (EAGAIN == SOCKERRNO)) {
1239 /* write to file as well */
1240 fwrite(buffer, 1, (size_t)written, dump);
1245 if(req->writedelay) {
1246 int quarters = req->writedelay * 4;
1247 logmsg("Pausing %d seconds", req->writedelay);
1248 while((quarters > 0) && !got_exit_signal) {
1253 } while((count > 0) && !got_exit_signal);
1257 } while(res && ((error = errno) == EINTR));
1259 logmsg("Error closing file %s error: %d %s",
1260 responsedump, error, strerror(error));
1262 if(got_exit_signal) {
1269 logmsg("Sending response failed. Only (%zu bytes) of (%zu bytes) "
1271 responsesize-count, responsesize);
1277 logmsg("Response sent (%zu bytes) and written to %s",
1278 responsesize, responsedump);
1287 if(2 == sscanf(ptr, "%31s %d", command, &num)) {
1288 if(!strcmp("wait", command)) {
1289 logmsg("Told to sleep for %d seconds", num);
1291 while((quarters > 0) && !got_exit_signal) {
1295 /* should not happen */
1297 logmsg("wait_ms() failed with error: (%d) %s",
1298 error, strerror(error));
1303 logmsg("Continuing after sleeping %d seconds", num);
1306 logmsg("Unknown command in reply command section");
1308 ptr = strchr(ptr, '\n');
1313 } while(ptr && *ptr);
1316 req->open = use_gopher?FALSE:persistant;
1318 prevtestno = req->testno;
1319 prevpartno = req->partno;
1324 static curl_socket_t connect_to(const char *ipaddr, unsigned short port)
1326 srvr_sockaddr_union_t serveraddr;
1327 curl_socket_t serverfd;
1330 const char *op_br = "";
1331 const char *cl_br = "";
1334 if(socket_domain == AF_INET6) {
1341 return CURL_SOCKET_BAD;
1343 logmsg("about to connect to %s%s%s:%hu",
1344 op_br, ipaddr, cl_br, port);
1347 serverfd = socket(socket_domain, SOCK_STREAM, 0);
1348 if(CURL_SOCKET_BAD == serverfd) {
1350 logmsg("Error creating socket for server connection: (%d) %s",
1351 error, strerror(error));
1352 return CURL_SOCKET_BAD;
1356 if(socket_domain_is_ip()) {
1357 /* Disable the Nagle algorithm */
1358 curl_socklen_t flag = 1;
1359 if(0 != setsockopt(serverfd, IPPROTO_TCP, TCP_NODELAY,
1360 (void *)&flag, sizeof(flag)))
1361 logmsg("====> TCP_NODELAY for server connection failed");
1365 switch(socket_domain) {
1367 memset(&serveraddr.sa4, 0, sizeof(serveraddr.sa4));
1368 serveraddr.sa4.sin_family = AF_INET;
1369 serveraddr.sa4.sin_port = htons(port);
1370 if(Curl_inet_pton(AF_INET, ipaddr, &serveraddr.sa4.sin_addr) < 1) {
1371 logmsg("Error inet_pton failed AF_INET conversion of '%s'", ipaddr);
1373 return CURL_SOCKET_BAD;
1376 rc = connect(serverfd, &serveraddr.sa, sizeof(serveraddr.sa4));
1380 memset(&serveraddr.sa6, 0, sizeof(serveraddr.sa6));
1381 serveraddr.sa6.sin6_family = AF_INET6;
1382 serveraddr.sa6.sin6_port = htons(port);
1383 if(Curl_inet_pton(AF_INET6, ipaddr, &serveraddr.sa6.sin6_addr) < 1) {
1384 logmsg("Error inet_pton failed AF_INET6 conversion of '%s'", ipaddr);
1386 return CURL_SOCKET_BAD;
1389 rc = connect(serverfd, &serveraddr.sa, sizeof(serveraddr.sa6));
1391 #endif /* ENABLE_IPV6 */
1392 #ifdef USE_UNIX_SOCKETS
1394 logmsg("Proxying through Unix socket is not (yet?) supported.");
1395 return CURL_SOCKET_BAD;
1396 #endif /* USE_UNIX_SOCKETS */
1399 if(got_exit_signal) {
1401 return CURL_SOCKET_BAD;
1406 logmsg("Error connecting to server port %hu: (%d) %s",
1407 port, error, strerror(error));
1409 return CURL_SOCKET_BAD;
1412 logmsg("connected fine to %s%s%s:%hu, now tunnel",
1413 op_br, ipaddr, cl_br, port);
1419 * A CONNECT has been received, a CONNECT response has been sent.
1421 * This function needs to connect to the server, and then pass data between
1422 * the client and the server back and forth until the connection is closed by
1425 * When doing FTP through a CONNECT proxy, we expect that the data connection
1426 * will be setup while the first connect is still being kept up. Therefore we
1427 * must accept a new connection and deal with it appropriately.
1430 #define data_or_ctrl(x) ((x)?"DATA":"CTRL")
1435 static void http_connect(curl_socket_t *infdp,
1436 curl_socket_t rootfd,
1438 unsigned short ipport)
1440 curl_socket_t serverfd[2] = {CURL_SOCKET_BAD, CURL_SOCKET_BAD};
1441 curl_socket_t clientfd[2] = {CURL_SOCKET_BAD, CURL_SOCKET_BAD};
1442 ssize_t toc[2] = {0, 0}; /* number of bytes to client */
1443 ssize_t tos[2] = {0, 0}; /* number of bytes to server */
1444 char readclient[2][256];
1445 char readserver[2][256];
1446 bool poll_client_rd[2] = { TRUE, TRUE };
1447 bool poll_server_rd[2] = { TRUE, TRUE };
1448 bool poll_client_wr[2] = { TRUE, TRUE };
1449 bool poll_server_wr[2] = { TRUE, TRUE };
1450 bool primary = FALSE;
1451 bool secondary = FALSE;
1452 int max_tunnel_idx; /* CTRL or DATA */
1455 int timeout_count = 0;
1457 /* primary tunnel client endpoint already connected */
1458 clientfd[CTRL] = *infdp;
1460 /* Sleep here to make sure the client reads CONNECT response's
1461 'end of headers' separate from the server data that follows.
1462 This is done to prevent triggering libcurl known bug #39. */
1463 for(loop = 2; (loop > 0) && !got_exit_signal; loop--)
1466 goto http_connect_cleanup;
1468 serverfd[CTRL] = connect_to(ipaddr, ipport);
1469 if(serverfd[CTRL] == CURL_SOCKET_BAD)
1470 goto http_connect_cleanup;
1472 /* Primary tunnel socket endpoints are now connected. Tunnel data back and
1473 forth over the primary tunnel until client or server breaks the primary
1474 tunnel, simultaneously allowing establishment, operation and teardown of
1475 a secondary tunnel that may be used for passive FTP data connection. */
1477 max_tunnel_idx = CTRL;
1480 while(!got_exit_signal) {
1484 struct timeval timeout = {1, 0}; /* 1000 ms */
1486 curl_socket_t maxfd = (curl_socket_t)-1;
1491 if((clientfd[DATA] == CURL_SOCKET_BAD) &&
1492 (serverfd[DATA] == CURL_SOCKET_BAD) &&
1493 poll_client_rd[CTRL] && poll_client_wr[CTRL] &&
1494 poll_server_rd[CTRL] && poll_server_wr[CTRL]) {
1495 /* listener socket is monitored to allow client to establish
1496 secondary tunnel only when this tunnel is not established
1497 and primary one is fully operational */
1498 FD_SET(rootfd, &input);
1502 /* set tunnel sockets to wait for */
1503 for(i = 0; i <= max_tunnel_idx; i++) {
1504 /* client side socket monitoring */
1505 if(clientfd[i] != CURL_SOCKET_BAD) {
1506 if(poll_client_rd[i]) {
1507 /* unless told not to do so, monitor readability */
1508 FD_SET(clientfd[i], &input);
1509 if(clientfd[i] > maxfd)
1510 maxfd = clientfd[i];
1512 if(poll_client_wr[i] && toc[i]) {
1513 /* unless told not to do so, monitor writability
1514 if there is data ready to be sent to client */
1515 FD_SET(clientfd[i], &output);
1516 if(clientfd[i] > maxfd)
1517 maxfd = clientfd[i];
1520 /* server side socket monitoring */
1521 if(serverfd[i] != CURL_SOCKET_BAD) {
1522 if(poll_server_rd[i]) {
1523 /* unless told not to do so, monitor readability */
1524 FD_SET(serverfd[i], &input);
1525 if(serverfd[i] > maxfd)
1526 maxfd = serverfd[i];
1528 if(poll_server_wr[i] && tos[i]) {
1529 /* unless told not to do so, monitor writability
1530 if there is data ready to be sent to server */
1531 FD_SET(serverfd[i], &output);
1532 if(serverfd[i] > maxfd)
1533 maxfd = serverfd[i];
1540 rc = select((int)maxfd + 1, &input, &output, NULL, &timeout);
1552 /* ---------------------------------------------------------- */
1554 /* passive mode FTP may establish a secondary tunnel */
1555 if((clientfd[DATA] == CURL_SOCKET_BAD) &&
1556 (serverfd[DATA] == CURL_SOCKET_BAD) && FD_ISSET(rootfd, &input)) {
1557 /* a new connection on listener socket (most likely from client) */
1558 curl_socket_t datafd = accept(rootfd, NULL, NULL);
1559 if(datafd != CURL_SOCKET_BAD) {
1560 struct httprequest req2;
1562 memset(&req2, 0, sizeof(req2));
1563 logmsg("====> Client connect DATA");
1565 if(socket_domain_is_ip()) {
1566 /* Disable the Nagle algorithm */
1567 curl_socklen_t flag = 1;
1568 if(0 != setsockopt(datafd, IPPROTO_TCP, TCP_NODELAY,
1569 (void *)&flag, sizeof(flag)))
1570 logmsg("====> TCP_NODELAY for client DATA connection failed");
1573 req2.pipelining = FALSE;
1574 init_httprequest(&req2);
1575 while(!req2.done_processing) {
1576 err = get_request(datafd, &req2);
1578 /* this socket must be closed, done or not */
1583 /* skip this and close the socket if err < 0 */
1585 err = send_doc(datafd, &req2);
1586 if(!err && req2.connect_request) {
1587 /* sleep to prevent triggering libcurl known bug #39. */
1588 for(loop = 2; (loop > 0) && !got_exit_signal; loop--)
1590 if(!got_exit_signal) {
1591 /* connect to the server */
1592 serverfd[DATA] = connect_to(ipaddr, req2.connect_port);
1593 if(serverfd[DATA] != CURL_SOCKET_BAD) {
1594 /* secondary tunnel established, now we have two
1596 poll_client_rd[DATA] = TRUE;
1597 poll_client_wr[DATA] = TRUE;
1598 poll_server_rd[DATA] = TRUE;
1599 poll_server_wr[DATA] = TRUE;
1600 max_tunnel_idx = DATA;
1604 clientfd[DATA] = datafd;
1605 datafd = CURL_SOCKET_BAD;
1610 if(datafd != CURL_SOCKET_BAD) {
1611 /* secondary tunnel not established */
1612 shutdown(datafd, SHUT_RDWR);
1620 /* ---------------------------------------------------------- */
1622 /* react to tunnel endpoint readable/writable notifications */
1623 for(i = 0; i <= max_tunnel_idx; i++) {
1625 if(clientfd[i] != CURL_SOCKET_BAD) {
1626 len = sizeof(readclient[i]) - tos[i];
1627 if(len && FD_ISSET(clientfd[i], &input)) {
1628 /* read from client */
1629 rc = sread(clientfd[i], &readclient[i][tos[i]], len);
1631 logmsg("[%s] got %zd, STOP READING client", data_or_ctrl(i), rc);
1632 shutdown(clientfd[i], SHUT_RD);
1633 poll_client_rd[i] = FALSE;
1636 logmsg("[%s] READ %zd bytes from client", data_or_ctrl(i), rc);
1637 logmsg("[%s] READ \"%s\"", data_or_ctrl(i),
1638 data_to_hex(&readclient[i][tos[i]], rc));
1643 if(serverfd[i] != CURL_SOCKET_BAD) {
1644 len = sizeof(readserver[i])-toc[i];
1645 if(len && FD_ISSET(serverfd[i], &input)) {
1646 /* read from server */
1647 rc = sread(serverfd[i], &readserver[i][toc[i]], len);
1649 logmsg("[%s] got %zd, STOP READING server", data_or_ctrl(i), rc);
1650 shutdown(serverfd[i], SHUT_RD);
1651 poll_server_rd[i] = FALSE;
1654 logmsg("[%s] READ %zd bytes from server", data_or_ctrl(i), rc);
1655 logmsg("[%s] READ \"%s\"", data_or_ctrl(i),
1656 data_to_hex(&readserver[i][toc[i]], rc));
1661 if(clientfd[i] != CURL_SOCKET_BAD) {
1662 if(toc[i] && FD_ISSET(clientfd[i], &output)) {
1663 /* write to client */
1664 rc = swrite(clientfd[i], readserver[i], toc[i]);
1666 logmsg("[%s] got %zd, STOP WRITING client", data_or_ctrl(i), rc);
1667 shutdown(clientfd[i], SHUT_WR);
1668 poll_client_wr[i] = FALSE;
1672 logmsg("[%s] SENT %zd bytes to client", data_or_ctrl(i), rc);
1673 logmsg("[%s] SENT \"%s\"", data_or_ctrl(i),
1674 data_to_hex(readserver[i], rc));
1676 memmove(&readserver[i][0], &readserver[i][rc], toc[i]-rc);
1681 if(serverfd[i] != CURL_SOCKET_BAD) {
1682 if(tos[i] && FD_ISSET(serverfd[i], &output)) {
1683 /* write to server */
1684 rc = swrite(serverfd[i], readclient[i], tos[i]);
1686 logmsg("[%s] got %zd, STOP WRITING server", data_or_ctrl(i), rc);
1687 shutdown(serverfd[i], SHUT_WR);
1688 poll_server_wr[i] = FALSE;
1692 logmsg("[%s] SENT %zd bytes to server", data_or_ctrl(i), rc);
1693 logmsg("[%s] SENT \"%s\"", data_or_ctrl(i),
1694 data_to_hex(readclient[i], rc));
1696 memmove(&readclient[i][0], &readclient[i][rc], tos[i]-rc);
1705 /* ---------------------------------------------------------- */
1707 /* endpoint read/write disabling, endpoint closing and tunnel teardown */
1708 for(i = 0; i <= max_tunnel_idx; i++) {
1709 for(loop = 2; loop > 0; loop--) {
1710 /* loop twice to satisfy condition interdependencies without
1711 having to await select timeout or another socket event */
1712 if(clientfd[i] != CURL_SOCKET_BAD) {
1713 if(poll_client_rd[i] && !poll_server_wr[i]) {
1714 logmsg("[%s] DISABLED READING client", data_or_ctrl(i));
1715 shutdown(clientfd[i], SHUT_RD);
1716 poll_client_rd[i] = FALSE;
1718 if(poll_client_wr[i] && !poll_server_rd[i] && !toc[i]) {
1719 logmsg("[%s] DISABLED WRITING client", data_or_ctrl(i));
1720 shutdown(clientfd[i], SHUT_WR);
1721 poll_client_wr[i] = FALSE;
1725 if(serverfd[i] != CURL_SOCKET_BAD) {
1726 if(poll_server_rd[i] && !poll_client_wr[i]) {
1727 logmsg("[%s] DISABLED READING server", data_or_ctrl(i));
1728 shutdown(serverfd[i], SHUT_RD);
1729 poll_server_rd[i] = FALSE;
1731 if(poll_server_wr[i] && !poll_client_rd[i] && !tos[i]) {
1732 logmsg("[%s] DISABLED WRITING server", data_or_ctrl(i));
1733 shutdown(serverfd[i], SHUT_WR);
1734 poll_server_wr[i] = FALSE;
1742 /* allow kernel to place FIN bit packet on the wire */
1745 /* socket clearing */
1746 for(i = 0; i <= max_tunnel_idx; i++) {
1747 for(loop = 2; loop > 0; loop--) {
1748 if(clientfd[i] != CURL_SOCKET_BAD) {
1749 if(!poll_client_wr[i] && !poll_client_rd[i]) {
1750 logmsg("[%s] CLOSING client socket", data_or_ctrl(i));
1751 sclose(clientfd[i]);
1752 clientfd[i] = CURL_SOCKET_BAD;
1753 if(serverfd[i] == CURL_SOCKET_BAD) {
1754 logmsg("[%s] ENDING", data_or_ctrl(i));
1762 if(serverfd[i] != CURL_SOCKET_BAD) {
1763 if(!poll_server_wr[i] && !poll_server_rd[i]) {
1764 logmsg("[%s] CLOSING server socket", data_or_ctrl(i));
1765 sclose(serverfd[i]);
1766 serverfd[i] = CURL_SOCKET_BAD;
1767 if(clientfd[i] == CURL_SOCKET_BAD) {
1768 logmsg("[%s] ENDING", data_or_ctrl(i));
1779 /* ---------------------------------------------------------- */
1781 max_tunnel_idx = secondary ? DATA : CTRL;
1784 /* exit loop upon primary tunnel teardown */
1790 if(timeout_count > 5) {
1791 logmsg("CONNECT proxy timeout after %d idle seconds!", timeout_count);
1797 http_connect_cleanup:
1799 for(i = DATA; i >= CTRL; i--) {
1800 if(serverfd[i] != CURL_SOCKET_BAD) {
1801 logmsg("[%s] CLOSING server socket (cleanup)", data_or_ctrl(i));
1802 shutdown(serverfd[i], SHUT_RDWR);
1803 sclose(serverfd[i]);
1805 if(clientfd[i] != CURL_SOCKET_BAD) {
1806 logmsg("[%s] CLOSING client socket (cleanup)", data_or_ctrl(i));
1807 shutdown(clientfd[i], SHUT_RDWR);
1808 sclose(clientfd[i]);
1810 if((serverfd[i] != CURL_SOCKET_BAD) ||
1811 (clientfd[i] != CURL_SOCKET_BAD)) {
1812 logmsg("[%s] ABORTING", data_or_ctrl(i));
1816 *infdp = CURL_SOCKET_BAD;
1819 static void http2(struct httprequest *req)
1822 logmsg("switched to http2");
1823 /* left to implement */
1827 /* returns a socket handle, or 0 if there are no more waiting sockets,
1828 or < 0 if there was an error */
1829 static curl_socket_t accept_connection(curl_socket_t sock)
1831 curl_socket_t msgsock = CURL_SOCKET_BAD;
1835 if(MAX_SOCKETS == num_sockets) {
1836 logmsg("Too many open sockets!");
1837 return CURL_SOCKET_BAD;
1840 msgsock = accept(sock, NULL, NULL);
1842 if(got_exit_signal) {
1843 if(CURL_SOCKET_BAD != msgsock)
1845 return CURL_SOCKET_BAD;
1848 if(CURL_SOCKET_BAD == msgsock) {
1850 if(EAGAIN == error || EWOULDBLOCK == error) {
1851 /* nothing to accept */
1854 logmsg("MAJOR ERROR: accept() failed with error: (%d) %s",
1855 error, strerror(error));
1856 return CURL_SOCKET_BAD;
1859 if(0 != curlx_nonblock(msgsock, TRUE)) {
1861 logmsg("curlx_nonblock failed with error: (%d) %s",
1862 error, strerror(error));
1864 return CURL_SOCKET_BAD;
1867 if(0 != setsockopt(msgsock, SOL_SOCKET, SO_KEEPALIVE,
1868 (void *)&flag, sizeof(flag))) {
1870 logmsg("setsockopt(SO_KEEPALIVE) failed with error: (%d) %s",
1871 error, strerror(error));
1873 return CURL_SOCKET_BAD;
1877 ** As soon as this server accepts a connection from the test harness it
1878 ** must set the server logs advisor read lock to indicate that server
1879 ** logs should not be read until this lock is removed by this server.
1882 if(!serverlogslocked)
1883 set_advisor_read_lock(SERVERLOGS_LOCK);
1884 serverlogslocked += 1;
1886 logmsg("====> Client connect");
1888 all_sockets[num_sockets] = msgsock;
1892 if(socket_domain_is_ip()) {
1894 * Disable the Nagle algorithm to make it easier to send out a large
1895 * response in many small segments to torture the clients more.
1897 if(0 != setsockopt(msgsock, IPPROTO_TCP, TCP_NODELAY,
1898 (void *)&flag, sizeof(flag)))
1899 logmsg("====> TCP_NODELAY failed");
1906 /* returns 1 if the connection should be serviced again immediately, 0 if there
1907 is no data waiting, or < 0 if it should be closed */
1908 static int service_connection(curl_socket_t msgsock, struct httprequest *req,
1909 curl_socket_t listensock,
1910 const char *connecthost)
1915 while(!req->done_processing) {
1916 int rc = get_request(msgsock, req);
1918 /* Nothing further to read now, possibly because the socket was closed */
1924 /* bounce treatment requested */
1925 if((req->testno == prevtestno) &&
1926 (req->partno == prevpartno)) {
1928 logmsg("BOUNCE part number to %ld", req->partno);
1937 send_doc(msgsock, req);
1941 if(req->testno < 0) {
1942 logmsg("special request received, no persistency");
1946 logmsg("instructed to close connection after server-reply");
1950 if(req->connect_request) {
1951 /* a CONNECT request, setup and talk the tunnel */
1953 logmsg("received CONNECT but isn't running as proxy!");
1957 http_connect(&msgsock, listensock, connecthost, req->connect_port);
1962 if(req->upgrade_request) {
1963 /* an upgrade request, switch to http2 here */
1968 /* if we got a CONNECT, loop and get another request as well! */
1971 logmsg("=> persistant connection request ended, awaits new request\n");
1978 int main(int argc, char *argv[])
1980 srvr_sockaddr_union_t me;
1981 curl_socket_t sock = CURL_SOCKET_BAD;
1982 int wrotepidfile = 0;
1984 unsigned short port = DEFAULT_PORT;
1985 #ifdef USE_UNIX_SOCKETS
1986 const char *unix_socket = NULL;
1987 bool unlink_socket = false;
1989 const char *pidname = ".http.pid";
1990 struct httprequest req;
1995 const char *connecthost = "127.0.0.1";
1996 const char *socket_type = "IPv4";
1998 const char *location_str = port_str;
2000 /* a default CONNECT port is basically pointless but still ... */
2003 memset(&req, 0, sizeof(req));
2006 if(!strcmp("--version", argv[arg])) {
2011 #ifdef USE_UNIX_SOCKETS
2017 else if(!strcmp("--pidfile", argv[arg])) {
2020 pidname = argv[arg++];
2022 else if(!strcmp("--logfile", argv[arg])) {
2025 serverlogfile = argv[arg++];
2027 else if(!strcmp("--gopher", argv[arg])) {
2030 end_of_headers = "\r\n"; /* gopher style is much simpler */
2032 else if(!strcmp("--ipv4", argv[arg])) {
2033 socket_type = "IPv4";
2034 socket_domain = AF_INET;
2035 location_str = port_str;
2038 else if(!strcmp("--ipv6", argv[arg])) {
2040 socket_type = "IPv6";
2041 socket_domain = AF_INET6;
2042 location_str = port_str;
2046 else if(!strcmp("--unix-socket", argv[arg])) {
2049 #ifdef USE_UNIX_SOCKETS
2050 unix_socket = argv[arg];
2051 if(strlen(unix_socket) >= sizeof(me.sau.sun_path)) {
2052 fprintf(stderr, "sws: socket path must be shorter than %zu chars\n",
2053 sizeof(me.sau.sun_path));
2056 socket_type = "unix";
2057 socket_domain = AF_UNIX;
2058 location_str = unix_socket;
2063 else if(!strcmp("--port", argv[arg])) {
2067 unsigned long ulnum = strtoul(argv[arg], &endptr, 10);
2068 if((endptr != argv[arg] + strlen(argv[arg])) ||
2069 (ulnum < 1025UL) || (ulnum > 65535UL)) {
2070 fprintf(stderr, "sws: invalid --port argument (%s)\n",
2074 port = curlx_ultous(ulnum);
2078 else if(!strcmp("--srcdir", argv[arg])) {
2085 else if(!strcmp("--connect", argv[arg])) {
2086 /* The connect host IP number that the proxy will connect to no matter
2087 what the client asks for, but also use this as a hint that we run as
2088 a proxy and do a few different internal choices */
2091 connecthost = argv[arg];
2094 logmsg("Run as proxy, CONNECT to host %s", connecthost);
2098 puts("Usage: sws [option]\n"
2100 " --logfile [file]\n"
2101 " --pidfile [file]\n"
2104 " --unix-socket [file]\n"
2106 " --srcdir [path]\n"
2107 " --connect [ip4-addr]\n"
2113 snprintf(port_str, sizeof(port_str), "port %hu", port);
2117 atexit(win32_cleanup);
2120 install_signal_handlers();
2122 pid = (long)getpid();
2124 sock = socket(socket_domain, SOCK_STREAM, 0);
2126 all_sockets[0] = sock;
2129 if(CURL_SOCKET_BAD == sock) {
2131 logmsg("Error creating socket: (%d) %s",
2132 error, strerror(error));
2137 if(0 != setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
2138 (void *)&flag, sizeof(flag))) {
2140 logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s",
2141 error, strerror(error));
2144 if(0 != curlx_nonblock(sock, TRUE)) {
2146 logmsg("curlx_nonblock failed with error: (%d) %s",
2147 error, strerror(error));
2151 switch(socket_domain) {
2153 memset(&me.sa4, 0, sizeof(me.sa4));
2154 me.sa4.sin_family = AF_INET;
2155 me.sa4.sin_addr.s_addr = INADDR_ANY;
2156 me.sa4.sin_port = htons(port);
2157 rc = bind(sock, &me.sa, sizeof(me.sa4));
2161 memset(&me.sa6, 0, sizeof(me.sa6));
2162 me.sa6.sin6_family = AF_INET6;
2163 me.sa6.sin6_addr = in6addr_any;
2164 me.sa6.sin6_port = htons(port);
2165 rc = bind(sock, &me.sa, sizeof(me.sa6));
2167 #endif /* ENABLE_IPV6 */
2168 #ifdef USE_UNIX_SOCKETS
2170 memset(&me.sau, 0, sizeof(me.sau));
2171 me.sau.sun_family = AF_UNIX;
2172 strncpy(me.sau.sun_path, unix_socket, sizeof(me.sau.sun_path));
2173 rc = bind(sock, &me.sa, sizeof(me.sau));
2174 if(0 != rc && errno == EADDRINUSE) {
2175 struct stat statbuf;
2176 /* socket already exists. Perhaps it is stale? */
2177 int unixfd = socket(AF_UNIX, SOCK_STREAM, 0);
2178 if(CURL_SOCKET_BAD == unixfd) {
2180 logmsg("Error binding socket, failed to create socket at %s: (%d) %s",
2181 unix_socket, error, strerror(error));
2184 /* check whether the server is alive */
2185 rc = connect(unixfd, &me.sa, sizeof(me.sau));
2188 if(ECONNREFUSED != error) {
2189 logmsg("Error binding socket, failed to connect to %s: (%d) %s",
2190 unix_socket, error, strerror(error));
2193 /* socket server is not alive, now check if it was actually a socket.
2194 * Systems which have Unix sockets will also have lstat */
2195 rc = lstat(unix_socket, &statbuf);
2197 logmsg("Error binding socket, failed to stat %s: (%d) %s",
2198 unix_socket, errno, strerror(errno));
2201 if((statbuf.st_mode & S_IFSOCK) != S_IFSOCK) {
2202 logmsg("Error binding socket, failed to stat %s: (%d) %s",
2203 unix_socket, error, strerror(error));
2206 /* dead socket, cleanup and retry bind */
2207 rc = unlink(unix_socket);
2209 logmsg("Error binding socket, failed to unlink %s: (%d) %s",
2210 unix_socket, errno, strerror(errno));
2213 /* stale socket is gone, retry bind */
2214 rc = bind(sock, &me.sa, sizeof(me.sau));
2217 #endif /* USE_UNIX_SOCKETS */
2221 logmsg("Error binding socket on %s: (%d) %s",
2222 location_str, error, strerror(error));
2226 logmsg("Running %s %s version on %s",
2227 use_gopher?"GOPHER":"HTTP", socket_type, location_str);
2229 /* start accepting connections */
2230 rc = listen(sock, 5);
2233 logmsg("listen() failed with error: (%d) %s",
2234 error, strerror(error));
2238 #ifdef USE_UNIX_SOCKETS
2239 /* listen succeeds, so let's assume a valid listening Unix socket */
2240 unlink_socket = true;
2244 ** As soon as this server writes its pid file the test harness will
2245 ** attempt to connect to this server and initiate its verification.
2248 wrotepidfile = write_pidfile(pidname);
2252 /* initialization of httprequest struct is done before get_request(), but
2253 the pipelining struct field must be initialized previously to FALSE
2254 every time a new connection arrives. */
2256 req.pipelining = FALSE;
2257 init_httprequest(&req);
2262 struct timeval timeout = {0, 250000L}; /* 250 ms */
2263 curl_socket_t maxfd = (curl_socket_t)-1;
2265 /* Clear out closed sockets */
2266 for(socket_idx = num_sockets - 1; socket_idx >= 1; --socket_idx) {
2267 if(CURL_SOCKET_BAD == all_sockets[socket_idx]) {
2268 char *dst = (char *) (all_sockets + socket_idx);
2269 char *src = (char *) (all_sockets + socket_idx + 1);
2270 char *end = (char *) (all_sockets + num_sockets);
2271 memmove(dst, src, end - src);
2279 /* Set up for select */
2283 for(socket_idx = 0; socket_idx < num_sockets; ++socket_idx) {
2284 /* Listen on all sockets */
2285 FD_SET(all_sockets[socket_idx], &input);
2286 if(all_sockets[socket_idx] > maxfd)
2287 maxfd = all_sockets[socket_idx];
2293 rc = select((int)maxfd + 1, &input, &output, NULL, &timeout);
2296 logmsg("select() failed with error: (%d) %s",
2297 error, strerror(error));
2305 /* Timed out - try again */
2309 /* Check if the listening socket is ready to accept */
2310 if(FD_ISSET(all_sockets[0], &input)) {
2311 /* Service all queued connections */
2312 curl_socket_t msgsock;
2314 msgsock = accept_connection(sock);
2315 logmsg("accept_connection %d returned %d", sock, msgsock);
2316 if(CURL_SOCKET_BAD == msgsock)
2318 } while(msgsock > 0);
2321 /* Service all connections that are ready */
2322 for(socket_idx = 1; socket_idx < num_sockets; ++socket_idx) {
2323 if(FD_ISSET(all_sockets[socket_idx], &input)) {
2327 /* Service this connection until it has nothing available */
2329 rc = service_connection(all_sockets[socket_idx], &req, sock,
2335 logmsg("====> Client disconnect %d", req.connmon);
2338 const char *keepopen = "[DISCONNECT]\n";
2339 storerequest(keepopen, strlen(keepopen));
2343 /* When instructed to close connection after server-reply we
2344 wait a very small amount of time before doing so. If this
2345 is not done client might get an ECONNRESET before reading
2346 a single byte of server-reply. */
2349 if(all_sockets[socket_idx] != CURL_SOCKET_BAD) {
2350 sclose(all_sockets[socket_idx]);
2351 all_sockets[socket_idx] = CURL_SOCKET_BAD;
2354 serverlogslocked -= 1;
2355 if(!serverlogslocked)
2356 clear_advisor_read_lock(SERVERLOGS_LOCK);
2358 if(req.testno == DOCNUMBER_QUIT)
2362 /* Reset the request, unless we're still in the middle of reading */
2364 init_httprequest(&req);
2375 for(socket_idx = 1; socket_idx < num_sockets; ++socket_idx)
2376 if((all_sockets[socket_idx] != sock) &&
2377 (all_sockets[socket_idx] != CURL_SOCKET_BAD))
2378 sclose(all_sockets[socket_idx]);
2380 if(sock != CURL_SOCKET_BAD)
2383 #ifdef USE_UNIX_SOCKETS
2384 if(unlink_socket && socket_domain == AF_UNIX) {
2385 rc = unlink(unix_socket);
2386 logmsg("unlink(%s) = %d (%s)", unix_socket, rc, strerror(rc));
2391 logmsg("signalled to die");
2396 if(serverlogslocked) {
2397 serverlogslocked = 0;
2398 clear_advisor_read_lock(SERVERLOGS_LOCK);
2401 restore_signal_handlers();
2403 if(got_exit_signal) {
2404 logmsg("========> %s sws (%s pid: %ld) exits with signal (%d)",
2405 socket_type, location_str, pid, exit_signal);
2407 * To properly set the return status of the process we
2408 * must raise the same signal SIGINT or SIGTERM that we
2409 * caught and let the old handler take care of it.
2414 logmsg("========> sws quits");