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