xref: /aosp_15_r20/external/curl/tests/server/rtspd.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 /*
27*6236dae4SAndroid Build Coastguard Worker  * curl's test suite Real Time Streaming Protocol (RTSP) server.
28*6236dae4SAndroid Build Coastguard Worker  *
29*6236dae4SAndroid Build Coastguard Worker  * This source file was started based on curl's HTTP test suite server.
30*6236dae4SAndroid Build Coastguard Worker  */
31*6236dae4SAndroid Build Coastguard Worker 
32*6236dae4SAndroid Build Coastguard Worker #include <signal.h>
33*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETINET_IN_H
34*6236dae4SAndroid Build Coastguard Worker #include <netinet/in.h>
35*6236dae4SAndroid Build Coastguard Worker #endif
36*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETINET_IN6_H
37*6236dae4SAndroid Build Coastguard Worker #include <netinet/in6.h>
38*6236dae4SAndroid Build Coastguard Worker #endif
39*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_ARPA_INET_H
40*6236dae4SAndroid Build Coastguard Worker #include <arpa/inet.h>
41*6236dae4SAndroid Build Coastguard Worker #endif
42*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETDB_H
43*6236dae4SAndroid Build Coastguard Worker #include <netdb.h>
44*6236dae4SAndroid Build Coastguard Worker #endif
45*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETINET_TCP_H
46*6236dae4SAndroid Build Coastguard Worker #include <netinet/tcp.h> /* for TCP_NODELAY */
47*6236dae4SAndroid Build Coastguard Worker #endif
48*6236dae4SAndroid Build Coastguard Worker 
49*6236dae4SAndroid Build Coastguard Worker #include "curlx.h" /* from the private lib dir */
50*6236dae4SAndroid Build Coastguard Worker #include "getpart.h"
51*6236dae4SAndroid Build Coastguard Worker #include "util.h"
52*6236dae4SAndroid Build Coastguard Worker #include "server_sockaddr.h"
53*6236dae4SAndroid Build Coastguard Worker 
54*6236dae4SAndroid Build Coastguard Worker /* include memdebug.h last */
55*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
56*6236dae4SAndroid Build Coastguard Worker 
57*6236dae4SAndroid Build Coastguard Worker #ifdef USE_WINSOCK
58*6236dae4SAndroid Build Coastguard Worker #undef  EINTR
59*6236dae4SAndroid Build Coastguard Worker #define EINTR    4 /* errno.h value */
60*6236dae4SAndroid Build Coastguard Worker #undef  ERANGE
61*6236dae4SAndroid Build Coastguard Worker #define ERANGE  34 /* errno.h value */
62*6236dae4SAndroid Build Coastguard Worker #endif
63*6236dae4SAndroid Build Coastguard Worker 
64*6236dae4SAndroid Build Coastguard Worker #ifdef USE_IPV6
65*6236dae4SAndroid Build Coastguard Worker static bool use_ipv6 = FALSE;
66*6236dae4SAndroid Build Coastguard Worker #endif
67*6236dae4SAndroid Build Coastguard Worker static const char *ipv_inuse = "IPv4";
68*6236dae4SAndroid Build Coastguard Worker static int serverlogslocked = 0;
69*6236dae4SAndroid Build Coastguard Worker 
70*6236dae4SAndroid Build Coastguard Worker #define REQBUFSIZ 150000
71*6236dae4SAndroid Build Coastguard Worker #define REQBUFSIZ_TXT "149999"
72*6236dae4SAndroid Build Coastguard Worker 
73*6236dae4SAndroid Build Coastguard Worker static long prevtestno = -1;    /* previous test number we served */
74*6236dae4SAndroid Build Coastguard Worker static long prevpartno = -1;    /* previous part number we served */
75*6236dae4SAndroid Build Coastguard Worker static bool prevbounce = FALSE; /* instructs the server to increase the part
76*6236dae4SAndroid Build Coastguard Worker                                    number for a test in case the identical
77*6236dae4SAndroid Build Coastguard Worker                                    testno+partno request shows up again */
78*6236dae4SAndroid Build Coastguard Worker 
79*6236dae4SAndroid Build Coastguard Worker #define RCMD_NORMALREQ 0 /* default request, use the tests file normally */
80*6236dae4SAndroid Build Coastguard Worker #define RCMD_IDLE      1 /* told to sit idle */
81*6236dae4SAndroid Build Coastguard Worker #define RCMD_STREAM    2 /* told to stream */
82*6236dae4SAndroid Build Coastguard Worker 
83*6236dae4SAndroid Build Coastguard Worker typedef enum {
84*6236dae4SAndroid Build Coastguard Worker   RPROT_NONE = 0,
85*6236dae4SAndroid Build Coastguard Worker   RPROT_RTSP = 1,
86*6236dae4SAndroid Build Coastguard Worker   RPROT_HTTP = 2
87*6236dae4SAndroid Build Coastguard Worker } reqprot_t;
88*6236dae4SAndroid Build Coastguard Worker 
89*6236dae4SAndroid Build Coastguard Worker #define SET_RTP_PKT_CHN(p,c)  ((p)[1] = (char)((c) & 0xFF))
90*6236dae4SAndroid Build Coastguard Worker 
91*6236dae4SAndroid Build Coastguard Worker #define SET_RTP_PKT_LEN(p,l) (((p)[2] = (char)(((l) >> 8) & 0xFF)), \
92*6236dae4SAndroid Build Coastguard Worker                               ((p)[3] = (char)((l) & 0xFF)))
93*6236dae4SAndroid Build Coastguard Worker 
94*6236dae4SAndroid Build Coastguard Worker struct httprequest {
95*6236dae4SAndroid Build Coastguard Worker   char reqbuf[REQBUFSIZ]; /* buffer area for the incoming request */
96*6236dae4SAndroid Build Coastguard Worker   size_t checkindex; /* where to start checking of the request */
97*6236dae4SAndroid Build Coastguard Worker   size_t offset;     /* size of the incoming request */
98*6236dae4SAndroid Build Coastguard Worker   long testno;       /* test number found in the request */
99*6236dae4SAndroid Build Coastguard Worker   long partno;       /* part number found in the request */
100*6236dae4SAndroid Build Coastguard Worker   bool open;      /* keep connection open info, as found in the request */
101*6236dae4SAndroid Build Coastguard Worker   bool auth_req;  /* authentication required, don't wait for body unless
102*6236dae4SAndroid Build Coastguard Worker                      there's an Authorization header */
103*6236dae4SAndroid Build Coastguard Worker   bool auth;      /* Authorization header present in the incoming request */
104*6236dae4SAndroid Build Coastguard Worker   size_t cl;      /* Content-Length of the incoming request */
105*6236dae4SAndroid Build Coastguard Worker   bool digest;    /* Authorization digest header found */
106*6236dae4SAndroid Build Coastguard Worker   bool ntlm;      /* Authorization NTLM header found */
107*6236dae4SAndroid Build Coastguard Worker   int pipe;       /* if non-zero, expect this many requests to do a "piped"
108*6236dae4SAndroid Build Coastguard Worker                      request/response */
109*6236dae4SAndroid Build Coastguard Worker   int skip;       /* if non-zero, the server is instructed to not read this
110*6236dae4SAndroid Build Coastguard Worker                      many bytes from a PUT/POST request. Ie the client sends N
111*6236dae4SAndroid Build Coastguard Worker                      bytes said in Content-Length, but the server only reads N
112*6236dae4SAndroid Build Coastguard Worker                      - skip bytes. */
113*6236dae4SAndroid Build Coastguard Worker   int rcmd;       /* doing a special command, see defines above */
114*6236dae4SAndroid Build Coastguard Worker   reqprot_t protocol; /* request protocol, HTTP or RTSP */
115*6236dae4SAndroid Build Coastguard Worker   int prot_version;   /* HTTP or RTSP version (major*10 + minor) */
116*6236dae4SAndroid Build Coastguard Worker   bool pipelining;    /* true if request is pipelined */
117*6236dae4SAndroid Build Coastguard Worker   char *rtp_buffer;
118*6236dae4SAndroid Build Coastguard Worker   size_t rtp_buffersize;
119*6236dae4SAndroid Build Coastguard Worker };
120*6236dae4SAndroid Build Coastguard Worker 
121*6236dae4SAndroid Build Coastguard Worker static int ProcessRequest(struct httprequest *req);
122*6236dae4SAndroid Build Coastguard Worker static void storerequest(char *reqbuf, size_t totalsize);
123*6236dae4SAndroid Build Coastguard Worker 
124*6236dae4SAndroid Build Coastguard Worker #define DEFAULT_PORT 8999
125*6236dae4SAndroid Build Coastguard Worker 
126*6236dae4SAndroid Build Coastguard Worker #ifndef DEFAULT_LOGFILE
127*6236dae4SAndroid Build Coastguard Worker #define DEFAULT_LOGFILE "log/rtspd.log"
128*6236dae4SAndroid Build Coastguard Worker #endif
129*6236dae4SAndroid Build Coastguard Worker 
130*6236dae4SAndroid Build Coastguard Worker const char *serverlogfile = DEFAULT_LOGFILE;
131*6236dae4SAndroid Build Coastguard Worker static const char *logdir = "log";
132*6236dae4SAndroid Build Coastguard Worker static char loglockfile[256];
133*6236dae4SAndroid Build Coastguard Worker 
134*6236dae4SAndroid Build Coastguard Worker #define RTSPDVERSION "curl test suite RTSP server/0.1"
135*6236dae4SAndroid Build Coastguard Worker 
136*6236dae4SAndroid Build Coastguard Worker #define REQUEST_DUMP  "server.input"
137*6236dae4SAndroid Build Coastguard Worker #define RESPONSE_DUMP "server.response"
138*6236dae4SAndroid Build Coastguard Worker 
139*6236dae4SAndroid Build Coastguard Worker /* very-big-path support */
140*6236dae4SAndroid Build Coastguard Worker #define MAXDOCNAMELEN 140000
141*6236dae4SAndroid Build Coastguard Worker #define MAXDOCNAMELEN_TXT "139999"
142*6236dae4SAndroid Build Coastguard Worker 
143*6236dae4SAndroid Build Coastguard Worker #define REQUEST_KEYWORD_SIZE 256
144*6236dae4SAndroid Build Coastguard Worker #define REQUEST_KEYWORD_SIZE_TXT "255"
145*6236dae4SAndroid Build Coastguard Worker 
146*6236dae4SAndroid Build Coastguard Worker #define CMD_AUTH_REQUIRED "auth_required"
147*6236dae4SAndroid Build Coastguard Worker 
148*6236dae4SAndroid Build Coastguard Worker /* 'idle' means that it will accept the request fine but never respond
149*6236dae4SAndroid Build Coastguard Worker    any data. Just keep the connection alive. */
150*6236dae4SAndroid Build Coastguard Worker #define CMD_IDLE "idle"
151*6236dae4SAndroid Build Coastguard Worker 
152*6236dae4SAndroid Build Coastguard Worker /* 'stream' means to send a never-ending stream of data */
153*6236dae4SAndroid Build Coastguard Worker #define CMD_STREAM "stream"
154*6236dae4SAndroid Build Coastguard Worker 
155*6236dae4SAndroid Build Coastguard Worker #define END_OF_HEADERS "\r\n\r\n"
156*6236dae4SAndroid Build Coastguard Worker 
157*6236dae4SAndroid Build Coastguard Worker enum {
158*6236dae4SAndroid Build Coastguard Worker   DOCNUMBER_NOTHING = -7,
159*6236dae4SAndroid Build Coastguard Worker   DOCNUMBER_QUIT    = -6,
160*6236dae4SAndroid Build Coastguard Worker   DOCNUMBER_BADCONNECT = -5,
161*6236dae4SAndroid Build Coastguard Worker   DOCNUMBER_INTERNAL = -4,
162*6236dae4SAndroid Build Coastguard Worker   DOCNUMBER_CONNECT = -3,
163*6236dae4SAndroid Build Coastguard Worker   DOCNUMBER_WERULEZ = -2,
164*6236dae4SAndroid Build Coastguard Worker   DOCNUMBER_404     = -1
165*6236dae4SAndroid Build Coastguard Worker };
166*6236dae4SAndroid Build Coastguard Worker 
167*6236dae4SAndroid Build Coastguard Worker 
168*6236dae4SAndroid Build Coastguard Worker /* sent as reply to a QUIT */
169*6236dae4SAndroid Build Coastguard Worker static const char *docquit =
170*6236dae4SAndroid Build Coastguard Worker "HTTP/1.1 200 Goodbye" END_OF_HEADERS;
171*6236dae4SAndroid Build Coastguard Worker 
172*6236dae4SAndroid Build Coastguard Worker /* sent as reply to a CONNECT */
173*6236dae4SAndroid Build Coastguard Worker static const char *docconnect =
174*6236dae4SAndroid Build Coastguard Worker "HTTP/1.1 200 Mighty fine indeed" END_OF_HEADERS;
175*6236dae4SAndroid Build Coastguard Worker 
176*6236dae4SAndroid Build Coastguard Worker /* sent as reply to a "bad" CONNECT */
177*6236dae4SAndroid Build Coastguard Worker static const char *docbadconnect =
178*6236dae4SAndroid Build Coastguard Worker "HTTP/1.1 501 Forbidden you fool" END_OF_HEADERS;
179*6236dae4SAndroid Build Coastguard Worker 
180*6236dae4SAndroid Build Coastguard Worker /* send back this on HTTP 404 file not found */
181*6236dae4SAndroid Build Coastguard Worker static const char *doc404_HTTP = "HTTP/1.1 404 Not Found\r\n"
182*6236dae4SAndroid Build Coastguard Worker     "Server: " RTSPDVERSION "\r\n"
183*6236dae4SAndroid Build Coastguard Worker     "Connection: close\r\n"
184*6236dae4SAndroid Build Coastguard Worker     "Content-Type: text/html"
185*6236dae4SAndroid Build Coastguard Worker     END_OF_HEADERS
186*6236dae4SAndroid Build Coastguard Worker     "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
187*6236dae4SAndroid Build Coastguard Worker     "<HTML><HEAD>\n"
188*6236dae4SAndroid Build Coastguard Worker     "<TITLE>404 Not Found</TITLE>\n"
189*6236dae4SAndroid Build Coastguard Worker     "</HEAD><BODY>\n"
190*6236dae4SAndroid Build Coastguard Worker     "<H1>Not Found</H1>\n"
191*6236dae4SAndroid Build Coastguard Worker     "The requested URL was not found on this server.\n"
192*6236dae4SAndroid Build Coastguard Worker     "<P><HR><ADDRESS>" RTSPDVERSION "</ADDRESS>\n" "</BODY></HTML>\n";
193*6236dae4SAndroid Build Coastguard Worker 
194*6236dae4SAndroid Build Coastguard Worker /* send back this on RTSP 404 file not found */
195*6236dae4SAndroid Build Coastguard Worker static const char *doc404_RTSP = "RTSP/1.0 404 Not Found\r\n"
196*6236dae4SAndroid Build Coastguard Worker     "Server: " RTSPDVERSION
197*6236dae4SAndroid Build Coastguard Worker     END_OF_HEADERS;
198*6236dae4SAndroid Build Coastguard Worker 
199*6236dae4SAndroid Build Coastguard Worker /* Default size to send away fake RTP data */
200*6236dae4SAndroid Build Coastguard Worker #define RTP_DATA_SIZE 12
201*6236dae4SAndroid Build Coastguard Worker static const char *RTP_DATA = "$_1234\n\0Rsdf";
202*6236dae4SAndroid Build Coastguard Worker 
ProcessRequest(struct httprequest * req)203*6236dae4SAndroid Build Coastguard Worker static int ProcessRequest(struct httprequest *req)
204*6236dae4SAndroid Build Coastguard Worker {
205*6236dae4SAndroid Build Coastguard Worker   char *line = &req->reqbuf[req->checkindex];
206*6236dae4SAndroid Build Coastguard Worker   bool chunked = FALSE;
207*6236dae4SAndroid Build Coastguard Worker   static char request[REQUEST_KEYWORD_SIZE];
208*6236dae4SAndroid Build Coastguard Worker   static char doc[MAXDOCNAMELEN];
209*6236dae4SAndroid Build Coastguard Worker   static char prot_str[5];
210*6236dae4SAndroid Build Coastguard Worker   int prot_major, prot_minor;
211*6236dae4SAndroid Build Coastguard Worker   char *end = strstr(line, END_OF_HEADERS);
212*6236dae4SAndroid Build Coastguard Worker 
213*6236dae4SAndroid Build Coastguard Worker   logmsg("ProcessRequest() called with testno %ld and line [%s]",
214*6236dae4SAndroid Build Coastguard Worker          req->testno, line);
215*6236dae4SAndroid Build Coastguard Worker 
216*6236dae4SAndroid Build Coastguard Worker   /* try to figure out the request characteristics as soon as possible, but
217*6236dae4SAndroid Build Coastguard Worker      only once! */
218*6236dae4SAndroid Build Coastguard Worker   if((req->testno == DOCNUMBER_NOTHING) &&
219*6236dae4SAndroid Build Coastguard Worker      sscanf(line,
220*6236dae4SAndroid Build Coastguard Worker             "%" REQUEST_KEYWORD_SIZE_TXT"s %" MAXDOCNAMELEN_TXT "s %4s/%d.%d",
221*6236dae4SAndroid Build Coastguard Worker             request,
222*6236dae4SAndroid Build Coastguard Worker             doc,
223*6236dae4SAndroid Build Coastguard Worker             prot_str,
224*6236dae4SAndroid Build Coastguard Worker             &prot_major,
225*6236dae4SAndroid Build Coastguard Worker             &prot_minor) == 5) {
226*6236dae4SAndroid Build Coastguard Worker     char *ptr;
227*6236dae4SAndroid Build Coastguard Worker     char logbuf[256];
228*6236dae4SAndroid Build Coastguard Worker 
229*6236dae4SAndroid Build Coastguard Worker     if(!strcmp(prot_str, "HTTP")) {
230*6236dae4SAndroid Build Coastguard Worker       req->protocol = RPROT_HTTP;
231*6236dae4SAndroid Build Coastguard Worker     }
232*6236dae4SAndroid Build Coastguard Worker     else if(!strcmp(prot_str, "RTSP")) {
233*6236dae4SAndroid Build Coastguard Worker       req->protocol = RPROT_RTSP;
234*6236dae4SAndroid Build Coastguard Worker     }
235*6236dae4SAndroid Build Coastguard Worker     else {
236*6236dae4SAndroid Build Coastguard Worker       req->protocol = RPROT_NONE;
237*6236dae4SAndroid Build Coastguard Worker       logmsg("got unknown protocol %s", prot_str);
238*6236dae4SAndroid Build Coastguard Worker       return 1;
239*6236dae4SAndroid Build Coastguard Worker     }
240*6236dae4SAndroid Build Coastguard Worker 
241*6236dae4SAndroid Build Coastguard Worker     req->prot_version = prot_major*10 + prot_minor;
242*6236dae4SAndroid Build Coastguard Worker 
243*6236dae4SAndroid Build Coastguard Worker     /* find the last slash */
244*6236dae4SAndroid Build Coastguard Worker     ptr = strrchr(doc, '/');
245*6236dae4SAndroid Build Coastguard Worker 
246*6236dae4SAndroid Build Coastguard Worker     /* get the number after it */
247*6236dae4SAndroid Build Coastguard Worker     if(ptr) {
248*6236dae4SAndroid Build Coastguard Worker       FILE *stream;
249*6236dae4SAndroid Build Coastguard Worker       if((strlen(doc) + strlen(request)) < 200)
250*6236dae4SAndroid Build Coastguard Worker         msnprintf(logbuf, sizeof(logbuf), "Got request: %s %s %s/%d.%d",
251*6236dae4SAndroid Build Coastguard Worker                   request, doc, prot_str, prot_major, prot_minor);
252*6236dae4SAndroid Build Coastguard Worker       else
253*6236dae4SAndroid Build Coastguard Worker         msnprintf(logbuf, sizeof(logbuf), "Got a *HUGE* request %s/%d.%d",
254*6236dae4SAndroid Build Coastguard Worker                   prot_str, prot_major, prot_minor);
255*6236dae4SAndroid Build Coastguard Worker       logmsg("%s", logbuf);
256*6236dae4SAndroid Build Coastguard Worker 
257*6236dae4SAndroid Build Coastguard Worker       if(!strncmp("/verifiedserver", ptr, 15)) {
258*6236dae4SAndroid Build Coastguard Worker         logmsg("Are-we-friendly question received");
259*6236dae4SAndroid Build Coastguard Worker         req->testno = DOCNUMBER_WERULEZ;
260*6236dae4SAndroid Build Coastguard Worker         return 1; /* done */
261*6236dae4SAndroid Build Coastguard Worker       }
262*6236dae4SAndroid Build Coastguard Worker 
263*6236dae4SAndroid Build Coastguard Worker       if(!strncmp("/quit", ptr, 5)) {
264*6236dae4SAndroid Build Coastguard Worker         logmsg("Request-to-quit received");
265*6236dae4SAndroid Build Coastguard Worker         req->testno = DOCNUMBER_QUIT;
266*6236dae4SAndroid Build Coastguard Worker         return 1; /* done */
267*6236dae4SAndroid Build Coastguard Worker       }
268*6236dae4SAndroid Build Coastguard Worker 
269*6236dae4SAndroid Build Coastguard Worker       ptr++; /* skip the slash */
270*6236dae4SAndroid Build Coastguard Worker 
271*6236dae4SAndroid Build Coastguard Worker       /* skip all non-numericals following the slash */
272*6236dae4SAndroid Build Coastguard Worker       while(*ptr && !ISDIGIT(*ptr))
273*6236dae4SAndroid Build Coastguard Worker         ptr++;
274*6236dae4SAndroid Build Coastguard Worker 
275*6236dae4SAndroid Build Coastguard Worker       req->testno = strtol(ptr, &ptr, 10);
276*6236dae4SAndroid Build Coastguard Worker 
277*6236dae4SAndroid Build Coastguard Worker       if(req->testno > 10000) {
278*6236dae4SAndroid Build Coastguard Worker         req->partno = req->testno % 10000;
279*6236dae4SAndroid Build Coastguard Worker         req->testno /= 10000;
280*6236dae4SAndroid Build Coastguard Worker       }
281*6236dae4SAndroid Build Coastguard Worker       else
282*6236dae4SAndroid Build Coastguard Worker         req->partno = 0;
283*6236dae4SAndroid Build Coastguard Worker 
284*6236dae4SAndroid Build Coastguard Worker       msnprintf(logbuf, sizeof(logbuf), "Requested test number %ld part %ld",
285*6236dae4SAndroid Build Coastguard Worker                 req->testno, req->partno);
286*6236dae4SAndroid Build Coastguard Worker       logmsg("%s", logbuf);
287*6236dae4SAndroid Build Coastguard Worker 
288*6236dae4SAndroid Build Coastguard Worker       stream = test2fopen(req->testno, logdir);
289*6236dae4SAndroid Build Coastguard Worker 
290*6236dae4SAndroid Build Coastguard Worker       if(!stream) {
291*6236dae4SAndroid Build Coastguard Worker         int error = errno;
292*6236dae4SAndroid Build Coastguard Worker         logmsg("fopen() failed with error: %d %s", error, strerror(error));
293*6236dae4SAndroid Build Coastguard Worker         logmsg("Couldn't open test file %ld", req->testno);
294*6236dae4SAndroid Build Coastguard Worker         req->open = FALSE; /* closes connection */
295*6236dae4SAndroid Build Coastguard Worker         return 1; /* done */
296*6236dae4SAndroid Build Coastguard Worker       }
297*6236dae4SAndroid Build Coastguard Worker       else {
298*6236dae4SAndroid Build Coastguard Worker         char *cmd = NULL;
299*6236dae4SAndroid Build Coastguard Worker         size_t cmdsize = 0;
300*6236dae4SAndroid Build Coastguard Worker         int num = 0;
301*6236dae4SAndroid Build Coastguard Worker 
302*6236dae4SAndroid Build Coastguard Worker         int rtp_channel = 0;
303*6236dae4SAndroid Build Coastguard Worker         int rtp_size = 0;
304*6236dae4SAndroid Build Coastguard Worker         int rtp_size_err = 0;
305*6236dae4SAndroid Build Coastguard Worker         int rtp_partno = -1;
306*6236dae4SAndroid Build Coastguard Worker         char *rtp_scratch = NULL;
307*6236dae4SAndroid Build Coastguard Worker 
308*6236dae4SAndroid Build Coastguard Worker         /* get the custom server control "commands" */
309*6236dae4SAndroid Build Coastguard Worker         int error = getpart(&cmd, &cmdsize, "reply", "servercmd", stream);
310*6236dae4SAndroid Build Coastguard Worker         fclose(stream);
311*6236dae4SAndroid Build Coastguard Worker         if(error) {
312*6236dae4SAndroid Build Coastguard Worker           logmsg("getpart() failed with error: %d", error);
313*6236dae4SAndroid Build Coastguard Worker           req->open = FALSE; /* closes connection */
314*6236dae4SAndroid Build Coastguard Worker           return 1; /* done */
315*6236dae4SAndroid Build Coastguard Worker         }
316*6236dae4SAndroid Build Coastguard Worker         ptr = cmd;
317*6236dae4SAndroid Build Coastguard Worker 
318*6236dae4SAndroid Build Coastguard Worker         if(cmdsize) {
319*6236dae4SAndroid Build Coastguard Worker           logmsg("Found a reply-servercmd section!");
320*6236dae4SAndroid Build Coastguard Worker           do {
321*6236dae4SAndroid Build Coastguard Worker             rtp_size_err = 0;
322*6236dae4SAndroid Build Coastguard Worker             if(!strncmp(CMD_AUTH_REQUIRED, ptr, strlen(CMD_AUTH_REQUIRED))) {
323*6236dae4SAndroid Build Coastguard Worker               logmsg("instructed to require authorization header");
324*6236dae4SAndroid Build Coastguard Worker               req->auth_req = TRUE;
325*6236dae4SAndroid Build Coastguard Worker             }
326*6236dae4SAndroid Build Coastguard Worker             else if(!strncmp(CMD_IDLE, ptr, strlen(CMD_IDLE))) {
327*6236dae4SAndroid Build Coastguard Worker               logmsg("instructed to idle");
328*6236dae4SAndroid Build Coastguard Worker               req->rcmd = RCMD_IDLE;
329*6236dae4SAndroid Build Coastguard Worker               req->open = TRUE;
330*6236dae4SAndroid Build Coastguard Worker             }
331*6236dae4SAndroid Build Coastguard Worker             else if(!strncmp(CMD_STREAM, ptr, strlen(CMD_STREAM))) {
332*6236dae4SAndroid Build Coastguard Worker               logmsg("instructed to stream");
333*6236dae4SAndroid Build Coastguard Worker               req->rcmd = RCMD_STREAM;
334*6236dae4SAndroid Build Coastguard Worker             }
335*6236dae4SAndroid Build Coastguard Worker             else if(1 == sscanf(ptr, "pipe: %d", &num)) {
336*6236dae4SAndroid Build Coastguard Worker               logmsg("instructed to allow a pipe size of %d", num);
337*6236dae4SAndroid Build Coastguard Worker               if(num < 0)
338*6236dae4SAndroid Build Coastguard Worker                 logmsg("negative pipe size ignored");
339*6236dae4SAndroid Build Coastguard Worker               else if(num > 0)
340*6236dae4SAndroid Build Coastguard Worker                 req->pipe = num-1; /* decrease by one since we don't count the
341*6236dae4SAndroid Build Coastguard Worker                                       first request in this number */
342*6236dae4SAndroid Build Coastguard Worker             }
343*6236dae4SAndroid Build Coastguard Worker             else if(1 == sscanf(ptr, "skip: %d", &num)) {
344*6236dae4SAndroid Build Coastguard Worker               logmsg("instructed to skip this number of bytes %d", num);
345*6236dae4SAndroid Build Coastguard Worker               req->skip = num;
346*6236dae4SAndroid Build Coastguard Worker             }
347*6236dae4SAndroid Build Coastguard Worker             else if(3 <= sscanf(ptr,
348*6236dae4SAndroid Build Coastguard Worker                                 "rtp: part %d channel %d size %d size_err %d",
349*6236dae4SAndroid Build Coastguard Worker                                 &rtp_partno, &rtp_channel, &rtp_size,
350*6236dae4SAndroid Build Coastguard Worker                                 &rtp_size_err)) {
351*6236dae4SAndroid Build Coastguard Worker 
352*6236dae4SAndroid Build Coastguard Worker               if(rtp_partno == req->partno) {
353*6236dae4SAndroid Build Coastguard Worker                 int i = 0;
354*6236dae4SAndroid Build Coastguard Worker                 logmsg("RTP: part %d channel %d size %d size_err %d",
355*6236dae4SAndroid Build Coastguard Worker                        rtp_partno, rtp_channel, rtp_size, rtp_size_err);
356*6236dae4SAndroid Build Coastguard Worker 
357*6236dae4SAndroid Build Coastguard Worker                 /* Make our scratch buffer enough to fit all the
358*6236dae4SAndroid Build Coastguard Worker                  * desired data and one for padding */
359*6236dae4SAndroid Build Coastguard Worker                 rtp_scratch = malloc(rtp_size + 4 + RTP_DATA_SIZE);
360*6236dae4SAndroid Build Coastguard Worker 
361*6236dae4SAndroid Build Coastguard Worker                 /* RTP is signalled with a $ */
362*6236dae4SAndroid Build Coastguard Worker                 rtp_scratch[0] = '$';
363*6236dae4SAndroid Build Coastguard Worker 
364*6236dae4SAndroid Build Coastguard Worker                 /* The channel follows and is one byte */
365*6236dae4SAndroid Build Coastguard Worker                 SET_RTP_PKT_CHN(rtp_scratch, rtp_channel);
366*6236dae4SAndroid Build Coastguard Worker 
367*6236dae4SAndroid Build Coastguard Worker                 /* Length follows and is a two byte short in network order */
368*6236dae4SAndroid Build Coastguard Worker                 SET_RTP_PKT_LEN(rtp_scratch, rtp_size + rtp_size_err);
369*6236dae4SAndroid Build Coastguard Worker 
370*6236dae4SAndroid Build Coastguard Worker                 /* Fill it with junk data */
371*6236dae4SAndroid Build Coastguard Worker                 for(i = 0; i < rtp_size; i += RTP_DATA_SIZE) {
372*6236dae4SAndroid Build Coastguard Worker                   memcpy(rtp_scratch + 4 + i, RTP_DATA, RTP_DATA_SIZE);
373*6236dae4SAndroid Build Coastguard Worker                 }
374*6236dae4SAndroid Build Coastguard Worker 
375*6236dae4SAndroid Build Coastguard Worker                 if(!req->rtp_buffer) {
376*6236dae4SAndroid Build Coastguard Worker                   req->rtp_buffer = rtp_scratch;
377*6236dae4SAndroid Build Coastguard Worker                   req->rtp_buffersize = rtp_size + 4;
378*6236dae4SAndroid Build Coastguard Worker                 }
379*6236dae4SAndroid Build Coastguard Worker                 else {
380*6236dae4SAndroid Build Coastguard Worker                   req->rtp_buffer = realloc(req->rtp_buffer,
381*6236dae4SAndroid Build Coastguard Worker                                             req->rtp_buffersize +
382*6236dae4SAndroid Build Coastguard Worker                                             rtp_size + 4);
383*6236dae4SAndroid Build Coastguard Worker                   memcpy(req->rtp_buffer + req->rtp_buffersize, rtp_scratch,
384*6236dae4SAndroid Build Coastguard Worker                          rtp_size + 4);
385*6236dae4SAndroid Build Coastguard Worker                   req->rtp_buffersize += rtp_size + 4;
386*6236dae4SAndroid Build Coastguard Worker                   free(rtp_scratch);
387*6236dae4SAndroid Build Coastguard Worker                 }
388*6236dae4SAndroid Build Coastguard Worker                 logmsg("rtp_buffersize is %zu, rtp_size is %d.",
389*6236dae4SAndroid Build Coastguard Worker                        req->rtp_buffersize, rtp_size);
390*6236dae4SAndroid Build Coastguard Worker               }
391*6236dae4SAndroid Build Coastguard Worker             }
392*6236dae4SAndroid Build Coastguard Worker             else {
393*6236dae4SAndroid Build Coastguard Worker               logmsg("funny instruction found: %s", ptr);
394*6236dae4SAndroid Build Coastguard Worker             }
395*6236dae4SAndroid Build Coastguard Worker 
396*6236dae4SAndroid Build Coastguard Worker             ptr = strchr(ptr, '\n');
397*6236dae4SAndroid Build Coastguard Worker             if(ptr)
398*6236dae4SAndroid Build Coastguard Worker               ptr++;
399*6236dae4SAndroid Build Coastguard Worker             else
400*6236dae4SAndroid Build Coastguard Worker               ptr = NULL;
401*6236dae4SAndroid Build Coastguard Worker           } while(ptr && *ptr);
402*6236dae4SAndroid Build Coastguard Worker           logmsg("Done parsing server commands");
403*6236dae4SAndroid Build Coastguard Worker         }
404*6236dae4SAndroid Build Coastguard Worker         free(cmd);
405*6236dae4SAndroid Build Coastguard Worker       }
406*6236dae4SAndroid Build Coastguard Worker     }
407*6236dae4SAndroid Build Coastguard Worker     else {
408*6236dae4SAndroid Build Coastguard Worker       if(sscanf(req->reqbuf, "CONNECT %" MAXDOCNAMELEN_TXT "s HTTP/%d.%d",
409*6236dae4SAndroid Build Coastguard Worker                 doc, &prot_major, &prot_minor) == 3) {
410*6236dae4SAndroid Build Coastguard Worker         msnprintf(logbuf, sizeof(logbuf),
411*6236dae4SAndroid Build Coastguard Worker                   "Received a CONNECT %s HTTP/%d.%d request",
412*6236dae4SAndroid Build Coastguard Worker                   doc, prot_major, prot_minor);
413*6236dae4SAndroid Build Coastguard Worker         logmsg("%s", logbuf);
414*6236dae4SAndroid Build Coastguard Worker 
415*6236dae4SAndroid Build Coastguard Worker         if(req->prot_version == 10)
416*6236dae4SAndroid Build Coastguard Worker           req->open = FALSE; /* HTTP 1.0 closes connection by default */
417*6236dae4SAndroid Build Coastguard Worker 
418*6236dae4SAndroid Build Coastguard Worker         if(!strncmp(doc, "bad", 3))
419*6236dae4SAndroid Build Coastguard Worker           /* if the host name starts with bad, we fake an error here */
420*6236dae4SAndroid Build Coastguard Worker           req->testno = DOCNUMBER_BADCONNECT;
421*6236dae4SAndroid Build Coastguard Worker         else if(!strncmp(doc, "test", 4)) {
422*6236dae4SAndroid Build Coastguard Worker           /* if the host name starts with test, the port number used in the
423*6236dae4SAndroid Build Coastguard Worker              CONNECT line will be used as test number! */
424*6236dae4SAndroid Build Coastguard Worker           char *portp = strchr(doc, ':');
425*6236dae4SAndroid Build Coastguard Worker           if(portp && (*(portp + 1) != '\0') && ISDIGIT(*(portp + 1)))
426*6236dae4SAndroid Build Coastguard Worker             req->testno = strtol(portp + 1, NULL, 10);
427*6236dae4SAndroid Build Coastguard Worker           else
428*6236dae4SAndroid Build Coastguard Worker             req->testno = DOCNUMBER_CONNECT;
429*6236dae4SAndroid Build Coastguard Worker         }
430*6236dae4SAndroid Build Coastguard Worker         else
431*6236dae4SAndroid Build Coastguard Worker           req->testno = DOCNUMBER_CONNECT;
432*6236dae4SAndroid Build Coastguard Worker       }
433*6236dae4SAndroid Build Coastguard Worker       else {
434*6236dae4SAndroid Build Coastguard Worker         logmsg("Did not find test number in PATH");
435*6236dae4SAndroid Build Coastguard Worker         req->testno = DOCNUMBER_404;
436*6236dae4SAndroid Build Coastguard Worker       }
437*6236dae4SAndroid Build Coastguard Worker     }
438*6236dae4SAndroid Build Coastguard Worker   }
439*6236dae4SAndroid Build Coastguard Worker 
440*6236dae4SAndroid Build Coastguard Worker   if(!end) {
441*6236dae4SAndroid Build Coastguard Worker     /* we don't have a complete request yet! */
442*6236dae4SAndroid Build Coastguard Worker     logmsg("ProcessRequest returned without a complete request");
443*6236dae4SAndroid Build Coastguard Worker     return 0; /* not complete yet */
444*6236dae4SAndroid Build Coastguard Worker   }
445*6236dae4SAndroid Build Coastguard Worker   logmsg("ProcessRequest found a complete request");
446*6236dae4SAndroid Build Coastguard Worker 
447*6236dae4SAndroid Build Coastguard Worker   if(req->pipe)
448*6236dae4SAndroid Build Coastguard Worker     /* we do have a full set, advance the checkindex to after the end of the
449*6236dae4SAndroid Build Coastguard Worker        headers, for the pipelining case mostly */
450*6236dae4SAndroid Build Coastguard Worker     req->checkindex += (end - line) + strlen(END_OF_HEADERS);
451*6236dae4SAndroid Build Coastguard Worker 
452*6236dae4SAndroid Build Coastguard Worker   /* **** Persistence ****
453*6236dae4SAndroid Build Coastguard Worker    *
454*6236dae4SAndroid Build Coastguard Worker    * If the request is an HTTP/1.0 one, we close the connection unconditionally
455*6236dae4SAndroid Build Coastguard Worker    * when we're done.
456*6236dae4SAndroid Build Coastguard Worker    *
457*6236dae4SAndroid Build Coastguard Worker    * If the request is an HTTP/1.1 one, we MUST check for a "Connection:"
458*6236dae4SAndroid Build Coastguard Worker    * header that might say "close". If it does, we close a connection when
459*6236dae4SAndroid Build Coastguard Worker    * this request is processed. Otherwise, we keep the connection alive for X
460*6236dae4SAndroid Build Coastguard Worker    * seconds.
461*6236dae4SAndroid Build Coastguard Worker    */
462*6236dae4SAndroid Build Coastguard Worker 
463*6236dae4SAndroid Build Coastguard Worker   do {
464*6236dae4SAndroid Build Coastguard Worker     if(got_exit_signal)
465*6236dae4SAndroid Build Coastguard Worker       return 1; /* done */
466*6236dae4SAndroid Build Coastguard Worker 
467*6236dae4SAndroid Build Coastguard Worker     if((req->cl == 0) && strncasecompare("Content-Length:", line, 15)) {
468*6236dae4SAndroid Build Coastguard Worker       /* If we don't ignore content-length, we read it and we read the whole
469*6236dae4SAndroid Build Coastguard Worker          request including the body before we return. If we've been told to
470*6236dae4SAndroid Build Coastguard Worker          ignore the content-length, we will return as soon as all headers
471*6236dae4SAndroid Build Coastguard Worker          have been received */
472*6236dae4SAndroid Build Coastguard Worker       char *endptr;
473*6236dae4SAndroid Build Coastguard Worker       char *ptr = line + 15;
474*6236dae4SAndroid Build Coastguard Worker       unsigned long clen = 0;
475*6236dae4SAndroid Build Coastguard Worker       while(*ptr && ISSPACE(*ptr))
476*6236dae4SAndroid Build Coastguard Worker         ptr++;
477*6236dae4SAndroid Build Coastguard Worker       endptr = ptr;
478*6236dae4SAndroid Build Coastguard Worker       errno = 0;
479*6236dae4SAndroid Build Coastguard Worker       clen = strtoul(ptr, &endptr, 10);
480*6236dae4SAndroid Build Coastguard Worker       if((ptr == endptr) || !ISSPACE(*endptr) || (ERANGE == errno)) {
481*6236dae4SAndroid Build Coastguard Worker         /* this assumes that a zero Content-Length is valid */
482*6236dae4SAndroid Build Coastguard Worker         logmsg("Found invalid Content-Length: (%s) in the request", ptr);
483*6236dae4SAndroid Build Coastguard Worker         req->open = FALSE; /* closes connection */
484*6236dae4SAndroid Build Coastguard Worker         return 1; /* done */
485*6236dae4SAndroid Build Coastguard Worker       }
486*6236dae4SAndroid Build Coastguard Worker       req->cl = clen - req->skip;
487*6236dae4SAndroid Build Coastguard Worker 
488*6236dae4SAndroid Build Coastguard Worker       logmsg("Found Content-Length: %lu in the request", clen);
489*6236dae4SAndroid Build Coastguard Worker       if(req->skip)
490*6236dae4SAndroid Build Coastguard Worker         logmsg("... but will abort after %zu bytes", req->cl);
491*6236dae4SAndroid Build Coastguard Worker       break;
492*6236dae4SAndroid Build Coastguard Worker     }
493*6236dae4SAndroid Build Coastguard Worker     else if(strncasecompare("Transfer-Encoding: chunked", line,
494*6236dae4SAndroid Build Coastguard Worker                             strlen("Transfer-Encoding: chunked"))) {
495*6236dae4SAndroid Build Coastguard Worker       /* chunked data coming in */
496*6236dae4SAndroid Build Coastguard Worker       chunked = TRUE;
497*6236dae4SAndroid Build Coastguard Worker     }
498*6236dae4SAndroid Build Coastguard Worker 
499*6236dae4SAndroid Build Coastguard Worker     if(chunked) {
500*6236dae4SAndroid Build Coastguard Worker       if(strstr(req->reqbuf, "\r\n0\r\n\r\n"))
501*6236dae4SAndroid Build Coastguard Worker         /* end of chunks reached */
502*6236dae4SAndroid Build Coastguard Worker         return 1; /* done */
503*6236dae4SAndroid Build Coastguard Worker       else
504*6236dae4SAndroid Build Coastguard Worker         return 0; /* not done */
505*6236dae4SAndroid Build Coastguard Worker     }
506*6236dae4SAndroid Build Coastguard Worker 
507*6236dae4SAndroid Build Coastguard Worker     line = strchr(line, '\n');
508*6236dae4SAndroid Build Coastguard Worker     if(line)
509*6236dae4SAndroid Build Coastguard Worker       line++;
510*6236dae4SAndroid Build Coastguard Worker 
511*6236dae4SAndroid Build Coastguard Worker   } while(line);
512*6236dae4SAndroid Build Coastguard Worker 
513*6236dae4SAndroid Build Coastguard Worker   if(!req->auth && strstr(req->reqbuf, "Authorization:")) {
514*6236dae4SAndroid Build Coastguard Worker     req->auth = TRUE; /* Authorization: header present! */
515*6236dae4SAndroid Build Coastguard Worker     if(req->auth_req)
516*6236dae4SAndroid Build Coastguard Worker       logmsg("Authorization header found, as required");
517*6236dae4SAndroid Build Coastguard Worker   }
518*6236dae4SAndroid Build Coastguard Worker 
519*6236dae4SAndroid Build Coastguard Worker   if(!req->digest && strstr(req->reqbuf, "Authorization: Digest")) {
520*6236dae4SAndroid Build Coastguard Worker     /* If the client is passing this Digest-header, we set the part number
521*6236dae4SAndroid Build Coastguard Worker        to 1000. Not only to spice up the complexity of this, but to make
522*6236dae4SAndroid Build Coastguard Worker        Digest stuff to work in the test suite. */
523*6236dae4SAndroid Build Coastguard Worker     req->partno += 1000;
524*6236dae4SAndroid Build Coastguard Worker     req->digest = TRUE; /* header found */
525*6236dae4SAndroid Build Coastguard Worker     logmsg("Received Digest request, sending back data %ld", req->partno);
526*6236dae4SAndroid Build Coastguard Worker   }
527*6236dae4SAndroid Build Coastguard Worker   else if(!req->ntlm &&
528*6236dae4SAndroid Build Coastguard Worker           strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAD")) {
529*6236dae4SAndroid Build Coastguard Worker     /* If the client is passing this type-3 NTLM header */
530*6236dae4SAndroid Build Coastguard Worker     req->partno += 1002;
531*6236dae4SAndroid Build Coastguard Worker     req->ntlm = TRUE; /* NTLM found */
532*6236dae4SAndroid Build Coastguard Worker     logmsg("Received NTLM type-3, sending back data %ld", req->partno);
533*6236dae4SAndroid Build Coastguard Worker     if(req->cl) {
534*6236dae4SAndroid Build Coastguard Worker       logmsg("  Expecting %zu POSTed bytes", req->cl);
535*6236dae4SAndroid Build Coastguard Worker     }
536*6236dae4SAndroid Build Coastguard Worker   }
537*6236dae4SAndroid Build Coastguard Worker   else if(!req->ntlm &&
538*6236dae4SAndroid Build Coastguard Worker           strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAB")) {
539*6236dae4SAndroid Build Coastguard Worker     /* If the client is passing this type-1 NTLM header */
540*6236dae4SAndroid Build Coastguard Worker     req->partno += 1001;
541*6236dae4SAndroid Build Coastguard Worker     req->ntlm = TRUE; /* NTLM found */
542*6236dae4SAndroid Build Coastguard Worker     logmsg("Received NTLM type-1, sending back data %ld", req->partno);
543*6236dae4SAndroid Build Coastguard Worker   }
544*6236dae4SAndroid Build Coastguard Worker   else if((req->partno >= 1000) &&
545*6236dae4SAndroid Build Coastguard Worker           strstr(req->reqbuf, "Authorization: Basic")) {
546*6236dae4SAndroid Build Coastguard Worker     /* If the client is passing this Basic-header and the part number is
547*6236dae4SAndroid Build Coastguard Worker        already >=1000, we add 1 to the part number.  This allows simple Basic
548*6236dae4SAndroid Build Coastguard Worker        authentication negotiation to work in the test suite. */
549*6236dae4SAndroid Build Coastguard Worker     req->partno += 1;
550*6236dae4SAndroid Build Coastguard Worker     logmsg("Received Basic request, sending back data %ld", req->partno);
551*6236dae4SAndroid Build Coastguard Worker   }
552*6236dae4SAndroid Build Coastguard Worker   if(strstr(req->reqbuf, "Connection: close"))
553*6236dae4SAndroid Build Coastguard Worker     req->open = FALSE; /* close connection after this request */
554*6236dae4SAndroid Build Coastguard Worker 
555*6236dae4SAndroid Build Coastguard Worker   if(!req->pipe &&
556*6236dae4SAndroid Build Coastguard Worker      req->open &&
557*6236dae4SAndroid Build Coastguard Worker      req->prot_version >= 11 &&
558*6236dae4SAndroid Build Coastguard Worker      req->reqbuf + req->offset > end + strlen(END_OF_HEADERS) &&
559*6236dae4SAndroid Build Coastguard Worker      (!strncmp(req->reqbuf, "GET", strlen("GET")) ||
560*6236dae4SAndroid Build Coastguard Worker       !strncmp(req->reqbuf, "HEAD", strlen("HEAD")))) {
561*6236dae4SAndroid Build Coastguard Worker     /* If we have a persistent connection, HTTP version >= 1.1
562*6236dae4SAndroid Build Coastguard Worker        and GET/HEAD request, enable pipelining. */
563*6236dae4SAndroid Build Coastguard Worker     req->checkindex = (end - req->reqbuf) + strlen(END_OF_HEADERS);
564*6236dae4SAndroid Build Coastguard Worker     req->pipelining = TRUE;
565*6236dae4SAndroid Build Coastguard Worker   }
566*6236dae4SAndroid Build Coastguard Worker 
567*6236dae4SAndroid Build Coastguard Worker   while(req->pipe) {
568*6236dae4SAndroid Build Coastguard Worker     if(got_exit_signal)
569*6236dae4SAndroid Build Coastguard Worker       return 1; /* done */
570*6236dae4SAndroid Build Coastguard Worker     /* scan for more header ends within this chunk */
571*6236dae4SAndroid Build Coastguard Worker     line = &req->reqbuf[req->checkindex];
572*6236dae4SAndroid Build Coastguard Worker     end = strstr(line, END_OF_HEADERS);
573*6236dae4SAndroid Build Coastguard Worker     if(!end)
574*6236dae4SAndroid Build Coastguard Worker       break;
575*6236dae4SAndroid Build Coastguard Worker     req->checkindex += (end - line) + strlen(END_OF_HEADERS);
576*6236dae4SAndroid Build Coastguard Worker     req->pipe--;
577*6236dae4SAndroid Build Coastguard Worker   }
578*6236dae4SAndroid Build Coastguard Worker 
579*6236dae4SAndroid Build Coastguard Worker   /* If authentication is required and no auth was provided, end now. This
580*6236dae4SAndroid Build Coastguard Worker      makes the server NOT wait for PUT/POST data and you can then make the
581*6236dae4SAndroid Build Coastguard Worker      test case send a rejection before any such data has been sent. Test case
582*6236dae4SAndroid Build Coastguard Worker      154 uses this.*/
583*6236dae4SAndroid Build Coastguard Worker   if(req->auth_req && !req->auth)
584*6236dae4SAndroid Build Coastguard Worker     return 1; /* done */
585*6236dae4SAndroid Build Coastguard Worker 
586*6236dae4SAndroid Build Coastguard Worker   if(req->cl > 0) {
587*6236dae4SAndroid Build Coastguard Worker     if(req->cl <= req->offset - (end - req->reqbuf) - strlen(END_OF_HEADERS))
588*6236dae4SAndroid Build Coastguard Worker       return 1; /* done */
589*6236dae4SAndroid Build Coastguard Worker     else
590*6236dae4SAndroid Build Coastguard Worker       return 0; /* not complete yet */
591*6236dae4SAndroid Build Coastguard Worker   }
592*6236dae4SAndroid Build Coastguard Worker 
593*6236dae4SAndroid Build Coastguard Worker   return 1; /* done */
594*6236dae4SAndroid Build Coastguard Worker }
595*6236dae4SAndroid Build Coastguard Worker 
596*6236dae4SAndroid Build Coastguard Worker /* store the entire request in a file */
storerequest(char * reqbuf,size_t totalsize)597*6236dae4SAndroid Build Coastguard Worker static void storerequest(char *reqbuf, size_t totalsize)
598*6236dae4SAndroid Build Coastguard Worker {
599*6236dae4SAndroid Build Coastguard Worker   int res;
600*6236dae4SAndroid Build Coastguard Worker   int error = 0;
601*6236dae4SAndroid Build Coastguard Worker   size_t written;
602*6236dae4SAndroid Build Coastguard Worker   size_t writeleft;
603*6236dae4SAndroid Build Coastguard Worker   FILE *dump;
604*6236dae4SAndroid Build Coastguard Worker   char dumpfile[256];
605*6236dae4SAndroid Build Coastguard Worker 
606*6236dae4SAndroid Build Coastguard Worker   msnprintf(dumpfile, sizeof(dumpfile), "%s/%s", logdir, REQUEST_DUMP);
607*6236dae4SAndroid Build Coastguard Worker 
608*6236dae4SAndroid Build Coastguard Worker   if(!reqbuf)
609*6236dae4SAndroid Build Coastguard Worker     return;
610*6236dae4SAndroid Build Coastguard Worker   if(totalsize == 0)
611*6236dae4SAndroid Build Coastguard Worker     return;
612*6236dae4SAndroid Build Coastguard Worker 
613*6236dae4SAndroid Build Coastguard Worker   do {
614*6236dae4SAndroid Build Coastguard Worker     dump = fopen(dumpfile, "ab");
615*6236dae4SAndroid Build Coastguard Worker   } while(!dump && ((error = errno) == EINTR));
616*6236dae4SAndroid Build Coastguard Worker   if(!dump) {
617*6236dae4SAndroid Build Coastguard Worker     logmsg("Error opening file %s error: %d %s",
618*6236dae4SAndroid Build Coastguard Worker            dumpfile, error, strerror(error));
619*6236dae4SAndroid Build Coastguard Worker     logmsg("Failed to write request input to %s", dumpfile);
620*6236dae4SAndroid Build Coastguard Worker     return;
621*6236dae4SAndroid Build Coastguard Worker   }
622*6236dae4SAndroid Build Coastguard Worker 
623*6236dae4SAndroid Build Coastguard Worker   writeleft = totalsize;
624*6236dae4SAndroid Build Coastguard Worker   do {
625*6236dae4SAndroid Build Coastguard Worker     written = fwrite(&reqbuf[totalsize-writeleft],
626*6236dae4SAndroid Build Coastguard Worker                      1, writeleft, dump);
627*6236dae4SAndroid Build Coastguard Worker     if(got_exit_signal)
628*6236dae4SAndroid Build Coastguard Worker       goto storerequest_cleanup;
629*6236dae4SAndroid Build Coastguard Worker     if(written > 0)
630*6236dae4SAndroid Build Coastguard Worker       writeleft -= written;
631*6236dae4SAndroid Build Coastguard Worker   } while((writeleft > 0) && ((error = errno) == EINTR));
632*6236dae4SAndroid Build Coastguard Worker 
633*6236dae4SAndroid Build Coastguard Worker   if(writeleft == 0)
634*6236dae4SAndroid Build Coastguard Worker     logmsg("Wrote request (%zu bytes) input to %s", totalsize, dumpfile);
635*6236dae4SAndroid Build Coastguard Worker   else if(writeleft > 0) {
636*6236dae4SAndroid Build Coastguard Worker     logmsg("Error writing file %s error: %d %s",
637*6236dae4SAndroid Build Coastguard Worker            dumpfile, error, strerror(error));
638*6236dae4SAndroid Build Coastguard Worker     logmsg("Wrote only (%zu bytes) of (%zu bytes) request input to %s",
639*6236dae4SAndroid Build Coastguard Worker            totalsize-writeleft, totalsize, dumpfile);
640*6236dae4SAndroid Build Coastguard Worker   }
641*6236dae4SAndroid Build Coastguard Worker 
642*6236dae4SAndroid Build Coastguard Worker storerequest_cleanup:
643*6236dae4SAndroid Build Coastguard Worker 
644*6236dae4SAndroid Build Coastguard Worker   do {
645*6236dae4SAndroid Build Coastguard Worker     res = fclose(dump);
646*6236dae4SAndroid Build Coastguard Worker   } while(res && ((error = errno) == EINTR));
647*6236dae4SAndroid Build Coastguard Worker   if(res)
648*6236dae4SAndroid Build Coastguard Worker     logmsg("Error closing file %s error: %d %s",
649*6236dae4SAndroid Build Coastguard Worker            dumpfile, error, strerror(error));
650*6236dae4SAndroid Build Coastguard Worker }
651*6236dae4SAndroid Build Coastguard Worker 
652*6236dae4SAndroid Build Coastguard Worker /* return 0 on success, non-zero on failure */
get_request(curl_socket_t sock,struct httprequest * req)653*6236dae4SAndroid Build Coastguard Worker static int get_request(curl_socket_t sock, struct httprequest *req)
654*6236dae4SAndroid Build Coastguard Worker {
655*6236dae4SAndroid Build Coastguard Worker   int error;
656*6236dae4SAndroid Build Coastguard Worker   int fail = 0;
657*6236dae4SAndroid Build Coastguard Worker   int done_processing = 0;
658*6236dae4SAndroid Build Coastguard Worker   char *reqbuf = req->reqbuf;
659*6236dae4SAndroid Build Coastguard Worker   ssize_t got = 0;
660*6236dae4SAndroid Build Coastguard Worker 
661*6236dae4SAndroid Build Coastguard Worker   char *pipereq = NULL;
662*6236dae4SAndroid Build Coastguard Worker   size_t pipereq_length = 0;
663*6236dae4SAndroid Build Coastguard Worker 
664*6236dae4SAndroid Build Coastguard Worker   if(req->pipelining) {
665*6236dae4SAndroid Build Coastguard Worker     pipereq = reqbuf + req->checkindex;
666*6236dae4SAndroid Build Coastguard Worker     pipereq_length = req->offset - req->checkindex;
667*6236dae4SAndroid Build Coastguard Worker   }
668*6236dae4SAndroid Build Coastguard Worker 
669*6236dae4SAndroid Build Coastguard Worker   /*** Init the httprequest structure properly for the upcoming request ***/
670*6236dae4SAndroid Build Coastguard Worker 
671*6236dae4SAndroid Build Coastguard Worker   req->checkindex = 0;
672*6236dae4SAndroid Build Coastguard Worker   req->offset = 0;
673*6236dae4SAndroid Build Coastguard Worker   req->testno = DOCNUMBER_NOTHING;
674*6236dae4SAndroid Build Coastguard Worker   req->partno = 0;
675*6236dae4SAndroid Build Coastguard Worker   req->open = TRUE;
676*6236dae4SAndroid Build Coastguard Worker   req->auth_req = FALSE;
677*6236dae4SAndroid Build Coastguard Worker   req->auth = FALSE;
678*6236dae4SAndroid Build Coastguard Worker   req->cl = 0;
679*6236dae4SAndroid Build Coastguard Worker   req->digest = FALSE;
680*6236dae4SAndroid Build Coastguard Worker   req->ntlm = FALSE;
681*6236dae4SAndroid Build Coastguard Worker   req->pipe = 0;
682*6236dae4SAndroid Build Coastguard Worker   req->skip = 0;
683*6236dae4SAndroid Build Coastguard Worker   req->rcmd = RCMD_NORMALREQ;
684*6236dae4SAndroid Build Coastguard Worker   req->protocol = RPROT_NONE;
685*6236dae4SAndroid Build Coastguard Worker   req->prot_version = 0;
686*6236dae4SAndroid Build Coastguard Worker   req->pipelining = FALSE;
687*6236dae4SAndroid Build Coastguard Worker   req->rtp_buffer = NULL;
688*6236dae4SAndroid Build Coastguard Worker   req->rtp_buffersize = 0;
689*6236dae4SAndroid Build Coastguard Worker 
690*6236dae4SAndroid Build Coastguard Worker   /*** end of httprequest init ***/
691*6236dae4SAndroid Build Coastguard Worker 
692*6236dae4SAndroid Build Coastguard Worker   while(!done_processing && (req->offset < REQBUFSIZ-1)) {
693*6236dae4SAndroid Build Coastguard Worker     if(pipereq_length && pipereq) {
694*6236dae4SAndroid Build Coastguard Worker       memmove(reqbuf, pipereq, pipereq_length);
695*6236dae4SAndroid Build Coastguard Worker       got = curlx_uztosz(pipereq_length);
696*6236dae4SAndroid Build Coastguard Worker       pipereq_length = 0;
697*6236dae4SAndroid Build Coastguard Worker     }
698*6236dae4SAndroid Build Coastguard Worker     else {
699*6236dae4SAndroid Build Coastguard Worker       if(req->skip)
700*6236dae4SAndroid Build Coastguard Worker         /* we are instructed to not read the entire thing, so we make sure to
701*6236dae4SAndroid Build Coastguard Worker            only read what we're supposed to and NOT read the enire thing the
702*6236dae4SAndroid Build Coastguard Worker            client wants to send! */
703*6236dae4SAndroid Build Coastguard Worker         got = sread(sock, reqbuf + req->offset, req->cl);
704*6236dae4SAndroid Build Coastguard Worker       else
705*6236dae4SAndroid Build Coastguard Worker         got = sread(sock, reqbuf + req->offset, REQBUFSIZ-1 - req->offset);
706*6236dae4SAndroid Build Coastguard Worker     }
707*6236dae4SAndroid Build Coastguard Worker     if(got_exit_signal)
708*6236dae4SAndroid Build Coastguard Worker       return 1;
709*6236dae4SAndroid Build Coastguard Worker     if(got == 0) {
710*6236dae4SAndroid Build Coastguard Worker       logmsg("Connection closed by client");
711*6236dae4SAndroid Build Coastguard Worker       fail = 1;
712*6236dae4SAndroid Build Coastguard Worker     }
713*6236dae4SAndroid Build Coastguard Worker     else if(got < 0) {
714*6236dae4SAndroid Build Coastguard Worker       error = SOCKERRNO;
715*6236dae4SAndroid Build Coastguard Worker       logmsg("recv() returned error: (%d) %s", error, sstrerror(error));
716*6236dae4SAndroid Build Coastguard Worker       fail = 1;
717*6236dae4SAndroid Build Coastguard Worker     }
718*6236dae4SAndroid Build Coastguard Worker     if(fail) {
719*6236dae4SAndroid Build Coastguard Worker       /* dump the request received so far to the external file */
720*6236dae4SAndroid Build Coastguard Worker       reqbuf[req->offset] = '\0';
721*6236dae4SAndroid Build Coastguard Worker       storerequest(reqbuf, req->offset);
722*6236dae4SAndroid Build Coastguard Worker       return 1;
723*6236dae4SAndroid Build Coastguard Worker     }
724*6236dae4SAndroid Build Coastguard Worker 
725*6236dae4SAndroid Build Coastguard Worker     logmsg("Read %zd bytes", got);
726*6236dae4SAndroid Build Coastguard Worker 
727*6236dae4SAndroid Build Coastguard Worker     req->offset += (size_t)got;
728*6236dae4SAndroid Build Coastguard Worker     reqbuf[req->offset] = '\0';
729*6236dae4SAndroid Build Coastguard Worker 
730*6236dae4SAndroid Build Coastguard Worker     done_processing = ProcessRequest(req);
731*6236dae4SAndroid Build Coastguard Worker     if(got_exit_signal)
732*6236dae4SAndroid Build Coastguard Worker       return 1;
733*6236dae4SAndroid Build Coastguard Worker     if(done_processing && req->pipe) {
734*6236dae4SAndroid Build Coastguard Worker       logmsg("Waiting for another piped request");
735*6236dae4SAndroid Build Coastguard Worker       done_processing = 0;
736*6236dae4SAndroid Build Coastguard Worker       req->pipe--;
737*6236dae4SAndroid Build Coastguard Worker     }
738*6236dae4SAndroid Build Coastguard Worker   }
739*6236dae4SAndroid Build Coastguard Worker 
740*6236dae4SAndroid Build Coastguard Worker   if((req->offset == REQBUFSIZ-1) && (got > 0)) {
741*6236dae4SAndroid Build Coastguard Worker     logmsg("Request would overflow buffer, closing connection");
742*6236dae4SAndroid Build Coastguard Worker     /* dump request received so far to external file anyway */
743*6236dae4SAndroid Build Coastguard Worker     reqbuf[REQBUFSIZ-1] = '\0';
744*6236dae4SAndroid Build Coastguard Worker     fail = 1;
745*6236dae4SAndroid Build Coastguard Worker   }
746*6236dae4SAndroid Build Coastguard Worker   else if(req->offset > REQBUFSIZ-1) {
747*6236dae4SAndroid Build Coastguard Worker     logmsg("Request buffer overflow, closing connection");
748*6236dae4SAndroid Build Coastguard Worker     /* dump request received so far to external file anyway */
749*6236dae4SAndroid Build Coastguard Worker     reqbuf[REQBUFSIZ-1] = '\0';
750*6236dae4SAndroid Build Coastguard Worker     fail = 1;
751*6236dae4SAndroid Build Coastguard Worker   }
752*6236dae4SAndroid Build Coastguard Worker   else
753*6236dae4SAndroid Build Coastguard Worker     reqbuf[req->offset] = '\0';
754*6236dae4SAndroid Build Coastguard Worker 
755*6236dae4SAndroid Build Coastguard Worker   /* dump the request to an external file */
756*6236dae4SAndroid Build Coastguard Worker   storerequest(reqbuf, req->pipelining ? req->checkindex : req->offset);
757*6236dae4SAndroid Build Coastguard Worker   if(got_exit_signal)
758*6236dae4SAndroid Build Coastguard Worker     return 1;
759*6236dae4SAndroid Build Coastguard Worker 
760*6236dae4SAndroid Build Coastguard Worker   return fail; /* return 0 on success */
761*6236dae4SAndroid Build Coastguard Worker }
762*6236dae4SAndroid Build Coastguard Worker 
763*6236dae4SAndroid Build Coastguard Worker /* returns -1 on failure */
send_doc(curl_socket_t sock,struct httprequest * req)764*6236dae4SAndroid Build Coastguard Worker static int send_doc(curl_socket_t sock, struct httprequest *req)
765*6236dae4SAndroid Build Coastguard Worker {
766*6236dae4SAndroid Build Coastguard Worker   ssize_t written;
767*6236dae4SAndroid Build Coastguard Worker   size_t count;
768*6236dae4SAndroid Build Coastguard Worker   const char *buffer;
769*6236dae4SAndroid Build Coastguard Worker   char *ptr = NULL;
770*6236dae4SAndroid Build Coastguard Worker   char *cmd = NULL;
771*6236dae4SAndroid Build Coastguard Worker   size_t cmdsize = 0;
772*6236dae4SAndroid Build Coastguard Worker   FILE *dump;
773*6236dae4SAndroid Build Coastguard Worker   bool persistent = TRUE;
774*6236dae4SAndroid Build Coastguard Worker   bool sendfailure = FALSE;
775*6236dae4SAndroid Build Coastguard Worker   size_t responsesize;
776*6236dae4SAndroid Build Coastguard Worker   int error = 0;
777*6236dae4SAndroid Build Coastguard Worker   int res;
778*6236dae4SAndroid Build Coastguard Worker   static char weare[256];
779*6236dae4SAndroid Build Coastguard Worker   char responsedump[256];
780*6236dae4SAndroid Build Coastguard Worker 
781*6236dae4SAndroid Build Coastguard Worker   msnprintf(responsedump, sizeof(responsedump), "%s/%s",
782*6236dae4SAndroid Build Coastguard Worker             logdir, RESPONSE_DUMP);
783*6236dae4SAndroid Build Coastguard Worker 
784*6236dae4SAndroid Build Coastguard Worker   logmsg("Send response number %ld part %ld", req->testno, req->partno);
785*6236dae4SAndroid Build Coastguard Worker 
786*6236dae4SAndroid Build Coastguard Worker   switch(req->rcmd) {
787*6236dae4SAndroid Build Coastguard Worker   default:
788*6236dae4SAndroid Build Coastguard Worker   case RCMD_NORMALREQ:
789*6236dae4SAndroid Build Coastguard Worker     break; /* continue with business as usual */
790*6236dae4SAndroid Build Coastguard Worker   case RCMD_STREAM:
791*6236dae4SAndroid Build Coastguard Worker #define STREAMTHIS "a string to stream 01234567890\n"
792*6236dae4SAndroid Build Coastguard Worker     count = strlen(STREAMTHIS);
793*6236dae4SAndroid Build Coastguard Worker     for(;;) {
794*6236dae4SAndroid Build Coastguard Worker       written = swrite(sock, STREAMTHIS, count);
795*6236dae4SAndroid Build Coastguard Worker       if(got_exit_signal)
796*6236dae4SAndroid Build Coastguard Worker         return -1;
797*6236dae4SAndroid Build Coastguard Worker       if(written != (ssize_t)count) {
798*6236dae4SAndroid Build Coastguard Worker         logmsg("Stopped streaming");
799*6236dae4SAndroid Build Coastguard Worker         break;
800*6236dae4SAndroid Build Coastguard Worker       }
801*6236dae4SAndroid Build Coastguard Worker     }
802*6236dae4SAndroid Build Coastguard Worker     return -1;
803*6236dae4SAndroid Build Coastguard Worker   case RCMD_IDLE:
804*6236dae4SAndroid Build Coastguard Worker     /* Do nothing. Sit idle. Pretend it rains. */
805*6236dae4SAndroid Build Coastguard Worker     return 0;
806*6236dae4SAndroid Build Coastguard Worker   }
807*6236dae4SAndroid Build Coastguard Worker 
808*6236dae4SAndroid Build Coastguard Worker   req->open = FALSE;
809*6236dae4SAndroid Build Coastguard Worker 
810*6236dae4SAndroid Build Coastguard Worker   if(req->testno < 0) {
811*6236dae4SAndroid Build Coastguard Worker     size_t msglen;
812*6236dae4SAndroid Build Coastguard Worker     char msgbuf[64];
813*6236dae4SAndroid Build Coastguard Worker 
814*6236dae4SAndroid Build Coastguard Worker     switch(req->testno) {
815*6236dae4SAndroid Build Coastguard Worker     case DOCNUMBER_QUIT:
816*6236dae4SAndroid Build Coastguard Worker       logmsg("Replying to QUIT");
817*6236dae4SAndroid Build Coastguard Worker       buffer = docquit;
818*6236dae4SAndroid Build Coastguard Worker       break;
819*6236dae4SAndroid Build Coastguard Worker     case DOCNUMBER_WERULEZ:
820*6236dae4SAndroid Build Coastguard Worker       /* we got a "friends?" question, reply back that we sure are */
821*6236dae4SAndroid Build Coastguard Worker       logmsg("Identifying ourselves as friends");
822*6236dae4SAndroid Build Coastguard Worker       msnprintf(msgbuf, sizeof(msgbuf), "RTSP_SERVER WE ROOLZ: %"
823*6236dae4SAndroid Build Coastguard Worker                 CURL_FORMAT_CURL_OFF_T "\r\n", our_getpid());
824*6236dae4SAndroid Build Coastguard Worker       msglen = strlen(msgbuf);
825*6236dae4SAndroid Build Coastguard Worker       msnprintf(weare, sizeof(weare),
826*6236dae4SAndroid Build Coastguard Worker                 "HTTP/1.1 200 OK\r\nContent-Length: %zu\r\n\r\n%s",
827*6236dae4SAndroid Build Coastguard Worker                 msglen, msgbuf);
828*6236dae4SAndroid Build Coastguard Worker       buffer = weare;
829*6236dae4SAndroid Build Coastguard Worker       break;
830*6236dae4SAndroid Build Coastguard Worker     case DOCNUMBER_INTERNAL:
831*6236dae4SAndroid Build Coastguard Worker       logmsg("Bailing out due to internal error");
832*6236dae4SAndroid Build Coastguard Worker       return -1;
833*6236dae4SAndroid Build Coastguard Worker     case DOCNUMBER_CONNECT:
834*6236dae4SAndroid Build Coastguard Worker       logmsg("Replying to CONNECT");
835*6236dae4SAndroid Build Coastguard Worker       buffer = docconnect;
836*6236dae4SAndroid Build Coastguard Worker       break;
837*6236dae4SAndroid Build Coastguard Worker     case DOCNUMBER_BADCONNECT:
838*6236dae4SAndroid Build Coastguard Worker       logmsg("Replying to a bad CONNECT");
839*6236dae4SAndroid Build Coastguard Worker       buffer = docbadconnect;
840*6236dae4SAndroid Build Coastguard Worker       break;
841*6236dae4SAndroid Build Coastguard Worker     case DOCNUMBER_404:
842*6236dae4SAndroid Build Coastguard Worker     default:
843*6236dae4SAndroid Build Coastguard Worker       logmsg("Replying to with a 404");
844*6236dae4SAndroid Build Coastguard Worker       if(req->protocol == RPROT_HTTP) {
845*6236dae4SAndroid Build Coastguard Worker         buffer = doc404_HTTP;
846*6236dae4SAndroid Build Coastguard Worker       }
847*6236dae4SAndroid Build Coastguard Worker       else {
848*6236dae4SAndroid Build Coastguard Worker         buffer = doc404_RTSP;
849*6236dae4SAndroid Build Coastguard Worker       }
850*6236dae4SAndroid Build Coastguard Worker       break;
851*6236dae4SAndroid Build Coastguard Worker     }
852*6236dae4SAndroid Build Coastguard Worker 
853*6236dae4SAndroid Build Coastguard Worker     count = strlen(buffer);
854*6236dae4SAndroid Build Coastguard Worker   }
855*6236dae4SAndroid Build Coastguard Worker   else {
856*6236dae4SAndroid Build Coastguard Worker     FILE *stream = test2fopen(req->testno, logdir);
857*6236dae4SAndroid Build Coastguard Worker     char partbuf[80]="data";
858*6236dae4SAndroid Build Coastguard Worker     if(0 != req->partno)
859*6236dae4SAndroid Build Coastguard Worker       msnprintf(partbuf, sizeof(partbuf), "data%ld", req->partno);
860*6236dae4SAndroid Build Coastguard Worker     if(!stream) {
861*6236dae4SAndroid Build Coastguard Worker       error = errno;
862*6236dae4SAndroid Build Coastguard Worker       logmsg("fopen() failed with error: %d %s", error, strerror(error));
863*6236dae4SAndroid Build Coastguard Worker       logmsg("Couldn't open test file");
864*6236dae4SAndroid Build Coastguard Worker       return 0;
865*6236dae4SAndroid Build Coastguard Worker     }
866*6236dae4SAndroid Build Coastguard Worker     else {
867*6236dae4SAndroid Build Coastguard Worker       error = getpart(&ptr, &count, "reply", partbuf, stream);
868*6236dae4SAndroid Build Coastguard Worker       fclose(stream);
869*6236dae4SAndroid Build Coastguard Worker       if(error) {
870*6236dae4SAndroid Build Coastguard Worker         logmsg("getpart() failed with error: %d", error);
871*6236dae4SAndroid Build Coastguard Worker         return 0;
872*6236dae4SAndroid Build Coastguard Worker       }
873*6236dae4SAndroid Build Coastguard Worker       buffer = ptr;
874*6236dae4SAndroid Build Coastguard Worker     }
875*6236dae4SAndroid Build Coastguard Worker 
876*6236dae4SAndroid Build Coastguard Worker     if(got_exit_signal) {
877*6236dae4SAndroid Build Coastguard Worker       free(ptr);
878*6236dae4SAndroid Build Coastguard Worker       return -1;
879*6236dae4SAndroid Build Coastguard Worker     }
880*6236dae4SAndroid Build Coastguard Worker 
881*6236dae4SAndroid Build Coastguard Worker     /* re-open the same file again */
882*6236dae4SAndroid Build Coastguard Worker     stream = test2fopen(req->testno, logdir);
883*6236dae4SAndroid Build Coastguard Worker     if(!stream) {
884*6236dae4SAndroid Build Coastguard Worker       error = errno;
885*6236dae4SAndroid Build Coastguard Worker       logmsg("fopen() failed with error: %d %s", error, strerror(error));
886*6236dae4SAndroid Build Coastguard Worker       logmsg("Couldn't open test file");
887*6236dae4SAndroid Build Coastguard Worker       free(ptr);
888*6236dae4SAndroid Build Coastguard Worker       return 0;
889*6236dae4SAndroid Build Coastguard Worker     }
890*6236dae4SAndroid Build Coastguard Worker     else {
891*6236dae4SAndroid Build Coastguard Worker       /* get the custom server control "commands" */
892*6236dae4SAndroid Build Coastguard Worker       error = getpart(&cmd, &cmdsize, "reply", "postcmd", stream);
893*6236dae4SAndroid Build Coastguard Worker       fclose(stream);
894*6236dae4SAndroid Build Coastguard Worker       if(error) {
895*6236dae4SAndroid Build Coastguard Worker         logmsg("getpart() failed with error: %d", error);
896*6236dae4SAndroid Build Coastguard Worker         free(ptr);
897*6236dae4SAndroid Build Coastguard Worker         return 0;
898*6236dae4SAndroid Build Coastguard Worker       }
899*6236dae4SAndroid Build Coastguard Worker     }
900*6236dae4SAndroid Build Coastguard Worker   }
901*6236dae4SAndroid Build Coastguard Worker 
902*6236dae4SAndroid Build Coastguard Worker   if(got_exit_signal) {
903*6236dae4SAndroid Build Coastguard Worker     free(ptr);
904*6236dae4SAndroid Build Coastguard Worker     free(cmd);
905*6236dae4SAndroid Build Coastguard Worker     return -1;
906*6236dae4SAndroid Build Coastguard Worker   }
907*6236dae4SAndroid Build Coastguard Worker 
908*6236dae4SAndroid Build Coastguard Worker   /* If the word 'swsclose' is present anywhere in the reply chunk, the
909*6236dae4SAndroid Build Coastguard Worker      connection will be closed after the data has been sent to the requesting
910*6236dae4SAndroid Build Coastguard Worker      client... */
911*6236dae4SAndroid Build Coastguard Worker   if(strstr(buffer, "swsclose") || !count) {
912*6236dae4SAndroid Build Coastguard Worker     persistent = FALSE;
913*6236dae4SAndroid Build Coastguard Worker     logmsg("connection close instruction \"swsclose\" found in response");
914*6236dae4SAndroid Build Coastguard Worker   }
915*6236dae4SAndroid Build Coastguard Worker   if(strstr(buffer, "swsbounce")) {
916*6236dae4SAndroid Build Coastguard Worker     prevbounce = TRUE;
917*6236dae4SAndroid Build Coastguard Worker     logmsg("enable \"swsbounce\" in the next request");
918*6236dae4SAndroid Build Coastguard Worker   }
919*6236dae4SAndroid Build Coastguard Worker   else
920*6236dae4SAndroid Build Coastguard Worker     prevbounce = FALSE;
921*6236dae4SAndroid Build Coastguard Worker 
922*6236dae4SAndroid Build Coastguard Worker   dump = fopen(responsedump, "ab");
923*6236dae4SAndroid Build Coastguard Worker   if(!dump) {
924*6236dae4SAndroid Build Coastguard Worker     error = errno;
925*6236dae4SAndroid Build Coastguard Worker     logmsg("fopen() failed with error: %d %s", error, strerror(error));
926*6236dae4SAndroid Build Coastguard Worker     logmsg("Error opening file: %s", responsedump);
927*6236dae4SAndroid Build Coastguard Worker     logmsg("couldn't create logfile: %s", responsedump);
928*6236dae4SAndroid Build Coastguard Worker     free(ptr);
929*6236dae4SAndroid Build Coastguard Worker     free(cmd);
930*6236dae4SAndroid Build Coastguard Worker     return -1;
931*6236dae4SAndroid Build Coastguard Worker   }
932*6236dae4SAndroid Build Coastguard Worker 
933*6236dae4SAndroid Build Coastguard Worker   responsesize = count;
934*6236dae4SAndroid Build Coastguard Worker   do {
935*6236dae4SAndroid Build Coastguard Worker     /* Ok, we send no more than 200 bytes at a time, just to make sure that
936*6236dae4SAndroid Build Coastguard Worker        larger chunks are split up so that the client will need to do multiple
937*6236dae4SAndroid Build Coastguard Worker        recv() calls to get it and thus we exercise that code better */
938*6236dae4SAndroid Build Coastguard Worker     size_t num = count;
939*6236dae4SAndroid Build Coastguard Worker     if(num > 200)
940*6236dae4SAndroid Build Coastguard Worker       num = 200;
941*6236dae4SAndroid Build Coastguard Worker     written = swrite(sock, buffer, num);
942*6236dae4SAndroid Build Coastguard Worker     if(written < 0) {
943*6236dae4SAndroid Build Coastguard Worker       sendfailure = TRUE;
944*6236dae4SAndroid Build Coastguard Worker       break;
945*6236dae4SAndroid Build Coastguard Worker     }
946*6236dae4SAndroid Build Coastguard Worker     else {
947*6236dae4SAndroid Build Coastguard Worker       logmsg("Sent off %zd bytes", written);
948*6236dae4SAndroid Build Coastguard Worker     }
949*6236dae4SAndroid Build Coastguard Worker     /* write to file as well */
950*6236dae4SAndroid Build Coastguard Worker     fwrite(buffer, 1, (size_t)written, dump);
951*6236dae4SAndroid Build Coastguard Worker     if(got_exit_signal)
952*6236dae4SAndroid Build Coastguard Worker       break;
953*6236dae4SAndroid Build Coastguard Worker 
954*6236dae4SAndroid Build Coastguard Worker     count -= written;
955*6236dae4SAndroid Build Coastguard Worker     buffer += written;
956*6236dae4SAndroid Build Coastguard Worker   } while(count > 0);
957*6236dae4SAndroid Build Coastguard Worker 
958*6236dae4SAndroid Build Coastguard Worker   /* Send out any RTP data */
959*6236dae4SAndroid Build Coastguard Worker   if(req->rtp_buffer) {
960*6236dae4SAndroid Build Coastguard Worker     logmsg("About to write %zu RTP bytes", req->rtp_buffersize);
961*6236dae4SAndroid Build Coastguard Worker     count = req->rtp_buffersize;
962*6236dae4SAndroid Build Coastguard Worker     do {
963*6236dae4SAndroid Build Coastguard Worker       size_t num = count;
964*6236dae4SAndroid Build Coastguard Worker       if(num > 200)
965*6236dae4SAndroid Build Coastguard Worker         num = 200;
966*6236dae4SAndroid Build Coastguard Worker       written = swrite(sock, req->rtp_buffer + (req->rtp_buffersize - count),
967*6236dae4SAndroid Build Coastguard Worker                        num);
968*6236dae4SAndroid Build Coastguard Worker       if(written < 0) {
969*6236dae4SAndroid Build Coastguard Worker         sendfailure = TRUE;
970*6236dae4SAndroid Build Coastguard Worker         break;
971*6236dae4SAndroid Build Coastguard Worker       }
972*6236dae4SAndroid Build Coastguard Worker       count -= written;
973*6236dae4SAndroid Build Coastguard Worker     } while(count > 0);
974*6236dae4SAndroid Build Coastguard Worker 
975*6236dae4SAndroid Build Coastguard Worker     free(req->rtp_buffer);
976*6236dae4SAndroid Build Coastguard Worker     req->rtp_buffersize = 0;
977*6236dae4SAndroid Build Coastguard Worker   }
978*6236dae4SAndroid Build Coastguard Worker 
979*6236dae4SAndroid Build Coastguard Worker   do {
980*6236dae4SAndroid Build Coastguard Worker     res = fclose(dump);
981*6236dae4SAndroid Build Coastguard Worker   } while(res && ((error = errno) == EINTR));
982*6236dae4SAndroid Build Coastguard Worker   if(res)
983*6236dae4SAndroid Build Coastguard Worker     logmsg("Error closing file %s error: %d %s",
984*6236dae4SAndroid Build Coastguard Worker            responsedump, error, strerror(error));
985*6236dae4SAndroid Build Coastguard Worker 
986*6236dae4SAndroid Build Coastguard Worker   if(got_exit_signal) {
987*6236dae4SAndroid Build Coastguard Worker     free(ptr);
988*6236dae4SAndroid Build Coastguard Worker     free(cmd);
989*6236dae4SAndroid Build Coastguard Worker     return -1;
990*6236dae4SAndroid Build Coastguard Worker   }
991*6236dae4SAndroid Build Coastguard Worker 
992*6236dae4SAndroid Build Coastguard Worker   if(sendfailure) {
993*6236dae4SAndroid Build Coastguard Worker     logmsg("Sending response failed. Only (%zu bytes) of "
994*6236dae4SAndroid Build Coastguard Worker            "(%zu bytes) were sent",
995*6236dae4SAndroid Build Coastguard Worker            responsesize-count, responsesize);
996*6236dae4SAndroid Build Coastguard Worker     free(ptr);
997*6236dae4SAndroid Build Coastguard Worker     free(cmd);
998*6236dae4SAndroid Build Coastguard Worker     return -1;
999*6236dae4SAndroid Build Coastguard Worker   }
1000*6236dae4SAndroid Build Coastguard Worker 
1001*6236dae4SAndroid Build Coastguard Worker   logmsg("Response sent (%zu bytes) and written to %s",
1002*6236dae4SAndroid Build Coastguard Worker          responsesize, responsedump);
1003*6236dae4SAndroid Build Coastguard Worker   free(ptr);
1004*6236dae4SAndroid Build Coastguard Worker 
1005*6236dae4SAndroid Build Coastguard Worker   if(cmdsize > 0) {
1006*6236dae4SAndroid Build Coastguard Worker     char command[32];
1007*6236dae4SAndroid Build Coastguard Worker     int quarters;
1008*6236dae4SAndroid Build Coastguard Worker     int num;
1009*6236dae4SAndroid Build Coastguard Worker     ptr = cmd;
1010*6236dae4SAndroid Build Coastguard Worker     do {
1011*6236dae4SAndroid Build Coastguard Worker       if(2 == sscanf(ptr, "%31s %d", command, &num)) {
1012*6236dae4SAndroid Build Coastguard Worker         if(!strcmp("wait", command)) {
1013*6236dae4SAndroid Build Coastguard Worker           logmsg("Told to sleep for %d seconds", num);
1014*6236dae4SAndroid Build Coastguard Worker           quarters = num * 4;
1015*6236dae4SAndroid Build Coastguard Worker           while(quarters > 0) {
1016*6236dae4SAndroid Build Coastguard Worker             quarters--;
1017*6236dae4SAndroid Build Coastguard Worker             res = wait_ms(250);
1018*6236dae4SAndroid Build Coastguard Worker             if(got_exit_signal)
1019*6236dae4SAndroid Build Coastguard Worker               break;
1020*6236dae4SAndroid Build Coastguard Worker             if(res) {
1021*6236dae4SAndroid Build Coastguard Worker               /* should not happen */
1022*6236dae4SAndroid Build Coastguard Worker               error = errno;
1023*6236dae4SAndroid Build Coastguard Worker               logmsg("wait_ms() failed with error: (%d) %s",
1024*6236dae4SAndroid Build Coastguard Worker                      error, strerror(error));
1025*6236dae4SAndroid Build Coastguard Worker               break;
1026*6236dae4SAndroid Build Coastguard Worker             }
1027*6236dae4SAndroid Build Coastguard Worker           }
1028*6236dae4SAndroid Build Coastguard Worker           if(!quarters)
1029*6236dae4SAndroid Build Coastguard Worker             logmsg("Continuing after sleeping %d seconds", num);
1030*6236dae4SAndroid Build Coastguard Worker         }
1031*6236dae4SAndroid Build Coastguard Worker         else
1032*6236dae4SAndroid Build Coastguard Worker           logmsg("Unknown command in reply command section");
1033*6236dae4SAndroid Build Coastguard Worker       }
1034*6236dae4SAndroid Build Coastguard Worker       ptr = strchr(ptr, '\n');
1035*6236dae4SAndroid Build Coastguard Worker       if(ptr)
1036*6236dae4SAndroid Build Coastguard Worker         ptr++;
1037*6236dae4SAndroid Build Coastguard Worker       else
1038*6236dae4SAndroid Build Coastguard Worker         ptr = NULL;
1039*6236dae4SAndroid Build Coastguard Worker     } while(ptr && *ptr);
1040*6236dae4SAndroid Build Coastguard Worker   }
1041*6236dae4SAndroid Build Coastguard Worker   free(cmd);
1042*6236dae4SAndroid Build Coastguard Worker   req->open = persistent;
1043*6236dae4SAndroid Build Coastguard Worker 
1044*6236dae4SAndroid Build Coastguard Worker   prevtestno = req->testno;
1045*6236dae4SAndroid Build Coastguard Worker   prevpartno = req->partno;
1046*6236dae4SAndroid Build Coastguard Worker 
1047*6236dae4SAndroid Build Coastguard Worker   return 0;
1048*6236dae4SAndroid Build Coastguard Worker }
1049*6236dae4SAndroid Build Coastguard Worker 
1050*6236dae4SAndroid Build Coastguard Worker 
main(int argc,char * argv[])1051*6236dae4SAndroid Build Coastguard Worker int main(int argc, char *argv[])
1052*6236dae4SAndroid Build Coastguard Worker {
1053*6236dae4SAndroid Build Coastguard Worker   srvr_sockaddr_union_t me;
1054*6236dae4SAndroid Build Coastguard Worker   curl_socket_t sock = CURL_SOCKET_BAD;
1055*6236dae4SAndroid Build Coastguard Worker   curl_socket_t msgsock = CURL_SOCKET_BAD;
1056*6236dae4SAndroid Build Coastguard Worker   int wrotepidfile = 0;
1057*6236dae4SAndroid Build Coastguard Worker   int wroteportfile = 0;
1058*6236dae4SAndroid Build Coastguard Worker   int flag;
1059*6236dae4SAndroid Build Coastguard Worker   unsigned short port = DEFAULT_PORT;
1060*6236dae4SAndroid Build Coastguard Worker   const char *pidname = ".rtsp.pid";
1061*6236dae4SAndroid Build Coastguard Worker   const char *portname = NULL; /* none by default */
1062*6236dae4SAndroid Build Coastguard Worker   struct httprequest req;
1063*6236dae4SAndroid Build Coastguard Worker   int rc;
1064*6236dae4SAndroid Build Coastguard Worker   int error;
1065*6236dae4SAndroid Build Coastguard Worker   int arg = 1;
1066*6236dae4SAndroid Build Coastguard Worker 
1067*6236dae4SAndroid Build Coastguard Worker   memset(&req, 0, sizeof(req));
1068*6236dae4SAndroid Build Coastguard Worker 
1069*6236dae4SAndroid Build Coastguard Worker   while(argc > arg) {
1070*6236dae4SAndroid Build Coastguard Worker     if(!strcmp("--version", argv[arg])) {
1071*6236dae4SAndroid Build Coastguard Worker       printf("rtspd IPv4%s"
1072*6236dae4SAndroid Build Coastguard Worker              "\n"
1073*6236dae4SAndroid Build Coastguard Worker              ,
1074*6236dae4SAndroid Build Coastguard Worker #ifdef USE_IPV6
1075*6236dae4SAndroid Build Coastguard Worker              "/IPv6"
1076*6236dae4SAndroid Build Coastguard Worker #else
1077*6236dae4SAndroid Build Coastguard Worker              ""
1078*6236dae4SAndroid Build Coastguard Worker #endif
1079*6236dae4SAndroid Build Coastguard Worker              );
1080*6236dae4SAndroid Build Coastguard Worker       return 0;
1081*6236dae4SAndroid Build Coastguard Worker     }
1082*6236dae4SAndroid Build Coastguard Worker     else if(!strcmp("--pidfile", argv[arg])) {
1083*6236dae4SAndroid Build Coastguard Worker       arg++;
1084*6236dae4SAndroid Build Coastguard Worker       if(argc > arg)
1085*6236dae4SAndroid Build Coastguard Worker         pidname = argv[arg++];
1086*6236dae4SAndroid Build Coastguard Worker     }
1087*6236dae4SAndroid Build Coastguard Worker     else if(!strcmp("--portfile", argv[arg])) {
1088*6236dae4SAndroid Build Coastguard Worker       arg++;
1089*6236dae4SAndroid Build Coastguard Worker       if(argc > arg)
1090*6236dae4SAndroid Build Coastguard Worker         portname = argv[arg++];
1091*6236dae4SAndroid Build Coastguard Worker     }
1092*6236dae4SAndroid Build Coastguard Worker     else if(!strcmp("--logfile", argv[arg])) {
1093*6236dae4SAndroid Build Coastguard Worker       arg++;
1094*6236dae4SAndroid Build Coastguard Worker       if(argc > arg)
1095*6236dae4SAndroid Build Coastguard Worker         serverlogfile = argv[arg++];
1096*6236dae4SAndroid Build Coastguard Worker     }
1097*6236dae4SAndroid Build Coastguard Worker     else if(!strcmp("--logdir", argv[arg])) {
1098*6236dae4SAndroid Build Coastguard Worker       arg++;
1099*6236dae4SAndroid Build Coastguard Worker       if(argc > arg)
1100*6236dae4SAndroid Build Coastguard Worker         logdir = argv[arg++];
1101*6236dae4SAndroid Build Coastguard Worker     }
1102*6236dae4SAndroid Build Coastguard Worker     else if(!strcmp("--ipv4", argv[arg])) {
1103*6236dae4SAndroid Build Coastguard Worker #ifdef USE_IPV6
1104*6236dae4SAndroid Build Coastguard Worker       ipv_inuse = "IPv4";
1105*6236dae4SAndroid Build Coastguard Worker       use_ipv6 = FALSE;
1106*6236dae4SAndroid Build Coastguard Worker #endif
1107*6236dae4SAndroid Build Coastguard Worker       arg++;
1108*6236dae4SAndroid Build Coastguard Worker     }
1109*6236dae4SAndroid Build Coastguard Worker     else if(!strcmp("--ipv6", argv[arg])) {
1110*6236dae4SAndroid Build Coastguard Worker #ifdef USE_IPV6
1111*6236dae4SAndroid Build Coastguard Worker       ipv_inuse = "IPv6";
1112*6236dae4SAndroid Build Coastguard Worker       use_ipv6 = TRUE;
1113*6236dae4SAndroid Build Coastguard Worker #endif
1114*6236dae4SAndroid Build Coastguard Worker       arg++;
1115*6236dae4SAndroid Build Coastguard Worker     }
1116*6236dae4SAndroid Build Coastguard Worker     else if(!strcmp("--port", argv[arg])) {
1117*6236dae4SAndroid Build Coastguard Worker       arg++;
1118*6236dae4SAndroid Build Coastguard Worker       if(argc > arg) {
1119*6236dae4SAndroid Build Coastguard Worker         char *endptr;
1120*6236dae4SAndroid Build Coastguard Worker         unsigned long ulnum = strtoul(argv[arg], &endptr, 10);
1121*6236dae4SAndroid Build Coastguard Worker         port = curlx_ultous(ulnum);
1122*6236dae4SAndroid Build Coastguard Worker         arg++;
1123*6236dae4SAndroid Build Coastguard Worker       }
1124*6236dae4SAndroid Build Coastguard Worker     }
1125*6236dae4SAndroid Build Coastguard Worker     else if(!strcmp("--srcdir", argv[arg])) {
1126*6236dae4SAndroid Build Coastguard Worker       arg++;
1127*6236dae4SAndroid Build Coastguard Worker       if(argc > arg) {
1128*6236dae4SAndroid Build Coastguard Worker         path = argv[arg];
1129*6236dae4SAndroid Build Coastguard Worker         arg++;
1130*6236dae4SAndroid Build Coastguard Worker       }
1131*6236dae4SAndroid Build Coastguard Worker     }
1132*6236dae4SAndroid Build Coastguard Worker     else {
1133*6236dae4SAndroid Build Coastguard Worker       puts("Usage: rtspd [option]\n"
1134*6236dae4SAndroid Build Coastguard Worker            " --version\n"
1135*6236dae4SAndroid Build Coastguard Worker            " --logfile [file]\n"
1136*6236dae4SAndroid Build Coastguard Worker            " --logdir [directory]\n"
1137*6236dae4SAndroid Build Coastguard Worker            " --pidfile [file]\n"
1138*6236dae4SAndroid Build Coastguard Worker            " --portfile [file]\n"
1139*6236dae4SAndroid Build Coastguard Worker            " --ipv4\n"
1140*6236dae4SAndroid Build Coastguard Worker            " --ipv6\n"
1141*6236dae4SAndroid Build Coastguard Worker            " --port [port]\n"
1142*6236dae4SAndroid Build Coastguard Worker            " --srcdir [path]");
1143*6236dae4SAndroid Build Coastguard Worker       return 0;
1144*6236dae4SAndroid Build Coastguard Worker     }
1145*6236dae4SAndroid Build Coastguard Worker   }
1146*6236dae4SAndroid Build Coastguard Worker 
1147*6236dae4SAndroid Build Coastguard Worker   msnprintf(loglockfile, sizeof(loglockfile), "%s/%s/rtsp-%s.lock",
1148*6236dae4SAndroid Build Coastguard Worker             logdir, SERVERLOGS_LOCKDIR, ipv_inuse);
1149*6236dae4SAndroid Build Coastguard Worker 
1150*6236dae4SAndroid Build Coastguard Worker #ifdef _WIN32
1151*6236dae4SAndroid Build Coastguard Worker   win32_init();
1152*6236dae4SAndroid Build Coastguard Worker   atexit(win32_cleanup);
1153*6236dae4SAndroid Build Coastguard Worker #endif
1154*6236dae4SAndroid Build Coastguard Worker 
1155*6236dae4SAndroid Build Coastguard Worker   install_signal_handlers(false);
1156*6236dae4SAndroid Build Coastguard Worker 
1157*6236dae4SAndroid Build Coastguard Worker #ifdef USE_IPV6
1158*6236dae4SAndroid Build Coastguard Worker   if(!use_ipv6)
1159*6236dae4SAndroid Build Coastguard Worker #endif
1160*6236dae4SAndroid Build Coastguard Worker     sock = socket(AF_INET, SOCK_STREAM, 0);
1161*6236dae4SAndroid Build Coastguard Worker #ifdef USE_IPV6
1162*6236dae4SAndroid Build Coastguard Worker   else
1163*6236dae4SAndroid Build Coastguard Worker     sock = socket(AF_INET6, SOCK_STREAM, 0);
1164*6236dae4SAndroid Build Coastguard Worker #endif
1165*6236dae4SAndroid Build Coastguard Worker 
1166*6236dae4SAndroid Build Coastguard Worker   if(CURL_SOCKET_BAD == sock) {
1167*6236dae4SAndroid Build Coastguard Worker     error = SOCKERRNO;
1168*6236dae4SAndroid Build Coastguard Worker     logmsg("Error creating socket: (%d) %s", error, sstrerror(error));
1169*6236dae4SAndroid Build Coastguard Worker     goto server_cleanup;
1170*6236dae4SAndroid Build Coastguard Worker   }
1171*6236dae4SAndroid Build Coastguard Worker 
1172*6236dae4SAndroid Build Coastguard Worker   flag = 1;
1173*6236dae4SAndroid Build Coastguard Worker   if(0 != setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
1174*6236dae4SAndroid Build Coastguard Worker             (void *)&flag, sizeof(flag))) {
1175*6236dae4SAndroid Build Coastguard Worker     error = SOCKERRNO;
1176*6236dae4SAndroid Build Coastguard Worker     logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s",
1177*6236dae4SAndroid Build Coastguard Worker            error, sstrerror(error));
1178*6236dae4SAndroid Build Coastguard Worker     goto server_cleanup;
1179*6236dae4SAndroid Build Coastguard Worker   }
1180*6236dae4SAndroid Build Coastguard Worker 
1181*6236dae4SAndroid Build Coastguard Worker #ifdef USE_IPV6
1182*6236dae4SAndroid Build Coastguard Worker   if(!use_ipv6) {
1183*6236dae4SAndroid Build Coastguard Worker #endif
1184*6236dae4SAndroid Build Coastguard Worker     memset(&me.sa4, 0, sizeof(me.sa4));
1185*6236dae4SAndroid Build Coastguard Worker     me.sa4.sin_family = AF_INET;
1186*6236dae4SAndroid Build Coastguard Worker     me.sa4.sin_addr.s_addr = INADDR_ANY;
1187*6236dae4SAndroid Build Coastguard Worker     me.sa4.sin_port = htons(port);
1188*6236dae4SAndroid Build Coastguard Worker     rc = bind(sock, &me.sa, sizeof(me.sa4));
1189*6236dae4SAndroid Build Coastguard Worker #ifdef USE_IPV6
1190*6236dae4SAndroid Build Coastguard Worker   }
1191*6236dae4SAndroid Build Coastguard Worker   else {
1192*6236dae4SAndroid Build Coastguard Worker     memset(&me.sa6, 0, sizeof(me.sa6));
1193*6236dae4SAndroid Build Coastguard Worker     me.sa6.sin6_family = AF_INET6;
1194*6236dae4SAndroid Build Coastguard Worker     me.sa6.sin6_addr = in6addr_any;
1195*6236dae4SAndroid Build Coastguard Worker     me.sa6.sin6_port = htons(port);
1196*6236dae4SAndroid Build Coastguard Worker     rc = bind(sock, &me.sa, sizeof(me.sa6));
1197*6236dae4SAndroid Build Coastguard Worker   }
1198*6236dae4SAndroid Build Coastguard Worker #endif /* USE_IPV6 */
1199*6236dae4SAndroid Build Coastguard Worker   if(0 != rc) {
1200*6236dae4SAndroid Build Coastguard Worker     error = SOCKERRNO;
1201*6236dae4SAndroid Build Coastguard Worker     logmsg("Error binding socket on port %hu: (%d) %s",
1202*6236dae4SAndroid Build Coastguard Worker            port, error, sstrerror(error));
1203*6236dae4SAndroid Build Coastguard Worker     goto server_cleanup;
1204*6236dae4SAndroid Build Coastguard Worker   }
1205*6236dae4SAndroid Build Coastguard Worker 
1206*6236dae4SAndroid Build Coastguard Worker   if(!port) {
1207*6236dae4SAndroid Build Coastguard Worker     /* The system was supposed to choose a port number, figure out which
1208*6236dae4SAndroid Build Coastguard Worker        port we actually got and update the listener port value with it. */
1209*6236dae4SAndroid Build Coastguard Worker     curl_socklen_t la_size;
1210*6236dae4SAndroid Build Coastguard Worker     srvr_sockaddr_union_t localaddr;
1211*6236dae4SAndroid Build Coastguard Worker #ifdef USE_IPV6
1212*6236dae4SAndroid Build Coastguard Worker     if(!use_ipv6)
1213*6236dae4SAndroid Build Coastguard Worker #endif
1214*6236dae4SAndroid Build Coastguard Worker       la_size = sizeof(localaddr.sa4);
1215*6236dae4SAndroid Build Coastguard Worker #ifdef USE_IPV6
1216*6236dae4SAndroid Build Coastguard Worker     else
1217*6236dae4SAndroid Build Coastguard Worker       la_size = sizeof(localaddr.sa6);
1218*6236dae4SAndroid Build Coastguard Worker #endif
1219*6236dae4SAndroid Build Coastguard Worker     memset(&localaddr.sa, 0, (size_t)la_size);
1220*6236dae4SAndroid Build Coastguard Worker     if(getsockname(sock, &localaddr.sa, &la_size) < 0) {
1221*6236dae4SAndroid Build Coastguard Worker       error = SOCKERRNO;
1222*6236dae4SAndroid Build Coastguard Worker       logmsg("getsockname() failed with error: (%d) %s",
1223*6236dae4SAndroid Build Coastguard Worker              error, sstrerror(error));
1224*6236dae4SAndroid Build Coastguard Worker       sclose(sock);
1225*6236dae4SAndroid Build Coastguard Worker       goto server_cleanup;
1226*6236dae4SAndroid Build Coastguard Worker     }
1227*6236dae4SAndroid Build Coastguard Worker     switch(localaddr.sa.sa_family) {
1228*6236dae4SAndroid Build Coastguard Worker     case AF_INET:
1229*6236dae4SAndroid Build Coastguard Worker       port = ntohs(localaddr.sa4.sin_port);
1230*6236dae4SAndroid Build Coastguard Worker       break;
1231*6236dae4SAndroid Build Coastguard Worker #ifdef USE_IPV6
1232*6236dae4SAndroid Build Coastguard Worker     case AF_INET6:
1233*6236dae4SAndroid Build Coastguard Worker       port = ntohs(localaddr.sa6.sin6_port);
1234*6236dae4SAndroid Build Coastguard Worker       break;
1235*6236dae4SAndroid Build Coastguard Worker #endif
1236*6236dae4SAndroid Build Coastguard Worker     default:
1237*6236dae4SAndroid Build Coastguard Worker       break;
1238*6236dae4SAndroid Build Coastguard Worker     }
1239*6236dae4SAndroid Build Coastguard Worker     if(!port) {
1240*6236dae4SAndroid Build Coastguard Worker       /* Real failure, listener port shall not be zero beyond this point. */
1241*6236dae4SAndroid Build Coastguard Worker       logmsg("Apparently getsockname() succeeded, with listener port zero.");
1242*6236dae4SAndroid Build Coastguard Worker       logmsg("A valid reason for this failure is a binary built without");
1243*6236dae4SAndroid Build Coastguard Worker       logmsg("proper network library linkage. This might not be the only");
1244*6236dae4SAndroid Build Coastguard Worker       logmsg("reason, but double check it before anything else.");
1245*6236dae4SAndroid Build Coastguard Worker       sclose(sock);
1246*6236dae4SAndroid Build Coastguard Worker       goto server_cleanup;
1247*6236dae4SAndroid Build Coastguard Worker     }
1248*6236dae4SAndroid Build Coastguard Worker   }
1249*6236dae4SAndroid Build Coastguard Worker   logmsg("Running %s version on port %d", ipv_inuse, (int)port);
1250*6236dae4SAndroid Build Coastguard Worker 
1251*6236dae4SAndroid Build Coastguard Worker   /* start accepting connections */
1252*6236dae4SAndroid Build Coastguard Worker   rc = listen(sock, 5);
1253*6236dae4SAndroid Build Coastguard Worker   if(0 != rc) {
1254*6236dae4SAndroid Build Coastguard Worker     error = SOCKERRNO;
1255*6236dae4SAndroid Build Coastguard Worker     logmsg("listen() failed with error: (%d) %s",
1256*6236dae4SAndroid Build Coastguard Worker            error, sstrerror(error));
1257*6236dae4SAndroid Build Coastguard Worker     goto server_cleanup;
1258*6236dae4SAndroid Build Coastguard Worker   }
1259*6236dae4SAndroid Build Coastguard Worker 
1260*6236dae4SAndroid Build Coastguard Worker   /*
1261*6236dae4SAndroid Build Coastguard Worker   ** As soon as this server writes its pid file the test harness will
1262*6236dae4SAndroid Build Coastguard Worker   ** attempt to connect to this server and initiate its verification.
1263*6236dae4SAndroid Build Coastguard Worker   */
1264*6236dae4SAndroid Build Coastguard Worker 
1265*6236dae4SAndroid Build Coastguard Worker   wrotepidfile = write_pidfile(pidname);
1266*6236dae4SAndroid Build Coastguard Worker   if(!wrotepidfile)
1267*6236dae4SAndroid Build Coastguard Worker     goto server_cleanup;
1268*6236dae4SAndroid Build Coastguard Worker 
1269*6236dae4SAndroid Build Coastguard Worker   if(portname) {
1270*6236dae4SAndroid Build Coastguard Worker     wroteportfile = write_portfile(portname, port);
1271*6236dae4SAndroid Build Coastguard Worker     if(!wroteportfile)
1272*6236dae4SAndroid Build Coastguard Worker       goto server_cleanup;
1273*6236dae4SAndroid Build Coastguard Worker   }
1274*6236dae4SAndroid Build Coastguard Worker 
1275*6236dae4SAndroid Build Coastguard Worker   for(;;) {
1276*6236dae4SAndroid Build Coastguard Worker     msgsock = accept(sock, NULL, NULL);
1277*6236dae4SAndroid Build Coastguard Worker 
1278*6236dae4SAndroid Build Coastguard Worker     if(got_exit_signal)
1279*6236dae4SAndroid Build Coastguard Worker       break;
1280*6236dae4SAndroid Build Coastguard Worker     if(CURL_SOCKET_BAD == msgsock) {
1281*6236dae4SAndroid Build Coastguard Worker       error = SOCKERRNO;
1282*6236dae4SAndroid Build Coastguard Worker       logmsg("MAJOR ERROR: accept() failed with error: (%d) %s",
1283*6236dae4SAndroid Build Coastguard Worker              error, sstrerror(error));
1284*6236dae4SAndroid Build Coastguard Worker       break;
1285*6236dae4SAndroid Build Coastguard Worker     }
1286*6236dae4SAndroid Build Coastguard Worker 
1287*6236dae4SAndroid Build Coastguard Worker     /*
1288*6236dae4SAndroid Build Coastguard Worker     ** As soon as this server accepts a connection from the test harness it
1289*6236dae4SAndroid Build Coastguard Worker     ** must set the server logs advisor read lock to indicate that server
1290*6236dae4SAndroid Build Coastguard Worker     ** logs should not be read until this lock is removed by this server.
1291*6236dae4SAndroid Build Coastguard Worker     */
1292*6236dae4SAndroid Build Coastguard Worker 
1293*6236dae4SAndroid Build Coastguard Worker     set_advisor_read_lock(loglockfile);
1294*6236dae4SAndroid Build Coastguard Worker     serverlogslocked = 1;
1295*6236dae4SAndroid Build Coastguard Worker 
1296*6236dae4SAndroid Build Coastguard Worker     logmsg("====> Client connect");
1297*6236dae4SAndroid Build Coastguard Worker 
1298*6236dae4SAndroid Build Coastguard Worker #ifdef TCP_NODELAY
1299*6236dae4SAndroid Build Coastguard Worker     /*
1300*6236dae4SAndroid Build Coastguard Worker      * Disable the Nagle algorithm to make it easier to send out a large
1301*6236dae4SAndroid Build Coastguard Worker      * response in many small segments to torture the clients more.
1302*6236dae4SAndroid Build Coastguard Worker      */
1303*6236dae4SAndroid Build Coastguard Worker     flag = 1;
1304*6236dae4SAndroid Build Coastguard Worker     if(setsockopt(msgsock, IPPROTO_TCP, TCP_NODELAY,
1305*6236dae4SAndroid Build Coastguard Worker                    (void *)&flag, sizeof(flag)) == -1) {
1306*6236dae4SAndroid Build Coastguard Worker       logmsg("====> TCP_NODELAY failed");
1307*6236dae4SAndroid Build Coastguard Worker     }
1308*6236dae4SAndroid Build Coastguard Worker #endif
1309*6236dae4SAndroid Build Coastguard Worker 
1310*6236dae4SAndroid Build Coastguard Worker     /* initialization of httprequest struct is done in get_request(), but due
1311*6236dae4SAndroid Build Coastguard Worker        to pipelining treatment the pipelining struct field must be initialized
1312*6236dae4SAndroid Build Coastguard Worker        previously to FALSE every time a new connection arrives. */
1313*6236dae4SAndroid Build Coastguard Worker 
1314*6236dae4SAndroid Build Coastguard Worker     req.pipelining = FALSE;
1315*6236dae4SAndroid Build Coastguard Worker 
1316*6236dae4SAndroid Build Coastguard Worker     do {
1317*6236dae4SAndroid Build Coastguard Worker       if(got_exit_signal)
1318*6236dae4SAndroid Build Coastguard Worker         break;
1319*6236dae4SAndroid Build Coastguard Worker 
1320*6236dae4SAndroid Build Coastguard Worker       if(get_request(msgsock, &req))
1321*6236dae4SAndroid Build Coastguard Worker         /* non-zero means error, break out of loop */
1322*6236dae4SAndroid Build Coastguard Worker         break;
1323*6236dae4SAndroid Build Coastguard Worker 
1324*6236dae4SAndroid Build Coastguard Worker       if(prevbounce) {
1325*6236dae4SAndroid Build Coastguard Worker         /* bounce treatment requested */
1326*6236dae4SAndroid Build Coastguard Worker         if((req.testno == prevtestno) &&
1327*6236dae4SAndroid Build Coastguard Worker            (req.partno == prevpartno)) {
1328*6236dae4SAndroid Build Coastguard Worker           req.partno++;
1329*6236dae4SAndroid Build Coastguard Worker           logmsg("BOUNCE part number to %ld", req.partno);
1330*6236dae4SAndroid Build Coastguard Worker         }
1331*6236dae4SAndroid Build Coastguard Worker         else {
1332*6236dae4SAndroid Build Coastguard Worker           prevbounce = FALSE;
1333*6236dae4SAndroid Build Coastguard Worker           prevtestno = -1;
1334*6236dae4SAndroid Build Coastguard Worker           prevpartno = -1;
1335*6236dae4SAndroid Build Coastguard Worker         }
1336*6236dae4SAndroid Build Coastguard Worker       }
1337*6236dae4SAndroid Build Coastguard Worker 
1338*6236dae4SAndroid Build Coastguard Worker       send_doc(msgsock, &req);
1339*6236dae4SAndroid Build Coastguard Worker       if(got_exit_signal)
1340*6236dae4SAndroid Build Coastguard Worker         break;
1341*6236dae4SAndroid Build Coastguard Worker 
1342*6236dae4SAndroid Build Coastguard Worker       if((req.testno < 0) && (req.testno != DOCNUMBER_CONNECT)) {
1343*6236dae4SAndroid Build Coastguard Worker         logmsg("special request received, no persistency");
1344*6236dae4SAndroid Build Coastguard Worker         break;
1345*6236dae4SAndroid Build Coastguard Worker       }
1346*6236dae4SAndroid Build Coastguard Worker       if(!req.open) {
1347*6236dae4SAndroid Build Coastguard Worker         logmsg("instructed to close connection after server-reply");
1348*6236dae4SAndroid Build Coastguard Worker         break;
1349*6236dae4SAndroid Build Coastguard Worker       }
1350*6236dae4SAndroid Build Coastguard Worker 
1351*6236dae4SAndroid Build Coastguard Worker       if(req.open)
1352*6236dae4SAndroid Build Coastguard Worker         logmsg("=> persistent connection request ended, awaits new request");
1353*6236dae4SAndroid Build Coastguard Worker       /* if we got a CONNECT, loop and get another request as well! */
1354*6236dae4SAndroid Build Coastguard Worker     } while(req.open || (req.testno == DOCNUMBER_CONNECT));
1355*6236dae4SAndroid Build Coastguard Worker 
1356*6236dae4SAndroid Build Coastguard Worker     if(got_exit_signal)
1357*6236dae4SAndroid Build Coastguard Worker       break;
1358*6236dae4SAndroid Build Coastguard Worker 
1359*6236dae4SAndroid Build Coastguard Worker     logmsg("====> Client disconnect");
1360*6236dae4SAndroid Build Coastguard Worker     sclose(msgsock);
1361*6236dae4SAndroid Build Coastguard Worker     msgsock = CURL_SOCKET_BAD;
1362*6236dae4SAndroid Build Coastguard Worker 
1363*6236dae4SAndroid Build Coastguard Worker     if(serverlogslocked) {
1364*6236dae4SAndroid Build Coastguard Worker       serverlogslocked = 0;
1365*6236dae4SAndroid Build Coastguard Worker       clear_advisor_read_lock(loglockfile);
1366*6236dae4SAndroid Build Coastguard Worker     }
1367*6236dae4SAndroid Build Coastguard Worker 
1368*6236dae4SAndroid Build Coastguard Worker     if(req.testno == DOCNUMBER_QUIT)
1369*6236dae4SAndroid Build Coastguard Worker       break;
1370*6236dae4SAndroid Build Coastguard Worker   }
1371*6236dae4SAndroid Build Coastguard Worker 
1372*6236dae4SAndroid Build Coastguard Worker server_cleanup:
1373*6236dae4SAndroid Build Coastguard Worker 
1374*6236dae4SAndroid Build Coastguard Worker   if((msgsock != sock) && (msgsock != CURL_SOCKET_BAD))
1375*6236dae4SAndroid Build Coastguard Worker     sclose(msgsock);
1376*6236dae4SAndroid Build Coastguard Worker 
1377*6236dae4SAndroid Build Coastguard Worker   if(sock != CURL_SOCKET_BAD)
1378*6236dae4SAndroid Build Coastguard Worker     sclose(sock);
1379*6236dae4SAndroid Build Coastguard Worker 
1380*6236dae4SAndroid Build Coastguard Worker   if(got_exit_signal)
1381*6236dae4SAndroid Build Coastguard Worker     logmsg("signalled to die");
1382*6236dae4SAndroid Build Coastguard Worker 
1383*6236dae4SAndroid Build Coastguard Worker   if(wrotepidfile)
1384*6236dae4SAndroid Build Coastguard Worker     unlink(pidname);
1385*6236dae4SAndroid Build Coastguard Worker   if(wroteportfile)
1386*6236dae4SAndroid Build Coastguard Worker     unlink(portname);
1387*6236dae4SAndroid Build Coastguard Worker 
1388*6236dae4SAndroid Build Coastguard Worker   if(serverlogslocked) {
1389*6236dae4SAndroid Build Coastguard Worker     serverlogslocked = 0;
1390*6236dae4SAndroid Build Coastguard Worker     clear_advisor_read_lock(loglockfile);
1391*6236dae4SAndroid Build Coastguard Worker   }
1392*6236dae4SAndroid Build Coastguard Worker 
1393*6236dae4SAndroid Build Coastguard Worker   restore_signal_handlers(false);
1394*6236dae4SAndroid Build Coastguard Worker 
1395*6236dae4SAndroid Build Coastguard Worker   if(got_exit_signal) {
1396*6236dae4SAndroid Build Coastguard Worker     logmsg("========> %s rtspd (port: %d pid: %ld) exits with signal (%d)",
1397*6236dae4SAndroid Build Coastguard Worker            ipv_inuse, (int)port, (long)getpid(), exit_signal);
1398*6236dae4SAndroid Build Coastguard Worker     /*
1399*6236dae4SAndroid Build Coastguard Worker      * To properly set the return status of the process we
1400*6236dae4SAndroid Build Coastguard Worker      * must raise the same signal SIGINT or SIGTERM that we
1401*6236dae4SAndroid Build Coastguard Worker      * caught and let the old handler take care of it.
1402*6236dae4SAndroid Build Coastguard Worker      */
1403*6236dae4SAndroid Build Coastguard Worker     raise(exit_signal);
1404*6236dae4SAndroid Build Coastguard Worker   }
1405*6236dae4SAndroid Build Coastguard Worker 
1406*6236dae4SAndroid Build Coastguard Worker   logmsg("========> rtspd quits");
1407*6236dae4SAndroid Build Coastguard Worker   return 0;
1408*6236dae4SAndroid Build Coastguard Worker }
1409