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