113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci#include "server_setup.h" 2513498266Sopenharmony_ci 2613498266Sopenharmony_ci/* sws.c: simple (silly?) web server 2713498266Sopenharmony_ci 2813498266Sopenharmony_ci This code was originally graciously donated to the project by Juergen 2913498266Sopenharmony_ci Wilke. Thanks a bunch! 3013498266Sopenharmony_ci 3113498266Sopenharmony_ci */ 3213498266Sopenharmony_ci 3313498266Sopenharmony_ci#include <signal.h> 3413498266Sopenharmony_ci#ifdef HAVE_NETINET_IN_H 3513498266Sopenharmony_ci#include <netinet/in.h> 3613498266Sopenharmony_ci#endif 3713498266Sopenharmony_ci#ifdef HAVE_NETINET_IN6_H 3813498266Sopenharmony_ci#include <netinet/in6.h> 3913498266Sopenharmony_ci#endif 4013498266Sopenharmony_ci#ifdef HAVE_ARPA_INET_H 4113498266Sopenharmony_ci#include <arpa/inet.h> 4213498266Sopenharmony_ci#endif 4313498266Sopenharmony_ci#ifdef HAVE_NETDB_H 4413498266Sopenharmony_ci#include <netdb.h> 4513498266Sopenharmony_ci#endif 4613498266Sopenharmony_ci#ifdef HAVE_NETINET_TCP_H 4713498266Sopenharmony_ci#include <netinet/tcp.h> /* for TCP_NODELAY */ 4813498266Sopenharmony_ci#endif 4913498266Sopenharmony_ci 5013498266Sopenharmony_ci#define ENABLE_CURLX_PRINTF 5113498266Sopenharmony_ci/* make the curlx header define all printf() functions to use the curlx_* 5213498266Sopenharmony_ci versions instead */ 5313498266Sopenharmony_ci#include "curlx.h" /* from the private lib dir */ 5413498266Sopenharmony_ci#include "getpart.h" 5513498266Sopenharmony_ci#include "inet_pton.h" 5613498266Sopenharmony_ci#include "util.h" 5713498266Sopenharmony_ci#include "server_sockaddr.h" 5813498266Sopenharmony_ci 5913498266Sopenharmony_ci/* include memdebug.h last */ 6013498266Sopenharmony_ci#include "memdebug.h" 6113498266Sopenharmony_ci 6213498266Sopenharmony_ci#ifdef USE_WINSOCK 6313498266Sopenharmony_ci#undef EINTR 6413498266Sopenharmony_ci#define EINTR 4 /* errno.h value */ 6513498266Sopenharmony_ci#undef EAGAIN 6613498266Sopenharmony_ci#define EAGAIN 11 /* errno.h value */ 6713498266Sopenharmony_ci#undef ERANGE 6813498266Sopenharmony_ci#define ERANGE 34 /* errno.h value */ 6913498266Sopenharmony_ci#endif 7013498266Sopenharmony_ci 7113498266Sopenharmony_cistatic enum { 7213498266Sopenharmony_ci socket_domain_inet = AF_INET 7313498266Sopenharmony_ci#ifdef ENABLE_IPV6 7413498266Sopenharmony_ci , socket_domain_inet6 = AF_INET6 7513498266Sopenharmony_ci#endif 7613498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS 7713498266Sopenharmony_ci , socket_domain_unix = AF_UNIX 7813498266Sopenharmony_ci#endif 7913498266Sopenharmony_ci} socket_domain = AF_INET; 8013498266Sopenharmony_cistatic bool use_gopher = FALSE; 8113498266Sopenharmony_cistatic int serverlogslocked = 0; 8213498266Sopenharmony_cistatic bool is_proxy = FALSE; 8313498266Sopenharmony_ci 8413498266Sopenharmony_ci#define REQBUFSIZ (2*1024*1024) 8513498266Sopenharmony_ci 8613498266Sopenharmony_ci#define MAX_SLEEP_TIME_MS 250 8713498266Sopenharmony_ci 8813498266Sopenharmony_cistatic long prevtestno = -1; /* previous test number we served */ 8913498266Sopenharmony_cistatic long prevpartno = -1; /* previous part number we served */ 9013498266Sopenharmony_cistatic bool prevbounce = FALSE; /* instructs the server to increase the part 9113498266Sopenharmony_ci number for a test in case the identical 9213498266Sopenharmony_ci testno+partno request shows up again */ 9313498266Sopenharmony_ci 9413498266Sopenharmony_ci#define RCMD_NORMALREQ 0 /* default request, use the tests file normally */ 9513498266Sopenharmony_ci#define RCMD_IDLE 1 /* told to sit idle */ 9613498266Sopenharmony_ci#define RCMD_STREAM 2 /* told to stream */ 9713498266Sopenharmony_ci 9813498266Sopenharmony_cistruct httprequest { 9913498266Sopenharmony_ci char reqbuf[REQBUFSIZ]; /* buffer area for the incoming request */ 10013498266Sopenharmony_ci bool connect_request; /* if a CONNECT */ 10113498266Sopenharmony_ci unsigned short connect_port; /* the port number CONNECT used */ 10213498266Sopenharmony_ci size_t checkindex; /* where to start checking of the request */ 10313498266Sopenharmony_ci size_t offset; /* size of the incoming request */ 10413498266Sopenharmony_ci long testno; /* test number found in the request */ 10513498266Sopenharmony_ci long partno; /* part number found in the request */ 10613498266Sopenharmony_ci bool open; /* keep connection open info, as found in the request */ 10713498266Sopenharmony_ci bool auth_req; /* authentication required, don't wait for body unless 10813498266Sopenharmony_ci there's an Authorization header */ 10913498266Sopenharmony_ci bool auth; /* Authorization header present in the incoming request */ 11013498266Sopenharmony_ci size_t cl; /* Content-Length of the incoming request */ 11113498266Sopenharmony_ci bool digest; /* Authorization digest header found */ 11213498266Sopenharmony_ci bool ntlm; /* Authorization ntlm header found */ 11313498266Sopenharmony_ci int delay; /* if non-zero, delay this number of msec after connect */ 11413498266Sopenharmony_ci int writedelay; /* if non-zero, delay this number of milliseconds between 11513498266Sopenharmony_ci writes in the response */ 11613498266Sopenharmony_ci int skip; /* if non-zero, the server is instructed to not read this 11713498266Sopenharmony_ci many bytes from a PUT/POST request. Ie the client sends N 11813498266Sopenharmony_ci bytes said in Content-Length, but the server only reads N 11913498266Sopenharmony_ci - skip bytes. */ 12013498266Sopenharmony_ci int rcmd; /* doing a special command, see defines above */ 12113498266Sopenharmony_ci int prot_version; /* HTTP version * 10 */ 12213498266Sopenharmony_ci int callcount; /* times ProcessRequest() gets called */ 12313498266Sopenharmony_ci bool skipall; /* skip all incoming data */ 12413498266Sopenharmony_ci bool noexpect; /* refuse Expect: (don't read the body) */ 12513498266Sopenharmony_ci bool connmon; /* monitor the state of the connection, log disconnects */ 12613498266Sopenharmony_ci bool upgrade; /* test case allows upgrade */ 12713498266Sopenharmony_ci bool upgrade_request; /* upgrade request found and allowed */ 12813498266Sopenharmony_ci bool close; /* similar to swsclose in response: close connection after 12913498266Sopenharmony_ci response is sent */ 13013498266Sopenharmony_ci int done_processing; 13113498266Sopenharmony_ci}; 13213498266Sopenharmony_ci 13313498266Sopenharmony_ci#define MAX_SOCKETS 1024 13413498266Sopenharmony_ci 13513498266Sopenharmony_cistatic curl_socket_t all_sockets[MAX_SOCKETS]; 13613498266Sopenharmony_cistatic size_t num_sockets = 0; 13713498266Sopenharmony_ci 13813498266Sopenharmony_cistatic int ProcessRequest(struct httprequest *req); 13913498266Sopenharmony_cistatic void storerequest(const char *reqbuf, size_t totalsize); 14013498266Sopenharmony_ci 14113498266Sopenharmony_ci#define DEFAULT_PORT 8999 14213498266Sopenharmony_ci 14313498266Sopenharmony_ci#ifndef DEFAULT_LOGFILE 14413498266Sopenharmony_ci#define DEFAULT_LOGFILE "log/sws.log" 14513498266Sopenharmony_ci#endif 14613498266Sopenharmony_ci 14713498266Sopenharmony_ciconst char *serverlogfile = DEFAULT_LOGFILE; 14813498266Sopenharmony_cistatic const char *logdir = "log"; 14913498266Sopenharmony_cistatic char loglockfile[256]; 15013498266Sopenharmony_ci 15113498266Sopenharmony_ci#define SWSVERSION "curl test suite HTTP server/0.1" 15213498266Sopenharmony_ci 15313498266Sopenharmony_ci#define REQUEST_DUMP "server.input" 15413498266Sopenharmony_ci#define RESPONSE_DUMP "server.response" 15513498266Sopenharmony_ci 15613498266Sopenharmony_ci/* when told to run as proxy, we store the logs in different files so that 15713498266Sopenharmony_ci they can co-exist with the same program running as a "server" */ 15813498266Sopenharmony_ci#define REQUEST_PROXY_DUMP "proxy.input" 15913498266Sopenharmony_ci#define RESPONSE_PROXY_DUMP "proxy.response" 16013498266Sopenharmony_ci 16113498266Sopenharmony_ci/* file in which additional instructions may be found */ 16213498266Sopenharmony_ci#define DEFAULT_CMDFILE "log/server.cmd" 16313498266Sopenharmony_ciconst char *cmdfile = DEFAULT_CMDFILE; 16413498266Sopenharmony_ci 16513498266Sopenharmony_ci/* very-big-path support */ 16613498266Sopenharmony_ci#define MAXDOCNAMELEN 140000 16713498266Sopenharmony_ci#define MAXDOCNAMELEN_TXT "139999" 16813498266Sopenharmony_ci 16913498266Sopenharmony_ci#define REQUEST_KEYWORD_SIZE 256 17013498266Sopenharmony_ci#define REQUEST_KEYWORD_SIZE_TXT "255" 17113498266Sopenharmony_ci 17213498266Sopenharmony_ci#define CMD_AUTH_REQUIRED "auth_required" 17313498266Sopenharmony_ci 17413498266Sopenharmony_ci/* 'idle' means that it will accept the request fine but never respond 17513498266Sopenharmony_ci any data. Just keep the connection alive. */ 17613498266Sopenharmony_ci#define CMD_IDLE "idle" 17713498266Sopenharmony_ci 17813498266Sopenharmony_ci/* 'stream' means to send a never-ending stream of data */ 17913498266Sopenharmony_ci#define CMD_STREAM "stream" 18013498266Sopenharmony_ci 18113498266Sopenharmony_ci/* 'connection-monitor' will output when a server/proxy connection gets 18213498266Sopenharmony_ci disconnected as for some cases it is important that it gets done at the 18313498266Sopenharmony_ci proper point - like with NTLM */ 18413498266Sopenharmony_ci#define CMD_CONNECTIONMONITOR "connection-monitor" 18513498266Sopenharmony_ci 18613498266Sopenharmony_ci/* upgrade to http2/websocket/xxxx */ 18713498266Sopenharmony_ci#define CMD_UPGRADE "upgrade" 18813498266Sopenharmony_ci 18913498266Sopenharmony_ci/* close connection */ 19013498266Sopenharmony_ci#define CMD_SWSCLOSE "swsclose" 19113498266Sopenharmony_ci 19213498266Sopenharmony_ci/* deny Expect: requests */ 19313498266Sopenharmony_ci#define CMD_NOEXPECT "no-expect" 19413498266Sopenharmony_ci 19513498266Sopenharmony_ci#define END_OF_HEADERS "\r\n\r\n" 19613498266Sopenharmony_ci 19713498266Sopenharmony_cienum { 19813498266Sopenharmony_ci DOCNUMBER_NOTHING = -4, 19913498266Sopenharmony_ci DOCNUMBER_QUIT = -3, 20013498266Sopenharmony_ci DOCNUMBER_WERULEZ = -2, 20113498266Sopenharmony_ci DOCNUMBER_404 = -1 20213498266Sopenharmony_ci}; 20313498266Sopenharmony_ci 20413498266Sopenharmony_cistatic const char *end_of_headers = END_OF_HEADERS; 20513498266Sopenharmony_ci 20613498266Sopenharmony_ci/* sent as reply to a QUIT */ 20713498266Sopenharmony_cistatic const char *docquit = 20813498266Sopenharmony_ci"HTTP/1.1 200 Goodbye" END_OF_HEADERS; 20913498266Sopenharmony_ci 21013498266Sopenharmony_ci/* send back this on 404 file not found */ 21113498266Sopenharmony_cistatic const char *doc404 = "HTTP/1.1 404 Not Found\r\n" 21213498266Sopenharmony_ci "Server: " SWSVERSION "\r\n" 21313498266Sopenharmony_ci "Connection: close\r\n" 21413498266Sopenharmony_ci "Content-Type: text/html" 21513498266Sopenharmony_ci END_OF_HEADERS 21613498266Sopenharmony_ci "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" 21713498266Sopenharmony_ci "<HTML><HEAD>\n" 21813498266Sopenharmony_ci "<TITLE>404 Not Found</TITLE>\n" 21913498266Sopenharmony_ci "</HEAD><BODY>\n" 22013498266Sopenharmony_ci "<H1>Not Found</H1>\n" 22113498266Sopenharmony_ci "The requested URL was not found on this server.\n" 22213498266Sopenharmony_ci "<P><HR><ADDRESS>" SWSVERSION "</ADDRESS>\n" "</BODY></HTML>\n"; 22313498266Sopenharmony_ci 22413498266Sopenharmony_ci/* work around for handling trailing headers */ 22513498266Sopenharmony_cistatic int already_recv_zeroed_chunk = FALSE; 22613498266Sopenharmony_ci 22713498266Sopenharmony_ci/* returns true if the current socket is an IP one */ 22813498266Sopenharmony_cistatic bool socket_domain_is_ip(void) 22913498266Sopenharmony_ci{ 23013498266Sopenharmony_ci switch(socket_domain) { 23113498266Sopenharmony_ci case AF_INET: 23213498266Sopenharmony_ci#ifdef ENABLE_IPV6 23313498266Sopenharmony_ci case AF_INET6: 23413498266Sopenharmony_ci#endif 23513498266Sopenharmony_ci return true; 23613498266Sopenharmony_ci default: 23713498266Sopenharmony_ci /* case AF_UNIX: */ 23813498266Sopenharmony_ci return false; 23913498266Sopenharmony_ci } 24013498266Sopenharmony_ci} 24113498266Sopenharmony_ci 24213498266Sopenharmony_ci/* parse the file on disk that might have a test number for us */ 24313498266Sopenharmony_cistatic int parse_cmdfile(struct httprequest *req) 24413498266Sopenharmony_ci{ 24513498266Sopenharmony_ci FILE *f = fopen(cmdfile, FOPEN_READTEXT); 24613498266Sopenharmony_ci if(f) { 24713498266Sopenharmony_ci int testnum = DOCNUMBER_NOTHING; 24813498266Sopenharmony_ci char buf[256]; 24913498266Sopenharmony_ci while(fgets(buf, sizeof(buf), f)) { 25013498266Sopenharmony_ci if(1 == sscanf(buf, "Testnum %d", &testnum)) { 25113498266Sopenharmony_ci logmsg("[%s] cmdfile says testnum %d", cmdfile, testnum); 25213498266Sopenharmony_ci req->testno = testnum; 25313498266Sopenharmony_ci } 25413498266Sopenharmony_ci } 25513498266Sopenharmony_ci fclose(f); 25613498266Sopenharmony_ci } 25713498266Sopenharmony_ci return 0; 25813498266Sopenharmony_ci} 25913498266Sopenharmony_ci 26013498266Sopenharmony_ci/* based on the testno, parse the correct server commands */ 26113498266Sopenharmony_cistatic int parse_servercmd(struct httprequest *req) 26213498266Sopenharmony_ci{ 26313498266Sopenharmony_ci FILE *stream; 26413498266Sopenharmony_ci int error; 26513498266Sopenharmony_ci 26613498266Sopenharmony_ci stream = test2fopen(req->testno, logdir); 26713498266Sopenharmony_ci req->close = FALSE; 26813498266Sopenharmony_ci req->connmon = FALSE; 26913498266Sopenharmony_ci 27013498266Sopenharmony_ci if(!stream) { 27113498266Sopenharmony_ci error = errno; 27213498266Sopenharmony_ci logmsg("fopen() failed with error: %d %s", error, strerror(error)); 27313498266Sopenharmony_ci logmsg(" Couldn't open test file %ld", req->testno); 27413498266Sopenharmony_ci req->open = FALSE; /* closes connection */ 27513498266Sopenharmony_ci return 1; /* done */ 27613498266Sopenharmony_ci } 27713498266Sopenharmony_ci else { 27813498266Sopenharmony_ci char *orgcmd = NULL; 27913498266Sopenharmony_ci char *cmd = NULL; 28013498266Sopenharmony_ci size_t cmdsize = 0; 28113498266Sopenharmony_ci int num = 0; 28213498266Sopenharmony_ci 28313498266Sopenharmony_ci /* get the custom server control "commands" */ 28413498266Sopenharmony_ci error = getpart(&orgcmd, &cmdsize, "reply", "servercmd", stream); 28513498266Sopenharmony_ci fclose(stream); 28613498266Sopenharmony_ci if(error) { 28713498266Sopenharmony_ci logmsg("getpart() failed with error: %d", error); 28813498266Sopenharmony_ci req->open = FALSE; /* closes connection */ 28913498266Sopenharmony_ci return 1; /* done */ 29013498266Sopenharmony_ci } 29113498266Sopenharmony_ci 29213498266Sopenharmony_ci cmd = orgcmd; 29313498266Sopenharmony_ci while(cmd && cmdsize) { 29413498266Sopenharmony_ci char *check; 29513498266Sopenharmony_ci 29613498266Sopenharmony_ci if(!strncmp(CMD_AUTH_REQUIRED, cmd, strlen(CMD_AUTH_REQUIRED))) { 29713498266Sopenharmony_ci logmsg("instructed to require authorization header"); 29813498266Sopenharmony_ci req->auth_req = TRUE; 29913498266Sopenharmony_ci } 30013498266Sopenharmony_ci else if(!strncmp(CMD_IDLE, cmd, strlen(CMD_IDLE))) { 30113498266Sopenharmony_ci logmsg("instructed to idle"); 30213498266Sopenharmony_ci req->rcmd = RCMD_IDLE; 30313498266Sopenharmony_ci req->open = TRUE; 30413498266Sopenharmony_ci } 30513498266Sopenharmony_ci else if(!strncmp(CMD_STREAM, cmd, strlen(CMD_STREAM))) { 30613498266Sopenharmony_ci logmsg("instructed to stream"); 30713498266Sopenharmony_ci req->rcmd = RCMD_STREAM; 30813498266Sopenharmony_ci } 30913498266Sopenharmony_ci else if(!strncmp(CMD_CONNECTIONMONITOR, cmd, 31013498266Sopenharmony_ci strlen(CMD_CONNECTIONMONITOR))) { 31113498266Sopenharmony_ci logmsg("enabled connection monitoring"); 31213498266Sopenharmony_ci req->connmon = TRUE; 31313498266Sopenharmony_ci } 31413498266Sopenharmony_ci else if(!strncmp(CMD_UPGRADE, cmd, strlen(CMD_UPGRADE))) { 31513498266Sopenharmony_ci logmsg("enabled upgrade"); 31613498266Sopenharmony_ci req->upgrade = TRUE; 31713498266Sopenharmony_ci } 31813498266Sopenharmony_ci else if(!strncmp(CMD_SWSCLOSE, cmd, strlen(CMD_SWSCLOSE))) { 31913498266Sopenharmony_ci logmsg("swsclose: close this connection after response"); 32013498266Sopenharmony_ci req->close = TRUE; 32113498266Sopenharmony_ci } 32213498266Sopenharmony_ci else if(1 == sscanf(cmd, "skip: %d", &num)) { 32313498266Sopenharmony_ci logmsg("instructed to skip this number of bytes %d", num); 32413498266Sopenharmony_ci req->skip = num; 32513498266Sopenharmony_ci } 32613498266Sopenharmony_ci else if(!strncmp(CMD_NOEXPECT, cmd, strlen(CMD_NOEXPECT))) { 32713498266Sopenharmony_ci logmsg("instructed to reject Expect: 100-continue"); 32813498266Sopenharmony_ci req->noexpect = TRUE; 32913498266Sopenharmony_ci } 33013498266Sopenharmony_ci else if(1 == sscanf(cmd, "delay: %d", &num)) { 33113498266Sopenharmony_ci logmsg("instructed to delay %d msecs after connect", num); 33213498266Sopenharmony_ci req->delay = num; 33313498266Sopenharmony_ci } 33413498266Sopenharmony_ci else if(1 == sscanf(cmd, "writedelay: %d", &num)) { 33513498266Sopenharmony_ci logmsg("instructed to delay %d msecs between packets", num); 33613498266Sopenharmony_ci req->writedelay = num; 33713498266Sopenharmony_ci } 33813498266Sopenharmony_ci else { 33913498266Sopenharmony_ci logmsg("Unknown <servercmd> instruction found: %s", cmd); 34013498266Sopenharmony_ci } 34113498266Sopenharmony_ci /* try to deal with CRLF or just LF */ 34213498266Sopenharmony_ci check = strchr(cmd, '\r'); 34313498266Sopenharmony_ci if(!check) 34413498266Sopenharmony_ci check = strchr(cmd, '\n'); 34513498266Sopenharmony_ci 34613498266Sopenharmony_ci if(check) { 34713498266Sopenharmony_ci /* get to the letter following the newline */ 34813498266Sopenharmony_ci while((*check == '\r') || (*check == '\n')) 34913498266Sopenharmony_ci check++; 35013498266Sopenharmony_ci 35113498266Sopenharmony_ci if(!*check) 35213498266Sopenharmony_ci /* if we reached a zero, get out */ 35313498266Sopenharmony_ci break; 35413498266Sopenharmony_ci cmd = check; 35513498266Sopenharmony_ci } 35613498266Sopenharmony_ci else 35713498266Sopenharmony_ci break; 35813498266Sopenharmony_ci } 35913498266Sopenharmony_ci free(orgcmd); 36013498266Sopenharmony_ci } 36113498266Sopenharmony_ci 36213498266Sopenharmony_ci return 0; /* OK! */ 36313498266Sopenharmony_ci} 36413498266Sopenharmony_ci 36513498266Sopenharmony_cistatic int ProcessRequest(struct httprequest *req) 36613498266Sopenharmony_ci{ 36713498266Sopenharmony_ci char *line = &req->reqbuf[req->checkindex]; 36813498266Sopenharmony_ci bool chunked = FALSE; 36913498266Sopenharmony_ci static char request[REQUEST_KEYWORD_SIZE]; 37013498266Sopenharmony_ci char logbuf[456]; 37113498266Sopenharmony_ci int prot_major = 0; 37213498266Sopenharmony_ci int prot_minor = 0; 37313498266Sopenharmony_ci char *end = strstr(line, end_of_headers); 37413498266Sopenharmony_ci 37513498266Sopenharmony_ci req->callcount++; 37613498266Sopenharmony_ci 37713498266Sopenharmony_ci logmsg("Process %zu bytes request%s", req->offset, 37813498266Sopenharmony_ci req->callcount > 1?" [CONTINUED]":""); 37913498266Sopenharmony_ci 38013498266Sopenharmony_ci /* try to figure out the request characteristics as soon as possible, but 38113498266Sopenharmony_ci only once! */ 38213498266Sopenharmony_ci 38313498266Sopenharmony_ci if(use_gopher && 38413498266Sopenharmony_ci (req->testno == DOCNUMBER_NOTHING) && 38513498266Sopenharmony_ci !strncmp("/verifiedserver", line, 15)) { 38613498266Sopenharmony_ci logmsg("Are-we-friendly question received"); 38713498266Sopenharmony_ci req->testno = DOCNUMBER_WERULEZ; 38813498266Sopenharmony_ci return 1; /* done */ 38913498266Sopenharmony_ci } 39013498266Sopenharmony_ci 39113498266Sopenharmony_ci else if(req->testno == DOCNUMBER_NOTHING) { 39213498266Sopenharmony_ci char *http; 39313498266Sopenharmony_ci bool fine = FALSE; 39413498266Sopenharmony_ci char *httppath = NULL; 39513498266Sopenharmony_ci size_t npath = 0; /* httppath length */ 39613498266Sopenharmony_ci 39713498266Sopenharmony_ci if(sscanf(line, 39813498266Sopenharmony_ci "%" REQUEST_KEYWORD_SIZE_TXT"s ", request)) { 39913498266Sopenharmony_ci http = strstr(line + strlen(request), "HTTP/"); 40013498266Sopenharmony_ci 40113498266Sopenharmony_ci if(http && sscanf(http, "HTTP/%d.%d", 40213498266Sopenharmony_ci &prot_major, 40313498266Sopenharmony_ci &prot_minor) == 2) { 40413498266Sopenharmony_ci /* between the request keyword and HTTP/ there's a path */ 40513498266Sopenharmony_ci httppath = line + strlen(request); 40613498266Sopenharmony_ci npath = http - httppath; 40713498266Sopenharmony_ci 40813498266Sopenharmony_ci /* trim leading spaces */ 40913498266Sopenharmony_ci while(npath && ISSPACE(*httppath)) { 41013498266Sopenharmony_ci httppath++; 41113498266Sopenharmony_ci npath--; 41213498266Sopenharmony_ci } 41313498266Sopenharmony_ci /* trim ending spaces */ 41413498266Sopenharmony_ci while(npath && ISSPACE(httppath[npath - 1])) { 41513498266Sopenharmony_ci npath--; 41613498266Sopenharmony_ci } 41713498266Sopenharmony_ci if(npath) 41813498266Sopenharmony_ci fine = TRUE; 41913498266Sopenharmony_ci } 42013498266Sopenharmony_ci } 42113498266Sopenharmony_ci 42213498266Sopenharmony_ci if(fine) { 42313498266Sopenharmony_ci char *ptr; 42413498266Sopenharmony_ci 42513498266Sopenharmony_ci req->prot_version = prot_major*10 + prot_minor; 42613498266Sopenharmony_ci 42713498266Sopenharmony_ci /* find the last slash */ 42813498266Sopenharmony_ci ptr = &httppath[npath]; 42913498266Sopenharmony_ci while(ptr >= httppath) { 43013498266Sopenharmony_ci if(*ptr == '/') 43113498266Sopenharmony_ci break; 43213498266Sopenharmony_ci ptr--; 43313498266Sopenharmony_ci } 43413498266Sopenharmony_ci 43513498266Sopenharmony_ci /* get the number after it */ 43613498266Sopenharmony_ci if(*ptr == '/') { 43713498266Sopenharmony_ci if((npath + strlen(request)) < 400) 43813498266Sopenharmony_ci msnprintf(logbuf, sizeof(logbuf), "Got request: %s %.*s HTTP/%d.%d", 43913498266Sopenharmony_ci request, (int)npath, httppath, prot_major, prot_minor); 44013498266Sopenharmony_ci else 44113498266Sopenharmony_ci msnprintf(logbuf, sizeof(logbuf), "Got a *HUGE* request HTTP/%d.%d", 44213498266Sopenharmony_ci prot_major, prot_minor); 44313498266Sopenharmony_ci logmsg("%s", logbuf); 44413498266Sopenharmony_ci 44513498266Sopenharmony_ci if(!strncmp("/verifiedserver", ptr, 15)) { 44613498266Sopenharmony_ci logmsg("Are-we-friendly question received"); 44713498266Sopenharmony_ci req->testno = DOCNUMBER_WERULEZ; 44813498266Sopenharmony_ci return 1; /* done */ 44913498266Sopenharmony_ci } 45013498266Sopenharmony_ci 45113498266Sopenharmony_ci if(!strncmp("/quit", ptr, 5)) { 45213498266Sopenharmony_ci logmsg("Request-to-quit received"); 45313498266Sopenharmony_ci req->testno = DOCNUMBER_QUIT; 45413498266Sopenharmony_ci return 1; /* done */ 45513498266Sopenharmony_ci } 45613498266Sopenharmony_ci 45713498266Sopenharmony_ci ptr++; /* skip the slash */ 45813498266Sopenharmony_ci 45913498266Sopenharmony_ci req->testno = strtol(ptr, &ptr, 10); 46013498266Sopenharmony_ci 46113498266Sopenharmony_ci if(req->testno > 10000) { 46213498266Sopenharmony_ci req->partno = req->testno % 10000; 46313498266Sopenharmony_ci req->testno /= 10000; 46413498266Sopenharmony_ci } 46513498266Sopenharmony_ci else 46613498266Sopenharmony_ci req->partno = 0; 46713498266Sopenharmony_ci 46813498266Sopenharmony_ci if(req->testno) { 46913498266Sopenharmony_ci 47013498266Sopenharmony_ci msnprintf(logbuf, sizeof(logbuf), "Serve test number %ld part %ld", 47113498266Sopenharmony_ci req->testno, req->partno); 47213498266Sopenharmony_ci logmsg("%s", logbuf); 47313498266Sopenharmony_ci } 47413498266Sopenharmony_ci else { 47513498266Sopenharmony_ci logmsg("No test number in path"); 47613498266Sopenharmony_ci req->testno = DOCNUMBER_NOTHING; 47713498266Sopenharmony_ci } 47813498266Sopenharmony_ci 47913498266Sopenharmony_ci } 48013498266Sopenharmony_ci 48113498266Sopenharmony_ci if(req->testno == DOCNUMBER_NOTHING) { 48213498266Sopenharmony_ci /* didn't find any in the first scan, try alternative test case 48313498266Sopenharmony_ci number placements */ 48413498266Sopenharmony_ci static char doc[MAXDOCNAMELEN]; 48513498266Sopenharmony_ci if(sscanf(req->reqbuf, "CONNECT %" MAXDOCNAMELEN_TXT "s HTTP/%d.%d", 48613498266Sopenharmony_ci doc, &prot_major, &prot_minor) == 3) { 48713498266Sopenharmony_ci char *portp = NULL; 48813498266Sopenharmony_ci 48913498266Sopenharmony_ci msnprintf(logbuf, sizeof(logbuf), 49013498266Sopenharmony_ci "Received a CONNECT %s HTTP/%d.%d request", 49113498266Sopenharmony_ci doc, prot_major, prot_minor); 49213498266Sopenharmony_ci logmsg("%s", logbuf); 49313498266Sopenharmony_ci 49413498266Sopenharmony_ci req->connect_request = TRUE; 49513498266Sopenharmony_ci 49613498266Sopenharmony_ci if(req->prot_version == 10) 49713498266Sopenharmony_ci req->open = FALSE; /* HTTP 1.0 closes connection by default */ 49813498266Sopenharmony_ci 49913498266Sopenharmony_ci if(doc[0] == '[') { 50013498266Sopenharmony_ci char *p = &doc[1]; 50113498266Sopenharmony_ci unsigned long part = 0; 50213498266Sopenharmony_ci /* scan through the hexgroups and store the value of the last group 50313498266Sopenharmony_ci in the 'part' variable and use as test case number!! */ 50413498266Sopenharmony_ci while(*p && (ISXDIGIT(*p) || (*p == ':') || (*p == '.'))) { 50513498266Sopenharmony_ci char *endp; 50613498266Sopenharmony_ci part = strtoul(p, &endp, 16); 50713498266Sopenharmony_ci if(ISXDIGIT(*p)) 50813498266Sopenharmony_ci p = endp; 50913498266Sopenharmony_ci else 51013498266Sopenharmony_ci p++; 51113498266Sopenharmony_ci } 51213498266Sopenharmony_ci if(*p != ']') 51313498266Sopenharmony_ci logmsg("Invalid CONNECT IPv6 address format"); 51413498266Sopenharmony_ci else if(*(p + 1) != ':') 51513498266Sopenharmony_ci logmsg("Invalid CONNECT IPv6 port format"); 51613498266Sopenharmony_ci else 51713498266Sopenharmony_ci portp = p + 1; 51813498266Sopenharmony_ci 51913498266Sopenharmony_ci req->testno = part; 52013498266Sopenharmony_ci } 52113498266Sopenharmony_ci else 52213498266Sopenharmony_ci portp = strchr(doc, ':'); 52313498266Sopenharmony_ci 52413498266Sopenharmony_ci if(portp && (*(portp + 1) != '\0') && ISDIGIT(*(portp + 1))) { 52513498266Sopenharmony_ci unsigned long ulnum = strtoul(portp + 1, NULL, 10); 52613498266Sopenharmony_ci if(!ulnum || (ulnum > 65535UL)) 52713498266Sopenharmony_ci logmsg("Invalid CONNECT port received"); 52813498266Sopenharmony_ci else 52913498266Sopenharmony_ci req->connect_port = curlx_ultous(ulnum); 53013498266Sopenharmony_ci 53113498266Sopenharmony_ci } 53213498266Sopenharmony_ci logmsg("Port number: %d, test case number: %ld", 53313498266Sopenharmony_ci req->connect_port, req->testno); 53413498266Sopenharmony_ci } 53513498266Sopenharmony_ci } 53613498266Sopenharmony_ci 53713498266Sopenharmony_ci if(req->testno == DOCNUMBER_NOTHING) 53813498266Sopenharmony_ci /* might get the test number */ 53913498266Sopenharmony_ci parse_cmdfile(req); 54013498266Sopenharmony_ci 54113498266Sopenharmony_ci if(req->testno == DOCNUMBER_NOTHING) { 54213498266Sopenharmony_ci logmsg("Did not find test number in PATH"); 54313498266Sopenharmony_ci req->testno = DOCNUMBER_404; 54413498266Sopenharmony_ci } 54513498266Sopenharmony_ci else 54613498266Sopenharmony_ci parse_servercmd(req); 54713498266Sopenharmony_ci } 54813498266Sopenharmony_ci else if((req->offset >= 3)) { 54913498266Sopenharmony_ci unsigned char *l = (unsigned char *)line; 55013498266Sopenharmony_ci logmsg("** Unusual request. Starts with %02x %02x %02x (%c%c%c)", 55113498266Sopenharmony_ci l[0], l[1], l[2], l[0], l[1], l[2]); 55213498266Sopenharmony_ci } 55313498266Sopenharmony_ci } 55413498266Sopenharmony_ci 55513498266Sopenharmony_ci if(!end) { 55613498266Sopenharmony_ci /* we don't have a complete request yet! */ 55713498266Sopenharmony_ci logmsg("request not complete yet"); 55813498266Sopenharmony_ci return 0; /* not complete yet */ 55913498266Sopenharmony_ci } 56013498266Sopenharmony_ci logmsg("- request found to be complete (%ld)", req->testno); 56113498266Sopenharmony_ci 56213498266Sopenharmony_ci if(req->testno == DOCNUMBER_NOTHING) { 56313498266Sopenharmony_ci /* check for a Testno: header with the test case number */ 56413498266Sopenharmony_ci char *testno = strstr(line, "\nTestno: "); 56513498266Sopenharmony_ci if(testno) { 56613498266Sopenharmony_ci req->testno = strtol(&testno[9], NULL, 10); 56713498266Sopenharmony_ci logmsg("Found test number %ld in Testno: header!", req->testno); 56813498266Sopenharmony_ci } 56913498266Sopenharmony_ci else { 57013498266Sopenharmony_ci logmsg("No Testno: header"); 57113498266Sopenharmony_ci } 57213498266Sopenharmony_ci } 57313498266Sopenharmony_ci 57413498266Sopenharmony_ci /* find and parse <servercmd> for this test */ 57513498266Sopenharmony_ci parse_servercmd(req); 57613498266Sopenharmony_ci 57713498266Sopenharmony_ci if(use_gopher) { 57813498266Sopenharmony_ci /* when using gopher we cannot check the request until the entire 57913498266Sopenharmony_ci thing has been received */ 58013498266Sopenharmony_ci char *ptr; 58113498266Sopenharmony_ci 58213498266Sopenharmony_ci /* find the last slash in the line */ 58313498266Sopenharmony_ci ptr = strrchr(line, '/'); 58413498266Sopenharmony_ci 58513498266Sopenharmony_ci if(ptr) { 58613498266Sopenharmony_ci ptr++; /* skip the slash */ 58713498266Sopenharmony_ci 58813498266Sopenharmony_ci /* skip all non-numericals following the slash */ 58913498266Sopenharmony_ci while(*ptr && !ISDIGIT(*ptr)) 59013498266Sopenharmony_ci ptr++; 59113498266Sopenharmony_ci 59213498266Sopenharmony_ci req->testno = strtol(ptr, &ptr, 10); 59313498266Sopenharmony_ci 59413498266Sopenharmony_ci if(req->testno > 10000) { 59513498266Sopenharmony_ci req->partno = req->testno % 10000; 59613498266Sopenharmony_ci req->testno /= 10000; 59713498266Sopenharmony_ci } 59813498266Sopenharmony_ci else 59913498266Sopenharmony_ci req->partno = 0; 60013498266Sopenharmony_ci 60113498266Sopenharmony_ci msnprintf(logbuf, sizeof(logbuf), 60213498266Sopenharmony_ci "Requested GOPHER test number %ld part %ld", 60313498266Sopenharmony_ci req->testno, req->partno); 60413498266Sopenharmony_ci logmsg("%s", logbuf); 60513498266Sopenharmony_ci } 60613498266Sopenharmony_ci } 60713498266Sopenharmony_ci 60813498266Sopenharmony_ci /* **** Persistence **** 60913498266Sopenharmony_ci * 61013498266Sopenharmony_ci * If the request is an HTTP/1.0 one, we close the connection unconditionally 61113498266Sopenharmony_ci * when we're done. 61213498266Sopenharmony_ci * 61313498266Sopenharmony_ci * If the request is an HTTP/1.1 one, we MUST check for a "Connection:" 61413498266Sopenharmony_ci * header that might say "close". If it does, we close a connection when 61513498266Sopenharmony_ci * this request is processed. Otherwise, we keep the connection alive for X 61613498266Sopenharmony_ci * seconds. 61713498266Sopenharmony_ci */ 61813498266Sopenharmony_ci 61913498266Sopenharmony_ci do { 62013498266Sopenharmony_ci if(got_exit_signal) 62113498266Sopenharmony_ci return 1; /* done */ 62213498266Sopenharmony_ci 62313498266Sopenharmony_ci if((req->cl == 0) && strncasecompare("Content-Length:", line, 15)) { 62413498266Sopenharmony_ci /* If we don't ignore content-length, we read it and we read the whole 62513498266Sopenharmony_ci request including the body before we return. If we've been told to 62613498266Sopenharmony_ci ignore the content-length, we will return as soon as all headers 62713498266Sopenharmony_ci have been received */ 62813498266Sopenharmony_ci char *endptr; 62913498266Sopenharmony_ci char *ptr = line + 15; 63013498266Sopenharmony_ci unsigned long clen = 0; 63113498266Sopenharmony_ci while(*ptr && ISSPACE(*ptr)) 63213498266Sopenharmony_ci ptr++; 63313498266Sopenharmony_ci endptr = ptr; 63413498266Sopenharmony_ci errno = 0; 63513498266Sopenharmony_ci clen = strtoul(ptr, &endptr, 10); 63613498266Sopenharmony_ci if((ptr == endptr) || !ISSPACE(*endptr) || (ERANGE == errno)) { 63713498266Sopenharmony_ci /* this assumes that a zero Content-Length is valid */ 63813498266Sopenharmony_ci logmsg("Found invalid Content-Length: (%s) in the request", ptr); 63913498266Sopenharmony_ci req->open = FALSE; /* closes connection */ 64013498266Sopenharmony_ci return 1; /* done */ 64113498266Sopenharmony_ci } 64213498266Sopenharmony_ci if(req->skipall) 64313498266Sopenharmony_ci req->cl = 0; 64413498266Sopenharmony_ci else 64513498266Sopenharmony_ci req->cl = clen - req->skip; 64613498266Sopenharmony_ci 64713498266Sopenharmony_ci logmsg("Found Content-Length: %lu in the request", clen); 64813498266Sopenharmony_ci if(req->skip) 64913498266Sopenharmony_ci logmsg("... but will abort after %zu bytes", req->cl); 65013498266Sopenharmony_ci } 65113498266Sopenharmony_ci else if(strncasecompare("Transfer-Encoding: chunked", line, 65213498266Sopenharmony_ci strlen("Transfer-Encoding: chunked"))) { 65313498266Sopenharmony_ci /* chunked data coming in */ 65413498266Sopenharmony_ci chunked = TRUE; 65513498266Sopenharmony_ci } 65613498266Sopenharmony_ci else if(req->noexpect && 65713498266Sopenharmony_ci strncasecompare("Expect: 100-continue", line, 65813498266Sopenharmony_ci strlen("Expect: 100-continue"))) { 65913498266Sopenharmony_ci if(req->cl) 66013498266Sopenharmony_ci req->cl = 0; 66113498266Sopenharmony_ci req->skipall = TRUE; 66213498266Sopenharmony_ci logmsg("Found Expect: 100-continue, ignore body"); 66313498266Sopenharmony_ci } 66413498266Sopenharmony_ci 66513498266Sopenharmony_ci if(chunked) { 66613498266Sopenharmony_ci if(strstr(req->reqbuf, "\r\n0\r\n\r\n")) { 66713498266Sopenharmony_ci /* end of chunks reached */ 66813498266Sopenharmony_ci return 1; /* done */ 66913498266Sopenharmony_ci } 67013498266Sopenharmony_ci else if(strstr(req->reqbuf, "\r\n0\r\n")) { 67113498266Sopenharmony_ci char *last_crlf_char = strstr(req->reqbuf, "\r\n\r\n"); 67213498266Sopenharmony_ci while(TRUE) { 67313498266Sopenharmony_ci if(!strstr(last_crlf_char + 4, "\r\n\r\n")) 67413498266Sopenharmony_ci break; 67513498266Sopenharmony_ci last_crlf_char = strstr(last_crlf_char + 4, "\r\n\r\n"); 67613498266Sopenharmony_ci } 67713498266Sopenharmony_ci if(last_crlf_char && 67813498266Sopenharmony_ci last_crlf_char > strstr(req->reqbuf, "\r\n0\r\n")) 67913498266Sopenharmony_ci return 1; 68013498266Sopenharmony_ci already_recv_zeroed_chunk = TRUE; 68113498266Sopenharmony_ci return 0; 68213498266Sopenharmony_ci } 68313498266Sopenharmony_ci else if(already_recv_zeroed_chunk && strstr(req->reqbuf, "\r\n\r\n")) 68413498266Sopenharmony_ci return 1; 68513498266Sopenharmony_ci else 68613498266Sopenharmony_ci return 0; /* not done */ 68713498266Sopenharmony_ci } 68813498266Sopenharmony_ci 68913498266Sopenharmony_ci line = strchr(line, '\n'); 69013498266Sopenharmony_ci if(line) 69113498266Sopenharmony_ci line++; 69213498266Sopenharmony_ci 69313498266Sopenharmony_ci } while(line); 69413498266Sopenharmony_ci 69513498266Sopenharmony_ci if(!req->auth && strstr(req->reqbuf, "Authorization:")) { 69613498266Sopenharmony_ci req->auth = TRUE; /* Authorization: header present! */ 69713498266Sopenharmony_ci if(req->auth_req) 69813498266Sopenharmony_ci logmsg("Authorization header found, as required"); 69913498266Sopenharmony_ci } 70013498266Sopenharmony_ci 70113498266Sopenharmony_ci if(strstr(req->reqbuf, "Authorization: Negotiate")) { 70213498266Sopenharmony_ci /* Negotiate iterations */ 70313498266Sopenharmony_ci static long prev_testno = -1; 70413498266Sopenharmony_ci static long prev_partno = -1; 70513498266Sopenharmony_ci logmsg("Negotiate: prev_testno: %ld, prev_partno: %ld", 70613498266Sopenharmony_ci prev_testno, prev_partno); 70713498266Sopenharmony_ci if(req->testno != prev_testno) { 70813498266Sopenharmony_ci prev_testno = req->testno; 70913498266Sopenharmony_ci prev_partno = req->partno; 71013498266Sopenharmony_ci } 71113498266Sopenharmony_ci prev_partno += 1; 71213498266Sopenharmony_ci req->partno = prev_partno; 71313498266Sopenharmony_ci } 71413498266Sopenharmony_ci else if(!req->digest && strstr(req->reqbuf, "Authorization: Digest")) { 71513498266Sopenharmony_ci /* If the client is passing this Digest-header, we set the part number 71613498266Sopenharmony_ci to 1000. Not only to spice up the complexity of this, but to make 71713498266Sopenharmony_ci Digest stuff to work in the test suite. */ 71813498266Sopenharmony_ci req->partno += 1000; 71913498266Sopenharmony_ci req->digest = TRUE; /* header found */ 72013498266Sopenharmony_ci logmsg("Received Digest request, sending back data %ld", req->partno); 72113498266Sopenharmony_ci } 72213498266Sopenharmony_ci else if(!req->ntlm && 72313498266Sopenharmony_ci strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAD")) { 72413498266Sopenharmony_ci /* If the client is passing this type-3 NTLM header */ 72513498266Sopenharmony_ci req->partno += 1002; 72613498266Sopenharmony_ci req->ntlm = TRUE; /* NTLM found */ 72713498266Sopenharmony_ci logmsg("Received NTLM type-3, sending back data %ld", req->partno); 72813498266Sopenharmony_ci if(req->cl) { 72913498266Sopenharmony_ci logmsg(" Expecting %zu POSTed bytes", req->cl); 73013498266Sopenharmony_ci } 73113498266Sopenharmony_ci } 73213498266Sopenharmony_ci else if(!req->ntlm && 73313498266Sopenharmony_ci strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAB")) { 73413498266Sopenharmony_ci /* If the client is passing this type-1 NTLM header */ 73513498266Sopenharmony_ci req->partno += 1001; 73613498266Sopenharmony_ci req->ntlm = TRUE; /* NTLM found */ 73713498266Sopenharmony_ci logmsg("Received NTLM type-1, sending back data %ld", req->partno); 73813498266Sopenharmony_ci } 73913498266Sopenharmony_ci else if((req->partno >= 1000) && 74013498266Sopenharmony_ci strstr(req->reqbuf, "Authorization: Basic")) { 74113498266Sopenharmony_ci /* If the client is passing this Basic-header and the part number is 74213498266Sopenharmony_ci already >=1000, we add 1 to the part number. This allows simple Basic 74313498266Sopenharmony_ci authentication negotiation to work in the test suite. */ 74413498266Sopenharmony_ci req->partno += 1; 74513498266Sopenharmony_ci logmsg("Received Basic request, sending back data %ld", req->partno); 74613498266Sopenharmony_ci } 74713498266Sopenharmony_ci if(strstr(req->reqbuf, "Connection: close")) 74813498266Sopenharmony_ci req->open = FALSE; /* close connection after this request */ 74913498266Sopenharmony_ci 75013498266Sopenharmony_ci if(req->open && 75113498266Sopenharmony_ci req->prot_version >= 11 && 75213498266Sopenharmony_ci req->reqbuf + req->offset > end + strlen(end_of_headers) && 75313498266Sopenharmony_ci !req->cl && 75413498266Sopenharmony_ci (!strncmp(req->reqbuf, "GET", strlen("GET")) || 75513498266Sopenharmony_ci !strncmp(req->reqbuf, "HEAD", strlen("HEAD")))) { 75613498266Sopenharmony_ci /* If we have a persistent connection, HTTP version >= 1.1 75713498266Sopenharmony_ci and GET/HEAD request, enable pipelining. */ 75813498266Sopenharmony_ci req->checkindex = (end - req->reqbuf) + strlen(end_of_headers); 75913498266Sopenharmony_ci } 76013498266Sopenharmony_ci 76113498266Sopenharmony_ci /* If authentication is required and no auth was provided, end now. This 76213498266Sopenharmony_ci makes the server NOT wait for PUT/POST data and you can then make the 76313498266Sopenharmony_ci test case send a rejection before any such data has been sent. Test case 76413498266Sopenharmony_ci 154 uses this.*/ 76513498266Sopenharmony_ci if(req->auth_req && !req->auth) { 76613498266Sopenharmony_ci logmsg("Return early due to auth requested by none provided"); 76713498266Sopenharmony_ci return 1; /* done */ 76813498266Sopenharmony_ci } 76913498266Sopenharmony_ci 77013498266Sopenharmony_ci if(req->upgrade && strstr(req->reqbuf, "Upgrade:")) { 77113498266Sopenharmony_ci /* we allow upgrade and there was one! */ 77213498266Sopenharmony_ci logmsg("Found Upgrade: in request and allow it"); 77313498266Sopenharmony_ci req->upgrade_request = TRUE; 77413498266Sopenharmony_ci return 0; /* not done */ 77513498266Sopenharmony_ci } 77613498266Sopenharmony_ci 77713498266Sopenharmony_ci if(req->cl > 0) { 77813498266Sopenharmony_ci if(req->cl <= req->offset - (end - req->reqbuf) - strlen(end_of_headers)) 77913498266Sopenharmony_ci return 1; /* done */ 78013498266Sopenharmony_ci else 78113498266Sopenharmony_ci return 0; /* not complete yet */ 78213498266Sopenharmony_ci } 78313498266Sopenharmony_ci 78413498266Sopenharmony_ci return 1; /* done */ 78513498266Sopenharmony_ci} 78613498266Sopenharmony_ci 78713498266Sopenharmony_ci/* store the entire request in a file */ 78813498266Sopenharmony_cistatic void storerequest(const char *reqbuf, size_t totalsize) 78913498266Sopenharmony_ci{ 79013498266Sopenharmony_ci int res; 79113498266Sopenharmony_ci int error = 0; 79213498266Sopenharmony_ci size_t written; 79313498266Sopenharmony_ci size_t writeleft; 79413498266Sopenharmony_ci FILE *dump; 79513498266Sopenharmony_ci char dumpfile[256]; 79613498266Sopenharmony_ci 79713498266Sopenharmony_ci msnprintf(dumpfile, sizeof(dumpfile), "%s/%s", 79813498266Sopenharmony_ci logdir, is_proxy?REQUEST_PROXY_DUMP:REQUEST_DUMP); 79913498266Sopenharmony_ci 80013498266Sopenharmony_ci if(!reqbuf) 80113498266Sopenharmony_ci return; 80213498266Sopenharmony_ci if(totalsize == 0) 80313498266Sopenharmony_ci return; 80413498266Sopenharmony_ci 80513498266Sopenharmony_ci do { 80613498266Sopenharmony_ci dump = fopen(dumpfile, "ab"); 80713498266Sopenharmony_ci } while(!dump && ((error = errno) == EINTR)); 80813498266Sopenharmony_ci if(!dump) { 80913498266Sopenharmony_ci logmsg("[2] Error opening file %s error: %d %s", 81013498266Sopenharmony_ci dumpfile, error, strerror(error)); 81113498266Sopenharmony_ci logmsg("Failed to write request input "); 81213498266Sopenharmony_ci return; 81313498266Sopenharmony_ci } 81413498266Sopenharmony_ci 81513498266Sopenharmony_ci writeleft = totalsize; 81613498266Sopenharmony_ci do { 81713498266Sopenharmony_ci written = fwrite(&reqbuf[totalsize-writeleft], 81813498266Sopenharmony_ci 1, writeleft, dump); 81913498266Sopenharmony_ci if(got_exit_signal) 82013498266Sopenharmony_ci goto storerequest_cleanup; 82113498266Sopenharmony_ci if(written > 0) 82213498266Sopenharmony_ci writeleft -= written; 82313498266Sopenharmony_ci } while((writeleft > 0) && ((error = errno) == EINTR)); 82413498266Sopenharmony_ci 82513498266Sopenharmony_ci if(writeleft == 0) 82613498266Sopenharmony_ci logmsg("Wrote request (%zu bytes) input to %s", totalsize, dumpfile); 82713498266Sopenharmony_ci else if(writeleft > 0) { 82813498266Sopenharmony_ci logmsg("Error writing file %s error: %d %s", 82913498266Sopenharmony_ci dumpfile, error, strerror(error)); 83013498266Sopenharmony_ci logmsg("Wrote only (%zu bytes) of (%zu bytes) request input to %s", 83113498266Sopenharmony_ci totalsize-writeleft, totalsize, dumpfile); 83213498266Sopenharmony_ci } 83313498266Sopenharmony_ci 83413498266Sopenharmony_cistorerequest_cleanup: 83513498266Sopenharmony_ci 83613498266Sopenharmony_ci do { 83713498266Sopenharmony_ci res = fclose(dump); 83813498266Sopenharmony_ci } while(res && ((error = errno) == EINTR)); 83913498266Sopenharmony_ci if(res) 84013498266Sopenharmony_ci logmsg("Error closing file %s error: %d %s", 84113498266Sopenharmony_ci dumpfile, error, strerror(error)); 84213498266Sopenharmony_ci} 84313498266Sopenharmony_ci 84413498266Sopenharmony_cistatic void init_httprequest(struct httprequest *req) 84513498266Sopenharmony_ci{ 84613498266Sopenharmony_ci req->checkindex = 0; 84713498266Sopenharmony_ci req->offset = 0; 84813498266Sopenharmony_ci req->testno = DOCNUMBER_NOTHING; 84913498266Sopenharmony_ci req->partno = 0; 85013498266Sopenharmony_ci req->connect_request = FALSE; 85113498266Sopenharmony_ci req->open = TRUE; 85213498266Sopenharmony_ci req->auth_req = FALSE; 85313498266Sopenharmony_ci req->auth = FALSE; 85413498266Sopenharmony_ci req->cl = 0; 85513498266Sopenharmony_ci req->digest = FALSE; 85613498266Sopenharmony_ci req->ntlm = FALSE; 85713498266Sopenharmony_ci req->skip = 0; 85813498266Sopenharmony_ci req->skipall = FALSE; 85913498266Sopenharmony_ci req->noexpect = FALSE; 86013498266Sopenharmony_ci req->delay = 0; 86113498266Sopenharmony_ci req->writedelay = 0; 86213498266Sopenharmony_ci req->rcmd = RCMD_NORMALREQ; 86313498266Sopenharmony_ci req->prot_version = 0; 86413498266Sopenharmony_ci req->callcount = 0; 86513498266Sopenharmony_ci req->connect_port = 0; 86613498266Sopenharmony_ci req->done_processing = 0; 86713498266Sopenharmony_ci req->upgrade = 0; 86813498266Sopenharmony_ci req->upgrade_request = 0; 86913498266Sopenharmony_ci} 87013498266Sopenharmony_ci 87113498266Sopenharmony_cistatic int send_doc(curl_socket_t sock, struct httprequest *req); 87213498266Sopenharmony_ci 87313498266Sopenharmony_ci/* returns 1 if the connection should be serviced again immediately, 0 if there 87413498266Sopenharmony_ci is no data waiting, or < 0 if it should be closed */ 87513498266Sopenharmony_cistatic int get_request(curl_socket_t sock, struct httprequest *req) 87613498266Sopenharmony_ci{ 87713498266Sopenharmony_ci int fail = 0; 87813498266Sopenharmony_ci char *reqbuf = req->reqbuf; 87913498266Sopenharmony_ci ssize_t got = 0; 88013498266Sopenharmony_ci int overflow = 0; 88113498266Sopenharmony_ci 88213498266Sopenharmony_ci if(req->upgrade_request) { 88313498266Sopenharmony_ci /* upgraded connection, work it differently until end of connection */ 88413498266Sopenharmony_ci logmsg("Upgraded connection, this is no longer HTTP/1"); 88513498266Sopenharmony_ci send_doc(sock, req); 88613498266Sopenharmony_ci 88713498266Sopenharmony_ci /* dump the request received so far to the external file */ 88813498266Sopenharmony_ci reqbuf[req->offset] = '\0'; 88913498266Sopenharmony_ci storerequest(reqbuf, req->offset); 89013498266Sopenharmony_ci req->offset = 0; 89113498266Sopenharmony_ci 89213498266Sopenharmony_ci /* read websocket traffic */ 89313498266Sopenharmony_ci if(req->open) { 89413498266Sopenharmony_ci logmsg("wait for websocket traffic"); 89513498266Sopenharmony_ci do { 89613498266Sopenharmony_ci got = sread(sock, reqbuf + req->offset, REQBUFSIZ - req->offset); 89713498266Sopenharmony_ci if(got > 0) { 89813498266Sopenharmony_ci req->offset += got; 89913498266Sopenharmony_ci logmsg("Got %zu bytes from client", got); 90013498266Sopenharmony_ci } 90113498266Sopenharmony_ci 90213498266Sopenharmony_ci if((got == -1) && ((EAGAIN == errno) || (EWOULDBLOCK == errno))) { 90313498266Sopenharmony_ci int rc; 90413498266Sopenharmony_ci fd_set input; 90513498266Sopenharmony_ci fd_set output; 90613498266Sopenharmony_ci struct timeval timeout = {1, 0}; /* 1000 ms */ 90713498266Sopenharmony_ci 90813498266Sopenharmony_ci logmsg("Got EAGAIN from sread"); 90913498266Sopenharmony_ci FD_ZERO(&input); 91013498266Sopenharmony_ci FD_ZERO(&output); 91113498266Sopenharmony_ci got = 0; 91213498266Sopenharmony_ci FD_SET(sock, &input); 91313498266Sopenharmony_ci do { 91413498266Sopenharmony_ci logmsg("Wait until readable"); 91513498266Sopenharmony_ci rc = select((int)sock + 1, &input, &output, NULL, &timeout); 91613498266Sopenharmony_ci } while(rc < 0 && errno == EINTR && !got_exit_signal); 91713498266Sopenharmony_ci logmsg("readable %d", rc); 91813498266Sopenharmony_ci if(rc) 91913498266Sopenharmony_ci got = 1; 92013498266Sopenharmony_ci } 92113498266Sopenharmony_ci } while(got > 0); 92213498266Sopenharmony_ci } 92313498266Sopenharmony_ci else { 92413498266Sopenharmony_ci logmsg("NO wait for websocket traffic"); 92513498266Sopenharmony_ci } 92613498266Sopenharmony_ci if(req->offset) { 92713498266Sopenharmony_ci logmsg("log the websocket traffic"); 92813498266Sopenharmony_ci /* dump the incoming websocket traffic to the external file */ 92913498266Sopenharmony_ci reqbuf[req->offset] = '\0'; 93013498266Sopenharmony_ci storerequest(reqbuf, req->offset); 93113498266Sopenharmony_ci req->offset = 0; 93213498266Sopenharmony_ci } 93313498266Sopenharmony_ci init_httprequest(req); 93413498266Sopenharmony_ci 93513498266Sopenharmony_ci return -1; 93613498266Sopenharmony_ci } 93713498266Sopenharmony_ci 93813498266Sopenharmony_ci if(req->offset >= REQBUFSIZ-1) { 93913498266Sopenharmony_ci /* buffer is already full; do nothing */ 94013498266Sopenharmony_ci overflow = 1; 94113498266Sopenharmony_ci } 94213498266Sopenharmony_ci else { 94313498266Sopenharmony_ci if(req->skip) 94413498266Sopenharmony_ci /* we are instructed to not read the entire thing, so we make sure to 94513498266Sopenharmony_ci only read what we're supposed to and NOT read the entire thing the 94613498266Sopenharmony_ci client wants to send! */ 94713498266Sopenharmony_ci got = sread(sock, reqbuf + req->offset, req->cl); 94813498266Sopenharmony_ci else 94913498266Sopenharmony_ci got = sread(sock, reqbuf + req->offset, REQBUFSIZ-1 - req->offset); 95013498266Sopenharmony_ci 95113498266Sopenharmony_ci if(got_exit_signal) 95213498266Sopenharmony_ci return -1; 95313498266Sopenharmony_ci if(got == 0) { 95413498266Sopenharmony_ci logmsg("Connection closed by client"); 95513498266Sopenharmony_ci fail = 1; 95613498266Sopenharmony_ci } 95713498266Sopenharmony_ci else if(got < 0) { 95813498266Sopenharmony_ci int error = SOCKERRNO; 95913498266Sopenharmony_ci if(EAGAIN == error || EWOULDBLOCK == error) { 96013498266Sopenharmony_ci /* nothing to read at the moment */ 96113498266Sopenharmony_ci return 0; 96213498266Sopenharmony_ci } 96313498266Sopenharmony_ci logmsg("recv() returned error: (%d) %s", error, sstrerror(error)); 96413498266Sopenharmony_ci fail = 1; 96513498266Sopenharmony_ci } 96613498266Sopenharmony_ci if(fail) { 96713498266Sopenharmony_ci /* dump the request received so far to the external file */ 96813498266Sopenharmony_ci reqbuf[req->offset] = '\0'; 96913498266Sopenharmony_ci storerequest(reqbuf, req->offset); 97013498266Sopenharmony_ci return -1; 97113498266Sopenharmony_ci } 97213498266Sopenharmony_ci 97313498266Sopenharmony_ci logmsg("Read %zd bytes", got); 97413498266Sopenharmony_ci 97513498266Sopenharmony_ci req->offset += (size_t)got; 97613498266Sopenharmony_ci reqbuf[req->offset] = '\0'; 97713498266Sopenharmony_ci 97813498266Sopenharmony_ci req->done_processing = ProcessRequest(req); 97913498266Sopenharmony_ci if(got_exit_signal) 98013498266Sopenharmony_ci return -1; 98113498266Sopenharmony_ci } 98213498266Sopenharmony_ci 98313498266Sopenharmony_ci if(overflow || (req->offset == REQBUFSIZ-1 && got > 0)) { 98413498266Sopenharmony_ci logmsg("Request would overflow buffer, closing connection"); 98513498266Sopenharmony_ci /* dump request received so far to external file anyway */ 98613498266Sopenharmony_ci reqbuf[REQBUFSIZ-1] = '\0'; 98713498266Sopenharmony_ci fail = 1; 98813498266Sopenharmony_ci } 98913498266Sopenharmony_ci else if(req->offset > REQBUFSIZ-1) { 99013498266Sopenharmony_ci logmsg("Request buffer overflow, closing connection"); 99113498266Sopenharmony_ci /* dump request received so far to external file anyway */ 99213498266Sopenharmony_ci reqbuf[REQBUFSIZ-1] = '\0'; 99313498266Sopenharmony_ci fail = 1; 99413498266Sopenharmony_ci } 99513498266Sopenharmony_ci else 99613498266Sopenharmony_ci reqbuf[req->offset] = '\0'; 99713498266Sopenharmony_ci 99813498266Sopenharmony_ci /* at the end of a request dump it to an external file */ 99913498266Sopenharmony_ci if(fail || req->done_processing) 100013498266Sopenharmony_ci storerequest(reqbuf, req->offset); 100113498266Sopenharmony_ci if(got_exit_signal) 100213498266Sopenharmony_ci return -1; 100313498266Sopenharmony_ci 100413498266Sopenharmony_ci return fail ? -1 : 1; 100513498266Sopenharmony_ci} 100613498266Sopenharmony_ci 100713498266Sopenharmony_ci/* returns -1 on failure */ 100813498266Sopenharmony_cistatic int send_doc(curl_socket_t sock, struct httprequest *req) 100913498266Sopenharmony_ci{ 101013498266Sopenharmony_ci ssize_t written; 101113498266Sopenharmony_ci size_t count; 101213498266Sopenharmony_ci const char *buffer; 101313498266Sopenharmony_ci char *ptr = NULL; 101413498266Sopenharmony_ci FILE *stream; 101513498266Sopenharmony_ci char *cmd = NULL; 101613498266Sopenharmony_ci size_t cmdsize = 0; 101713498266Sopenharmony_ci FILE *dump; 101813498266Sopenharmony_ci bool persistent = TRUE; 101913498266Sopenharmony_ci bool sendfailure = FALSE; 102013498266Sopenharmony_ci size_t responsesize; 102113498266Sopenharmony_ci int error = 0; 102213498266Sopenharmony_ci int res; 102313498266Sopenharmony_ci static char weare[256]; 102413498266Sopenharmony_ci char responsedump[256]; 102513498266Sopenharmony_ci 102613498266Sopenharmony_ci msnprintf(responsedump, sizeof(responsedump), "%s/%s", 102713498266Sopenharmony_ci logdir, is_proxy?RESPONSE_PROXY_DUMP:RESPONSE_DUMP); 102813498266Sopenharmony_ci 102913498266Sopenharmony_ci switch(req->rcmd) { 103013498266Sopenharmony_ci default: 103113498266Sopenharmony_ci case RCMD_NORMALREQ: 103213498266Sopenharmony_ci break; /* continue with business as usual */ 103313498266Sopenharmony_ci case RCMD_STREAM: 103413498266Sopenharmony_ci#define STREAMTHIS "a string to stream 01234567890\n" 103513498266Sopenharmony_ci count = strlen(STREAMTHIS); 103613498266Sopenharmony_ci for(;;) { 103713498266Sopenharmony_ci written = swrite(sock, STREAMTHIS, count); 103813498266Sopenharmony_ci if(got_exit_signal) 103913498266Sopenharmony_ci return -1; 104013498266Sopenharmony_ci if(written != (ssize_t)count) { 104113498266Sopenharmony_ci logmsg("Stopped streaming"); 104213498266Sopenharmony_ci break; 104313498266Sopenharmony_ci } 104413498266Sopenharmony_ci } 104513498266Sopenharmony_ci return -1; 104613498266Sopenharmony_ci case RCMD_IDLE: 104713498266Sopenharmony_ci /* Do nothing. Sit idle. Pretend it rains. */ 104813498266Sopenharmony_ci return 0; 104913498266Sopenharmony_ci } 105013498266Sopenharmony_ci 105113498266Sopenharmony_ci req->open = FALSE; 105213498266Sopenharmony_ci 105313498266Sopenharmony_ci if(req->testno < 0) { 105413498266Sopenharmony_ci size_t msglen; 105513498266Sopenharmony_ci char msgbuf[64]; 105613498266Sopenharmony_ci 105713498266Sopenharmony_ci switch(req->testno) { 105813498266Sopenharmony_ci case DOCNUMBER_QUIT: 105913498266Sopenharmony_ci logmsg("Replying to QUIT"); 106013498266Sopenharmony_ci buffer = docquit; 106113498266Sopenharmony_ci break; 106213498266Sopenharmony_ci case DOCNUMBER_WERULEZ: 106313498266Sopenharmony_ci /* we got a "friends?" question, reply back that we sure are */ 106413498266Sopenharmony_ci logmsg("Identifying ourselves as friends"); 106513498266Sopenharmony_ci msnprintf(msgbuf, sizeof(msgbuf), "WE ROOLZ: %" 106613498266Sopenharmony_ci CURL_FORMAT_CURL_OFF_T "\r\n", our_getpid()); 106713498266Sopenharmony_ci msglen = strlen(msgbuf); 106813498266Sopenharmony_ci if(use_gopher) 106913498266Sopenharmony_ci msnprintf(weare, sizeof(weare), "%s", msgbuf); 107013498266Sopenharmony_ci else 107113498266Sopenharmony_ci msnprintf(weare, sizeof(weare), 107213498266Sopenharmony_ci "HTTP/1.1 200 OK\r\nContent-Length: %zu\r\n\r\n%s", 107313498266Sopenharmony_ci msglen, msgbuf); 107413498266Sopenharmony_ci buffer = weare; 107513498266Sopenharmony_ci break; 107613498266Sopenharmony_ci case DOCNUMBER_404: 107713498266Sopenharmony_ci default: 107813498266Sopenharmony_ci logmsg("Replying to with a 404"); 107913498266Sopenharmony_ci buffer = doc404; 108013498266Sopenharmony_ci break; 108113498266Sopenharmony_ci } 108213498266Sopenharmony_ci 108313498266Sopenharmony_ci count = strlen(buffer); 108413498266Sopenharmony_ci } 108513498266Sopenharmony_ci else { 108613498266Sopenharmony_ci char partbuf[80]; 108713498266Sopenharmony_ci 108813498266Sopenharmony_ci /* select the <data> tag for "normal" requests and the <connect> one 108913498266Sopenharmony_ci for CONNECT requests (within the <reply> section) */ 109013498266Sopenharmony_ci const char *section = req->connect_request?"connect":"data"; 109113498266Sopenharmony_ci 109213498266Sopenharmony_ci if(req->partno) 109313498266Sopenharmony_ci msnprintf(partbuf, sizeof(partbuf), "%s%ld", section, req->partno); 109413498266Sopenharmony_ci else 109513498266Sopenharmony_ci msnprintf(partbuf, sizeof(partbuf), "%s", section); 109613498266Sopenharmony_ci 109713498266Sopenharmony_ci logmsg("Send response test%ld section <%s>", req->testno, partbuf); 109813498266Sopenharmony_ci 109913498266Sopenharmony_ci stream = test2fopen(req->testno, logdir); 110013498266Sopenharmony_ci if(!stream) { 110113498266Sopenharmony_ci error = errno; 110213498266Sopenharmony_ci logmsg("fopen() failed with error: %d %s", error, strerror(error)); 110313498266Sopenharmony_ci return 0; 110413498266Sopenharmony_ci } 110513498266Sopenharmony_ci else { 110613498266Sopenharmony_ci error = getpart(&ptr, &count, "reply", partbuf, stream); 110713498266Sopenharmony_ci fclose(stream); 110813498266Sopenharmony_ci if(error) { 110913498266Sopenharmony_ci logmsg("getpart() failed with error: %d", error); 111013498266Sopenharmony_ci return 0; 111113498266Sopenharmony_ci } 111213498266Sopenharmony_ci buffer = ptr; 111313498266Sopenharmony_ci } 111413498266Sopenharmony_ci 111513498266Sopenharmony_ci if(got_exit_signal) { 111613498266Sopenharmony_ci free(ptr); 111713498266Sopenharmony_ci return -1; 111813498266Sopenharmony_ci } 111913498266Sopenharmony_ci 112013498266Sopenharmony_ci /* re-open the same file again */ 112113498266Sopenharmony_ci stream = test2fopen(req->testno, logdir); 112213498266Sopenharmony_ci if(!stream) { 112313498266Sopenharmony_ci error = errno; 112413498266Sopenharmony_ci logmsg("fopen() failed with error: %d %s", error, strerror(error)); 112513498266Sopenharmony_ci free(ptr); 112613498266Sopenharmony_ci return 0; 112713498266Sopenharmony_ci } 112813498266Sopenharmony_ci else { 112913498266Sopenharmony_ci /* get the custom server control "commands" */ 113013498266Sopenharmony_ci error = getpart(&cmd, &cmdsize, "reply", "postcmd", stream); 113113498266Sopenharmony_ci fclose(stream); 113213498266Sopenharmony_ci if(error) { 113313498266Sopenharmony_ci logmsg("getpart() failed with error: %d", error); 113413498266Sopenharmony_ci free(ptr); 113513498266Sopenharmony_ci return 0; 113613498266Sopenharmony_ci } 113713498266Sopenharmony_ci } 113813498266Sopenharmony_ci } 113913498266Sopenharmony_ci 114013498266Sopenharmony_ci if(got_exit_signal) { 114113498266Sopenharmony_ci free(ptr); 114213498266Sopenharmony_ci free(cmd); 114313498266Sopenharmony_ci return -1; 114413498266Sopenharmony_ci } 114513498266Sopenharmony_ci 114613498266Sopenharmony_ci /* If the word 'swsclose' is present anywhere in the reply chunk, the 114713498266Sopenharmony_ci connection will be closed after the data has been sent to the requesting 114813498266Sopenharmony_ci client... */ 114913498266Sopenharmony_ci if(strstr(buffer, "swsclose") || !count || req->close) { 115013498266Sopenharmony_ci persistent = FALSE; 115113498266Sopenharmony_ci logmsg("connection close instruction \"swsclose\" found in response"); 115213498266Sopenharmony_ci } 115313498266Sopenharmony_ci if(strstr(buffer, "swsbounce")) { 115413498266Sopenharmony_ci prevbounce = TRUE; 115513498266Sopenharmony_ci logmsg("enable \"swsbounce\" in the next request"); 115613498266Sopenharmony_ci } 115713498266Sopenharmony_ci else 115813498266Sopenharmony_ci prevbounce = FALSE; 115913498266Sopenharmony_ci 116013498266Sopenharmony_ci dump = fopen(responsedump, "ab"); 116113498266Sopenharmony_ci if(!dump) { 116213498266Sopenharmony_ci error = errno; 116313498266Sopenharmony_ci logmsg("fopen() failed with error: %d %s", error, strerror(error)); 116413498266Sopenharmony_ci logmsg(" [5] Error opening file: %s", responsedump); 116513498266Sopenharmony_ci free(ptr); 116613498266Sopenharmony_ci free(cmd); 116713498266Sopenharmony_ci return -1; 116813498266Sopenharmony_ci } 116913498266Sopenharmony_ci 117013498266Sopenharmony_ci responsesize = count; 117113498266Sopenharmony_ci do { 117213498266Sopenharmony_ci /* Ok, we send no more than N bytes at a time, just to make sure that 117313498266Sopenharmony_ci larger chunks are split up so that the client will need to do multiple 117413498266Sopenharmony_ci recv() calls to get it and thus we exercise that code better */ 117513498266Sopenharmony_ci size_t num = count; 117613498266Sopenharmony_ci if(num > 20) 117713498266Sopenharmony_ci num = 20; 117813498266Sopenharmony_ci 117913498266Sopenharmony_ciretry: 118013498266Sopenharmony_ci written = swrite(sock, buffer, num); 118113498266Sopenharmony_ci if(written < 0) { 118213498266Sopenharmony_ci if((EWOULDBLOCK == SOCKERRNO) || (EAGAIN == SOCKERRNO)) { 118313498266Sopenharmony_ci wait_ms(10); 118413498266Sopenharmony_ci goto retry; 118513498266Sopenharmony_ci } 118613498266Sopenharmony_ci sendfailure = TRUE; 118713498266Sopenharmony_ci break; 118813498266Sopenharmony_ci } 118913498266Sopenharmony_ci 119013498266Sopenharmony_ci /* write to file as well */ 119113498266Sopenharmony_ci fwrite(buffer, 1, (size_t)written, dump); 119213498266Sopenharmony_ci 119313498266Sopenharmony_ci count -= written; 119413498266Sopenharmony_ci buffer += written; 119513498266Sopenharmony_ci 119613498266Sopenharmony_ci if(req->writedelay) { 119713498266Sopenharmony_ci int msecs_left = req->writedelay; 119813498266Sopenharmony_ci int intervals = msecs_left / MAX_SLEEP_TIME_MS; 119913498266Sopenharmony_ci if(msecs_left%MAX_SLEEP_TIME_MS) 120013498266Sopenharmony_ci intervals++; 120113498266Sopenharmony_ci logmsg("Pausing %d milliseconds after writing %zd bytes", 120213498266Sopenharmony_ci msecs_left, written); 120313498266Sopenharmony_ci while((intervals > 0) && !got_exit_signal) { 120413498266Sopenharmony_ci int sleep_time = msecs_left > MAX_SLEEP_TIME_MS ? 120513498266Sopenharmony_ci MAX_SLEEP_TIME_MS : msecs_left; 120613498266Sopenharmony_ci intervals--; 120713498266Sopenharmony_ci wait_ms(sleep_time); 120813498266Sopenharmony_ci msecs_left -= sleep_time; 120913498266Sopenharmony_ci } 121013498266Sopenharmony_ci } 121113498266Sopenharmony_ci } while((count > 0) && !got_exit_signal); 121213498266Sopenharmony_ci 121313498266Sopenharmony_ci do { 121413498266Sopenharmony_ci res = fclose(dump); 121513498266Sopenharmony_ci } while(res && ((error = errno) == EINTR)); 121613498266Sopenharmony_ci if(res) 121713498266Sopenharmony_ci logmsg("Error closing file %s error: %d %s", 121813498266Sopenharmony_ci responsedump, error, strerror(error)); 121913498266Sopenharmony_ci 122013498266Sopenharmony_ci if(got_exit_signal) { 122113498266Sopenharmony_ci free(ptr); 122213498266Sopenharmony_ci free(cmd); 122313498266Sopenharmony_ci return -1; 122413498266Sopenharmony_ci } 122513498266Sopenharmony_ci 122613498266Sopenharmony_ci if(sendfailure) { 122713498266Sopenharmony_ci logmsg("Sending response failed. Only (%zu bytes) of (%zu bytes) " 122813498266Sopenharmony_ci "were sent", 122913498266Sopenharmony_ci responsesize-count, responsesize); 123013498266Sopenharmony_ci prevtestno = req->testno; 123113498266Sopenharmony_ci prevpartno = req->partno; 123213498266Sopenharmony_ci free(ptr); 123313498266Sopenharmony_ci free(cmd); 123413498266Sopenharmony_ci return -1; 123513498266Sopenharmony_ci } 123613498266Sopenharmony_ci 123713498266Sopenharmony_ci logmsg("Response sent (%zu bytes) and written to %s", 123813498266Sopenharmony_ci responsesize, responsedump); 123913498266Sopenharmony_ci free(ptr); 124013498266Sopenharmony_ci 124113498266Sopenharmony_ci if(cmdsize > 0) { 124213498266Sopenharmony_ci char command[32]; 124313498266Sopenharmony_ci int quarters; 124413498266Sopenharmony_ci int num; 124513498266Sopenharmony_ci ptr = cmd; 124613498266Sopenharmony_ci do { 124713498266Sopenharmony_ci if(2 == sscanf(ptr, "%31s %d", command, &num)) { 124813498266Sopenharmony_ci if(!strcmp("wait", command)) { 124913498266Sopenharmony_ci logmsg("Told to sleep for %d seconds", num); 125013498266Sopenharmony_ci quarters = num * 4; 125113498266Sopenharmony_ci while((quarters > 0) && !got_exit_signal) { 125213498266Sopenharmony_ci quarters--; 125313498266Sopenharmony_ci res = wait_ms(250); 125413498266Sopenharmony_ci if(res) { 125513498266Sopenharmony_ci /* should not happen */ 125613498266Sopenharmony_ci error = errno; 125713498266Sopenharmony_ci logmsg("wait_ms() failed with error: (%d) %s", 125813498266Sopenharmony_ci error, strerror(error)); 125913498266Sopenharmony_ci break; 126013498266Sopenharmony_ci } 126113498266Sopenharmony_ci } 126213498266Sopenharmony_ci if(!quarters) 126313498266Sopenharmony_ci logmsg("Continuing after sleeping %d seconds", num); 126413498266Sopenharmony_ci } 126513498266Sopenharmony_ci else 126613498266Sopenharmony_ci logmsg("Unknown command in reply command section"); 126713498266Sopenharmony_ci } 126813498266Sopenharmony_ci ptr = strchr(ptr, '\n'); 126913498266Sopenharmony_ci if(ptr) 127013498266Sopenharmony_ci ptr++; 127113498266Sopenharmony_ci else 127213498266Sopenharmony_ci ptr = NULL; 127313498266Sopenharmony_ci } while(ptr && *ptr); 127413498266Sopenharmony_ci } 127513498266Sopenharmony_ci free(cmd); 127613498266Sopenharmony_ci req->open = use_gopher?FALSE:persistent; 127713498266Sopenharmony_ci 127813498266Sopenharmony_ci prevtestno = req->testno; 127913498266Sopenharmony_ci prevpartno = req->partno; 128013498266Sopenharmony_ci 128113498266Sopenharmony_ci return 0; 128213498266Sopenharmony_ci} 128313498266Sopenharmony_ci 128413498266Sopenharmony_cistatic curl_socket_t connect_to(const char *ipaddr, unsigned short port) 128513498266Sopenharmony_ci{ 128613498266Sopenharmony_ci srvr_sockaddr_union_t serveraddr; 128713498266Sopenharmony_ci curl_socket_t serverfd; 128813498266Sopenharmony_ci int error; 128913498266Sopenharmony_ci int rc = 0; 129013498266Sopenharmony_ci const char *op_br = ""; 129113498266Sopenharmony_ci const char *cl_br = ""; 129213498266Sopenharmony_ci 129313498266Sopenharmony_ci#ifdef ENABLE_IPV6 129413498266Sopenharmony_ci if(socket_domain == AF_INET6) { 129513498266Sopenharmony_ci op_br = "["; 129613498266Sopenharmony_ci cl_br = "]"; 129713498266Sopenharmony_ci } 129813498266Sopenharmony_ci#endif 129913498266Sopenharmony_ci 130013498266Sopenharmony_ci if(!ipaddr) 130113498266Sopenharmony_ci return CURL_SOCKET_BAD; 130213498266Sopenharmony_ci 130313498266Sopenharmony_ci logmsg("about to connect to %s%s%s:%hu", 130413498266Sopenharmony_ci op_br, ipaddr, cl_br, port); 130513498266Sopenharmony_ci 130613498266Sopenharmony_ci 130713498266Sopenharmony_ci serverfd = socket(socket_domain, SOCK_STREAM, 0); 130813498266Sopenharmony_ci if(CURL_SOCKET_BAD == serverfd) { 130913498266Sopenharmony_ci error = SOCKERRNO; 131013498266Sopenharmony_ci logmsg("Error creating socket for server connection: (%d) %s", 131113498266Sopenharmony_ci error, sstrerror(error)); 131213498266Sopenharmony_ci return CURL_SOCKET_BAD; 131313498266Sopenharmony_ci } 131413498266Sopenharmony_ci 131513498266Sopenharmony_ci#ifdef TCP_NODELAY 131613498266Sopenharmony_ci if(socket_domain_is_ip()) { 131713498266Sopenharmony_ci /* Disable the Nagle algorithm */ 131813498266Sopenharmony_ci curl_socklen_t flag = 1; 131913498266Sopenharmony_ci if(0 != setsockopt(serverfd, IPPROTO_TCP, TCP_NODELAY, 132013498266Sopenharmony_ci (void *)&flag, sizeof(flag))) 132113498266Sopenharmony_ci logmsg("====> TCP_NODELAY for server connection failed"); 132213498266Sopenharmony_ci } 132313498266Sopenharmony_ci#endif 132413498266Sopenharmony_ci 132513498266Sopenharmony_ci switch(socket_domain) { 132613498266Sopenharmony_ci case AF_INET: 132713498266Sopenharmony_ci memset(&serveraddr.sa4, 0, sizeof(serveraddr.sa4)); 132813498266Sopenharmony_ci serveraddr.sa4.sin_family = AF_INET; 132913498266Sopenharmony_ci serveraddr.sa4.sin_port = htons(port); 133013498266Sopenharmony_ci if(Curl_inet_pton(AF_INET, ipaddr, &serveraddr.sa4.sin_addr) < 1) { 133113498266Sopenharmony_ci logmsg("Error inet_pton failed AF_INET conversion of '%s'", ipaddr); 133213498266Sopenharmony_ci sclose(serverfd); 133313498266Sopenharmony_ci return CURL_SOCKET_BAD; 133413498266Sopenharmony_ci } 133513498266Sopenharmony_ci 133613498266Sopenharmony_ci rc = connect(serverfd, &serveraddr.sa, sizeof(serveraddr.sa4)); 133713498266Sopenharmony_ci break; 133813498266Sopenharmony_ci#ifdef ENABLE_IPV6 133913498266Sopenharmony_ci case AF_INET6: 134013498266Sopenharmony_ci memset(&serveraddr.sa6, 0, sizeof(serveraddr.sa6)); 134113498266Sopenharmony_ci serveraddr.sa6.sin6_family = AF_INET6; 134213498266Sopenharmony_ci serveraddr.sa6.sin6_port = htons(port); 134313498266Sopenharmony_ci if(Curl_inet_pton(AF_INET6, ipaddr, &serveraddr.sa6.sin6_addr) < 1) { 134413498266Sopenharmony_ci logmsg("Error inet_pton failed AF_INET6 conversion of '%s'", ipaddr); 134513498266Sopenharmony_ci sclose(serverfd); 134613498266Sopenharmony_ci return CURL_SOCKET_BAD; 134713498266Sopenharmony_ci } 134813498266Sopenharmony_ci 134913498266Sopenharmony_ci rc = connect(serverfd, &serveraddr.sa, sizeof(serveraddr.sa6)); 135013498266Sopenharmony_ci break; 135113498266Sopenharmony_ci#endif /* ENABLE_IPV6 */ 135213498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS 135313498266Sopenharmony_ci case AF_UNIX: 135413498266Sopenharmony_ci logmsg("Proxying through Unix socket is not (yet?) supported."); 135513498266Sopenharmony_ci return CURL_SOCKET_BAD; 135613498266Sopenharmony_ci#endif /* USE_UNIX_SOCKETS */ 135713498266Sopenharmony_ci } 135813498266Sopenharmony_ci 135913498266Sopenharmony_ci if(got_exit_signal) { 136013498266Sopenharmony_ci sclose(serverfd); 136113498266Sopenharmony_ci return CURL_SOCKET_BAD; 136213498266Sopenharmony_ci } 136313498266Sopenharmony_ci 136413498266Sopenharmony_ci if(rc) { 136513498266Sopenharmony_ci error = SOCKERRNO; 136613498266Sopenharmony_ci logmsg("Error connecting to server port %hu: (%d) %s", 136713498266Sopenharmony_ci port, error, sstrerror(error)); 136813498266Sopenharmony_ci sclose(serverfd); 136913498266Sopenharmony_ci return CURL_SOCKET_BAD; 137013498266Sopenharmony_ci } 137113498266Sopenharmony_ci 137213498266Sopenharmony_ci logmsg("connected fine to %s%s%s:%hu, now tunnel", 137313498266Sopenharmony_ci op_br, ipaddr, cl_br, port); 137413498266Sopenharmony_ci 137513498266Sopenharmony_ci return serverfd; 137613498266Sopenharmony_ci} 137713498266Sopenharmony_ci 137813498266Sopenharmony_ci/* 137913498266Sopenharmony_ci * A CONNECT has been received, a CONNECT response has been sent. 138013498266Sopenharmony_ci * 138113498266Sopenharmony_ci * This function needs to connect to the server, and then pass data between 138213498266Sopenharmony_ci * the client and the server back and forth until the connection is closed by 138313498266Sopenharmony_ci * either end. 138413498266Sopenharmony_ci * 138513498266Sopenharmony_ci * When doing FTP through a CONNECT proxy, we expect that the data connection 138613498266Sopenharmony_ci * will be setup while the first connect is still being kept up. Therefore we 138713498266Sopenharmony_ci * must accept a new connection and deal with it appropriately. 138813498266Sopenharmony_ci */ 138913498266Sopenharmony_ci 139013498266Sopenharmony_ci#define data_or_ctrl(x) ((x)?"DATA":"CTRL") 139113498266Sopenharmony_ci 139213498266Sopenharmony_ci#define CTRL 0 139313498266Sopenharmony_ci#define DATA 1 139413498266Sopenharmony_ci 139513498266Sopenharmony_cistatic void http_connect(curl_socket_t *infdp, 139613498266Sopenharmony_ci curl_socket_t rootfd, 139713498266Sopenharmony_ci const char *ipaddr, 139813498266Sopenharmony_ci unsigned short ipport, 139913498266Sopenharmony_ci int keepalive_secs) 140013498266Sopenharmony_ci{ 140113498266Sopenharmony_ci curl_socket_t serverfd[2] = {CURL_SOCKET_BAD, CURL_SOCKET_BAD}; 140213498266Sopenharmony_ci curl_socket_t clientfd[2] = {CURL_SOCKET_BAD, CURL_SOCKET_BAD}; 140313498266Sopenharmony_ci ssize_t toc[2] = {0, 0}; /* number of bytes to client */ 140413498266Sopenharmony_ci ssize_t tos[2] = {0, 0}; /* number of bytes to server */ 140513498266Sopenharmony_ci char readclient[2][256]; 140613498266Sopenharmony_ci char readserver[2][256]; 140713498266Sopenharmony_ci bool poll_client_rd[2] = { TRUE, TRUE }; 140813498266Sopenharmony_ci bool poll_server_rd[2] = { TRUE, TRUE }; 140913498266Sopenharmony_ci bool poll_client_wr[2] = { TRUE, TRUE }; 141013498266Sopenharmony_ci bool poll_server_wr[2] = { TRUE, TRUE }; 141113498266Sopenharmony_ci bool primary = FALSE; 141213498266Sopenharmony_ci bool secondary = FALSE; 141313498266Sopenharmony_ci int max_tunnel_idx; /* CTRL or DATA */ 141413498266Sopenharmony_ci int loop; 141513498266Sopenharmony_ci int i; 141613498266Sopenharmony_ci int timeout_count = 0; 141713498266Sopenharmony_ci 141813498266Sopenharmony_ci /* primary tunnel client endpoint already connected */ 141913498266Sopenharmony_ci clientfd[CTRL] = *infdp; 142013498266Sopenharmony_ci 142113498266Sopenharmony_ci /* Sleep here to make sure the client reads CONNECT response's 142213498266Sopenharmony_ci 'end of headers' separate from the server data that follows. 142313498266Sopenharmony_ci This is done to prevent triggering libcurl known bug #39. */ 142413498266Sopenharmony_ci for(loop = 2; (loop > 0) && !got_exit_signal; loop--) 142513498266Sopenharmony_ci wait_ms(250); 142613498266Sopenharmony_ci if(got_exit_signal) 142713498266Sopenharmony_ci goto http_connect_cleanup; 142813498266Sopenharmony_ci 142913498266Sopenharmony_ci serverfd[CTRL] = connect_to(ipaddr, ipport); 143013498266Sopenharmony_ci if(serverfd[CTRL] == CURL_SOCKET_BAD) 143113498266Sopenharmony_ci goto http_connect_cleanup; 143213498266Sopenharmony_ci 143313498266Sopenharmony_ci /* Primary tunnel socket endpoints are now connected. Tunnel data back and 143413498266Sopenharmony_ci forth over the primary tunnel until client or server breaks the primary 143513498266Sopenharmony_ci tunnel, simultaneously allowing establishment, operation and teardown of 143613498266Sopenharmony_ci a secondary tunnel that may be used for passive FTP data connection. */ 143713498266Sopenharmony_ci 143813498266Sopenharmony_ci max_tunnel_idx = CTRL; 143913498266Sopenharmony_ci primary = TRUE; 144013498266Sopenharmony_ci 144113498266Sopenharmony_ci while(!got_exit_signal) { 144213498266Sopenharmony_ci 144313498266Sopenharmony_ci fd_set input; 144413498266Sopenharmony_ci fd_set output; 144513498266Sopenharmony_ci struct timeval timeout = {1, 0}; /* 1000 ms */ 144613498266Sopenharmony_ci ssize_t rc; 144713498266Sopenharmony_ci curl_socket_t maxfd = (curl_socket_t)-1; 144813498266Sopenharmony_ci 144913498266Sopenharmony_ci FD_ZERO(&input); 145013498266Sopenharmony_ci FD_ZERO(&output); 145113498266Sopenharmony_ci 145213498266Sopenharmony_ci if((clientfd[DATA] == CURL_SOCKET_BAD) && 145313498266Sopenharmony_ci (serverfd[DATA] == CURL_SOCKET_BAD) && 145413498266Sopenharmony_ci poll_client_rd[CTRL] && poll_client_wr[CTRL] && 145513498266Sopenharmony_ci poll_server_rd[CTRL] && poll_server_wr[CTRL]) { 145613498266Sopenharmony_ci /* listener socket is monitored to allow client to establish 145713498266Sopenharmony_ci secondary tunnel only when this tunnel is not established 145813498266Sopenharmony_ci and primary one is fully operational */ 145913498266Sopenharmony_ci FD_SET(rootfd, &input); 146013498266Sopenharmony_ci maxfd = rootfd; 146113498266Sopenharmony_ci } 146213498266Sopenharmony_ci 146313498266Sopenharmony_ci /* set tunnel sockets to wait for */ 146413498266Sopenharmony_ci for(i = 0; i <= max_tunnel_idx; i++) { 146513498266Sopenharmony_ci /* client side socket monitoring */ 146613498266Sopenharmony_ci if(clientfd[i] != CURL_SOCKET_BAD) { 146713498266Sopenharmony_ci if(poll_client_rd[i]) { 146813498266Sopenharmony_ci /* unless told not to do so, monitor readability */ 146913498266Sopenharmony_ci FD_SET(clientfd[i], &input); 147013498266Sopenharmony_ci if(clientfd[i] > maxfd) 147113498266Sopenharmony_ci maxfd = clientfd[i]; 147213498266Sopenharmony_ci } 147313498266Sopenharmony_ci if(poll_client_wr[i] && toc[i]) { 147413498266Sopenharmony_ci /* unless told not to do so, monitor writability 147513498266Sopenharmony_ci if there is data ready to be sent to client */ 147613498266Sopenharmony_ci FD_SET(clientfd[i], &output); 147713498266Sopenharmony_ci if(clientfd[i] > maxfd) 147813498266Sopenharmony_ci maxfd = clientfd[i]; 147913498266Sopenharmony_ci } 148013498266Sopenharmony_ci } 148113498266Sopenharmony_ci /* server side socket monitoring */ 148213498266Sopenharmony_ci if(serverfd[i] != CURL_SOCKET_BAD) { 148313498266Sopenharmony_ci if(poll_server_rd[i]) { 148413498266Sopenharmony_ci /* unless told not to do so, monitor readability */ 148513498266Sopenharmony_ci FD_SET(serverfd[i], &input); 148613498266Sopenharmony_ci if(serverfd[i] > maxfd) 148713498266Sopenharmony_ci maxfd = serverfd[i]; 148813498266Sopenharmony_ci } 148913498266Sopenharmony_ci if(poll_server_wr[i] && tos[i]) { 149013498266Sopenharmony_ci /* unless told not to do so, monitor writability 149113498266Sopenharmony_ci if there is data ready to be sent to server */ 149213498266Sopenharmony_ci FD_SET(serverfd[i], &output); 149313498266Sopenharmony_ci if(serverfd[i] > maxfd) 149413498266Sopenharmony_ci maxfd = serverfd[i]; 149513498266Sopenharmony_ci } 149613498266Sopenharmony_ci } 149713498266Sopenharmony_ci } 149813498266Sopenharmony_ci if(got_exit_signal) 149913498266Sopenharmony_ci break; 150013498266Sopenharmony_ci 150113498266Sopenharmony_ci do { 150213498266Sopenharmony_ci rc = select((int)maxfd + 1, &input, &output, NULL, &timeout); 150313498266Sopenharmony_ci } while(rc < 0 && errno == EINTR && !got_exit_signal); 150413498266Sopenharmony_ci 150513498266Sopenharmony_ci if(got_exit_signal) 150613498266Sopenharmony_ci break; 150713498266Sopenharmony_ci 150813498266Sopenharmony_ci if(rc > 0) { 150913498266Sopenharmony_ci /* socket action */ 151013498266Sopenharmony_ci bool tcp_fin_wr = FALSE; 151113498266Sopenharmony_ci timeout_count = 0; 151213498266Sopenharmony_ci 151313498266Sopenharmony_ci /* ---------------------------------------------------------- */ 151413498266Sopenharmony_ci 151513498266Sopenharmony_ci /* passive mode FTP may establish a secondary tunnel */ 151613498266Sopenharmony_ci if((clientfd[DATA] == CURL_SOCKET_BAD) && 151713498266Sopenharmony_ci (serverfd[DATA] == CURL_SOCKET_BAD) && FD_ISSET(rootfd, &input)) { 151813498266Sopenharmony_ci /* a new connection on listener socket (most likely from client) */ 151913498266Sopenharmony_ci curl_socket_t datafd = accept(rootfd, NULL, NULL); 152013498266Sopenharmony_ci if(datafd != CURL_SOCKET_BAD) { 152113498266Sopenharmony_ci static struct httprequest *req2; 152213498266Sopenharmony_ci int err = 0; 152313498266Sopenharmony_ci if(!req2) { 152413498266Sopenharmony_ci req2 = malloc(sizeof(*req2)); 152513498266Sopenharmony_ci if(!req2) 152613498266Sopenharmony_ci exit(1); 152713498266Sopenharmony_ci } 152813498266Sopenharmony_ci memset(req2, 0, sizeof(*req2)); 152913498266Sopenharmony_ci logmsg("====> Client connect DATA"); 153013498266Sopenharmony_ci#ifdef TCP_NODELAY 153113498266Sopenharmony_ci if(socket_domain_is_ip()) { 153213498266Sopenharmony_ci /* Disable the Nagle algorithm */ 153313498266Sopenharmony_ci curl_socklen_t flag = 1; 153413498266Sopenharmony_ci if(0 != setsockopt(datafd, IPPROTO_TCP, TCP_NODELAY, 153513498266Sopenharmony_ci (void *)&flag, sizeof(flag))) 153613498266Sopenharmony_ci logmsg("====> TCP_NODELAY for client DATA connection failed"); 153713498266Sopenharmony_ci } 153813498266Sopenharmony_ci#endif 153913498266Sopenharmony_ci init_httprequest(req2); 154013498266Sopenharmony_ci while(!req2->done_processing) { 154113498266Sopenharmony_ci err = get_request(datafd, req2); 154213498266Sopenharmony_ci if(err < 0) { 154313498266Sopenharmony_ci /* this socket must be closed, done or not */ 154413498266Sopenharmony_ci break; 154513498266Sopenharmony_ci } 154613498266Sopenharmony_ci } 154713498266Sopenharmony_ci 154813498266Sopenharmony_ci /* skip this and close the socket if err < 0 */ 154913498266Sopenharmony_ci if(err >= 0) { 155013498266Sopenharmony_ci err = send_doc(datafd, req2); 155113498266Sopenharmony_ci if(!err && req2->connect_request) { 155213498266Sopenharmony_ci /* sleep to prevent triggering libcurl known bug #39. */ 155313498266Sopenharmony_ci for(loop = 2; (loop > 0) && !got_exit_signal; loop--) 155413498266Sopenharmony_ci wait_ms(250); 155513498266Sopenharmony_ci if(!got_exit_signal) { 155613498266Sopenharmony_ci /* connect to the server */ 155713498266Sopenharmony_ci serverfd[DATA] = connect_to(ipaddr, req2->connect_port); 155813498266Sopenharmony_ci if(serverfd[DATA] != CURL_SOCKET_BAD) { 155913498266Sopenharmony_ci /* secondary tunnel established, now we have two 156013498266Sopenharmony_ci connections */ 156113498266Sopenharmony_ci poll_client_rd[DATA] = TRUE; 156213498266Sopenharmony_ci poll_client_wr[DATA] = TRUE; 156313498266Sopenharmony_ci poll_server_rd[DATA] = TRUE; 156413498266Sopenharmony_ci poll_server_wr[DATA] = TRUE; 156513498266Sopenharmony_ci max_tunnel_idx = DATA; 156613498266Sopenharmony_ci secondary = TRUE; 156713498266Sopenharmony_ci toc[DATA] = 0; 156813498266Sopenharmony_ci tos[DATA] = 0; 156913498266Sopenharmony_ci clientfd[DATA] = datafd; 157013498266Sopenharmony_ci datafd = CURL_SOCKET_BAD; 157113498266Sopenharmony_ci } 157213498266Sopenharmony_ci } 157313498266Sopenharmony_ci } 157413498266Sopenharmony_ci } 157513498266Sopenharmony_ci if(datafd != CURL_SOCKET_BAD) { 157613498266Sopenharmony_ci /* secondary tunnel not established */ 157713498266Sopenharmony_ci shutdown(datafd, SHUT_RDWR); 157813498266Sopenharmony_ci sclose(datafd); 157913498266Sopenharmony_ci } 158013498266Sopenharmony_ci } 158113498266Sopenharmony_ci if(got_exit_signal) 158213498266Sopenharmony_ci break; 158313498266Sopenharmony_ci } 158413498266Sopenharmony_ci 158513498266Sopenharmony_ci /* ---------------------------------------------------------- */ 158613498266Sopenharmony_ci 158713498266Sopenharmony_ci /* react to tunnel endpoint readable/writable notifications */ 158813498266Sopenharmony_ci for(i = 0; i <= max_tunnel_idx; i++) { 158913498266Sopenharmony_ci size_t len; 159013498266Sopenharmony_ci if(clientfd[i] != CURL_SOCKET_BAD) { 159113498266Sopenharmony_ci len = sizeof(readclient[i]) - tos[i]; 159213498266Sopenharmony_ci if(len && FD_ISSET(clientfd[i], &input)) { 159313498266Sopenharmony_ci /* read from client */ 159413498266Sopenharmony_ci rc = sread(clientfd[i], &readclient[i][tos[i]], len); 159513498266Sopenharmony_ci if(rc <= 0) { 159613498266Sopenharmony_ci logmsg("[%s] got %zd, STOP READING client", data_or_ctrl(i), rc); 159713498266Sopenharmony_ci shutdown(clientfd[i], SHUT_RD); 159813498266Sopenharmony_ci poll_client_rd[i] = FALSE; 159913498266Sopenharmony_ci } 160013498266Sopenharmony_ci else { 160113498266Sopenharmony_ci logmsg("[%s] READ %zd bytes from client", data_or_ctrl(i), rc); 160213498266Sopenharmony_ci logmsg("[%s] READ \"%s\"", data_or_ctrl(i), 160313498266Sopenharmony_ci data_to_hex(&readclient[i][tos[i]], rc)); 160413498266Sopenharmony_ci tos[i] += rc; 160513498266Sopenharmony_ci } 160613498266Sopenharmony_ci } 160713498266Sopenharmony_ci } 160813498266Sopenharmony_ci if(serverfd[i] != CURL_SOCKET_BAD) { 160913498266Sopenharmony_ci len = sizeof(readserver[i])-toc[i]; 161013498266Sopenharmony_ci if(len && FD_ISSET(serverfd[i], &input)) { 161113498266Sopenharmony_ci /* read from server */ 161213498266Sopenharmony_ci rc = sread(serverfd[i], &readserver[i][toc[i]], len); 161313498266Sopenharmony_ci if(rc <= 0) { 161413498266Sopenharmony_ci logmsg("[%s] got %zd, STOP READING server", data_or_ctrl(i), rc); 161513498266Sopenharmony_ci shutdown(serverfd[i], SHUT_RD); 161613498266Sopenharmony_ci poll_server_rd[i] = FALSE; 161713498266Sopenharmony_ci } 161813498266Sopenharmony_ci else { 161913498266Sopenharmony_ci logmsg("[%s] READ %zd bytes from server", data_or_ctrl(i), rc); 162013498266Sopenharmony_ci logmsg("[%s] READ \"%s\"", data_or_ctrl(i), 162113498266Sopenharmony_ci data_to_hex(&readserver[i][toc[i]], rc)); 162213498266Sopenharmony_ci toc[i] += rc; 162313498266Sopenharmony_ci } 162413498266Sopenharmony_ci } 162513498266Sopenharmony_ci } 162613498266Sopenharmony_ci if(clientfd[i] != CURL_SOCKET_BAD) { 162713498266Sopenharmony_ci if(toc[i] && FD_ISSET(clientfd[i], &output)) { 162813498266Sopenharmony_ci /* write to client */ 162913498266Sopenharmony_ci rc = swrite(clientfd[i], readserver[i], toc[i]); 163013498266Sopenharmony_ci if(rc <= 0) { 163113498266Sopenharmony_ci logmsg("[%s] got %zd, STOP WRITING client", data_or_ctrl(i), rc); 163213498266Sopenharmony_ci shutdown(clientfd[i], SHUT_WR); 163313498266Sopenharmony_ci poll_client_wr[i] = FALSE; 163413498266Sopenharmony_ci tcp_fin_wr = TRUE; 163513498266Sopenharmony_ci } 163613498266Sopenharmony_ci else { 163713498266Sopenharmony_ci logmsg("[%s] SENT %zd bytes to client", data_or_ctrl(i), rc); 163813498266Sopenharmony_ci logmsg("[%s] SENT \"%s\"", data_or_ctrl(i), 163913498266Sopenharmony_ci data_to_hex(readserver[i], rc)); 164013498266Sopenharmony_ci if(toc[i] - rc) 164113498266Sopenharmony_ci memmove(&readserver[i][0], &readserver[i][rc], toc[i]-rc); 164213498266Sopenharmony_ci toc[i] -= rc; 164313498266Sopenharmony_ci } 164413498266Sopenharmony_ci } 164513498266Sopenharmony_ci } 164613498266Sopenharmony_ci if(serverfd[i] != CURL_SOCKET_BAD) { 164713498266Sopenharmony_ci if(tos[i] && FD_ISSET(serverfd[i], &output)) { 164813498266Sopenharmony_ci /* write to server */ 164913498266Sopenharmony_ci rc = swrite(serverfd[i], readclient[i], tos[i]); 165013498266Sopenharmony_ci if(rc <= 0) { 165113498266Sopenharmony_ci logmsg("[%s] got %zd, STOP WRITING server", data_or_ctrl(i), rc); 165213498266Sopenharmony_ci shutdown(serverfd[i], SHUT_WR); 165313498266Sopenharmony_ci poll_server_wr[i] = FALSE; 165413498266Sopenharmony_ci tcp_fin_wr = TRUE; 165513498266Sopenharmony_ci } 165613498266Sopenharmony_ci else { 165713498266Sopenharmony_ci logmsg("[%s] SENT %zd bytes to server", data_or_ctrl(i), rc); 165813498266Sopenharmony_ci logmsg("[%s] SENT \"%s\"", data_or_ctrl(i), 165913498266Sopenharmony_ci data_to_hex(readclient[i], rc)); 166013498266Sopenharmony_ci if(tos[i] - rc) 166113498266Sopenharmony_ci memmove(&readclient[i][0], &readclient[i][rc], tos[i]-rc); 166213498266Sopenharmony_ci tos[i] -= rc; 166313498266Sopenharmony_ci } 166413498266Sopenharmony_ci } 166513498266Sopenharmony_ci } 166613498266Sopenharmony_ci } 166713498266Sopenharmony_ci if(got_exit_signal) 166813498266Sopenharmony_ci break; 166913498266Sopenharmony_ci 167013498266Sopenharmony_ci /* ---------------------------------------------------------- */ 167113498266Sopenharmony_ci 167213498266Sopenharmony_ci /* endpoint read/write disabling, endpoint closing and tunnel teardown */ 167313498266Sopenharmony_ci for(i = 0; i <= max_tunnel_idx; i++) { 167413498266Sopenharmony_ci for(loop = 2; loop > 0; loop--) { 167513498266Sopenharmony_ci /* loop twice to satisfy condition interdependencies without 167613498266Sopenharmony_ci having to await select timeout or another socket event */ 167713498266Sopenharmony_ci if(clientfd[i] != CURL_SOCKET_BAD) { 167813498266Sopenharmony_ci if(poll_client_rd[i] && !poll_server_wr[i]) { 167913498266Sopenharmony_ci logmsg("[%s] DISABLED READING client", data_or_ctrl(i)); 168013498266Sopenharmony_ci shutdown(clientfd[i], SHUT_RD); 168113498266Sopenharmony_ci poll_client_rd[i] = FALSE; 168213498266Sopenharmony_ci } 168313498266Sopenharmony_ci if(poll_client_wr[i] && !poll_server_rd[i] && !toc[i]) { 168413498266Sopenharmony_ci logmsg("[%s] DISABLED WRITING client", data_or_ctrl(i)); 168513498266Sopenharmony_ci shutdown(clientfd[i], SHUT_WR); 168613498266Sopenharmony_ci poll_client_wr[i] = FALSE; 168713498266Sopenharmony_ci tcp_fin_wr = TRUE; 168813498266Sopenharmony_ci } 168913498266Sopenharmony_ci } 169013498266Sopenharmony_ci if(serverfd[i] != CURL_SOCKET_BAD) { 169113498266Sopenharmony_ci if(poll_server_rd[i] && !poll_client_wr[i]) { 169213498266Sopenharmony_ci logmsg("[%s] DISABLED READING server", data_or_ctrl(i)); 169313498266Sopenharmony_ci shutdown(serverfd[i], SHUT_RD); 169413498266Sopenharmony_ci poll_server_rd[i] = FALSE; 169513498266Sopenharmony_ci } 169613498266Sopenharmony_ci if(poll_server_wr[i] && !poll_client_rd[i] && !tos[i]) { 169713498266Sopenharmony_ci logmsg("[%s] DISABLED WRITING server", data_or_ctrl(i)); 169813498266Sopenharmony_ci shutdown(serverfd[i], SHUT_WR); 169913498266Sopenharmony_ci poll_server_wr[i] = FALSE; 170013498266Sopenharmony_ci tcp_fin_wr = TRUE; 170113498266Sopenharmony_ci } 170213498266Sopenharmony_ci } 170313498266Sopenharmony_ci } 170413498266Sopenharmony_ci } 170513498266Sopenharmony_ci 170613498266Sopenharmony_ci if(tcp_fin_wr) 170713498266Sopenharmony_ci /* allow kernel to place FIN bit packet on the wire */ 170813498266Sopenharmony_ci wait_ms(250); 170913498266Sopenharmony_ci 171013498266Sopenharmony_ci /* socket clearing */ 171113498266Sopenharmony_ci for(i = 0; i <= max_tunnel_idx; i++) { 171213498266Sopenharmony_ci for(loop = 2; loop > 0; loop--) { 171313498266Sopenharmony_ci if(clientfd[i] != CURL_SOCKET_BAD) { 171413498266Sopenharmony_ci if(!poll_client_wr[i] && !poll_client_rd[i]) { 171513498266Sopenharmony_ci logmsg("[%s] CLOSING client socket", data_or_ctrl(i)); 171613498266Sopenharmony_ci sclose(clientfd[i]); 171713498266Sopenharmony_ci clientfd[i] = CURL_SOCKET_BAD; 171813498266Sopenharmony_ci if(serverfd[i] == CURL_SOCKET_BAD) { 171913498266Sopenharmony_ci logmsg("[%s] ENDING", data_or_ctrl(i)); 172013498266Sopenharmony_ci if(i == DATA) 172113498266Sopenharmony_ci secondary = FALSE; 172213498266Sopenharmony_ci else 172313498266Sopenharmony_ci primary = FALSE; 172413498266Sopenharmony_ci } 172513498266Sopenharmony_ci } 172613498266Sopenharmony_ci } 172713498266Sopenharmony_ci if(serverfd[i] != CURL_SOCKET_BAD) { 172813498266Sopenharmony_ci if(!poll_server_wr[i] && !poll_server_rd[i]) { 172913498266Sopenharmony_ci logmsg("[%s] CLOSING server socket", data_or_ctrl(i)); 173013498266Sopenharmony_ci sclose(serverfd[i]); 173113498266Sopenharmony_ci serverfd[i] = CURL_SOCKET_BAD; 173213498266Sopenharmony_ci if(clientfd[i] == CURL_SOCKET_BAD) { 173313498266Sopenharmony_ci logmsg("[%s] ENDING", data_or_ctrl(i)); 173413498266Sopenharmony_ci if(i == DATA) 173513498266Sopenharmony_ci secondary = FALSE; 173613498266Sopenharmony_ci else 173713498266Sopenharmony_ci primary = FALSE; 173813498266Sopenharmony_ci } 173913498266Sopenharmony_ci } 174013498266Sopenharmony_ci } 174113498266Sopenharmony_ci } 174213498266Sopenharmony_ci } 174313498266Sopenharmony_ci 174413498266Sopenharmony_ci /* ---------------------------------------------------------- */ 174513498266Sopenharmony_ci 174613498266Sopenharmony_ci max_tunnel_idx = secondary ? DATA : CTRL; 174713498266Sopenharmony_ci 174813498266Sopenharmony_ci if(!primary) 174913498266Sopenharmony_ci /* exit loop upon primary tunnel teardown */ 175013498266Sopenharmony_ci break; 175113498266Sopenharmony_ci 175213498266Sopenharmony_ci } /* (rc > 0) */ 175313498266Sopenharmony_ci else { 175413498266Sopenharmony_ci timeout_count++; 175513498266Sopenharmony_ci if(timeout_count > keepalive_secs) { 175613498266Sopenharmony_ci logmsg("CONNECT proxy timeout after %d idle seconds!", timeout_count); 175713498266Sopenharmony_ci break; 175813498266Sopenharmony_ci } 175913498266Sopenharmony_ci } 176013498266Sopenharmony_ci } 176113498266Sopenharmony_ci 176213498266Sopenharmony_cihttp_connect_cleanup: 176313498266Sopenharmony_ci 176413498266Sopenharmony_ci for(i = DATA; i >= CTRL; i--) { 176513498266Sopenharmony_ci if(serverfd[i] != CURL_SOCKET_BAD) { 176613498266Sopenharmony_ci logmsg("[%s] CLOSING server socket (cleanup)", data_or_ctrl(i)); 176713498266Sopenharmony_ci shutdown(serverfd[i], SHUT_RDWR); 176813498266Sopenharmony_ci sclose(serverfd[i]); 176913498266Sopenharmony_ci } 177013498266Sopenharmony_ci if(clientfd[i] != CURL_SOCKET_BAD) { 177113498266Sopenharmony_ci logmsg("[%s] CLOSING client socket (cleanup)", data_or_ctrl(i)); 177213498266Sopenharmony_ci shutdown(clientfd[i], SHUT_RDWR); 177313498266Sopenharmony_ci sclose(clientfd[i]); 177413498266Sopenharmony_ci } 177513498266Sopenharmony_ci if((serverfd[i] != CURL_SOCKET_BAD) || 177613498266Sopenharmony_ci (clientfd[i] != CURL_SOCKET_BAD)) { 177713498266Sopenharmony_ci logmsg("[%s] ABORTING", data_or_ctrl(i)); 177813498266Sopenharmony_ci } 177913498266Sopenharmony_ci } 178013498266Sopenharmony_ci 178113498266Sopenharmony_ci *infdp = CURL_SOCKET_BAD; 178213498266Sopenharmony_ci} 178313498266Sopenharmony_ci 178413498266Sopenharmony_cistatic void http_upgrade(struct httprequest *req) 178513498266Sopenharmony_ci{ 178613498266Sopenharmony_ci (void)req; 178713498266Sopenharmony_ci logmsg("Upgraded to ... %u", req->upgrade_request); 178813498266Sopenharmony_ci /* left to implement */ 178913498266Sopenharmony_ci} 179013498266Sopenharmony_ci 179113498266Sopenharmony_ci 179213498266Sopenharmony_ci/* returns a socket handle, or 0 if there are no more waiting sockets, 179313498266Sopenharmony_ci or < 0 if there was an error */ 179413498266Sopenharmony_cistatic curl_socket_t accept_connection(curl_socket_t sock) 179513498266Sopenharmony_ci{ 179613498266Sopenharmony_ci curl_socket_t msgsock = CURL_SOCKET_BAD; 179713498266Sopenharmony_ci int error; 179813498266Sopenharmony_ci int flag = 1; 179913498266Sopenharmony_ci 180013498266Sopenharmony_ci if(MAX_SOCKETS == num_sockets) { 180113498266Sopenharmony_ci logmsg("Too many open sockets!"); 180213498266Sopenharmony_ci return CURL_SOCKET_BAD; 180313498266Sopenharmony_ci } 180413498266Sopenharmony_ci 180513498266Sopenharmony_ci msgsock = accept(sock, NULL, NULL); 180613498266Sopenharmony_ci 180713498266Sopenharmony_ci if(got_exit_signal) { 180813498266Sopenharmony_ci if(CURL_SOCKET_BAD != msgsock) 180913498266Sopenharmony_ci sclose(msgsock); 181013498266Sopenharmony_ci return CURL_SOCKET_BAD; 181113498266Sopenharmony_ci } 181213498266Sopenharmony_ci 181313498266Sopenharmony_ci if(CURL_SOCKET_BAD == msgsock) { 181413498266Sopenharmony_ci error = SOCKERRNO; 181513498266Sopenharmony_ci if(EAGAIN == error || EWOULDBLOCK == error) { 181613498266Sopenharmony_ci /* nothing to accept */ 181713498266Sopenharmony_ci return 0; 181813498266Sopenharmony_ci } 181913498266Sopenharmony_ci logmsg("MAJOR ERROR: accept() failed with error: (%d) %s", 182013498266Sopenharmony_ci error, sstrerror(error)); 182113498266Sopenharmony_ci return CURL_SOCKET_BAD; 182213498266Sopenharmony_ci } 182313498266Sopenharmony_ci 182413498266Sopenharmony_ci if(0 != curlx_nonblock(msgsock, TRUE)) { 182513498266Sopenharmony_ci error = SOCKERRNO; 182613498266Sopenharmony_ci logmsg("curlx_nonblock failed with error: (%d) %s", 182713498266Sopenharmony_ci error, sstrerror(error)); 182813498266Sopenharmony_ci sclose(msgsock); 182913498266Sopenharmony_ci return CURL_SOCKET_BAD; 183013498266Sopenharmony_ci } 183113498266Sopenharmony_ci 183213498266Sopenharmony_ci if(0 != setsockopt(msgsock, SOL_SOCKET, SO_KEEPALIVE, 183313498266Sopenharmony_ci (void *)&flag, sizeof(flag))) { 183413498266Sopenharmony_ci error = SOCKERRNO; 183513498266Sopenharmony_ci logmsg("setsockopt(SO_KEEPALIVE) failed with error: (%d) %s", 183613498266Sopenharmony_ci error, sstrerror(error)); 183713498266Sopenharmony_ci sclose(msgsock); 183813498266Sopenharmony_ci return CURL_SOCKET_BAD; 183913498266Sopenharmony_ci } 184013498266Sopenharmony_ci 184113498266Sopenharmony_ci /* 184213498266Sopenharmony_ci ** As soon as this server accepts a connection from the test harness it 184313498266Sopenharmony_ci ** must set the server logs advisor read lock to indicate that server 184413498266Sopenharmony_ci ** logs should not be read until this lock is removed by this server. 184513498266Sopenharmony_ci */ 184613498266Sopenharmony_ci 184713498266Sopenharmony_ci if(!serverlogslocked) 184813498266Sopenharmony_ci set_advisor_read_lock(loglockfile); 184913498266Sopenharmony_ci serverlogslocked += 1; 185013498266Sopenharmony_ci 185113498266Sopenharmony_ci logmsg("====> Client connect"); 185213498266Sopenharmony_ci 185313498266Sopenharmony_ci all_sockets[num_sockets] = msgsock; 185413498266Sopenharmony_ci num_sockets += 1; 185513498266Sopenharmony_ci 185613498266Sopenharmony_ci#ifdef TCP_NODELAY 185713498266Sopenharmony_ci if(socket_domain_is_ip()) { 185813498266Sopenharmony_ci /* 185913498266Sopenharmony_ci * Disable the Nagle algorithm to make it easier to send out a large 186013498266Sopenharmony_ci * response in many small segments to torture the clients more. 186113498266Sopenharmony_ci */ 186213498266Sopenharmony_ci if(0 != setsockopt(msgsock, IPPROTO_TCP, TCP_NODELAY, 186313498266Sopenharmony_ci (void *)&flag, sizeof(flag))) 186413498266Sopenharmony_ci logmsg("====> TCP_NODELAY failed"); 186513498266Sopenharmony_ci } 186613498266Sopenharmony_ci#endif 186713498266Sopenharmony_ci 186813498266Sopenharmony_ci return msgsock; 186913498266Sopenharmony_ci} 187013498266Sopenharmony_ci 187113498266Sopenharmony_ci/* returns 1 if the connection should be serviced again immediately, 0 if there 187213498266Sopenharmony_ci is no data waiting, or < 0 if it should be closed */ 187313498266Sopenharmony_cistatic int service_connection(curl_socket_t msgsock, struct httprequest *req, 187413498266Sopenharmony_ci curl_socket_t listensock, 187513498266Sopenharmony_ci const char *connecthost, 187613498266Sopenharmony_ci int keepalive_secs) 187713498266Sopenharmony_ci{ 187813498266Sopenharmony_ci if(got_exit_signal) 187913498266Sopenharmony_ci return -1; 188013498266Sopenharmony_ci 188113498266Sopenharmony_ci while(!req->done_processing) { 188213498266Sopenharmony_ci int rc = get_request(msgsock, req); 188313498266Sopenharmony_ci if(rc <= 0) { 188413498266Sopenharmony_ci /* Nothing further to read now, possibly because the socket was closed */ 188513498266Sopenharmony_ci return rc; 188613498266Sopenharmony_ci } 188713498266Sopenharmony_ci } 188813498266Sopenharmony_ci 188913498266Sopenharmony_ci if(prevbounce) { 189013498266Sopenharmony_ci /* bounce treatment requested */ 189113498266Sopenharmony_ci if((req->testno == prevtestno) && 189213498266Sopenharmony_ci (req->partno == prevpartno)) { 189313498266Sopenharmony_ci req->partno++; 189413498266Sopenharmony_ci logmsg("BOUNCE part number to %ld", req->partno); 189513498266Sopenharmony_ci } 189613498266Sopenharmony_ci else { 189713498266Sopenharmony_ci prevbounce = FALSE; 189813498266Sopenharmony_ci prevtestno = -1; 189913498266Sopenharmony_ci prevpartno = -1; 190013498266Sopenharmony_ci } 190113498266Sopenharmony_ci } 190213498266Sopenharmony_ci 190313498266Sopenharmony_ci send_doc(msgsock, req); 190413498266Sopenharmony_ci if(got_exit_signal) 190513498266Sopenharmony_ci return -1; 190613498266Sopenharmony_ci 190713498266Sopenharmony_ci if(req->testno < 0) { 190813498266Sopenharmony_ci logmsg("special request received, no persistency"); 190913498266Sopenharmony_ci return -1; 191013498266Sopenharmony_ci } 191113498266Sopenharmony_ci if(!req->open) { 191213498266Sopenharmony_ci logmsg("instructed to close connection after server-reply"); 191313498266Sopenharmony_ci return -1; 191413498266Sopenharmony_ci } 191513498266Sopenharmony_ci 191613498266Sopenharmony_ci if(req->connect_request) { 191713498266Sopenharmony_ci /* a CONNECT request, setup and talk the tunnel */ 191813498266Sopenharmony_ci if(!is_proxy) { 191913498266Sopenharmony_ci logmsg("received CONNECT but isn't running as proxy!"); 192013498266Sopenharmony_ci return 1; 192113498266Sopenharmony_ci } 192213498266Sopenharmony_ci else { 192313498266Sopenharmony_ci http_connect(&msgsock, listensock, connecthost, req->connect_port, 192413498266Sopenharmony_ci keepalive_secs); 192513498266Sopenharmony_ci return -1; 192613498266Sopenharmony_ci } 192713498266Sopenharmony_ci } 192813498266Sopenharmony_ci 192913498266Sopenharmony_ci if(req->upgrade_request) { 193013498266Sopenharmony_ci /* an upgrade request, switch to another protocol here */ 193113498266Sopenharmony_ci http_upgrade(req); 193213498266Sopenharmony_ci return 1; 193313498266Sopenharmony_ci } 193413498266Sopenharmony_ci 193513498266Sopenharmony_ci /* if we got a CONNECT, loop and get another request as well! */ 193613498266Sopenharmony_ci 193713498266Sopenharmony_ci if(req->open) { 193813498266Sopenharmony_ci logmsg("=> persistent connection request ended, awaits new request\n"); 193913498266Sopenharmony_ci return 1; 194013498266Sopenharmony_ci } 194113498266Sopenharmony_ci else { 194213498266Sopenharmony_ci logmsg("=> NOT a persistent connection, close close CLOSE\n"); 194313498266Sopenharmony_ci } 194413498266Sopenharmony_ci 194513498266Sopenharmony_ci return -1; 194613498266Sopenharmony_ci} 194713498266Sopenharmony_ci 194813498266Sopenharmony_ciint main(int argc, char *argv[]) 194913498266Sopenharmony_ci{ 195013498266Sopenharmony_ci srvr_sockaddr_union_t me; 195113498266Sopenharmony_ci curl_socket_t sock = CURL_SOCKET_BAD; 195213498266Sopenharmony_ci int wrotepidfile = 0; 195313498266Sopenharmony_ci int wroteportfile = 0; 195413498266Sopenharmony_ci int flag; 195513498266Sopenharmony_ci unsigned short port = DEFAULT_PORT; 195613498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS 195713498266Sopenharmony_ci const char *unix_socket = NULL; 195813498266Sopenharmony_ci bool unlink_socket = false; 195913498266Sopenharmony_ci#endif 196013498266Sopenharmony_ci const char *pidname = ".http.pid"; 196113498266Sopenharmony_ci const char *portname = ".http.port"; 196213498266Sopenharmony_ci struct httprequest *req = NULL; 196313498266Sopenharmony_ci int rc = 0; 196413498266Sopenharmony_ci int error; 196513498266Sopenharmony_ci int arg = 1; 196613498266Sopenharmony_ci const char *connecthost = "127.0.0.1"; 196713498266Sopenharmony_ci const char *socket_type = "IPv4"; 196813498266Sopenharmony_ci char port_str[11]; 196913498266Sopenharmony_ci const char *location_str = port_str; 197013498266Sopenharmony_ci int keepalive_secs = 5; 197113498266Sopenharmony_ci const char *protocol_type = "HTTP"; 197213498266Sopenharmony_ci 197313498266Sopenharmony_ci /* a default CONNECT port is basically pointless but still ... */ 197413498266Sopenharmony_ci size_t socket_idx; 197513498266Sopenharmony_ci 197613498266Sopenharmony_ci while(argc>arg) { 197713498266Sopenharmony_ci if(!strcmp("--version", argv[arg])) { 197813498266Sopenharmony_ci puts("sws IPv4" 197913498266Sopenharmony_ci#ifdef ENABLE_IPV6 198013498266Sopenharmony_ci "/IPv6" 198113498266Sopenharmony_ci#endif 198213498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS 198313498266Sopenharmony_ci "/unix" 198413498266Sopenharmony_ci#endif 198513498266Sopenharmony_ci ); 198613498266Sopenharmony_ci return 0; 198713498266Sopenharmony_ci } 198813498266Sopenharmony_ci else if(!strcmp("--pidfile", argv[arg])) { 198913498266Sopenharmony_ci arg++; 199013498266Sopenharmony_ci if(argc>arg) 199113498266Sopenharmony_ci pidname = argv[arg++]; 199213498266Sopenharmony_ci } 199313498266Sopenharmony_ci else if(!strcmp("--portfile", argv[arg])) { 199413498266Sopenharmony_ci arg++; 199513498266Sopenharmony_ci if(argc>arg) 199613498266Sopenharmony_ci portname = argv[arg++]; 199713498266Sopenharmony_ci } 199813498266Sopenharmony_ci else if(!strcmp("--logfile", argv[arg])) { 199913498266Sopenharmony_ci arg++; 200013498266Sopenharmony_ci if(argc>arg) 200113498266Sopenharmony_ci serverlogfile = argv[arg++]; 200213498266Sopenharmony_ci } 200313498266Sopenharmony_ci else if(!strcmp("--logdir", argv[arg])) { 200413498266Sopenharmony_ci arg++; 200513498266Sopenharmony_ci if(argc>arg) 200613498266Sopenharmony_ci logdir = argv[arg++]; 200713498266Sopenharmony_ci } 200813498266Sopenharmony_ci else if(!strcmp("--cmdfile", argv[arg])) { 200913498266Sopenharmony_ci arg++; 201013498266Sopenharmony_ci if(argc>arg) 201113498266Sopenharmony_ci cmdfile = argv[arg++]; 201213498266Sopenharmony_ci } 201313498266Sopenharmony_ci else if(!strcmp("--gopher", argv[arg])) { 201413498266Sopenharmony_ci arg++; 201513498266Sopenharmony_ci use_gopher = TRUE; 201613498266Sopenharmony_ci protocol_type = "GOPHER"; 201713498266Sopenharmony_ci end_of_headers = "\r\n"; /* gopher style is much simpler */ 201813498266Sopenharmony_ci } 201913498266Sopenharmony_ci else if(!strcmp("--ipv4", argv[arg])) { 202013498266Sopenharmony_ci socket_type = "IPv4"; 202113498266Sopenharmony_ci socket_domain = AF_INET; 202213498266Sopenharmony_ci location_str = port_str; 202313498266Sopenharmony_ci arg++; 202413498266Sopenharmony_ci } 202513498266Sopenharmony_ci else if(!strcmp("--ipv6", argv[arg])) { 202613498266Sopenharmony_ci#ifdef ENABLE_IPV6 202713498266Sopenharmony_ci socket_type = "IPv6"; 202813498266Sopenharmony_ci socket_domain = AF_INET6; 202913498266Sopenharmony_ci location_str = port_str; 203013498266Sopenharmony_ci#endif 203113498266Sopenharmony_ci arg++; 203213498266Sopenharmony_ci } 203313498266Sopenharmony_ci else if(!strcmp("--unix-socket", argv[arg])) { 203413498266Sopenharmony_ci arg++; 203513498266Sopenharmony_ci if(argc>arg) { 203613498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS 203713498266Sopenharmony_ci unix_socket = argv[arg]; 203813498266Sopenharmony_ci if(strlen(unix_socket) >= sizeof(me.sau.sun_path)) { 203913498266Sopenharmony_ci fprintf(stderr, 204013498266Sopenharmony_ci "sws: socket path must be shorter than %zu chars: %s\n", 204113498266Sopenharmony_ci sizeof(me.sau.sun_path), unix_socket); 204213498266Sopenharmony_ci return 0; 204313498266Sopenharmony_ci } 204413498266Sopenharmony_ci socket_type = "unix"; 204513498266Sopenharmony_ci socket_domain = AF_UNIX; 204613498266Sopenharmony_ci location_str = unix_socket; 204713498266Sopenharmony_ci#endif 204813498266Sopenharmony_ci arg++; 204913498266Sopenharmony_ci } 205013498266Sopenharmony_ci } 205113498266Sopenharmony_ci else if(!strcmp("--port", argv[arg])) { 205213498266Sopenharmony_ci arg++; 205313498266Sopenharmony_ci if(argc>arg) { 205413498266Sopenharmony_ci char *endptr; 205513498266Sopenharmony_ci unsigned long ulnum = strtoul(argv[arg], &endptr, 10); 205613498266Sopenharmony_ci if((endptr != argv[arg] + strlen(argv[arg])) || 205713498266Sopenharmony_ci (ulnum && ((ulnum < 1025UL) || (ulnum > 65535UL)))) { 205813498266Sopenharmony_ci fprintf(stderr, "sws: invalid --port argument (%s)\n", 205913498266Sopenharmony_ci argv[arg]); 206013498266Sopenharmony_ci return 0; 206113498266Sopenharmony_ci } 206213498266Sopenharmony_ci port = curlx_ultous(ulnum); 206313498266Sopenharmony_ci arg++; 206413498266Sopenharmony_ci } 206513498266Sopenharmony_ci } 206613498266Sopenharmony_ci else if(!strcmp("--srcdir", argv[arg])) { 206713498266Sopenharmony_ci arg++; 206813498266Sopenharmony_ci if(argc>arg) { 206913498266Sopenharmony_ci path = argv[arg]; 207013498266Sopenharmony_ci arg++; 207113498266Sopenharmony_ci } 207213498266Sopenharmony_ci } 207313498266Sopenharmony_ci else if(!strcmp("--keepalive", argv[arg])) { 207413498266Sopenharmony_ci arg++; 207513498266Sopenharmony_ci if(argc>arg) { 207613498266Sopenharmony_ci char *endptr; 207713498266Sopenharmony_ci unsigned long ulnum = strtoul(argv[arg], &endptr, 10); 207813498266Sopenharmony_ci if((endptr != argv[arg] + strlen(argv[arg])) || 207913498266Sopenharmony_ci (ulnum && (ulnum > 65535UL))) { 208013498266Sopenharmony_ci fprintf(stderr, "sws: invalid --keepalive argument (%s), must " 208113498266Sopenharmony_ci "be number of seconds\n", argv[arg]); 208213498266Sopenharmony_ci return 0; 208313498266Sopenharmony_ci } 208413498266Sopenharmony_ci keepalive_secs = curlx_ultous(ulnum); 208513498266Sopenharmony_ci arg++; 208613498266Sopenharmony_ci } 208713498266Sopenharmony_ci } 208813498266Sopenharmony_ci else if(!strcmp("--connect", argv[arg])) { 208913498266Sopenharmony_ci /* The connect host IP number that the proxy will connect to no matter 209013498266Sopenharmony_ci what the client asks for, but also use this as a hint that we run as 209113498266Sopenharmony_ci a proxy and do a few different internal choices */ 209213498266Sopenharmony_ci arg++; 209313498266Sopenharmony_ci if(argc>arg) { 209413498266Sopenharmony_ci connecthost = argv[arg]; 209513498266Sopenharmony_ci arg++; 209613498266Sopenharmony_ci is_proxy = TRUE; 209713498266Sopenharmony_ci logmsg("Run as proxy, CONNECT to host %s", connecthost); 209813498266Sopenharmony_ci } 209913498266Sopenharmony_ci } 210013498266Sopenharmony_ci else { 210113498266Sopenharmony_ci puts("Usage: sws [option]\n" 210213498266Sopenharmony_ci " --version\n" 210313498266Sopenharmony_ci " --logfile [file]\n" 210413498266Sopenharmony_ci " --logdir [directory]\n" 210513498266Sopenharmony_ci " --pidfile [file]\n" 210613498266Sopenharmony_ci " --portfile [file]\n" 210713498266Sopenharmony_ci " --ipv4\n" 210813498266Sopenharmony_ci " --ipv6\n" 210913498266Sopenharmony_ci " --unix-socket [file]\n" 211013498266Sopenharmony_ci " --port [port]\n" 211113498266Sopenharmony_ci " --srcdir [path]\n" 211213498266Sopenharmony_ci " --connect [ip4-addr]\n" 211313498266Sopenharmony_ci " --gopher"); 211413498266Sopenharmony_ci return 0; 211513498266Sopenharmony_ci } 211613498266Sopenharmony_ci } 211713498266Sopenharmony_ci 211813498266Sopenharmony_ci msnprintf(loglockfile, sizeof(loglockfile), "%s/%s/sws-%s%s-%s.lock", 211913498266Sopenharmony_ci logdir, SERVERLOGS_LOCKDIR, protocol_type, 212013498266Sopenharmony_ci is_proxy ? "-proxy" : "", socket_type); 212113498266Sopenharmony_ci 212213498266Sopenharmony_ci#ifdef _WIN32 212313498266Sopenharmony_ci win32_init(); 212413498266Sopenharmony_ci atexit(win32_cleanup); 212513498266Sopenharmony_ci#endif 212613498266Sopenharmony_ci 212713498266Sopenharmony_ci install_signal_handlers(false); 212813498266Sopenharmony_ci 212913498266Sopenharmony_ci req = calloc(1, sizeof(*req)); 213013498266Sopenharmony_ci if(!req) 213113498266Sopenharmony_ci goto sws_cleanup; 213213498266Sopenharmony_ci 213313498266Sopenharmony_ci sock = socket(socket_domain, SOCK_STREAM, 0); 213413498266Sopenharmony_ci 213513498266Sopenharmony_ci all_sockets[0] = sock; 213613498266Sopenharmony_ci num_sockets = 1; 213713498266Sopenharmony_ci 213813498266Sopenharmony_ci if(CURL_SOCKET_BAD == sock) { 213913498266Sopenharmony_ci error = SOCKERRNO; 214013498266Sopenharmony_ci logmsg("Error creating socket: (%d) %s", error, sstrerror(error)); 214113498266Sopenharmony_ci goto sws_cleanup; 214213498266Sopenharmony_ci } 214313498266Sopenharmony_ci 214413498266Sopenharmony_ci flag = 1; 214513498266Sopenharmony_ci if(0 != setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 214613498266Sopenharmony_ci (void *)&flag, sizeof(flag))) { 214713498266Sopenharmony_ci error = SOCKERRNO; 214813498266Sopenharmony_ci logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s", 214913498266Sopenharmony_ci error, sstrerror(error)); 215013498266Sopenharmony_ci goto sws_cleanup; 215113498266Sopenharmony_ci } 215213498266Sopenharmony_ci if(0 != curlx_nonblock(sock, TRUE)) { 215313498266Sopenharmony_ci error = SOCKERRNO; 215413498266Sopenharmony_ci logmsg("curlx_nonblock failed with error: (%d) %s", 215513498266Sopenharmony_ci error, sstrerror(error)); 215613498266Sopenharmony_ci goto sws_cleanup; 215713498266Sopenharmony_ci } 215813498266Sopenharmony_ci 215913498266Sopenharmony_ci switch(socket_domain) { 216013498266Sopenharmony_ci case AF_INET: 216113498266Sopenharmony_ci memset(&me.sa4, 0, sizeof(me.sa4)); 216213498266Sopenharmony_ci me.sa4.sin_family = AF_INET; 216313498266Sopenharmony_ci me.sa4.sin_addr.s_addr = INADDR_ANY; 216413498266Sopenharmony_ci me.sa4.sin_port = htons(port); 216513498266Sopenharmony_ci rc = bind(sock, &me.sa, sizeof(me.sa4)); 216613498266Sopenharmony_ci break; 216713498266Sopenharmony_ci#ifdef ENABLE_IPV6 216813498266Sopenharmony_ci case AF_INET6: 216913498266Sopenharmony_ci memset(&me.sa6, 0, sizeof(me.sa6)); 217013498266Sopenharmony_ci me.sa6.sin6_family = AF_INET6; 217113498266Sopenharmony_ci me.sa6.sin6_addr = in6addr_any; 217213498266Sopenharmony_ci me.sa6.sin6_port = htons(port); 217313498266Sopenharmony_ci rc = bind(sock, &me.sa, sizeof(me.sa6)); 217413498266Sopenharmony_ci break; 217513498266Sopenharmony_ci#endif /* ENABLE_IPV6 */ 217613498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS 217713498266Sopenharmony_ci case AF_UNIX: 217813498266Sopenharmony_ci rc = bind_unix_socket(sock, unix_socket, &me.sau); 217913498266Sopenharmony_ci#endif /* USE_UNIX_SOCKETS */ 218013498266Sopenharmony_ci } 218113498266Sopenharmony_ci if(0 != rc) { 218213498266Sopenharmony_ci error = SOCKERRNO; 218313498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS 218413498266Sopenharmony_ci if(socket_domain == AF_UNIX) 218513498266Sopenharmony_ci logmsg("Error binding socket on path %s: (%d) %s", 218613498266Sopenharmony_ci unix_socket, error, sstrerror(error)); 218713498266Sopenharmony_ci else 218813498266Sopenharmony_ci#endif 218913498266Sopenharmony_ci logmsg("Error binding socket on port %hu: (%d) %s", 219013498266Sopenharmony_ci port, error, sstrerror(error)); 219113498266Sopenharmony_ci goto sws_cleanup; 219213498266Sopenharmony_ci } 219313498266Sopenharmony_ci 219413498266Sopenharmony_ci if(!port) { 219513498266Sopenharmony_ci /* The system was supposed to choose a port number, figure out which 219613498266Sopenharmony_ci port we actually got and update the listener port value with it. */ 219713498266Sopenharmony_ci curl_socklen_t la_size; 219813498266Sopenharmony_ci srvr_sockaddr_union_t localaddr; 219913498266Sopenharmony_ci#ifdef ENABLE_IPV6 220013498266Sopenharmony_ci if(socket_domain != AF_INET6) 220113498266Sopenharmony_ci#endif 220213498266Sopenharmony_ci la_size = sizeof(localaddr.sa4); 220313498266Sopenharmony_ci#ifdef ENABLE_IPV6 220413498266Sopenharmony_ci else 220513498266Sopenharmony_ci la_size = sizeof(localaddr.sa6); 220613498266Sopenharmony_ci#endif 220713498266Sopenharmony_ci memset(&localaddr.sa, 0, (size_t)la_size); 220813498266Sopenharmony_ci if(getsockname(sock, &localaddr.sa, &la_size) < 0) { 220913498266Sopenharmony_ci error = SOCKERRNO; 221013498266Sopenharmony_ci logmsg("getsockname() failed with error: (%d) %s", 221113498266Sopenharmony_ci error, sstrerror(error)); 221213498266Sopenharmony_ci sclose(sock); 221313498266Sopenharmony_ci goto sws_cleanup; 221413498266Sopenharmony_ci } 221513498266Sopenharmony_ci switch(localaddr.sa.sa_family) { 221613498266Sopenharmony_ci case AF_INET: 221713498266Sopenharmony_ci port = ntohs(localaddr.sa4.sin_port); 221813498266Sopenharmony_ci break; 221913498266Sopenharmony_ci#ifdef ENABLE_IPV6 222013498266Sopenharmony_ci case AF_INET6: 222113498266Sopenharmony_ci port = ntohs(localaddr.sa6.sin6_port); 222213498266Sopenharmony_ci break; 222313498266Sopenharmony_ci#endif 222413498266Sopenharmony_ci default: 222513498266Sopenharmony_ci break; 222613498266Sopenharmony_ci } 222713498266Sopenharmony_ci if(!port) { 222813498266Sopenharmony_ci /* Real failure, listener port shall not be zero beyond this point. */ 222913498266Sopenharmony_ci logmsg("Apparently getsockname() succeeded, with listener port zero."); 223013498266Sopenharmony_ci logmsg("A valid reason for this failure is a binary built without"); 223113498266Sopenharmony_ci logmsg("proper network library linkage. This might not be the only"); 223213498266Sopenharmony_ci logmsg("reason, but double check it before anything else."); 223313498266Sopenharmony_ci sclose(sock); 223413498266Sopenharmony_ci goto sws_cleanup; 223513498266Sopenharmony_ci } 223613498266Sopenharmony_ci } 223713498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS 223813498266Sopenharmony_ci if(socket_domain != AF_UNIX) 223913498266Sopenharmony_ci#endif 224013498266Sopenharmony_ci msnprintf(port_str, sizeof(port_str), "port %hu", port); 224113498266Sopenharmony_ci 224213498266Sopenharmony_ci logmsg("Running %s %s version on %s", 224313498266Sopenharmony_ci protocol_type, socket_type, location_str); 224413498266Sopenharmony_ci 224513498266Sopenharmony_ci /* start accepting connections */ 224613498266Sopenharmony_ci rc = listen(sock, 5); 224713498266Sopenharmony_ci if(0 != rc) { 224813498266Sopenharmony_ci error = SOCKERRNO; 224913498266Sopenharmony_ci logmsg("listen() failed with error: (%d) %s", error, sstrerror(error)); 225013498266Sopenharmony_ci goto sws_cleanup; 225113498266Sopenharmony_ci } 225213498266Sopenharmony_ci 225313498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS 225413498266Sopenharmony_ci /* listen succeeds, so let's assume a valid listening Unix socket */ 225513498266Sopenharmony_ci unlink_socket = true; 225613498266Sopenharmony_ci#endif 225713498266Sopenharmony_ci 225813498266Sopenharmony_ci /* 225913498266Sopenharmony_ci ** As soon as this server writes its pid file the test harness will 226013498266Sopenharmony_ci ** attempt to connect to this server and initiate its verification. 226113498266Sopenharmony_ci */ 226213498266Sopenharmony_ci 226313498266Sopenharmony_ci wrotepidfile = write_pidfile(pidname); 226413498266Sopenharmony_ci if(!wrotepidfile) 226513498266Sopenharmony_ci goto sws_cleanup; 226613498266Sopenharmony_ci 226713498266Sopenharmony_ci wroteportfile = write_portfile(portname, port); 226813498266Sopenharmony_ci if(!wroteportfile) 226913498266Sopenharmony_ci goto sws_cleanup; 227013498266Sopenharmony_ci 227113498266Sopenharmony_ci /* initialization of httprequest struct is done before get_request(), but 227213498266Sopenharmony_ci the pipelining struct field must be initialized previously to FALSE 227313498266Sopenharmony_ci every time a new connection arrives. */ 227413498266Sopenharmony_ci 227513498266Sopenharmony_ci init_httprequest(req); 227613498266Sopenharmony_ci 227713498266Sopenharmony_ci for(;;) { 227813498266Sopenharmony_ci fd_set input; 227913498266Sopenharmony_ci fd_set output; 228013498266Sopenharmony_ci struct timeval timeout = {0, 250000L}; /* 250 ms */ 228113498266Sopenharmony_ci curl_socket_t maxfd = (curl_socket_t)-1; 228213498266Sopenharmony_ci int active; 228313498266Sopenharmony_ci 228413498266Sopenharmony_ci /* Clear out closed sockets */ 228513498266Sopenharmony_ci for(socket_idx = num_sockets - 1; socket_idx >= 1; --socket_idx) { 228613498266Sopenharmony_ci if(CURL_SOCKET_BAD == all_sockets[socket_idx]) { 228713498266Sopenharmony_ci char *dst = (char *) (all_sockets + socket_idx); 228813498266Sopenharmony_ci char *src = (char *) (all_sockets + socket_idx + 1); 228913498266Sopenharmony_ci char *end = (char *) (all_sockets + num_sockets); 229013498266Sopenharmony_ci memmove(dst, src, end - src); 229113498266Sopenharmony_ci num_sockets -= 1; 229213498266Sopenharmony_ci } 229313498266Sopenharmony_ci } 229413498266Sopenharmony_ci 229513498266Sopenharmony_ci if(got_exit_signal) 229613498266Sopenharmony_ci goto sws_cleanup; 229713498266Sopenharmony_ci 229813498266Sopenharmony_ci /* Set up for select */ 229913498266Sopenharmony_ci FD_ZERO(&input); 230013498266Sopenharmony_ci FD_ZERO(&output); 230113498266Sopenharmony_ci 230213498266Sopenharmony_ci for(socket_idx = 0; socket_idx < num_sockets; ++socket_idx) { 230313498266Sopenharmony_ci /* Listen on all sockets */ 230413498266Sopenharmony_ci FD_SET(all_sockets[socket_idx], &input); 230513498266Sopenharmony_ci if(all_sockets[socket_idx] > maxfd) 230613498266Sopenharmony_ci maxfd = all_sockets[socket_idx]; 230713498266Sopenharmony_ci } 230813498266Sopenharmony_ci 230913498266Sopenharmony_ci if(got_exit_signal) 231013498266Sopenharmony_ci goto sws_cleanup; 231113498266Sopenharmony_ci 231213498266Sopenharmony_ci do { 231313498266Sopenharmony_ci rc = select((int)maxfd + 1, &input, &output, NULL, &timeout); 231413498266Sopenharmony_ci } while(rc < 0 && errno == EINTR && !got_exit_signal); 231513498266Sopenharmony_ci 231613498266Sopenharmony_ci if(got_exit_signal) 231713498266Sopenharmony_ci goto sws_cleanup; 231813498266Sopenharmony_ci 231913498266Sopenharmony_ci if(rc < 0) { 232013498266Sopenharmony_ci error = SOCKERRNO; 232113498266Sopenharmony_ci logmsg("select() failed with error: (%d) %s", error, sstrerror(error)); 232213498266Sopenharmony_ci goto sws_cleanup; 232313498266Sopenharmony_ci } 232413498266Sopenharmony_ci 232513498266Sopenharmony_ci if(rc == 0) { 232613498266Sopenharmony_ci /* Timed out - try again */ 232713498266Sopenharmony_ci continue; 232813498266Sopenharmony_ci } 232913498266Sopenharmony_ci active = rc; /* a positive number */ 233013498266Sopenharmony_ci 233113498266Sopenharmony_ci /* Check if the listening socket is ready to accept */ 233213498266Sopenharmony_ci if(FD_ISSET(all_sockets[0], &input)) { 233313498266Sopenharmony_ci /* Service all queued connections */ 233413498266Sopenharmony_ci curl_socket_t msgsock; 233513498266Sopenharmony_ci do { 233613498266Sopenharmony_ci msgsock = accept_connection(sock); 233713498266Sopenharmony_ci logmsg("accept_connection %" CURL_FORMAT_SOCKET_T 233813498266Sopenharmony_ci " returned %" CURL_FORMAT_SOCKET_T, sock, msgsock); 233913498266Sopenharmony_ci if(CURL_SOCKET_BAD == msgsock) 234013498266Sopenharmony_ci goto sws_cleanup; 234113498266Sopenharmony_ci if(req->delay) 234213498266Sopenharmony_ci wait_ms(req->delay); 234313498266Sopenharmony_ci } while(msgsock > 0); 234413498266Sopenharmony_ci active--; 234513498266Sopenharmony_ci } 234613498266Sopenharmony_ci 234713498266Sopenharmony_ci /* Service all connections that are ready */ 234813498266Sopenharmony_ci for(socket_idx = 1; (socket_idx < num_sockets) && active; ++socket_idx) { 234913498266Sopenharmony_ci if(FD_ISSET(all_sockets[socket_idx], &input)) { 235013498266Sopenharmony_ci active--; 235113498266Sopenharmony_ci if(got_exit_signal) 235213498266Sopenharmony_ci goto sws_cleanup; 235313498266Sopenharmony_ci 235413498266Sopenharmony_ci /* Service this connection until it has nothing available */ 235513498266Sopenharmony_ci do { 235613498266Sopenharmony_ci rc = service_connection(all_sockets[socket_idx], req, sock, 235713498266Sopenharmony_ci connecthost, keepalive_secs); 235813498266Sopenharmony_ci if(got_exit_signal) 235913498266Sopenharmony_ci goto sws_cleanup; 236013498266Sopenharmony_ci 236113498266Sopenharmony_ci if(rc < 0) { 236213498266Sopenharmony_ci logmsg("====> Client disconnect %d", req->connmon); 236313498266Sopenharmony_ci 236413498266Sopenharmony_ci if(req->connmon) { 236513498266Sopenharmony_ci const char *keepopen = "[DISCONNECT]\n"; 236613498266Sopenharmony_ci storerequest(keepopen, strlen(keepopen)); 236713498266Sopenharmony_ci } 236813498266Sopenharmony_ci 236913498266Sopenharmony_ci if(!req->open) 237013498266Sopenharmony_ci /* When instructed to close connection after server-reply we 237113498266Sopenharmony_ci wait a very small amount of time before doing so. If this 237213498266Sopenharmony_ci is not done client might get an ECONNRESET before reading 237313498266Sopenharmony_ci a single byte of server-reply. */ 237413498266Sopenharmony_ci wait_ms(50); 237513498266Sopenharmony_ci 237613498266Sopenharmony_ci if(all_sockets[socket_idx] != CURL_SOCKET_BAD) { 237713498266Sopenharmony_ci sclose(all_sockets[socket_idx]); 237813498266Sopenharmony_ci all_sockets[socket_idx] = CURL_SOCKET_BAD; 237913498266Sopenharmony_ci } 238013498266Sopenharmony_ci 238113498266Sopenharmony_ci serverlogslocked -= 1; 238213498266Sopenharmony_ci if(!serverlogslocked) 238313498266Sopenharmony_ci clear_advisor_read_lock(loglockfile); 238413498266Sopenharmony_ci 238513498266Sopenharmony_ci if(req->testno == DOCNUMBER_QUIT) 238613498266Sopenharmony_ci goto sws_cleanup; 238713498266Sopenharmony_ci } 238813498266Sopenharmony_ci 238913498266Sopenharmony_ci /* Reset the request, unless we're still in the middle of reading */ 239013498266Sopenharmony_ci if(rc && !req->upgrade_request) 239113498266Sopenharmony_ci /* Note: resetting the HTTP request here can cause problems if: 239213498266Sopenharmony_ci * 1) req->skipall is TRUE, 239313498266Sopenharmony_ci * 2) the socket is still open, and 239413498266Sopenharmony_ci * 3) (stale) data is still available (or about to be available) 239513498266Sopenharmony_ci * on that socket 239613498266Sopenharmony_ci * In that case, this loop will run once more and treat that stale 239713498266Sopenharmony_ci * data (in service_connection()) as the first data received on 239813498266Sopenharmony_ci * this new HTTP request and report "** Unusual request" (skipall 239913498266Sopenharmony_ci * would have otherwise caused that data to be ignored). Normally, 240013498266Sopenharmony_ci * that socket will be closed by the client and there won't be any 240113498266Sopenharmony_ci * stale data to cause this, but stranger things have happened (see 240213498266Sopenharmony_ci * issue #11678). 240313498266Sopenharmony_ci */ 240413498266Sopenharmony_ci init_httprequest(req); 240513498266Sopenharmony_ci } while(rc > 0); 240613498266Sopenharmony_ci } 240713498266Sopenharmony_ci } 240813498266Sopenharmony_ci 240913498266Sopenharmony_ci if(got_exit_signal) 241013498266Sopenharmony_ci goto sws_cleanup; 241113498266Sopenharmony_ci } 241213498266Sopenharmony_ci 241313498266Sopenharmony_cisws_cleanup: 241413498266Sopenharmony_ci 241513498266Sopenharmony_ci for(socket_idx = 1; socket_idx < num_sockets; ++socket_idx) 241613498266Sopenharmony_ci if((all_sockets[socket_idx] != sock) && 241713498266Sopenharmony_ci (all_sockets[socket_idx] != CURL_SOCKET_BAD)) 241813498266Sopenharmony_ci sclose(all_sockets[socket_idx]); 241913498266Sopenharmony_ci 242013498266Sopenharmony_ci if(sock != CURL_SOCKET_BAD) 242113498266Sopenharmony_ci sclose(sock); 242213498266Sopenharmony_ci 242313498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS 242413498266Sopenharmony_ci if(unlink_socket && socket_domain == AF_UNIX) { 242513498266Sopenharmony_ci rc = unlink(unix_socket); 242613498266Sopenharmony_ci logmsg("unlink(%s) = %d (%s)", unix_socket, rc, strerror(rc)); 242713498266Sopenharmony_ci } 242813498266Sopenharmony_ci#endif 242913498266Sopenharmony_ci 243013498266Sopenharmony_ci free(req); 243113498266Sopenharmony_ci 243213498266Sopenharmony_ci if(got_exit_signal) 243313498266Sopenharmony_ci logmsg("signalled to die"); 243413498266Sopenharmony_ci 243513498266Sopenharmony_ci if(wrotepidfile) 243613498266Sopenharmony_ci unlink(pidname); 243713498266Sopenharmony_ci if(wroteportfile) 243813498266Sopenharmony_ci unlink(portname); 243913498266Sopenharmony_ci 244013498266Sopenharmony_ci if(serverlogslocked) { 244113498266Sopenharmony_ci serverlogslocked = 0; 244213498266Sopenharmony_ci clear_advisor_read_lock(loglockfile); 244313498266Sopenharmony_ci } 244413498266Sopenharmony_ci 244513498266Sopenharmony_ci restore_signal_handlers(false); 244613498266Sopenharmony_ci 244713498266Sopenharmony_ci if(got_exit_signal) { 244813498266Sopenharmony_ci logmsg("========> %s sws (%s pid: %ld) exits with signal (%d)", 244913498266Sopenharmony_ci socket_type, location_str, (long)getpid(), exit_signal); 245013498266Sopenharmony_ci /* 245113498266Sopenharmony_ci * To properly set the return status of the process we 245213498266Sopenharmony_ci * must raise the same signal SIGINT or SIGTERM that we 245313498266Sopenharmony_ci * caught and let the old handler take care of it. 245413498266Sopenharmony_ci */ 245513498266Sopenharmony_ci raise(exit_signal); 245613498266Sopenharmony_ci } 245713498266Sopenharmony_ci 245813498266Sopenharmony_ci logmsg("========> sws quits"); 245913498266Sopenharmony_ci return 0; 246013498266Sopenharmony_ci} 2461