34 #ifdef HAVE_NETINET_IN_H 35 #include <netinet/in.h> 37 #ifdef HAVE_ARPA_INET_H 38 #include <arpa/inet.h> 43 #ifdef HAVE_NETINET_TCP_H 44 #include <netinet/tcp.h> 47 #define ENABLE_CURLX_PRINTF 71 , socket_domain_inet6 = AF_INET6
73 #ifdef USE_UNIX_SOCKETS 74 , socket_domain_unix = AF_UNIX
81 #define REQBUFSIZ 150000 82 #define REQBUFSIZ_TXT "149999" 90 #define RCMD_NORMALREQ 0 127 #define MAX_SOCKETS 1024 135 #define DEFAULT_PORT 8999 137 #ifndef DEFAULT_LOGFILE 138 #define DEFAULT_LOGFILE "log/sws.log" 143 #define SWSVERSION "curl test suite HTTP server/0.1" 145 #define REQUEST_DUMP "log/server.input" 146 #define RESPONSE_DUMP "log/server.response" 150 #define REQUEST_PROXY_DUMP "log/proxy.input" 151 #define RESPONSE_PROXY_DUMP "log/proxy.response" 154 #define MAXDOCNAMELEN 140000 155 #define MAXDOCNAMELEN_TXT "139999" 157 #define REQUEST_KEYWORD_SIZE 256 158 #define REQUEST_KEYWORD_SIZE_TXT "255" 160 #define CMD_AUTH_REQUIRED "auth_required" 164 #define CMD_IDLE "idle" 167 #define CMD_STREAM "stream" 172 #define CMD_CONNECTIONMONITOR "connection-monitor" 175 #define CMD_UPGRADE "upgrade" 177 #define END_OF_HEADERS "\r\n\r\n" 193 static const char *
doc404 =
"HTTP/1.1 404 Not Found\r\n" 195 "Connection: close\r\n" 196 "Content-Type: text/html" 198 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" 200 "<TITLE>404 Not Found</TITLE>\n" 202 "<H1>Not Found</H1>\n" 203 "The requested URL was not found on this server.\n" 204 "<P><HR><ADDRESS>" SWSVERSION "</ADDRESS>\n" "</BODY></HTML>\n";
208 #ifndef HAVE_SIGINTERRUPT 209 #define siginterrupt(x,y) do {} while(0) 236 #if defined(SIGBREAK) && defined(WIN32) 255 int old_errno = errno;
268 old_sighup_handler = signal(SIGHUP, SIG_IGN);
269 if(old_sighup_handler == SIG_ERR)
270 logmsg(
"cannot install SIGHUP handler: %s", strerror(errno));
274 old_sigpipe_handler = signal(SIGPIPE, SIG_IGN);
275 if(old_sigpipe_handler == SIG_ERR)
276 logmsg(
"cannot install SIGPIPE handler: %s", strerror(errno));
280 old_sigalrm_handler = signal(SIGALRM, SIG_IGN);
281 if(old_sigalrm_handler == SIG_ERR)
282 logmsg(
"cannot install SIGALRM handler: %s", strerror(errno));
287 if(old_sigint_handler == SIG_ERR)
288 logmsg(
"cannot install SIGINT handler: %s", strerror(errno));
295 if(old_sigterm_handler == SIG_ERR)
296 logmsg(
"cannot install SIGTERM handler: %s", strerror(errno));
300 #if defined(SIGBREAK) && defined(WIN32) 303 if(old_sigbreak_handler == SIG_ERR)
304 logmsg(
"cannot install SIGBREAK handler: %s", strerror(errno));
313 if(SIG_ERR != old_sighup_handler)
314 (void)signal(SIGHUP, old_sighup_handler);
317 if(SIG_ERR != old_sigpipe_handler)
318 (void)signal(SIGPIPE, old_sigpipe_handler);
321 if(SIG_ERR != old_sigalrm_handler)
322 (void)signal(SIGALRM, old_sigalrm_handler);
325 if(SIG_ERR != old_sigint_handler)
326 (void)signal(SIGINT, old_sigint_handler);
329 if(SIG_ERR != old_sigterm_handler)
330 (void)signal(SIGTERM, old_sigterm_handler);
332 #if defined(SIGBREAK) && defined(WIN32) 333 if(SIG_ERR != old_sigbreak_handler)
334 (void)signal(SIGBREAK, old_sigbreak_handler);
362 stream = fopen(filename,
"rb");
365 logmsg(
"fopen() failed with error: %d %s", error, strerror(error));
366 logmsg(
" [1] Error opening file: %s", filename);
378 error =
getpart(&orgcmd, &cmdsize,
"reply",
"servercmd", stream);
381 logmsg(
"getpart() failed with error: %d", error);
389 while(cmd && cmdsize) {
393 logmsg(
"instructed to require authorization header");
397 logmsg(
"instructed to idle");
402 logmsg(
"instructed to stream");
407 logmsg(
"enabled connection monitoring");
411 logmsg(
"enabled upgrade to http2");
414 else if(1 == sscanf(cmd,
"pipe: %d", &num)) {
415 logmsg(
"instructed to allow a pipe size of %d", num);
417 logmsg(
"negative pipe size ignored");
422 else if(1 == sscanf(cmd,
"skip: %d", &num)) {
423 logmsg(
"instructed to skip this number of bytes %d", num);
426 else if(1 == sscanf(cmd,
"writedelay: %d", &num)) {
427 logmsg(
"instructed to delay %d secs between packets", num);
431 logmsg(
"Unknown <servercmd> instruction found: %s", cmd);
434 check = strchr(cmd,
'\r');
436 check = strchr(cmd,
'\n');
440 while((*check ==
'\r') || (*check ==
'\n'))
460 bool chunked =
FALSE;
464 int prot_major, prot_minor;
477 !strncmp(
"/verifiedserver", line, 15)) {
478 logmsg(
"Are-we-friendly question received");
495 ptr = strrchr(doc,
'/');
499 if((strlen(doc) + strlen(request)) < 400)
500 snprintf(logbuf,
sizeof(logbuf),
"Got request: %s %s HTTP/%d.%d",
501 request, doc, prot_major, prot_minor);
503 snprintf(logbuf,
sizeof(logbuf),
"Got a *HUGE* request HTTP/%d.%d",
504 prot_major, prot_minor);
507 if(!strncmp(
"/verifiedserver", ptr, 15)) {
508 logmsg(
"Are-we-friendly question received");
513 if(!strncmp(
"/quit", ptr, 5)) {
514 logmsg(
"Request-to-quit received");
525 req->
testno = strtol(ptr, &ptr, 10);
536 snprintf(logbuf,
sizeof(logbuf),
"Requested test number %ld part %ld",
552 if(sscanf(req->
reqbuf,
"CONNECT %" MAXDOCNAMELEN_TXT
"s HTTP/%d.%d",
553 doc, &prot_major, &prot_minor) == 3) {
555 unsigned long part = 0;
558 "Received a CONNECT %s HTTP/%d.%d request",
559 doc, prot_major, prot_minor);
571 while(*p && (
ISXDIGIT(*p) || (*p ==
':') || (*p ==
'.'))) {
573 part = strtoul(p, &endp, 16);
580 logmsg(
"Invalid CONNECT IPv6 address format");
581 else if(*(p + 1) !=
':')
582 logmsg(
"Invalid CONNECT IPv6 port format");
589 portp = strchr(doc,
':');
591 if(portp && (*(portp + 1) !=
'\0') &&
ISDIGIT(*(portp + 1))) {
592 unsigned long ulnum = strtoul(portp + 1, NULL, 10);
593 if(!ulnum || (ulnum > 65535UL))
594 logmsg(
"Invalid CONNECT port received");
599 logmsg(
"Port number: %d, test case number: %ld",
606 char *
testno = strstr(line,
"\nTestno: ");
608 req->
testno = strtol(&testno[9], NULL, 10);
609 logmsg(
"Found test number %d in Testno: header!", req->
testno);
618 ptr = strrchr(doc,
'.');
624 req->
testno = strtol(ptr, &ptr, 10);
630 logmsg(
"found test %d in requested host name", req->
testno);
637 "Requested test number %ld part %ld (from host name)",
644 logmsg(
"Did not find test number in PATH");
652 logmsg(
"** Unusual request. Starts with %02x %02x %02x",
653 line[0], line[1], line[2]);
658 logmsg(
"request not complete yet");
661 logmsg(
"- request found to be complete");
669 ptr = strrchr(line,
'/');
678 req->
testno = strtol(ptr, &ptr, 10);
688 "Requested GOPHER test number %ld part %ld",
720 char *
ptr = line + 15;
721 unsigned long clen = 0;
726 clen = strtoul(ptr, &endptr, 10);
727 if((ptr == endptr) || !
ISSPACE(*endptr) || (ERANGE == errno)) {
729 logmsg(
"Found invalid Content-Length: (%s) in the request", ptr);
733 req->
cl = clen - req->
skip;
735 logmsg(
"Found Content-Length: %lu in the request", clen);
737 logmsg(
"... but will abort after %zu bytes", req->
cl);
741 strlen(
"Transfer-Encoding: chunked"))) {
747 if(strstr(req->
reqbuf,
"\r\n0\r\n\r\n"))
754 line = strchr(line,
'\n');
760 if(!req->
auth && strstr(req->
reqbuf,
"Authorization:")) {
763 logmsg(
"Authorization header found, as required");
766 if(strstr(req->
reqbuf,
"Authorization: Negotiate")) {
768 static long prev_testno = -1;
769 static long prev_partno = -1;
770 logmsg(
"Negotiate: prev_testno: %d, prev_partno: %d",
771 prev_testno, prev_partno);
772 if(req->
testno != prev_testno) {
773 prev_testno = req->
testno;
774 prev_partno = req->
partno;
777 req->
partno = prev_partno;
779 else if(!req->
digest && strstr(req->
reqbuf,
"Authorization: Digest")) {
785 logmsg(
"Received Digest request, sending back data %ld", req->
partno);
787 else if(!req->
ntlm &&
788 strstr(req->
reqbuf,
"Authorization: NTLM TlRMTVNTUAAD")) {
792 logmsg(
"Received NTLM type-3, sending back data %ld", req->
partno);
794 logmsg(
" Expecting %zu POSTed bytes", req->
cl);
797 else if(!req->
ntlm &&
798 strstr(req->
reqbuf,
"Authorization: NTLM TlRMTVNTUAAB")) {
802 logmsg(
"Received NTLM type-1, sending back data %ld", req->
partno);
804 else if((req->
partno >= 1000) &&
805 strstr(req->
reqbuf,
"Authorization: Basic")) {
810 logmsg(
"Received Basic request, sending back data %ld", req->
partno);
812 if(strstr(req->
reqbuf,
"Connection: close"))
821 (!strncmp(req->
reqbuf,
"GET", strlen(
"GET")) ||
822 !strncmp(req->
reqbuf,
"HEAD", strlen(
"HEAD")))) {
846 logmsg(
"Return early due to auth requested by none provided");
852 logmsg(
"Found Upgrade: in request and allows it");
882 dump = fopen(dumpfile,
"ab");
883 }
while((dump == NULL) && ((error = errno) == EINTR));
885 logmsg(
"[2] Error opening file %s error: %d %s",
886 dumpfile, error, strerror(error));
887 logmsg(
"Failed to write request input ");
891 writeleft = totalsize;
893 written =
fwrite(&reqbuf[totalsize-writeleft],
896 goto storerequest_cleanup;
898 writeleft -= written;
899 }
while((writeleft > 0) && ((error = errno) == EINTR));
902 logmsg(
"Wrote request (%zu bytes) input to %s", totalsize, dumpfile);
903 else if(writeleft > 0) {
904 logmsg(
"Error writing file %s error: %d %s",
905 dumpfile, error, strerror(error));
906 logmsg(
"Wrote only (%zu bytes) of (%zu bytes) request input to %s",
907 totalsize-writeleft, totalsize, dumpfile);
910 storerequest_cleanup:
914 }
while(res && ((error = errno) == EINTR));
916 logmsg(
"Error closing file %s error: %d %s",
917 dumpfile, error, strerror(error));
960 char *pipereq = NULL;
961 size_t pipereq_length = 0;
979 if(pipereq_length && pipereq) {
980 memmove(reqbuf, pipereq, pipereq_length);
989 got = sread(sock, reqbuf + req->
offset, req->
cl);
996 logmsg(
"Connection closed by client");
1001 if(
EAGAIN == error || EWOULDBLOCK == error) {
1005 logmsg(
"recv() returned error: (%d) %s", error, strerror(error));
1010 reqbuf[req->
offset] =
'\0';
1015 logmsg(
"Read %zd bytes", got);
1018 reqbuf[req->
offset] =
'\0';
1024 logmsg(
"Waiting for another piped request");
1031 logmsg(
"Request would overflow buffer, closing connection");
1037 logmsg(
"Request buffer overflow, closing connection");
1043 reqbuf[req->
offset] =
'\0';
1051 return fail ? -1 : 1;
1065 bool persistant =
TRUE;
1066 bool sendfailure =
FALSE;
1067 size_t responsesize;
1071 static char weare[256];
1078 #define STREAMTHIS "a string to stream 01234567890\n" 1084 if(written != (
ssize_t)count) {
1085 logmsg(
"Stopped streaming");
1103 logmsg(
"Replying to QUIT");
1108 logmsg(
"Identifying ourselves as friends");
1109 snprintf(msgbuf,
sizeof(msgbuf),
"WE ROOLZ: %ld\r\n", (
long)getpid());
1110 msglen = strlen(msgbuf);
1112 snprintf(weare,
sizeof(weare),
"%s", msgbuf);
1115 "HTTP/1.1 200 OK\r\nContent-Length: %zu\r\n\r\n%s",
1121 logmsg(
"Replying to with a 404");
1126 count = strlen(buffer);
1137 snprintf(partbuf,
sizeof(partbuf),
"%s%ld", section, req->
partno);
1139 snprintf(partbuf,
sizeof(partbuf),
"%s", section);
1141 logmsg(
"Send response test%ld section <%s>", req->
testno, partbuf);
1143 stream = fopen(filename,
"rb");
1146 logmsg(
"fopen() failed with error: %d %s", error, strerror(error));
1147 logmsg(
" [3] Error opening file: %s", filename);
1151 error =
getpart(&ptr, &count,
"reply", partbuf, stream);
1154 logmsg(
"getpart() failed with error: %d", error);
1166 stream = fopen(filename,
"rb");
1169 logmsg(
"fopen() failed with error: %d %s", error, strerror(error));
1170 logmsg(
" [4] Error opening file: %s", filename);
1176 error =
getpart(&cmd, &cmdsize,
"reply",
"postcmd", stream);
1179 logmsg(
"getpart() failed with error: %d", error);
1195 if(strstr(buffer,
"swsclose") || !count) {
1197 logmsg(
"connection close instruction \"swsclose\" found in response");
1199 if(strstr(buffer,
"swsbounce")) {
1201 logmsg(
"enable \"swsbounce\" in the next request");
1206 dump = fopen(responsedump,
"ab");
1209 logmsg(
"fopen() failed with error: %d %s", error, strerror(error));
1210 logmsg(
" [5] Error opening file: %s", responsedump);
1216 responsesize = count;
1226 written = swrite(sock, buffer, num);
1237 fwrite(buffer, 1, (
size_t)written, dump);
1254 }
while(res && ((error = errno) == EINTR));
1256 logmsg(
"Error closing file %s error: %d %s",
1257 responsedump, error, strerror(error));
1266 logmsg(
"Sending response failed. Only (%zu bytes) of (%zu bytes) " 1268 responsesize-count, responsesize);
1274 logmsg(
"Response sent (%zu bytes) and written to %s",
1275 responsesize, responsedump);
1284 if(2 == sscanf(ptr,
"%31s %d", command, &num)) {
1285 if(!strcmp(
"wait", command)) {
1286 logmsg(
"Told to sleep for %d seconds", num);
1294 logmsg(
"wait_ms() failed with error: (%d) %s",
1295 error, strerror(error));
1300 logmsg(
"Continuing after sleeping %d seconds", num);
1303 logmsg(
"Unknown command in reply command section");
1305 ptr = strchr(ptr,
'\n');
1310 }
while(ptr && *ptr);
1327 const char *op_br =
"";
1328 const char *cl_br =
"";
1340 logmsg(
"about to connect to %s%s%s:%hu",
1341 op_br, ipaddr, cl_br, port);
1347 logmsg(
"Error creating socket for server conection: (%d) %s",
1348 error, strerror(error));
1356 if(0 != setsockopt(serverfd, IPPROTO_TCP, TCP_NODELAY,
1357 (
void *)&flag,
sizeof(flag)))
1358 logmsg(
"====> TCP_NODELAY for server conection failed");
1364 memset(&serveraddr.
sa4, 0,
sizeof(serveraddr.
sa4));
1365 serveraddr.
sa4.sin_family = AF_INET;
1366 serveraddr.
sa4.sin_port = htons(port);
1368 logmsg(
"Error inet_pton failed AF_INET conversion of '%s'", ipaddr);
1373 rc =
connect(serverfd, &serveraddr.
sa,
sizeof(serveraddr.
sa4));
1377 memset(&serveraddr.sa6, 0,
sizeof(serveraddr.sa6));
1378 serveraddr.sa6.sin6_family = AF_INET6;
1379 serveraddr.sa6.sin6_port = htons(port);
1380 if(
Curl_inet_pton(AF_INET6, ipaddr, &serveraddr.sa6.sin6_addr) < 1) {
1381 logmsg(
"Error inet_pton failed AF_INET6 conversion of '%s'", ipaddr);
1386 rc =
connect(serverfd, &serveraddr.
sa,
sizeof(serveraddr.sa6));
1389 #ifdef USE_UNIX_SOCKETS 1391 logmsg(
"Proxying through Unix socket is not (yet?) supported.");
1403 logmsg(
"Error connecting to server port %hu: (%d) %s",
1404 port, error, strerror(error));
1409 logmsg(
"connected fine to %s%s%s:%hu, now tunnel",
1410 op_br, ipaddr, cl_br, port);
1427 #define data_or_ctrl(x) ((x)?"DATA":"CTRL") 1435 unsigned short ipport)
1441 char readclient[2][256];
1442 char readserver[2][256];
1443 bool poll_client_rd[2] = {
TRUE,
TRUE };
1444 bool poll_server_rd[2] = {
TRUE, TRUE };
1445 bool poll_client_wr[2] = {
TRUE, TRUE };
1446 bool poll_server_wr[2] = {
TRUE, TRUE };
1447 bool primary =
FALSE;
1448 bool secondary =
FALSE;
1452 int timeout_count = 0;
1455 clientfd[
CTRL] = *infdp;
1463 goto http_connect_cleanup;
1466 if(serverfd[
CTRL] == CURL_SOCKET_BAD)
1467 goto http_connect_cleanup;
1474 max_tunnel_idx =
CTRL;
1481 struct timeval timeout = {1, 0};
1488 if((clientfd[
DATA] == CURL_SOCKET_BAD) &&
1489 (serverfd[
DATA] == CURL_SOCKET_BAD) &&
1490 poll_client_rd[
CTRL] && poll_client_wr[
CTRL] &&
1491 poll_server_rd[
CTRL] && poll_server_wr[
CTRL]) {
1495 FD_SET(rootfd, &input);
1500 for(i = 0; i <= max_tunnel_idx; i++) {
1502 if(clientfd[i] != CURL_SOCKET_BAD) {
1503 if(poll_client_rd[i]) {
1505 FD_SET(clientfd[i], &input);
1506 if(clientfd[i] > maxfd)
1507 maxfd = clientfd[
i];
1509 if(poll_client_wr[i] && toc[i]) {
1512 FD_SET(clientfd[i], &output);
1513 if(clientfd[i] > maxfd)
1514 maxfd = clientfd[
i];
1518 if(serverfd[i] != CURL_SOCKET_BAD) {
1519 if(poll_server_rd[i]) {
1521 FD_SET(serverfd[i], &input);
1522 if(serverfd[i] > maxfd)
1523 maxfd = serverfd[
i];
1525 if(poll_server_wr[i] && tos[i]) {
1528 FD_SET(serverfd[i], &output);
1529 if(serverfd[i] > maxfd)
1530 maxfd = serverfd[
i];
1537 rc = select((
int)maxfd + 1, &input, &output, NULL, &timeout);
1552 if((clientfd[
DATA] == CURL_SOCKET_BAD) &&
1553 (serverfd[
DATA] == CURL_SOCKET_BAD) && FD_ISSET(rootfd, &input)) {
1556 if(datafd != CURL_SOCKET_BAD) {
1559 memset(&req2, 0,
sizeof(req2));
1560 logmsg(
"====> Client connect DATA");
1565 if(0 != setsockopt(datafd, IPPROTO_TCP, TCP_NODELAY,
1566 (
void *)&flag,
sizeof(flag)))
1567 logmsg(
"====> TCP_NODELAY for client DATA conection failed");
1590 if(serverfd[
DATA] != CURL_SOCKET_BAD) {
1597 max_tunnel_idx =
DATA;
1601 clientfd[
DATA] = datafd;
1607 if(datafd != CURL_SOCKET_BAD) {
1609 shutdown(datafd, SHUT_RDWR);
1620 for(i = 0; i <= max_tunnel_idx; i++) {
1622 if(clientfd[i] != CURL_SOCKET_BAD) {
1623 len =
sizeof(readclient[
i]) - tos[i];
1624 if(len && FD_ISSET(clientfd[i], &input)) {
1626 rc = sread(clientfd[i], &readclient[i][tos[i]], len);
1629 shutdown(clientfd[i], SHUT_RD);
1630 poll_client_rd[
i] =
FALSE;
1640 if(serverfd[i] != CURL_SOCKET_BAD) {
1641 len =
sizeof(readserver[
i])-toc[i];
1642 if(len && FD_ISSET(serverfd[i], &input)) {
1644 rc = sread(serverfd[i], &readserver[i][toc[i]], len);
1647 shutdown(serverfd[i], SHUT_RD);
1648 poll_server_rd[
i] =
FALSE;
1658 if(clientfd[i] != CURL_SOCKET_BAD) {
1659 if(toc[i] && FD_ISSET(clientfd[i], &output)) {
1661 rc = swrite(clientfd[i], readserver[i], toc[i]);
1664 shutdown(clientfd[i], SHUT_WR);
1665 poll_client_wr[
i] =
FALSE;
1673 memmove(&readserver[i][0], &readserver[i][rc], toc[i]-rc);
1678 if(serverfd[i] != CURL_SOCKET_BAD) {
1679 if(tos[i] && FD_ISSET(serverfd[i], &output)) {
1681 rc = swrite(serverfd[i], readclient[i], tos[i]);
1684 shutdown(serverfd[i], SHUT_WR);
1685 poll_server_wr[
i] =
FALSE;
1693 memmove(&readclient[i][0], &readclient[i][rc], tos[i]-rc);
1705 for(i = 0; i <= max_tunnel_idx; i++) {
1706 for(loop = 2; loop > 0; loop--) {
1709 if(clientfd[i] != CURL_SOCKET_BAD) {
1710 if(poll_client_rd[i] && !poll_server_wr[i]) {
1712 shutdown(clientfd[i], SHUT_RD);
1713 poll_client_rd[
i] =
FALSE;
1715 if(poll_client_wr[i] && !poll_server_rd[i] && !toc[i]) {
1717 shutdown(clientfd[i], SHUT_WR);
1718 poll_client_wr[
i] =
FALSE;
1722 if(serverfd[i] != CURL_SOCKET_BAD) {
1723 if(poll_server_rd[i] && !poll_client_wr[i]) {
1725 shutdown(serverfd[i], SHUT_RD);
1726 poll_server_rd[
i] =
FALSE;
1728 if(poll_server_wr[i] && !poll_client_rd[i] && !tos[i]) {
1730 shutdown(serverfd[i], SHUT_WR);
1731 poll_server_wr[
i] =
FALSE;
1743 for(i = 0; i <= max_tunnel_idx; i++) {
1744 for(loop = 2; loop > 0; loop--) {
1745 if(clientfd[i] != CURL_SOCKET_BAD) {
1746 if(!poll_client_wr[i] && !poll_client_rd[i]) {
1750 if(serverfd[i] == CURL_SOCKET_BAD) {
1759 if(serverfd[i] != CURL_SOCKET_BAD) {
1760 if(!poll_server_wr[i] && !poll_server_rd[i]) {
1764 if(clientfd[i] == CURL_SOCKET_BAD) {
1778 max_tunnel_idx = secondary ?
DATA :
CTRL;
1787 if(timeout_count > 5) {
1788 logmsg(
"CONNECT proxy timeout after %d idle seconds!", timeout_count);
1794 http_connect_cleanup:
1797 if(serverfd[i] != CURL_SOCKET_BAD) {
1799 shutdown(serverfd[i], SHUT_RDWR);
1802 if(clientfd[i] != CURL_SOCKET_BAD) {
1804 shutdown(clientfd[i], SHUT_RDWR);
1807 if((serverfd[i] != CURL_SOCKET_BAD) ||
1808 (clientfd[i] != CURL_SOCKET_BAD)) {
1819 logmsg(
"switched to http2");
1833 logmsg(
"Too many open sockets!");
1837 msgsock = accept(sock, NULL, NULL);
1847 if(
EAGAIN == error || EWOULDBLOCK == error) {
1851 logmsg(
"MAJOR ERROR: accept() failed with error: (%d) %s",
1852 error, strerror(error));
1858 logmsg(
"curlx_nonblock failed with error: (%d) %s",
1859 error, strerror(error));
1864 if(0 != setsockopt(msgsock, SOL_SOCKET, SO_KEEPALIVE,
1865 (
void *)&flag,
sizeof(flag))) {
1867 logmsg(
"setsockopt(SO_KEEPALIVE) failed with error: (%d) %s",
1868 error, strerror(error));
1883 logmsg(
"====> Client connect");
1894 if(0 != setsockopt(msgsock, IPPROTO_TCP, TCP_NODELAY,
1895 (
void *)&flag,
sizeof(flag)))
1896 logmsg(
"====> TCP_NODELAY failed");
1907 const char *connecthost)
1939 logmsg(
"special request received, no persistency");
1943 logmsg(
"instructed to close connection after server-reply");
1950 logmsg(
"received CONNECT but isn't running as proxy!");
1968 logmsg(
"=> persistant connection request ended, awaits new request\n");
1982 #ifdef USE_UNIX_SOCKETS 1983 const char *unix_socket = NULL;
1984 bool unlink_socket =
false;
1986 const char *
pidname =
".http.pid";
1992 const char *connecthost =
"127.0.0.1";
1993 const char *socket_type =
"IPv4";
1995 const char *location_str = port_str;
2000 memset(&req, 0,
sizeof(req));
2003 if(!strcmp(
"--version", argv[arg])) {
2014 else if(!strcmp(
"--pidfile", argv[arg])) {
2017 pidname = argv[arg++];
2019 else if(!strcmp(
"--logfile", argv[arg])) {
2024 else if(!strcmp(
"--gopher", argv[arg])) {
2029 else if(!strcmp(
"--ipv4", argv[arg])) {
2030 socket_type =
"IPv4";
2032 location_str = port_str;
2035 else if(!strcmp(
"--ipv6", argv[arg])) {
2037 socket_type =
"IPv6";
2039 location_str = port_str;
2043 else if(!strcmp(
"--unix-socket", argv[arg])) {
2046 #ifdef USE_UNIX_SOCKETS 2047 unix_socket = argv[arg];
2048 if(strlen(unix_socket) >=
sizeof(me.sau.sun_path)) {
2049 fprintf(stderr,
"sws: socket path must be shorter than %zu chars\n",
2050 sizeof(me.sau.sun_path));
2053 socket_type =
"unix";
2055 location_str = unix_socket;
2060 else if(!strcmp(
"--port", argv[arg])) {
2064 unsigned long ulnum = strtoul(argv[arg], &endptr, 10);
2065 if((endptr != argv[arg] + strlen(argv[arg])) ||
2066 (ulnum < 1025UL) || (ulnum > 65535UL)) {
2067 fprintf(stderr,
"sws: invalid --port argument (%s)\n",
2075 else if(!strcmp(
"--srcdir", argv[arg])) {
2082 else if(!strcmp(
"--connect", argv[arg])) {
2088 connecthost = argv[arg];
2091 logmsg(
"Run as proxy, CONNECT to host %s", connecthost);
2095 puts(
"Usage: sws [option]\n" 2097 " --logfile [file]\n" 2098 " --pidfile [file]\n" 2101 " --unix-socket [file]\n" 2103 " --srcdir [path]\n" 2104 " --connect [ip4-addr]\n" 2110 snprintf(port_str,
sizeof(port_str),
"port %hu", port);
2119 pid = (long)getpid();
2128 logmsg(
"Error creating socket: (%d) %s",
2129 error, strerror(error));
2134 if(0 != setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
2135 (
void *)&flag,
sizeof(flag))) {
2137 logmsg(
"setsockopt(SO_REUSEADDR) failed with error: (%d) %s",
2138 error, strerror(error));
2143 logmsg(
"curlx_nonblock failed with error: (%d) %s",
2144 error, strerror(error));
2150 memset(&me.
sa4, 0,
sizeof(me.
sa4));
2151 me.
sa4.sin_family = AF_INET;
2152 me.
sa4.sin_addr.s_addr = INADDR_ANY;
2153 me.
sa4.sin_port = htons(port);
2154 rc =
bind(sock, &me.
sa,
sizeof(me.
sa4));
2158 memset(&me.sa6, 0,
sizeof(me.sa6));
2159 me.sa6.sin6_family = AF_INET6;
2160 me.sa6.sin6_addr = in6addr_any;
2161 me.sa6.sin6_port = htons(port);
2162 rc =
bind(sock, &me.
sa,
sizeof(me.sa6));
2165 #ifdef USE_UNIX_SOCKETS 2167 memset(&me.sau, 0,
sizeof(me.sau));
2168 me.sau.sun_family = AF_UNIX;
2169 strncpy(me.sau.sun_path, unix_socket,
sizeof(me.sau.sun_path));
2170 rc =
bind(sock, &me.
sa,
sizeof(me.sau));
2171 if(0 != rc && errno == EADDRINUSE) {
2172 struct stat statbuf;
2174 int unixfd = socket(AF_UNIX, SOCK_STREAM, 0);
2177 logmsg(
"Error binding socket, failed to create socket at %s: (%d) %s",
2178 unix_socket, error, strerror(error));
2182 rc =
connect(unixfd, &me.
sa,
sizeof(me.sau));
2185 if(ECONNREFUSED != error) {
2186 logmsg(
"Error binding socket, failed to connect to %s: (%d) %s",
2187 unix_socket, error, strerror(error));
2192 rc = lstat(unix_socket, &statbuf);
2194 logmsg(
"Error binding socket, failed to stat %s: (%d) %s",
2195 unix_socket, errno, strerror(errno));
2198 if((statbuf.st_mode & S_IFSOCK) != S_IFSOCK) {
2199 logmsg(
"Error binding socket, failed to stat %s: (%d) %s",
2200 unix_socket, error, strerror(error));
2204 rc = unlink(unix_socket);
2206 logmsg(
"Error binding socket, failed to unlink %s: (%d) %s",
2207 unix_socket, errno, strerror(errno));
2211 rc =
bind(sock, &me.
sa,
sizeof(me.sau));
2218 logmsg(
"Error binding socket on %s: (%d) %s",
2219 location_str, error, strerror(error));
2223 logmsg(
"Running %s %s version on %s",
2224 use_gopher?
"GOPHER":
"HTTP", socket_type, location_str);
2227 rc = listen(sock, 5);
2230 logmsg(
"listen() failed with error: (%d) %s",
2231 error, strerror(error));
2235 #ifdef USE_UNIX_SOCKETS 2237 unlink_socket =
true;
2259 struct timeval timeout = {0, 250000L};
2263 for(socket_idx =
num_sockets - 1; socket_idx >= 1; --socket_idx) {
2266 char *src = (
char *) (
all_sockets + socket_idx + 1);
2268 memmove(dst, src, end - src);
2280 for(socket_idx = 0; socket_idx <
num_sockets; ++socket_idx) {
2290 rc = select((
int)maxfd + 1, &input, &output, NULL, &timeout);
2293 logmsg(
"select() failed with error: (%d) %s",
2294 error, strerror(error));
2312 logmsg(
"accept_connection %d returned %d", sock, msgsock);
2315 }
while(msgsock > 0);
2319 for(socket_idx = 1; socket_idx <
num_sockets; ++socket_idx) {
2335 const char *keepopen =
"[DISCONNECT]\n";
2372 for(socket_idx = 1; socket_idx <
num_sockets; ++socket_idx)
2380 #ifdef USE_UNIX_SOCKETS 2382 rc = unlink(unix_socket);
2383 logmsg(
"unlink(%s) = %d (%s)", unix_socket, rc, strerror(rc));
2388 logmsg(
"signalled to die");
2401 logmsg(
"========> %s sws (%s pid: %ld) exits with signal (%d)",
2411 logmsg(
"========> sws quits");
#define siginterrupt(x, y)
#define CMD_CONNECTIONMONITOR
static volatile int exit_signal
char * data_to_hex(char *data, size_t len)
static void init_httprequest(struct httprequest *req)
RETSIGTYPE(* SIGHANDLER_T)(int)
int stat(const char *path, struct stat *buffer)
#define REQUEST_KEYWORD_SIZE
static enum @45 socket_domain
static const char * end_of_headers
static int ProcessRequest(struct httprequest *req)
static curl_socket_t accept_connection(curl_socket_t sock)
static void http_connect(curl_socket_t *infdp, curl_socket_t rootfd, const char *ipaddr, unsigned short ipport)
static int parse_servercmd(struct httprequest *req)
UNITTEST_START char * ptr
static const char * doc404
int write_pidfile(const char *filename)
#define RESPONSE_PROXY_DUMP
static void win32_cleanup(void)
void clear_advisor_read_lock(const char *filename)
static int get_request(curl_socket_t sock, struct httprequest *req)
static int serverlogslocked
ssize_t curlx_uztosz(size_t uznum)
static const char * docquit
int curlx_nonblock(curl_socket_t sockfd, int nonblock)
static size_t num_sockets
unsigned short curlx_ultous(unsigned long ulnum)
static RETSIGTYPE exit_signal_handler(int signum)
static void storerequest(const char *reqbuf, size_t totalsize)
static void install_signal_handlers(void)
CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t
UNITTEST_START char * output
void logmsg(const char *msg,...)
#define MAXDOCNAMELEN_TXT
curl_easy_setopt expects a curl_off_t argument for this option curl_easy_setopt expects a curl_write_callback argument for this option curl_easy_setopt expects a curl_ioctl_callback argument for this option curl_easy_setopt expects a curl_opensocket_callback argument for this option curl_easy_setopt expects a curl_debug_callback argument for this option curl_easy_setopt expects a curl_conv_callback argument for this option curl_easy_setopt expects a private data pointer as argument for this option curl_easy_setopt expects a FILE *argument for this option curl_easy_setopt expects a struct curl_httppost *argument for this option curl_easy_setopt expects a struct curl_slist *argument for this option curl_easy_getinfo expects a pointer to char *for this info curl_easy_getinfo expects a pointer to double for this info curl_easy_getinfo expects a pointer to struct curl_tlssessioninfo *for this info curl_easy_getinfo expects a pointer to curl_socket_t for this info size_t
ROSLIB_DECL std::string command(const std::string &cmd)
static int send_doc(curl_socket_t sock, struct httprequest *req)
static void http2(struct httprequest *req)
#define strncasecompare(a, b, c)
static curl_socket_t all_sockets[MAX_SOCKETS]
static int service_connection(curl_socket_t msgsock, struct httprequest *req, curl_socket_t listensock, const char *connecthost)
int Curl_inet_pton(int af, const char *src, void *dst)
static unsigned short port
unsigned short connect_port
#define REQUEST_PROXY_DUMP
static CURLcode win32_init(void)
#define REQUEST_KEYWORD_SIZE_TXT
SIG_ATOMIC_T got_exit_signal
static bool socket_domain_is_ip(void)
int main(int argc, char *argv[])
#define CMD_AUTH_REQUIRED
char * test2file(long testno)
static void restore_signal_handlers(void)
int getpart(char **outbuf, size_t *outlen, const char *main, const char *sub, FILE *stream)
static curl_socket_t connect_to(const char *ipaddr, unsigned short port)
static const char * pidname
static void dump(const char *text, FILE *stream, unsigned char *ptr, size_t size, char nohex)
const char * serverlogfile
void set_advisor_read_lock(const char *filename)