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


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:16