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