33 #ifdef HAVE_NETINET_IN_H 34 #include <netinet/in.h> 36 #ifdef HAVE_ARPA_INET_H 37 #include <arpa/inet.h> 42 #ifdef HAVE_NETINET_TCP_H 43 #include <netinet/tcp.h> 46 #define ENABLE_CURLX_PRINTF 70 #define REQBUFSIZ 150000 71 #define REQBUFSIZ_TXT "149999" 79 #define RCMD_NORMALREQ 0 89 #define SET_RTP_PKT_CHN(p,c) ((p)[1] = (unsigned char)((c) & 0xFF)) 91 #define SET_RTP_PKT_LEN(p,l) (((p)[2] = (unsigned char)(((l) >> 8) & 0xFF)), \ 92 ((p)[3] = (unsigned char)((l) & 0xFF))) 124 #define DEFAULT_PORT 8999 126 #ifndef DEFAULT_LOGFILE 127 #define DEFAULT_LOGFILE "log/rtspd.log" 132 #define RTSPDVERSION "curl test suite RTSP server/0.1" 134 #define REQUEST_DUMP "log/server.input" 135 #define RESPONSE_DUMP "log/server.response" 138 #define MAXDOCNAMELEN 140000 139 #define MAXDOCNAMELEN_TXT "139999" 141 #define REQUEST_KEYWORD_SIZE 256 142 #define REQUEST_KEYWORD_SIZE_TXT "255" 144 #define CMD_AUTH_REQUIRED "auth_required" 148 #define CMD_IDLE "idle" 151 #define CMD_STREAM "stream" 153 #define END_OF_HEADERS "\r\n\r\n" 181 "Connection: close\r\n" 182 "Content-Type: text/html" 184 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" 186 "<TITLE>404 Not Found</TITLE>\n" 188 "<H1>Not Found</H1>\n" 189 "The requested URL was not found on this server.\n" 190 "<P><HR><ADDRESS>" RTSPDVERSION "</ADDRESS>\n" "</BODY></HTML>\n";
198 #define RTP_DATA_SIZE 12 203 #ifndef HAVE_SIGINTERRUPT 204 #define siginterrupt(x,y) do {} while(0) 231 #if defined(SIGBREAK) && defined(WIN32) 250 int old_errno = errno;
263 old_sighup_handler = signal(SIGHUP, SIG_IGN);
264 if(old_sighup_handler == SIG_ERR)
265 logmsg(
"cannot install SIGHUP handler: %s", strerror(errno));
269 old_sigpipe_handler = signal(SIGPIPE, SIG_IGN);
270 if(old_sigpipe_handler == SIG_ERR)
271 logmsg(
"cannot install SIGPIPE handler: %s", strerror(errno));
275 old_sigalrm_handler = signal(SIGALRM, SIG_IGN);
276 if(old_sigalrm_handler == SIG_ERR)
277 logmsg(
"cannot install SIGALRM handler: %s", strerror(errno));
282 if(old_sigint_handler == SIG_ERR)
283 logmsg(
"cannot install SIGINT handler: %s", strerror(errno));
290 if(old_sigterm_handler == SIG_ERR)
291 logmsg(
"cannot install SIGTERM handler: %s", strerror(errno));
295 #if defined(SIGBREAK) && defined(WIN32) 298 if(old_sigbreak_handler == SIG_ERR)
299 logmsg(
"cannot install SIGBREAK handler: %s", strerror(errno));
308 if(SIG_ERR != old_sighup_handler)
309 (void)signal(SIGHUP, old_sighup_handler);
312 if(SIG_ERR != old_sigpipe_handler)
313 (void)signal(SIGPIPE, old_sigpipe_handler);
316 if(SIG_ERR != old_sigalrm_handler)
317 (void)signal(SIGALRM, old_sigalrm_handler);
320 if(SIG_ERR != old_sigint_handler)
321 (void)signal(SIGINT, old_sigint_handler);
324 if(SIG_ERR != old_sigterm_handler)
325 (void)signal(SIGTERM, old_sigterm_handler);
327 #if defined(SIGBREAK) && defined(WIN32) 328 if(SIG_ERR != old_sigbreak_handler)
329 (void)signal(SIGBREAK, old_sigbreak_handler);
336 bool chunked =
FALSE;
339 static char prot_str[5];
341 int prot_major, prot_minor;
346 logmsg(
"ProcessRequest() called with testno %ld and line [%s]",
361 if(!strcmp(prot_str,
"HTTP")) {
364 else if(!strcmp(prot_str,
"RTSP")) {
369 logmsg(
"got unknown protocol %s", prot_str);
376 ptr = strrchr(doc,
'/');
383 if((strlen(doc) + strlen(request)) < 200)
384 snprintf(logbuf,
sizeof(logbuf),
"Got request: %s %s %s/%d.%d",
385 request, doc, prot_str, prot_major, prot_minor);
387 snprintf(logbuf,
sizeof(logbuf),
"Got a *HUGE* request %s/%d.%d",
388 prot_str, prot_major, prot_minor);
391 if(!strncmp(
"/verifiedserver", ptr, 15)) {
392 logmsg(
"Are-we-friendly question received");
397 if(!strncmp(
"/quit", ptr, 5)) {
398 logmsg(
"Request-to-quit received");
409 req->
testno = strtol(ptr, &ptr, 10);
418 snprintf(logbuf,
sizeof(logbuf),
"Requested test number %ld part %ld",
424 stream = fopen(filename,
"rb");
427 logmsg(
"fopen() failed with error: %d %s", error, strerror(error));
428 logmsg(
"Error opening file: %s", filename);
442 char *rtp_scratch = NULL;
445 error =
getpart(&cmd, &cmdsize,
"reply",
"servercmd", stream);
448 logmsg(
"getpart() failed with error: %d", error);
455 logmsg(
"Found a reply-servercmd section!");
458 logmsg(
"instructed to require authorization header");
462 logmsg(
"instructed to idle");
467 logmsg(
"instructed to stream");
470 else if(1 == sscanf(ptr,
"pipe: %d", &num)) {
471 logmsg(
"instructed to allow a pipe size of %d", num);
473 logmsg(
"negative pipe size ignored");
478 else if(1 == sscanf(ptr,
"skip: %d", &num)) {
479 logmsg(
"instructed to skip this number of bytes %d", num);
482 else if(3 == sscanf(ptr,
"rtp: part %d channel %d size %d",
483 &rtp_partno, &rtp_channel, &rtp_size)) {
485 if(rtp_partno == req->
partno) {
486 logmsg(
"RTP: part %d channel %d size %d",
487 rtp_partno, rtp_channel, rtp_size);
494 rtp_scratch[0] =
'$';
520 logmsg(
"rtp_buffersize is %zu, rtp_size is %d.",
525 logmsg(
"funny instruction found: %s", ptr);
528 ptr = strchr(ptr,
'\n');
533 }
while(ptr && *ptr);
534 logmsg(
"Done parsing server commands");
540 if(sscanf(req->
reqbuf,
"CONNECT %" MAXDOCNAMELEN_TXT
"s HTTP/%d.%d",
541 doc, &prot_major, &prot_minor) == 3) {
543 "Received a CONNECT %s HTTP/%d.%d request",
544 doc, prot_major, prot_minor);
550 if(!strncmp(doc,
"bad", 3))
553 else if(!strncmp(doc,
"test", 4)) {
556 char *portp = strchr(doc,
':');
557 if(portp && (*(portp + 1) !=
'\0') &&
ISDIGIT(*(portp + 1)))
558 req->
testno = strtol(portp + 1, NULL, 10);
566 logmsg(
"Did not find test number in PATH");
574 logmsg(
"ProcessRequest returned without a complete request");
577 logmsg(
"ProcessRequest found a complete request");
605 char *
ptr = line + 15;
606 unsigned long clen = 0;
611 clen = strtoul(ptr, &endptr, 10);
612 if((ptr == endptr) || !
ISSPACE(*endptr) || (ERANGE == errno)) {
614 logmsg(
"Found invalid Content-Length: (%s) in the request", ptr);
618 req->
cl = clen - req->
skip;
620 logmsg(
"Found Content-Length: %lu in the request", clen);
622 logmsg(
"... but will abort after %zu bytes", req->
cl);
626 strlen(
"Transfer-Encoding: chunked"))) {
632 if(strstr(req->
reqbuf,
"\r\n0\r\n\r\n"))
639 line = strchr(line,
'\n');
645 if(!req->
auth && strstr(req->
reqbuf,
"Authorization:")) {
648 logmsg(
"Authorization header found, as required");
651 if(!req->
digest && strstr(req->
reqbuf,
"Authorization: Digest")) {
657 logmsg(
"Received Digest request, sending back data %ld", req->
partno);
659 else if(!req->
ntlm &&
660 strstr(req->
reqbuf,
"Authorization: NTLM TlRMTVNTUAAD")) {
664 logmsg(
"Received NTLM type-3, sending back data %ld", req->
partno);
666 logmsg(
" Expecting %zu POSTed bytes", req->
cl);
669 else if(!req->
ntlm &&
670 strstr(req->
reqbuf,
"Authorization: NTLM TlRMTVNTUAAB")) {
674 logmsg(
"Received NTLM type-1, sending back data %ld", req->
partno);
676 else if((req->
partno >= 1000) &&
677 strstr(req->
reqbuf,
"Authorization: Basic")) {
682 logmsg(
"Received Basic request, sending back data %ld", req->
partno);
684 if(strstr(req->
reqbuf,
"Connection: close"))
692 (!strncmp(req->
reqbuf,
"GET", strlen(
"GET")) ||
693 !strncmp(req->
reqbuf,
"HEAD", strlen(
"HEAD")))) {
745 }
while((dump == NULL) && ((error = errno) == EINTR));
747 logmsg(
"Error opening file %s error: %d %s",
753 writeleft = totalsize;
755 written =
fwrite(&reqbuf[totalsize-writeleft],
758 goto storerequest_cleanup;
760 writeleft -= written;
761 }
while((writeleft > 0) && ((error = errno) == EINTR));
765 else if(writeleft > 0) {
766 logmsg(
"Error writing file %s error: %d %s",
768 logmsg(
"Wrote only (%zu bytes) of (%zu bytes) request input to %s",
772 storerequest_cleanup:
776 }
while(res && ((error = errno) == EINTR));
778 logmsg(
"Error closing file %s error: %d %s",
791 char *pipereq = NULL;
792 size_t pipereq_length = 0;
823 if(pipereq_length && pipereq) {
824 memmove(reqbuf, pipereq, pipereq_length);
833 got = sread(sock, reqbuf + req->
offset, req->
cl);
840 logmsg(
"Connection closed by client");
845 logmsg(
"recv() returned error: (%d) %s", error, strerror(error));
850 reqbuf[req->
offset] =
'\0';
855 logmsg(
"Read %zd bytes", got);
858 reqbuf[req->
offset] =
'\0';
863 if(done_processing && req->
pipe) {
864 logmsg(
"Waiting for another piped request");
871 logmsg(
"Request would overflow buffer, closing connection");
877 logmsg(
"Request buffer overflow, closing connection");
883 reqbuf[req->
offset] =
'\0';
904 bool persistant =
TRUE;
905 bool sendfailure =
FALSE;
910 static char weare[256];
912 char partbuf[80]=
"data";
921 #define STREAMTHIS "a string to stream 01234567890\n" 927 if(written != (
ssize_t)count) {
928 logmsg(
"Stopped streaming");
946 logmsg(
"Replying to QUIT");
951 logmsg(
"Identifying ourselves as friends");
952 snprintf(msgbuf,
sizeof(msgbuf),
"RTSP_SERVER WE ROOLZ: %ld\r\n",
954 msglen = strlen(msgbuf);
956 "HTTP/1.1 200 OK\r\nContent-Length: %zu\r\n\r\n%s",
961 logmsg(
"Bailing out due to internal error");
964 logmsg(
"Replying to CONNECT");
968 logmsg(
"Replying to a bad CONNECT");
973 logmsg(
"Replying to with a 404");
983 count = strlen(buffer);
991 stream = fopen(filename,
"rb");
994 logmsg(
"fopen() failed with error: %d %s", error, strerror(error));
995 logmsg(
"Error opening file: %s", filename);
996 logmsg(
"Couldn't open test file");
1000 error =
getpart(&ptr, &count,
"reply", partbuf, stream);
1003 logmsg(
"getpart() failed with error: %d", error);
1015 stream = fopen(filename,
"rb");
1018 logmsg(
"fopen() failed with error: %d %s", error, strerror(error));
1019 logmsg(
"Error opening file: %s", filename);
1020 logmsg(
"Couldn't open test file");
1026 error =
getpart(&cmd, &cmdsize,
"reply",
"postcmd", stream);
1029 logmsg(
"getpart() failed with error: %d", error);
1045 if(strstr(buffer,
"swsclose") || !count) {
1047 logmsg(
"connection close instruction \"swsclose\" found in response");
1049 if(strstr(buffer,
"swsbounce")) {
1051 logmsg(
"enable \"swsbounce\" in the next request");
1059 logmsg(
"fopen() failed with error: %d %s", error, strerror(error));
1067 responsesize = count;
1075 written = swrite(sock, buffer, num);
1081 logmsg(
"Sent off %zd bytes", written);
1084 fwrite(buffer, 1, (
size_t)written, dump);
1115 }
while(res && ((error = errno) == EINTR));
1117 logmsg(
"Error closing file %s error: %d %s",
1127 logmsg(
"Sending response failed. Only (%zu bytes) of " 1128 "(%zu bytes) were sent",
1129 responsesize-count, responsesize);
1145 if(2 == sscanf(ptr,
"%31s %d", command, &num)) {
1146 if(!strcmp(
"wait", command)) {
1147 logmsg(
"Told to sleep for %d seconds", num);
1149 while(quarters > 0) {
1157 logmsg(
"wait_ms() failed with error: (%d) %s",
1158 error, strerror(error));
1163 logmsg(
"Continuing after sleeping %d seconds", num);
1166 logmsg(
"Unknown command in reply command section");
1168 ptr = strchr(ptr,
'\n');
1173 }
while(ptr && *ptr);
1176 req->
open = persistant;
1193 const char *
pidname =
".rtsp.pid";
1200 memset(&req, 0,
sizeof(req));
1203 if(!strcmp(
"--version", argv[arg])) {
1215 else if(!strcmp(
"--pidfile", argv[arg])) {
1218 pidname = argv[arg++];
1220 else if(!strcmp(
"--logfile", argv[arg])) {
1225 else if(!strcmp(
"--ipv4", argv[arg])) {
1232 else if(!strcmp(
"--ipv6", argv[arg])) {
1239 else if(!strcmp(
"--port", argv[arg])) {
1243 unsigned long ulnum = strtoul(argv[arg], &endptr, 10);
1244 if((endptr != argv[arg] + strlen(argv[arg])) ||
1245 (ulnum < 1025UL) || (ulnum > 65535UL)) {
1246 fprintf(stderr,
"rtspd: invalid --port argument (%s)\n",
1254 else if(!strcmp(
"--srcdir", argv[arg])) {
1262 puts(
"Usage: rtspd [option]\n" 1264 " --logfile [file]\n" 1265 " --pidfile [file]\n" 1269 " --srcdir [path]");
1281 pid = (long)getpid();
1286 sock = socket(AF_INET, SOCK_STREAM, 0);
1289 sock = socket(AF_INET6, SOCK_STREAM, 0);
1294 logmsg(
"Error creating socket: (%d) %s",
1295 error, strerror(error));
1296 goto server_cleanup;
1300 if(0 != setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
1301 (
void *)&flag,
sizeof(flag))) {
1303 logmsg(
"setsockopt(SO_REUSEADDR) failed with error: (%d) %s",
1304 error, strerror(error));
1305 goto server_cleanup;
1311 memset(&me.
sa4, 0,
sizeof(me.
sa4));
1312 me.
sa4.sin_family = AF_INET;
1313 me.
sa4.sin_addr.s_addr = INADDR_ANY;
1314 me.
sa4.sin_port = htons(port);
1315 rc =
bind(sock, &me.
sa,
sizeof(me.
sa4));
1319 memset(&me.sa6, 0,
sizeof(me.sa6));
1320 me.sa6.sin6_family = AF_INET6;
1321 me.sa6.sin6_addr = in6addr_any;
1322 me.sa6.sin6_port = htons(port);
1323 rc =
bind(sock, &me.
sa,
sizeof(me.sa6));
1328 logmsg(
"Error binding socket on port %hu: (%d) %s",
1329 port, error, strerror(error));
1330 goto server_cleanup;
1336 rc = listen(sock, 5);
1339 logmsg(
"listen() failed with error: (%d) %s",
1340 error, strerror(error));
1341 goto server_cleanup;
1351 goto server_cleanup;
1354 msgsock = accept(sock, NULL, NULL);
1360 logmsg(
"MAJOR ERROR: accept() failed with error: (%d) %s",
1361 error, strerror(error));
1374 logmsg(
"====> Client connect");
1382 if(setsockopt(msgsock, IPPROTO_TCP, TCP_NODELAY,
1383 (
void *)&flag,
sizeof(flag)) == -1) {
1384 logmsg(
"====> TCP_NODELAY failed");
1421 logmsg(
"special request received, no persistency");
1425 logmsg(
"instructed to close connection after server-reply");
1430 logmsg(
"=> persistant connection request ended, awaits new request");
1437 logmsg(
"====> Client disconnect");
1459 logmsg(
"signalled to die");
1472 logmsg(
"========> %s rtspd (port: %d pid: %ld) exits with signal (%d)",
1482 logmsg(
"========> rtspd quits");
#define CMD_AUTH_REQUIRED
static int get_request(curl_socket_t sock, struct httprequest *req)
UNITTEST_START char * ptr
int write_pidfile(const char *filename)
static const char * ipv_inuse
static int send_doc(curl_socket_t sock, struct httprequest *req)
static void win32_cleanup(void)
#define realloc(ptr, size)
void clear_advisor_read_lock(const char *filename)
const char * serverlogfile
ssize_t curlx_uztosz(size_t uznum)
static const char * docbadconnect
static int serverlogslocked
static RETSIGTYPE exit_signal_handler(int signum)
static volatile int exit_signal
#define siginterrupt(x, y)
unsigned short curlx_ultous(unsigned long ulnum)
memcpy(filename, filename1, strlen(filename1))
void logmsg(const char *msg,...)
#define SET_RTP_PKT_LEN(p, l)
curl_easy_setopt expects a curl_off_t argument for this option curl_easy_setopt expects a curl_write_callback argument for this option curl_easy_setopt expects a curl_ioctl_callback argument for this option curl_easy_setopt expects a curl_opensocket_callback argument for this option curl_easy_setopt expects a curl_debug_callback argument for this option curl_easy_setopt expects a curl_conv_callback argument for this option curl_easy_setopt expects a private data pointer as argument for this option curl_easy_setopt expects a FILE *argument for this option curl_easy_setopt expects a struct curl_httppost *argument for this option curl_easy_setopt expects a struct curl_slist *argument for this option curl_easy_getinfo expects a pointer to char *for this info curl_easy_getinfo expects a pointer to double for this info curl_easy_getinfo expects a pointer to struct curl_tlssessioninfo *for this info curl_easy_getinfo expects a pointer to curl_socket_t for this info size_t
ROSLIB_DECL std::string command(const std::string &cmd)
RETSIGTYPE(* SIGHANDLER_T)(int)
#define REQUEST_KEYWORD_SIZE
#define strncasecompare(a, b, c)
static void storerequest(char *reqbuf, size_t totalsize)
static const char * docquit
static void restore_signal_handlers(void)
static unsigned short port
static const char * RTP_DATA
static int ProcessRequest(struct httprequest *req)
static const char * doc404_RTSP
#define SET_RTP_PKT_CHN(p, c)
static CURLcode win32_init(void)
static void install_signal_handlers(void)
int main(int argc, char *argv[])
#define MAXDOCNAMELEN_TXT
static const char * doc404_HTTP
char * test2file(long testno)
SIG_ATOMIC_T got_exit_signal
int getpart(char **outbuf, size_t *outlen, const char *main, const char *sub, FILE *stream)
#define REQUEST_KEYWORD_SIZE_TXT
static const char * docconnect
static const char * pidname
static void dump(const char *text, FILE *stream, unsigned char *ptr, size_t size, char nohex)
void set_advisor_read_lock(const char *filename)