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