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