00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "server_setup.h"
00023
00024
00025
00026
00027
00028
00029
00030 #ifdef HAVE_SIGNAL_H
00031 #include <signal.h>
00032 #endif
00033 #ifdef HAVE_NETINET_IN_H
00034 #include <netinet/in.h>
00035 #endif
00036 #ifdef HAVE_ARPA_INET_H
00037 #include <arpa/inet.h>
00038 #endif
00039 #ifdef HAVE_NETDB_H
00040 #include <netdb.h>
00041 #endif
00042 #ifdef HAVE_NETINET_TCP_H
00043 #include <netinet/tcp.h>
00044 #endif
00045
00046 #define ENABLE_CURLX_PRINTF
00047
00048
00049 #include "curlx.h"
00050 #include "getpart.h"
00051 #include "util.h"
00052 #include "server_sockaddr.h"
00053
00054
00055 #include "memdebug.h"
00056
00057 #ifdef USE_WINSOCK
00058 #undef EINTR
00059 #define EINTR 4
00060 #undef ERANGE
00061 #define ERANGE 34
00062 #endif
00063
00064 #ifdef ENABLE_IPV6
00065 static bool use_ipv6 = FALSE;
00066 #endif
00067 static const char *ipv_inuse = "IPv4";
00068 static int serverlogslocked = 0;
00069
00070 #define REQBUFSIZ 150000
00071 #define REQBUFSIZ_TXT "149999"
00072
00073 static long prevtestno=-1;
00074 static long prevpartno=-1;
00075 static bool prevbounce=FALSE;
00076
00077
00078
00079 #define RCMD_NORMALREQ 0
00080 #define RCMD_IDLE 1
00081 #define RCMD_STREAM 2
00082
00083 typedef enum {
00084 RPROT_NONE = 0,
00085 RPROT_RTSP = 1,
00086 RPROT_HTTP = 2
00087 } reqprot_t;
00088
00089 #define SET_RTP_PKT_CHN(p,c) ((p)[1] = (unsigned char)((c) & 0xFF))
00090
00091 #define SET_RTP_PKT_LEN(p,l) (((p)[2] = (unsigned char)(((l) >> 8) & 0xFF)), \
00092 ((p)[3] = (unsigned char)((l) & 0xFF)))
00093
00094 struct httprequest {
00095 char reqbuf[REQBUFSIZ];
00096 size_t checkindex;
00097 size_t offset;
00098 long testno;
00099 long partno;
00100 bool open;
00101 bool auth_req;
00102
00103 bool auth;
00104 size_t cl;
00105 bool digest;
00106 bool ntlm;
00107 int pipe;
00108
00109 int skip;
00110
00111
00112
00113 int rcmd;
00114 reqprot_t protocol;
00115 int prot_version;
00116 bool pipelining;
00117 char *rtp_buffer;
00118 size_t rtp_buffersize;
00119 };
00120
00121 static int ProcessRequest(struct httprequest *req);
00122 static void storerequest(char *reqbuf, size_t totalsize);
00123
00124 #define DEFAULT_PORT 8999
00125
00126 #ifndef DEFAULT_LOGFILE
00127 #define DEFAULT_LOGFILE "log/rtspd.log"
00128 #endif
00129
00130 const char *serverlogfile = DEFAULT_LOGFILE;
00131
00132 #define RTSPDVERSION "curl test suite RTSP server/0.1"
00133
00134 #define REQUEST_DUMP "log/server.input"
00135 #define RESPONSE_DUMP "log/server.response"
00136
00137
00138 #define MAXDOCNAMELEN 140000
00139 #define MAXDOCNAMELEN_TXT "139999"
00140
00141 #define REQUEST_KEYWORD_SIZE 256
00142 #define REQUEST_KEYWORD_SIZE_TXT "255"
00143
00144 #define CMD_AUTH_REQUIRED "auth_required"
00145
00146
00147
00148 #define CMD_IDLE "idle"
00149
00150
00151 #define CMD_STREAM "stream"
00152
00153 #define END_OF_HEADERS "\r\n\r\n"
00154
00155 enum {
00156 DOCNUMBER_NOTHING = -7,
00157 DOCNUMBER_QUIT = -6,
00158 DOCNUMBER_BADCONNECT = -5,
00159 DOCNUMBER_INTERNAL= -4,
00160 DOCNUMBER_CONNECT = -3,
00161 DOCNUMBER_WERULEZ = -2,
00162 DOCNUMBER_404 = -1
00163 };
00164
00165
00166
00167 static const char *docquit =
00168 "HTTP/1.1 200 Goodbye" END_OF_HEADERS;
00169
00170
00171 static const char *docconnect =
00172 "HTTP/1.1 200 Mighty fine indeed" END_OF_HEADERS;
00173
00174
00175 static const char *docbadconnect =
00176 "HTTP/1.1 501 Forbidden you fool" END_OF_HEADERS;
00177
00178
00179 static const char *doc404_HTTP = "HTTP/1.1 404 Not Found\r\n"
00180 "Server: " RTSPDVERSION "\r\n"
00181 "Connection: close\r\n"
00182 "Content-Type: text/html"
00183 END_OF_HEADERS
00184 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
00185 "<HTML><HEAD>\n"
00186 "<TITLE>404 Not Found</TITLE>\n"
00187 "</HEAD><BODY>\n"
00188 "<H1>Not Found</H1>\n"
00189 "The requested URL was not found on this server.\n"
00190 "<P><HR><ADDRESS>" RTSPDVERSION "</ADDRESS>\n" "</BODY></HTML>\n";
00191
00192
00193 static const char *doc404_RTSP = "RTSP/1.0 404 Not Found\r\n"
00194 "Server: " RTSPDVERSION
00195 END_OF_HEADERS;
00196
00197
00198 #define RTP_DATA_SIZE 12
00199 static const char *RTP_DATA = "$_1234\n\0asdf";
00200
00201
00202
00203 #ifndef HAVE_SIGINTERRUPT
00204 #define siginterrupt(x,y) do {} while(0)
00205 #endif
00206
00207
00208
00209 typedef RETSIGTYPE (*SIGHANDLER_T)(int);
00210
00211 #ifdef SIGHUP
00212 static SIGHANDLER_T old_sighup_handler = SIG_ERR;
00213 #endif
00214
00215 #ifdef SIGPIPE
00216 static SIGHANDLER_T old_sigpipe_handler = SIG_ERR;
00217 #endif
00218
00219 #ifdef SIGALRM
00220 static SIGHANDLER_T old_sigalrm_handler = SIG_ERR;
00221 #endif
00222
00223 #ifdef SIGINT
00224 static SIGHANDLER_T old_sigint_handler = SIG_ERR;
00225 #endif
00226
00227 #ifdef SIGTERM
00228 static SIGHANDLER_T old_sigterm_handler = SIG_ERR;
00229 #endif
00230
00231 #if defined(SIGBREAK) && defined(WIN32)
00232 static SIGHANDLER_T old_sigbreak_handler = SIG_ERR;
00233 #endif
00234
00235
00236
00237 SIG_ATOMIC_T got_exit_signal = 0;
00238
00239
00240
00241 static volatile int exit_signal = 0;
00242
00243
00244
00245
00246
00247
00248 static RETSIGTYPE exit_signal_handler(int signum)
00249 {
00250 int old_errno = errno;
00251 if(got_exit_signal == 0) {
00252 got_exit_signal = 1;
00253 exit_signal = signum;
00254 }
00255 (void)signal(signum, exit_signal_handler);
00256 errno = old_errno;
00257 }
00258
00259 static void install_signal_handlers(void)
00260 {
00261 #ifdef SIGHUP
00262
00263 old_sighup_handler = signal(SIGHUP, SIG_IGN);
00264 if(old_sighup_handler == SIG_ERR)
00265 logmsg("cannot install SIGHUP handler: %s", strerror(errno));
00266 #endif
00267 #ifdef SIGPIPE
00268
00269 old_sigpipe_handler = signal(SIGPIPE, SIG_IGN);
00270 if(old_sigpipe_handler == SIG_ERR)
00271 logmsg("cannot install SIGPIPE handler: %s", strerror(errno));
00272 #endif
00273 #ifdef SIGALRM
00274
00275 old_sigalrm_handler = signal(SIGALRM, SIG_IGN);
00276 if(old_sigalrm_handler == SIG_ERR)
00277 logmsg("cannot install SIGALRM handler: %s", strerror(errno));
00278 #endif
00279 #ifdef SIGINT
00280
00281 old_sigint_handler = signal(SIGINT, exit_signal_handler);
00282 if(old_sigint_handler == SIG_ERR)
00283 logmsg("cannot install SIGINT handler: %s", strerror(errno));
00284 else
00285 siginterrupt(SIGINT, 1);
00286 #endif
00287 #ifdef SIGTERM
00288
00289 old_sigterm_handler = signal(SIGTERM, exit_signal_handler);
00290 if(old_sigterm_handler == SIG_ERR)
00291 logmsg("cannot install SIGTERM handler: %s", strerror(errno));
00292 else
00293 siginterrupt(SIGTERM, 1);
00294 #endif
00295 #if defined(SIGBREAK) && defined(WIN32)
00296
00297 old_sigbreak_handler = signal(SIGBREAK, exit_signal_handler);
00298 if(old_sigbreak_handler == SIG_ERR)
00299 logmsg("cannot install SIGBREAK handler: %s", strerror(errno));
00300 else
00301 siginterrupt(SIGBREAK, 1);
00302 #endif
00303 }
00304
00305 static void restore_signal_handlers(void)
00306 {
00307 #ifdef SIGHUP
00308 if(SIG_ERR != old_sighup_handler)
00309 (void)signal(SIGHUP, old_sighup_handler);
00310 #endif
00311 #ifdef SIGPIPE
00312 if(SIG_ERR != old_sigpipe_handler)
00313 (void)signal(SIGPIPE, old_sigpipe_handler);
00314 #endif
00315 #ifdef SIGALRM
00316 if(SIG_ERR != old_sigalrm_handler)
00317 (void)signal(SIGALRM, old_sigalrm_handler);
00318 #endif
00319 #ifdef SIGINT
00320 if(SIG_ERR != old_sigint_handler)
00321 (void)signal(SIGINT, old_sigint_handler);
00322 #endif
00323 #ifdef SIGTERM
00324 if(SIG_ERR != old_sigterm_handler)
00325 (void)signal(SIGTERM, old_sigterm_handler);
00326 #endif
00327 #if defined(SIGBREAK) && defined(WIN32)
00328 if(SIG_ERR != old_sigbreak_handler)
00329 (void)signal(SIGBREAK, old_sigbreak_handler);
00330 #endif
00331 }
00332
00333 static int ProcessRequest(struct httprequest *req)
00334 {
00335 char *line=&req->reqbuf[req->checkindex];
00336 bool chunked = FALSE;
00337 static char request[REQUEST_KEYWORD_SIZE];
00338 static char doc[MAXDOCNAMELEN];
00339 static char prot_str[5];
00340 char logbuf[256];
00341 int prot_major, prot_minor;
00342 char *end;
00343 int error;
00344 end = strstr(line, END_OF_HEADERS);
00345
00346 logmsg("ProcessRequest() called with testno %ld and line [%s]",
00347 req->testno, line);
00348
00349
00350
00351 if((req->testno == DOCNUMBER_NOTHING) &&
00352 sscanf(line,
00353 "%" REQUEST_KEYWORD_SIZE_TXT"s %" MAXDOCNAMELEN_TXT "s %4s/%d.%d",
00354 request,
00355 doc,
00356 prot_str,
00357 &prot_major,
00358 &prot_minor) == 5) {
00359 char *ptr;
00360
00361 if(!strcmp(prot_str, "HTTP")) {
00362 req->protocol = RPROT_HTTP;
00363 }
00364 else if(!strcmp(prot_str, "RTSP")) {
00365 req->protocol = RPROT_RTSP;
00366 }
00367 else {
00368 req->protocol = RPROT_NONE;
00369 logmsg("got unknown protocol %s", prot_str);
00370 return 1;
00371 }
00372
00373 req->prot_version = prot_major*10 + prot_minor;
00374
00375
00376 ptr = strrchr(doc, '/');
00377
00378
00379 if(ptr) {
00380 FILE *stream;
00381 char *filename;
00382
00383 if((strlen(doc) + strlen(request)) < 200)
00384 snprintf(logbuf, sizeof(logbuf), "Got request: %s %s %s/%d.%d",
00385 request, doc, prot_str, prot_major, prot_minor);
00386 else
00387 snprintf(logbuf, sizeof(logbuf), "Got a *HUGE* request %s/%d.%d",
00388 prot_str, prot_major, prot_minor);
00389 logmsg("%s", logbuf);
00390
00391 if(!strncmp("/verifiedserver", ptr, 15)) {
00392 logmsg("Are-we-friendly question received");
00393 req->testno = DOCNUMBER_WERULEZ;
00394 return 1;
00395 }
00396
00397 if(!strncmp("/quit", ptr, 5)) {
00398 logmsg("Request-to-quit received");
00399 req->testno = DOCNUMBER_QUIT;
00400 return 1;
00401 }
00402
00403 ptr++;
00404
00405
00406 while(*ptr && !ISDIGIT(*ptr))
00407 ptr++;
00408
00409 req->testno = strtol(ptr, &ptr, 10);
00410
00411 if(req->testno > 10000) {
00412 req->partno = req->testno % 10000;
00413 req->testno /= 10000;
00414 }
00415 else
00416 req->partno = 0;
00417
00418 snprintf(logbuf, sizeof(logbuf), "Requested test number %ld part %ld",
00419 req->testno, req->partno);
00420 logmsg("%s", logbuf);
00421
00422 filename = test2file(req->testno);
00423
00424 stream=fopen(filename, "rb");
00425 if(!stream) {
00426 error = errno;
00427 logmsg("fopen() failed with error: %d %s", error, strerror(error));
00428 logmsg("Error opening file: %s", filename);
00429 logmsg("Couldn't open test file %ld", req->testno);
00430 req->open = FALSE;
00431 return 1;
00432 }
00433 else {
00434 char *cmd = NULL;
00435 size_t cmdsize = 0;
00436 int num=0;
00437
00438 int rtp_channel = 0;
00439 int rtp_size = 0;
00440 int rtp_partno = -1;
00441 int i = 0;
00442 char *rtp_scratch = NULL;
00443
00444
00445 error = getpart(&cmd, &cmdsize, "reply", "servercmd", stream);
00446 fclose(stream);
00447 if(error) {
00448 logmsg("getpart() failed with error: %d", error);
00449 req->open = FALSE;
00450 return 1;
00451 }
00452 ptr = cmd;
00453
00454 if(cmdsize) {
00455 logmsg("Found a reply-servercmd section!");
00456 do {
00457 if(!strncmp(CMD_AUTH_REQUIRED, ptr, strlen(CMD_AUTH_REQUIRED))) {
00458 logmsg("instructed to require authorization header");
00459 req->auth_req = TRUE;
00460 }
00461 else if(!strncmp(CMD_IDLE, ptr, strlen(CMD_IDLE))) {
00462 logmsg("instructed to idle");
00463 req->rcmd = RCMD_IDLE;
00464 req->open = TRUE;
00465 }
00466 else if(!strncmp(CMD_STREAM, ptr, strlen(CMD_STREAM))) {
00467 logmsg("instructed to stream");
00468 req->rcmd = RCMD_STREAM;
00469 }
00470 else if(1 == sscanf(ptr, "pipe: %d", &num)) {
00471 logmsg("instructed to allow a pipe size of %d", num);
00472 if(num < 0)
00473 logmsg("negative pipe size ignored");
00474 else if(num > 0)
00475 req->pipe = num-1;
00476
00477 }
00478 else if(1 == sscanf(ptr, "skip: %d", &num)) {
00479 logmsg("instructed to skip this number of bytes %d", num);
00480 req->skip = num;
00481 }
00482 else if(3 == sscanf(ptr, "rtp: part %d channel %d size %d",
00483 &rtp_partno, &rtp_channel, &rtp_size)) {
00484
00485 if(rtp_partno == req->partno) {
00486 logmsg("RTP: part %d channel %d size %d",
00487 rtp_partno, rtp_channel, rtp_size);
00488
00489
00490
00491 rtp_scratch = malloc(rtp_size + 4 + RTP_DATA_SIZE);
00492
00493
00494 rtp_scratch[0] = '$';
00495
00496
00497 SET_RTP_PKT_CHN(rtp_scratch, rtp_channel);
00498
00499
00500 SET_RTP_PKT_LEN(rtp_scratch, rtp_size);
00501
00502
00503 for(i = 0; i < rtp_size; i+= RTP_DATA_SIZE) {
00504 memcpy(rtp_scratch + 4 + i, RTP_DATA, RTP_DATA_SIZE);
00505 }
00506
00507 if(req->rtp_buffer == NULL) {
00508 req->rtp_buffer = rtp_scratch;
00509 req->rtp_buffersize = rtp_size + 4;
00510 }
00511 else {
00512 req->rtp_buffer = realloc(req->rtp_buffer,
00513 req->rtp_buffersize +
00514 rtp_size + 4);
00515 memcpy(req->rtp_buffer + req->rtp_buffersize, rtp_scratch,
00516 rtp_size + 4);
00517 req->rtp_buffersize += rtp_size + 4;
00518 free(rtp_scratch);
00519 }
00520 logmsg("rtp_buffersize is %zu, rtp_size is %d.",
00521 req->rtp_buffersize, rtp_size);
00522 }
00523 }
00524 else {
00525 logmsg("funny instruction found: %s", ptr);
00526 }
00527
00528 ptr = strchr(ptr, '\n');
00529 if(ptr)
00530 ptr++;
00531 else
00532 ptr = NULL;
00533 } while(ptr && *ptr);
00534 logmsg("Done parsing server commands");
00535 }
00536 free(cmd);
00537 }
00538 }
00539 else {
00540 if(sscanf(req->reqbuf, "CONNECT %" MAXDOCNAMELEN_TXT "s HTTP/%d.%d",
00541 doc, &prot_major, &prot_minor) == 3) {
00542 snprintf(logbuf, sizeof(logbuf),
00543 "Received a CONNECT %s HTTP/%d.%d request",
00544 doc, prot_major, prot_minor);
00545 logmsg("%s", logbuf);
00546
00547 if(req->prot_version == 10)
00548 req->open = FALSE;
00549
00550 if(!strncmp(doc, "bad", 3))
00551
00552 req->testno = DOCNUMBER_BADCONNECT;
00553 else if(!strncmp(doc, "test", 4)) {
00554
00555
00556 char *portp = strchr(doc, ':');
00557 if(portp && (*(portp+1) != '\0') && ISDIGIT(*(portp+1)))
00558 req->testno = strtol(portp+1, NULL, 10);
00559 else
00560 req->testno = DOCNUMBER_CONNECT;
00561 }
00562 else
00563 req->testno = DOCNUMBER_CONNECT;
00564 }
00565 else {
00566 logmsg("Did not find test number in PATH");
00567 req->testno = DOCNUMBER_404;
00568 }
00569 }
00570 }
00571
00572 if(!end) {
00573
00574 logmsg("ProcessRequest returned without a complete request");
00575 return 0;
00576 }
00577 logmsg("ProcessRequest found a complete request");
00578
00579 if(req->pipe)
00580
00581
00582 req->checkindex += (end - line) + strlen(END_OF_HEADERS);
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595 do {
00596 if(got_exit_signal)
00597 return 1;
00598
00599 if((req->cl==0) && strncasecompare("Content-Length:", line, 15)) {
00600
00601
00602
00603
00604 char *endptr;
00605 char *ptr = line + 15;
00606 unsigned long clen = 0;
00607 while(*ptr && ISSPACE(*ptr))
00608 ptr++;
00609 endptr = ptr;
00610 errno = 0;
00611 clen = strtoul(ptr, &endptr, 10);
00612 if((ptr == endptr) || !ISSPACE(*endptr) || (ERANGE == errno)) {
00613
00614 logmsg("Found invalid Content-Length: (%s) in the request", ptr);
00615 req->open = FALSE;
00616 return 1;
00617 }
00618 req->cl = clen - req->skip;
00619
00620 logmsg("Found Content-Length: %lu in the request", clen);
00621 if(req->skip)
00622 logmsg("... but will abort after %zu bytes", req->cl);
00623 break;
00624 }
00625 else if(strncasecompare("Transfer-Encoding: chunked", line,
00626 strlen("Transfer-Encoding: chunked"))) {
00627
00628 chunked = TRUE;
00629 }
00630
00631 if(chunked) {
00632 if(strstr(req->reqbuf, "\r\n0\r\n\r\n"))
00633
00634 return 1;
00635 else
00636 return 0;
00637 }
00638
00639 line = strchr(line, '\n');
00640 if(line)
00641 line++;
00642
00643 } while(line);
00644
00645 if(!req->auth && strstr(req->reqbuf, "Authorization:")) {
00646 req->auth = TRUE;
00647 if(req->auth_req)
00648 logmsg("Authorization header found, as required");
00649 }
00650
00651 if(!req->digest && strstr(req->reqbuf, "Authorization: Digest")) {
00652
00653
00654
00655 req->partno += 1000;
00656 req->digest = TRUE;
00657 logmsg("Received Digest request, sending back data %ld", req->partno);
00658 }
00659 else if(!req->ntlm &&
00660 strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAD")) {
00661
00662 req->partno += 1002;
00663 req->ntlm = TRUE;
00664 logmsg("Received NTLM type-3, sending back data %ld", req->partno);
00665 if(req->cl) {
00666 logmsg(" Expecting %zu POSTed bytes", req->cl);
00667 }
00668 }
00669 else if(!req->ntlm &&
00670 strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAB")) {
00671
00672 req->partno += 1001;
00673 req->ntlm = TRUE;
00674 logmsg("Received NTLM type-1, sending back data %ld", req->partno);
00675 }
00676 else if((req->partno >= 1000) &&
00677 strstr(req->reqbuf, "Authorization: Basic")) {
00678
00679
00680
00681 req->partno += 1;
00682 logmsg("Received Basic request, sending back data %ld", req->partno);
00683 }
00684 if(strstr(req->reqbuf, "Connection: close"))
00685 req->open = FALSE;
00686
00687 if(!req->pipe &&
00688 req->open &&
00689 req->prot_version >= 11 &&
00690 end &&
00691 req->reqbuf + req->offset > end + strlen(END_OF_HEADERS) &&
00692 (!strncmp(req->reqbuf, "GET", strlen("GET")) ||
00693 !strncmp(req->reqbuf, "HEAD", strlen("HEAD")))) {
00694
00695
00696 req->checkindex = (end - req->reqbuf) + strlen(END_OF_HEADERS);
00697 req->pipelining = TRUE;
00698 }
00699
00700 while(req->pipe) {
00701 if(got_exit_signal)
00702 return 1;
00703
00704 line = &req->reqbuf[req->checkindex];
00705 end = strstr(line, END_OF_HEADERS);
00706 if(!end)
00707 break;
00708 req->checkindex += (end - line) + strlen(END_OF_HEADERS);
00709 req->pipe--;
00710 }
00711
00712
00713
00714
00715
00716 if(req->auth_req && !req->auth)
00717 return 1;
00718
00719 if(req->cl > 0) {
00720 if(req->cl <= req->offset - (end - req->reqbuf) - strlen(END_OF_HEADERS))
00721 return 1;
00722 else
00723 return 0;
00724 }
00725
00726 return 1;
00727 }
00728
00729
00730 static void storerequest(char *reqbuf, size_t totalsize)
00731 {
00732 int res;
00733 int error = 0;
00734 size_t written;
00735 size_t writeleft;
00736 FILE *dump;
00737
00738 if(reqbuf == NULL)
00739 return;
00740 if(totalsize == 0)
00741 return;
00742
00743 do {
00744 dump = fopen(REQUEST_DUMP, "ab");
00745 } while((dump == NULL) && ((error = errno) == EINTR));
00746 if(dump == NULL) {
00747 logmsg("Error opening file %s error: %d %s",
00748 REQUEST_DUMP, error, strerror(error));
00749 logmsg("Failed to write request input to " REQUEST_DUMP);
00750 return;
00751 }
00752
00753 writeleft = totalsize;
00754 do {
00755 written = fwrite(&reqbuf[totalsize-writeleft],
00756 1, writeleft, dump);
00757 if(got_exit_signal)
00758 goto storerequest_cleanup;
00759 if(written > 0)
00760 writeleft -= written;
00761 } while((writeleft > 0) && ((error = errno) == EINTR));
00762
00763 if(writeleft == 0)
00764 logmsg("Wrote request (%zu bytes) input to " REQUEST_DUMP, totalsize);
00765 else if(writeleft > 0) {
00766 logmsg("Error writing file %s error: %d %s",
00767 REQUEST_DUMP, error, strerror(error));
00768 logmsg("Wrote only (%zu bytes) of (%zu bytes) request input to %s",
00769 totalsize-writeleft, totalsize, REQUEST_DUMP);
00770 }
00771
00772 storerequest_cleanup:
00773
00774 do {
00775 res = fclose(dump);
00776 } while(res && ((error = errno) == EINTR));
00777 if(res)
00778 logmsg("Error closing file %s error: %d %s",
00779 REQUEST_DUMP, error, strerror(error));
00780 }
00781
00782
00783 static int get_request(curl_socket_t sock, struct httprequest *req)
00784 {
00785 int error;
00786 int fail = 0;
00787 int done_processing = 0;
00788 char *reqbuf = req->reqbuf;
00789 ssize_t got = 0;
00790
00791 char *pipereq = NULL;
00792 size_t pipereq_length = 0;
00793
00794 if(req->pipelining) {
00795 pipereq = reqbuf + req->checkindex;
00796 pipereq_length = req->offset - req->checkindex;
00797 }
00798
00799
00800
00801 req->checkindex = 0;
00802 req->offset = 0;
00803 req->testno = DOCNUMBER_NOTHING;
00804 req->partno = 0;
00805 req->open = TRUE;
00806 req->auth_req = FALSE;
00807 req->auth = FALSE;
00808 req->cl = 0;
00809 req->digest = FALSE;
00810 req->ntlm = FALSE;
00811 req->pipe = 0;
00812 req->skip = 0;
00813 req->rcmd = RCMD_NORMALREQ;
00814 req->protocol = RPROT_NONE;
00815 req->prot_version = 0;
00816 req->pipelining = FALSE;
00817 req->rtp_buffer = NULL;
00818 req->rtp_buffersize = 0;
00819
00820
00821
00822 while(!done_processing && (req->offset < REQBUFSIZ-1)) {
00823 if(pipereq_length && pipereq) {
00824 memmove(reqbuf, pipereq, pipereq_length);
00825 got = curlx_uztosz(pipereq_length);
00826 pipereq_length = 0;
00827 }
00828 else {
00829 if(req->skip)
00830
00831
00832
00833 got = sread(sock, reqbuf + req->offset, req->cl);
00834 else
00835 got = sread(sock, reqbuf + req->offset, REQBUFSIZ-1 - req->offset);
00836 }
00837 if(got_exit_signal)
00838 return 1;
00839 if(got == 0) {
00840 logmsg("Connection closed by client");
00841 fail = 1;
00842 }
00843 else if(got < 0) {
00844 error = SOCKERRNO;
00845 logmsg("recv() returned error: (%d) %s", error, strerror(error));
00846 fail = 1;
00847 }
00848 if(fail) {
00849
00850 reqbuf[req->offset] = '\0';
00851 storerequest(reqbuf, req->offset);
00852 return 1;
00853 }
00854
00855 logmsg("Read %zd bytes", got);
00856
00857 req->offset += (size_t)got;
00858 reqbuf[req->offset] = '\0';
00859
00860 done_processing = ProcessRequest(req);
00861 if(got_exit_signal)
00862 return 1;
00863 if(done_processing && req->pipe) {
00864 logmsg("Waiting for another piped request");
00865 done_processing = 0;
00866 req->pipe--;
00867 }
00868 }
00869
00870 if((req->offset == REQBUFSIZ-1) && (got > 0)) {
00871 logmsg("Request would overflow buffer, closing connection");
00872
00873 reqbuf[REQBUFSIZ-1] = '\0';
00874 fail = 1;
00875 }
00876 else if(req->offset > REQBUFSIZ-1) {
00877 logmsg("Request buffer overflow, closing connection");
00878
00879 reqbuf[REQBUFSIZ-1] = '\0';
00880 fail = 1;
00881 }
00882 else
00883 reqbuf[req->offset] = '\0';
00884
00885
00886 storerequest(reqbuf, req->pipelining ? req->checkindex : req->offset);
00887 if(got_exit_signal)
00888 return 1;
00889
00890 return fail;
00891 }
00892
00893
00894 static int send_doc(curl_socket_t sock, struct httprequest *req)
00895 {
00896 ssize_t written;
00897 size_t count;
00898 const char *buffer;
00899 char *ptr=NULL;
00900 FILE *stream;
00901 char *cmd=NULL;
00902 size_t cmdsize=0;
00903 FILE *dump;
00904 bool persistant = TRUE;
00905 bool sendfailure = FALSE;
00906 size_t responsesize;
00907 int error = 0;
00908 int res;
00909
00910 static char weare[256];
00911
00912 char partbuf[80]="data";
00913
00914 logmsg("Send response number %ld part %ld", req->testno, req->partno);
00915
00916 switch(req->rcmd) {
00917 default:
00918 case RCMD_NORMALREQ:
00919 break;
00920 case RCMD_STREAM:
00921 #define STREAMTHIS "a string to stream 01234567890\n"
00922 count = strlen(STREAMTHIS);
00923 for(;;) {
00924 written = swrite(sock, STREAMTHIS, count);
00925 if(got_exit_signal)
00926 return -1;
00927 if(written != (ssize_t)count) {
00928 logmsg("Stopped streaming");
00929 break;
00930 }
00931 }
00932 return -1;
00933 case RCMD_IDLE:
00934
00935 return 0;
00936 }
00937
00938 req->open = FALSE;
00939
00940 if(req->testno < 0) {
00941 size_t msglen;
00942 char msgbuf[64];
00943
00944 switch(req->testno) {
00945 case DOCNUMBER_QUIT:
00946 logmsg("Replying to QUIT");
00947 buffer = docquit;
00948 break;
00949 case DOCNUMBER_WERULEZ:
00950
00951 logmsg("Identifying ourselves as friends");
00952 snprintf(msgbuf, sizeof(msgbuf), "RTSP_SERVER WE ROOLZ: %ld\r\n",
00953 (long)getpid());
00954 msglen = strlen(msgbuf);
00955 snprintf(weare, sizeof(weare),
00956 "HTTP/1.1 200 OK\r\nContent-Length: %zu\r\n\r\n%s",
00957 msglen, msgbuf);
00958 buffer = weare;
00959 break;
00960 case DOCNUMBER_INTERNAL:
00961 logmsg("Bailing out due to internal error");
00962 return -1;
00963 case DOCNUMBER_CONNECT:
00964 logmsg("Replying to CONNECT");
00965 buffer = docconnect;
00966 break;
00967 case DOCNUMBER_BADCONNECT:
00968 logmsg("Replying to a bad CONNECT");
00969 buffer = docbadconnect;
00970 break;
00971 case DOCNUMBER_404:
00972 default:
00973 logmsg("Replying to with a 404");
00974 if(req->protocol == RPROT_HTTP) {
00975 buffer = doc404_HTTP;
00976 }
00977 else {
00978 buffer = doc404_RTSP;
00979 }
00980 break;
00981 }
00982
00983 count = strlen(buffer);
00984 }
00985 else {
00986 char *filename = test2file(req->testno);
00987
00988 if(0 != req->partno)
00989 snprintf(partbuf, sizeof(partbuf), "data%ld", req->partno);
00990
00991 stream=fopen(filename, "rb");
00992 if(!stream) {
00993 error = errno;
00994 logmsg("fopen() failed with error: %d %s", error, strerror(error));
00995 logmsg("Error opening file: %s", filename);
00996 logmsg("Couldn't open test file");
00997 return 0;
00998 }
00999 else {
01000 error = getpart(&ptr, &count, "reply", partbuf, stream);
01001 fclose(stream);
01002 if(error) {
01003 logmsg("getpart() failed with error: %d", error);
01004 return 0;
01005 }
01006 buffer = ptr;
01007 }
01008
01009 if(got_exit_signal) {
01010 free(ptr);
01011 return -1;
01012 }
01013
01014
01015 stream=fopen(filename, "rb");
01016 if(!stream) {
01017 error = errno;
01018 logmsg("fopen() failed with error: %d %s", error, strerror(error));
01019 logmsg("Error opening file: %s", filename);
01020 logmsg("Couldn't open test file");
01021 free(ptr);
01022 return 0;
01023 }
01024 else {
01025
01026 error = getpart(&cmd, &cmdsize, "reply", "postcmd", stream);
01027 fclose(stream);
01028 if(error) {
01029 logmsg("getpart() failed with error: %d", error);
01030 free(ptr);
01031 return 0;
01032 }
01033 }
01034 }
01035
01036 if(got_exit_signal) {
01037 free(ptr);
01038 free(cmd);
01039 return -1;
01040 }
01041
01042
01043
01044
01045 if(strstr(buffer, "swsclose") || !count) {
01046 persistant = FALSE;
01047 logmsg("connection close instruction \"swsclose\" found in response");
01048 }
01049 if(strstr(buffer, "swsbounce")) {
01050 prevbounce = TRUE;
01051 logmsg("enable \"swsbounce\" in the next request");
01052 }
01053 else
01054 prevbounce = FALSE;
01055
01056 dump = fopen(RESPONSE_DUMP, "ab");
01057 if(!dump) {
01058 error = errno;
01059 logmsg("fopen() failed with error: %d %s", error, strerror(error));
01060 logmsg("Error opening file: %s", RESPONSE_DUMP);
01061 logmsg("couldn't create logfile: " RESPONSE_DUMP);
01062 free(ptr);
01063 free(cmd);
01064 return -1;
01065 }
01066
01067 responsesize = count;
01068 do {
01069
01070
01071
01072 size_t num = count;
01073 if(num > 200)
01074 num = 200;
01075 written = swrite(sock, buffer, num);
01076 if(written < 0) {
01077 sendfailure = TRUE;
01078 break;
01079 }
01080 else {
01081 logmsg("Sent off %zd bytes", written);
01082 }
01083
01084 fwrite(buffer, 1, (size_t)written, dump);
01085 if(got_exit_signal)
01086 break;
01087
01088 count -= written;
01089 buffer += written;
01090 } while(count>0);
01091
01092
01093 if(req->rtp_buffer) {
01094 logmsg("About to write %zu RTP bytes", req->rtp_buffersize);
01095 count = req->rtp_buffersize;
01096 do {
01097 size_t num = count;
01098 if(num > 200)
01099 num = 200;
01100 written = swrite(sock, req->rtp_buffer + (req->rtp_buffersize - count),
01101 num);
01102 if(written < 0) {
01103 sendfailure = TRUE;
01104 break;
01105 }
01106 count -= written;
01107 } while(count > 0);
01108
01109 free(req->rtp_buffer);
01110 req->rtp_buffersize = 0;
01111 }
01112
01113 do {
01114 res = fclose(dump);
01115 } while(res && ((error = errno) == EINTR));
01116 if(res)
01117 logmsg("Error closing file %s error: %d %s",
01118 RESPONSE_DUMP, error, strerror(error));
01119
01120 if(got_exit_signal) {
01121 free(ptr);
01122 free(cmd);
01123 return -1;
01124 }
01125
01126 if(sendfailure) {
01127 logmsg("Sending response failed. Only (%zu bytes) of "
01128 "(%zu bytes) were sent",
01129 responsesize-count, responsesize);
01130 free(ptr);
01131 free(cmd);
01132 return -1;
01133 }
01134
01135 logmsg("Response sent (%zu bytes) and written to " RESPONSE_DUMP,
01136 responsesize);
01137 free(ptr);
01138
01139 if(cmdsize > 0) {
01140 char command[32];
01141 int quarters;
01142 int num;
01143 ptr=cmd;
01144 do {
01145 if(2 == sscanf(ptr, "%31s %d", command, &num)) {
01146 if(!strcmp("wait", command)) {
01147 logmsg("Told to sleep for %d seconds", num);
01148 quarters = num * 4;
01149 while(quarters > 0) {
01150 quarters--;
01151 res = wait_ms(250);
01152 if(got_exit_signal)
01153 break;
01154 if(res) {
01155
01156 error = errno;
01157 logmsg("wait_ms() failed with error: (%d) %s",
01158 error, strerror(error));
01159 break;
01160 }
01161 }
01162 if(!quarters)
01163 logmsg("Continuing after sleeping %d seconds", num);
01164 }
01165 else
01166 logmsg("Unknown command in reply command section");
01167 }
01168 ptr = strchr(ptr, '\n');
01169 if(ptr)
01170 ptr++;
01171 else
01172 ptr = NULL;
01173 } while(ptr && *ptr);
01174 }
01175 free(cmd);
01176 req->open = persistant;
01177
01178 prevtestno = req->testno;
01179 prevpartno = req->partno;
01180
01181 return 0;
01182 }
01183
01184
01185 int main(int argc, char *argv[])
01186 {
01187 srvr_sockaddr_union_t me;
01188 curl_socket_t sock = CURL_SOCKET_BAD;
01189 curl_socket_t msgsock = CURL_SOCKET_BAD;
01190 int wrotepidfile = 0;
01191 int flag;
01192 unsigned short port = DEFAULT_PORT;
01193 char *pidname= (char *)".rtsp.pid";
01194 struct httprequest req;
01195 int rc;
01196 int error;
01197 int arg=1;
01198 long pid;
01199
01200 while(argc>arg) {
01201 if(!strcmp("--version", argv[arg])) {
01202 printf("rtspd IPv4%s"
01203 "\n"
01204 ,
01205 #ifdef ENABLE_IPV6
01206 "/IPv6"
01207 #else
01208 ""
01209 #endif
01210 );
01211 return 0;
01212 }
01213 else if(!strcmp("--pidfile", argv[arg])) {
01214 arg++;
01215 if(argc>arg)
01216 pidname = argv[arg++];
01217 }
01218 else if(!strcmp("--logfile", argv[arg])) {
01219 arg++;
01220 if(argc>arg)
01221 serverlogfile = argv[arg++];
01222 }
01223 else if(!strcmp("--ipv4", argv[arg])) {
01224 #ifdef ENABLE_IPV6
01225 ipv_inuse = "IPv4";
01226 use_ipv6 = FALSE;
01227 #endif
01228 arg++;
01229 }
01230 else if(!strcmp("--ipv6", argv[arg])) {
01231 #ifdef ENABLE_IPV6
01232 ipv_inuse = "IPv6";
01233 use_ipv6 = TRUE;
01234 #endif
01235 arg++;
01236 }
01237 else if(!strcmp("--port", argv[arg])) {
01238 arg++;
01239 if(argc>arg) {
01240 char *endptr;
01241 unsigned long ulnum = strtoul(argv[arg], &endptr, 10);
01242 if((endptr != argv[arg] + strlen(argv[arg])) ||
01243 (ulnum < 1025UL) || (ulnum > 65535UL)) {
01244 fprintf(stderr, "rtspd: invalid --port argument (%s)\n",
01245 argv[arg]);
01246 return 0;
01247 }
01248 port = curlx_ultous(ulnum);
01249 arg++;
01250 }
01251 }
01252 else if(!strcmp("--srcdir", argv[arg])) {
01253 arg++;
01254 if(argc>arg) {
01255 path = argv[arg];
01256 arg++;
01257 }
01258 }
01259 else {
01260 puts("Usage: rtspd [option]\n"
01261 " --version\n"
01262 " --logfile [file]\n"
01263 " --pidfile [file]\n"
01264 " --ipv4\n"
01265 " --ipv6\n"
01266 " --port [port]\n"
01267 " --srcdir [path]");
01268 return 0;
01269 }
01270 }
01271
01272 #ifdef WIN32
01273 win32_init();
01274 atexit(win32_cleanup);
01275 #endif
01276
01277 install_signal_handlers();
01278
01279 pid = (long)getpid();
01280
01281 #ifdef ENABLE_IPV6
01282 if(!use_ipv6)
01283 #endif
01284 sock = socket(AF_INET, SOCK_STREAM, 0);
01285 #ifdef ENABLE_IPV6
01286 else
01287 sock = socket(AF_INET6, SOCK_STREAM, 0);
01288 #endif
01289
01290 if(CURL_SOCKET_BAD == sock) {
01291 error = SOCKERRNO;
01292 logmsg("Error creating socket: (%d) %s",
01293 error, strerror(error));
01294 goto server_cleanup;
01295 }
01296
01297 flag = 1;
01298 if(0 != setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
01299 (void *)&flag, sizeof(flag))) {
01300 error = SOCKERRNO;
01301 logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s",
01302 error, strerror(error));
01303 goto server_cleanup;
01304 }
01305
01306 #ifdef ENABLE_IPV6
01307 if(!use_ipv6) {
01308 #endif
01309 memset(&me.sa4, 0, sizeof(me.sa4));
01310 me.sa4.sin_family = AF_INET;
01311 me.sa4.sin_addr.s_addr = INADDR_ANY;
01312 me.sa4.sin_port = htons(port);
01313 rc = bind(sock, &me.sa, sizeof(me.sa4));
01314 #ifdef ENABLE_IPV6
01315 }
01316 else {
01317 memset(&me.sa6, 0, sizeof(me.sa6));
01318 me.sa6.sin6_family = AF_INET6;
01319 me.sa6.sin6_addr = in6addr_any;
01320 me.sa6.sin6_port = htons(port);
01321 rc = bind(sock, &me.sa, sizeof(me.sa6));
01322 }
01323 #endif
01324 if(0 != rc) {
01325 error = SOCKERRNO;
01326 logmsg("Error binding socket on port %hu: (%d) %s",
01327 port, error, strerror(error));
01328 goto server_cleanup;
01329 }
01330
01331 logmsg("Running %s version on port %d", ipv_inuse, (int)port);
01332
01333
01334 rc = listen(sock, 5);
01335 if(0 != rc) {
01336 error = SOCKERRNO;
01337 logmsg("listen() failed with error: (%d) %s",
01338 error, strerror(error));
01339 goto server_cleanup;
01340 }
01341
01342
01343
01344
01345
01346
01347 wrotepidfile = write_pidfile(pidname);
01348 if(!wrotepidfile)
01349 goto server_cleanup;
01350
01351 for(;;) {
01352 msgsock = accept(sock, NULL, NULL);
01353
01354 if(got_exit_signal)
01355 break;
01356 if(CURL_SOCKET_BAD == msgsock) {
01357 error = SOCKERRNO;
01358 logmsg("MAJOR ERROR: accept() failed with error: (%d) %s",
01359 error, strerror(error));
01360 break;
01361 }
01362
01363
01364
01365
01366
01367
01368
01369 set_advisor_read_lock(SERVERLOGS_LOCK);
01370 serverlogslocked = 1;
01371
01372 logmsg("====> Client connect");
01373
01374 #ifdef TCP_NODELAY
01375
01376
01377
01378
01379 flag = 1;
01380 if(setsockopt(msgsock, IPPROTO_TCP, TCP_NODELAY,
01381 (void *)&flag, sizeof(flag)) == -1) {
01382 logmsg("====> TCP_NODELAY failed");
01383 }
01384 #endif
01385
01386
01387
01388
01389
01390 req.pipelining = FALSE;
01391
01392 do {
01393 if(got_exit_signal)
01394 break;
01395
01396 if(get_request(msgsock, &req))
01397
01398 break;
01399
01400 if(prevbounce) {
01401
01402 if((req.testno == prevtestno) &&
01403 (req.partno == prevpartno)) {
01404 req.partno++;
01405 logmsg("BOUNCE part number to %ld", req.partno);
01406 }
01407 else {
01408 prevbounce = FALSE;
01409 prevtestno = -1;
01410 prevpartno = -1;
01411 }
01412 }
01413
01414 send_doc(msgsock, &req);
01415 if(got_exit_signal)
01416 break;
01417
01418 if((req.testno < 0) && (req.testno != DOCNUMBER_CONNECT)) {
01419 logmsg("special request received, no persistency");
01420 break;
01421 }
01422 if(!req.open) {
01423 logmsg("instructed to close connection after server-reply");
01424 break;
01425 }
01426
01427 if(req.open)
01428 logmsg("=> persistant connection request ended, awaits new request");
01429
01430 } while(req.open || (req.testno == DOCNUMBER_CONNECT));
01431
01432 if(got_exit_signal)
01433 break;
01434
01435 logmsg("====> Client disconnect");
01436 sclose(msgsock);
01437 msgsock = CURL_SOCKET_BAD;
01438
01439 if(serverlogslocked) {
01440 serverlogslocked = 0;
01441 clear_advisor_read_lock(SERVERLOGS_LOCK);
01442 }
01443
01444 if(req.testno == DOCNUMBER_QUIT)
01445 break;
01446 }
01447
01448 server_cleanup:
01449
01450 if((msgsock != sock) && (msgsock != CURL_SOCKET_BAD))
01451 sclose(msgsock);
01452
01453 if(sock != CURL_SOCKET_BAD)
01454 sclose(sock);
01455
01456 if(got_exit_signal)
01457 logmsg("signalled to die");
01458
01459 if(wrotepidfile)
01460 unlink(pidname);
01461
01462 if(serverlogslocked) {
01463 serverlogslocked = 0;
01464 clear_advisor_read_lock(SERVERLOGS_LOCK);
01465 }
01466
01467 restore_signal_handlers();
01468
01469 if(got_exit_signal) {
01470 logmsg("========> %s rtspd (port: %d pid: %ld) exits with signal (%d)",
01471 ipv_inuse, (int)port, pid, exit_signal);
01472
01473
01474
01475
01476
01477 raise(exit_signal);
01478 }
01479
01480 logmsg("========> rtspd quits");
01481 return 0;
01482 }
01483