00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "RTSPServer.hh"
00022 #include "RTSPCommon.hh"
00023 #include "Base64.hh"
00024 #include <GroupsockHelper.hh>
00025
00026 #if defined(__WIN32__) || defined(_WIN32) || defined(_QNX4)
00027 #else
00028 #include <signal.h>
00029 #define USE_SIGNALS 1
00030 #endif
00031
00033
00034 RTSPServer*
00035 RTSPServer::createNew(UsageEnvironment& env, Port ourPort,
00036 UserAuthenticationDatabase* authDatabase,
00037 unsigned reclamationTestSeconds) {
00038 int ourSocket = setUpOurSocket(env, ourPort);
00039 if (ourSocket == -1) return NULL;
00040
00041 return new RTSPServer(env, ourSocket, ourPort, authDatabase, reclamationTestSeconds);
00042 }
00043
00044 Boolean RTSPServer::lookupByName(UsageEnvironment& env,
00045 char const* name,
00046 RTSPServer*& resultServer) {
00047 resultServer = NULL;
00048
00049 Medium* medium;
00050 if (!Medium::lookupByName(env, name, medium)) return False;
00051
00052 if (!medium->isRTSPServer()) {
00053 env.setResultMsg(name, " is not a RTSP server");
00054 return False;
00055 }
00056
00057 resultServer = (RTSPServer*)medium;
00058 return True;
00059 }
00060
00061 void RTSPServer::addServerMediaSession(ServerMediaSession* serverMediaSession) {
00062 if (serverMediaSession == NULL) return;
00063
00064 char const* sessionName = serverMediaSession->streamName();
00065 if (sessionName == NULL) sessionName = "";
00066 removeServerMediaSession(sessionName);
00067
00068 fServerMediaSessions->Add(sessionName, (void*)serverMediaSession);
00069 }
00070
00071 ServerMediaSession* RTSPServer::lookupServerMediaSession(char const* streamName) {
00072 return (ServerMediaSession*)(fServerMediaSessions->Lookup(streamName));
00073 }
00074
00075 void RTSPServer::removeServerMediaSession(ServerMediaSession* serverMediaSession) {
00076 if (serverMediaSession == NULL) return;
00077
00078 fServerMediaSessions->Remove(serverMediaSession->streamName());
00079 if (serverMediaSession->referenceCount() == 0) {
00080 Medium::close(serverMediaSession);
00081 } else {
00082 serverMediaSession->deleteWhenUnreferenced() = True;
00083 }
00084 }
00085
00086 void RTSPServer::removeServerMediaSession(char const* streamName) {
00087 removeServerMediaSession((ServerMediaSession*)(fServerMediaSessions->Lookup(streamName)));
00088 }
00089
00090 char* RTSPServer
00091 ::rtspURL(ServerMediaSession const* serverMediaSession, int clientSocket) const {
00092 char* urlPrefix = rtspURLPrefix(clientSocket);
00093 char const* sessionName = serverMediaSession->streamName();
00094
00095 char* resultURL = new char[strlen(urlPrefix) + strlen(sessionName) + 1];
00096 sprintf(resultURL, "%s%s", urlPrefix, sessionName);
00097
00098 delete[] urlPrefix;
00099 return resultURL;
00100 }
00101
00102 char* RTSPServer::rtspURLPrefix(int clientSocket) const {
00103 struct sockaddr_in ourAddress;
00104 if (clientSocket < 0) {
00105
00106 ourAddress.sin_addr.s_addr = ReceivingInterfaceAddr != 0
00107 ? ReceivingInterfaceAddr
00108 : ourIPAddress(envir());
00109 } else {
00110 SOCKLEN_T namelen = sizeof ourAddress;
00111 getsockname(clientSocket, (struct sockaddr*)&ourAddress, &namelen);
00112 }
00113
00114 char urlBuffer[100];
00115
00116 portNumBits portNumHostOrder = ntohs(fRTSPServerPort.num());
00117 if (portNumHostOrder == 554 ) {
00118 sprintf(urlBuffer, "rtsp://%s/", AddressString(ourAddress).val());
00119 } else {
00120 sprintf(urlBuffer, "rtsp://%s:%hu/",
00121 AddressString(ourAddress).val(), portNumHostOrder);
00122 }
00123
00124 return strDup(urlBuffer);
00125 }
00126
00127 UserAuthenticationDatabase* RTSPServer::setAuthenticationDatabase(UserAuthenticationDatabase* newDB) {
00128 UserAuthenticationDatabase* oldDB = fAuthDB;
00129 fAuthDB = newDB;
00130
00131 return oldDB;
00132 }
00133
00134 Boolean RTSPServer::setUpTunnelingOverHTTP(Port httpPort) {
00135 fHTTPServerSocket = setUpOurSocket(envir(), httpPort);
00136 if (fHTTPServerSocket >= 0) {
00137 fHTTPServerPort = httpPort;
00138 envir().taskScheduler().turnOnBackgroundReadHandling(fHTTPServerSocket,
00139 (TaskScheduler::BackgroundHandlerProc*)&incomingConnectionHandlerHTTP, this);
00140 return True;
00141 }
00142
00143 return False;
00144 }
00145
00146 portNumBits RTSPServer::httpServerPortNum() const {
00147 return ntohs(fHTTPServerPort.num());
00148 }
00149
00150 #define LISTEN_BACKLOG_SIZE 20
00151
00152 int RTSPServer::setUpOurSocket(UsageEnvironment& env, Port& ourPort) {
00153 int ourSocket = -1;
00154
00155 do {
00156
00157
00158 #ifndef ALLOW_RTSP_SERVER_PORT_REUSE
00159 NoReuse dummy(env);
00160 #endif
00161
00162 ourSocket = setupStreamSocket(env, ourPort);
00163 if (ourSocket < 0) break;
00164
00165
00166 if (!increaseSendBufferTo(env, ourSocket, 50*1024)) break;
00167
00168
00169 if (listen(ourSocket, LISTEN_BACKLOG_SIZE) < 0) {
00170 env.setResultErrMsg("listen() failed: ");
00171 break;
00172 }
00173
00174 if (ourPort.num() == 0) {
00175
00176 if (!getSourcePort(env, ourSocket, ourPort)) break;
00177 }
00178
00179 return ourSocket;
00180 } while (0);
00181
00182 if (ourSocket != -1) ::closeSocket(ourSocket);
00183 return -1;
00184 }
00185
00186 Boolean RTSPServer
00187 ::specialClientAccessCheck(int , struct sockaddr_in& , char const* ) {
00188
00189 return True;
00190 }
00191
00192 RTSPServer::RTSPServer(UsageEnvironment& env,
00193 int ourSocket, Port ourPort,
00194 UserAuthenticationDatabase* authDatabase,
00195 unsigned reclamationTestSeconds)
00196 : Medium(env),
00197 fRTSPServerSocket(ourSocket), fRTSPServerPort(ourPort),
00198 fHTTPServerSocket(-1), fHTTPServerPort(0), fClientSessionsForHTTPTunneling(NULL),
00199 fAuthDB(authDatabase), fReclamationTestSeconds(reclamationTestSeconds),
00200 fServerMediaSessions(HashTable::create(STRING_HASH_KEYS)) {
00201 #ifdef USE_SIGNALS
00202
00203
00204 #ifdef SO_NOSIGPIPE
00205 int set_option = 1;
00206 setsockopt(ourSocket, SOL_SOCKET, SO_NOSIGPIPE, &set_option, sizeof set_option);
00207 #else
00208 signal(SIGPIPE, SIG_IGN);
00209 #endif
00210 #endif
00211
00212
00213 env.taskScheduler().turnOnBackgroundReadHandling(fRTSPServerSocket,
00214 (TaskScheduler::BackgroundHandlerProc*)&incomingConnectionHandlerRTSP, this);
00215 }
00216
00217 RTSPServer::~RTSPServer() {
00218
00219 envir().taskScheduler().turnOffBackgroundReadHandling(fRTSPServerSocket);
00220 ::closeSocket(fRTSPServerSocket);
00221
00222 envir().taskScheduler().turnOffBackgroundReadHandling(fHTTPServerSocket);
00223 ::closeSocket(fHTTPServerSocket);
00224
00225 delete fClientSessionsForHTTPTunneling;
00226
00227
00228 while (1) {
00229 ServerMediaSession* serverMediaSession
00230 = (ServerMediaSession*)fServerMediaSessions->RemoveNext();
00231 if (serverMediaSession == NULL) break;
00232 removeServerMediaSession(serverMediaSession);
00233 }
00234
00235
00236 delete fServerMediaSessions;
00237 }
00238
00239 Boolean RTSPServer::isRTSPServer() const {
00240 return True;
00241 }
00242
00243 void RTSPServer::incomingConnectionHandlerRTSP(void* instance, int ) {
00244 RTSPServer* server = (RTSPServer*)instance;
00245 server->incomingConnectionHandlerRTSP1();
00246 }
00247 void RTSPServer::incomingConnectionHandlerRTSP1() {
00248 incomingConnectionHandler(fRTSPServerSocket);
00249 }
00250
00251 void RTSPServer::incomingConnectionHandlerHTTP(void* instance, int ) {
00252 RTSPServer* server = (RTSPServer*)instance;
00253 server->incomingConnectionHandlerHTTP1();
00254 }
00255 void RTSPServer::incomingConnectionHandlerHTTP1() {
00256 incomingConnectionHandler(fHTTPServerSocket);
00257 }
00258
00259 void RTSPServer::incomingConnectionHandler(int serverSocket) {
00260 struct sockaddr_in clientAddr;
00261 SOCKLEN_T clientAddrLen = sizeof clientAddr;
00262 int clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientAddrLen);
00263 if (clientSocket < 0) {
00264 int err = envir().getErrno();
00265 if (err != EWOULDBLOCK) {
00266 envir().setResultErrMsg("accept() failed: ");
00267 }
00268 return;
00269 }
00270 makeSocketNonBlocking(clientSocket);
00271 increaseSendBufferTo(envir(), clientSocket, 50*1024);
00272
00273 #ifdef DEBUG
00274 envir() << "accept()ed connection from " << AddressString(clientAddr).val() << "\n";
00275 #endif
00276
00277
00278
00279
00280
00281 unsigned sessionId;
00282 do { sessionId = (unsigned)our_random32(); } while (sessionId == 0);
00283 (void)createNewClientSession(sessionId, clientSocket, clientAddr);
00284 }
00285
00286
00288
00289 RTSPServer::RTSPClientSession
00290 ::RTSPClientSession(RTSPServer& ourServer, unsigned sessionId, int clientSocket, struct sockaddr_in clientAddr)
00291 : fOurServer(ourServer), fOurSessionId(sessionId),
00292 fOurServerMediaSession(NULL),
00293 fClientInputSocket(clientSocket), fClientOutputSocket(clientSocket), fClientAddr(clientAddr),
00294 fSessionCookie(NULL), fLivenessCheckTask(NULL),
00295 fIsMulticast(False), fSessionIsActive(True), fStreamAfterSETUP(False),
00296 fTCPStreamIdCount(0), fNumStreamStates(0), fStreamStates(NULL), fRecursionCount(0) {
00297
00298 resetRequestBuffer();
00299 envir().taskScheduler().turnOnBackgroundReadHandling(fClientInputSocket,
00300 (TaskScheduler::BackgroundHandlerProc*)&incomingRequestHandler, this);
00301 noteLiveness();
00302 }
00303
00304 RTSPServer::RTSPClientSession::~RTSPClientSession() {
00305 closeSockets();
00306
00307 if (fSessionCookie != NULL) {
00308
00309 fOurServer.fClientSessionsForHTTPTunneling->Remove(fSessionCookie);
00310 delete[] fSessionCookie;
00311 }
00312
00313 reclaimStreamStates();
00314
00315 if (fOurServerMediaSession != NULL) {
00316 fOurServerMediaSession->decrementReferenceCount();
00317 if (fOurServerMediaSession->referenceCount() == 0
00318 && fOurServerMediaSession->deleteWhenUnreferenced()) {
00319 fOurServer.removeServerMediaSession(fOurServerMediaSession);
00320 fOurServerMediaSession = NULL;
00321 }
00322 }
00323 }
00324
00325 void RTSPServer::RTSPClientSession::closeSockets() {
00326
00327 envir().taskScheduler().unscheduleDelayedTask(fLivenessCheckTask);
00328
00329
00330 envir().taskScheduler().turnOffBackgroundReadHandling(fClientInputSocket);
00331
00332 if (fClientOutputSocket != fClientInputSocket) ::closeSocket(fClientOutputSocket);
00333 ::closeSocket(fClientInputSocket);
00334
00335 fClientInputSocket = fClientOutputSocket = -1;
00336 }
00337
00338 void RTSPServer::RTSPClientSession::reclaimStreamStates() {
00339 for (unsigned i = 0; i < fNumStreamStates; ++i) {
00340 if (fStreamStates[i].subsession != NULL) {
00341 fStreamStates[i].subsession->deleteStream(fOurSessionId,
00342 fStreamStates[i].streamToken);
00343 }
00344 }
00345 delete[] fStreamStates; fStreamStates = NULL;
00346 fNumStreamStates = 0;
00347 }
00348
00349 void RTSPServer::RTSPClientSession::resetRequestBuffer() {
00350 fRequestBytesAlreadySeen = 0;
00351 fRequestBufferBytesLeft = sizeof fRequestBuffer;
00352 fLastCRLF = &fRequestBuffer[-3];
00353 fBase64RemainderCount = 0;
00354 }
00355
00356 void RTSPServer::RTSPClientSession::incomingRequestHandler(void* instance, int ) {
00357 RTSPClientSession* session = (RTSPClientSession*)instance;
00358 session->incomingRequestHandler1();
00359 }
00360
00361 void RTSPServer::RTSPClientSession::incomingRequestHandler1() {
00362 struct sockaddr_in dummy;
00363
00364 int bytesRead = readSocket(envir(), fClientInputSocket, &fRequestBuffer[fRequestBytesAlreadySeen], fRequestBufferBytesLeft, dummy);
00365 handleRequestBytes(bytesRead);
00366 }
00367
00368 void RTSPServer::RTSPClientSession::handleAlternativeRequestByte(void* instance, u_int8_t requestByte) {
00369 RTSPClientSession* session = (RTSPClientSession*)instance;
00370 session->handleAlternativeRequestByte1(requestByte);
00371 }
00372
00373 void RTSPServer::RTSPClientSession::handleAlternativeRequestByte1(u_int8_t requestByte) {
00374
00375 if (fRequestBufferBytesLeft == 0 || fRequestBytesAlreadySeen >= RTSP_BUFFER_SIZE) return;
00376 fRequestBuffer[fRequestBytesAlreadySeen] = requestByte;
00377 handleRequestBytes(1);
00378 }
00379
00380 void RTSPServer::RTSPClientSession::handleRequestBytes(int newBytesRead) {
00381 int numBytesRemaining = 0;
00382 ++fRecursionCount;
00383
00384 do {
00385 noteLiveness();
00386
00387 if (newBytesRead <= 0 || (unsigned)newBytesRead >= fRequestBufferBytesLeft) {
00388
00389
00390 #ifdef DEBUG
00391 fprintf(stderr, "RTSPClientSession[%p]::handleRequestBytes() read %d new bytes (of %d); terminating connection!\n", this, newBytesRead, fRequestBufferBytesLeft);
00392 #endif
00393 fSessionIsActive = False;
00394 break;
00395 }
00396
00397 Boolean endOfMsg = False;
00398 unsigned char* ptr = &fRequestBuffer[fRequestBytesAlreadySeen];
00399 #ifdef DEBUG
00400 ptr[newBytesRead] = '\0';
00401 fprintf(stderr, "RTSPClientSession[%p]::handleRequestBytes() %s %d new bytes:%s\n",
00402 this, numBytesRemaining > 0 ? "processing" : "read", newBytesRead, ptr);
00403 #endif
00404
00405 if (fClientOutputSocket != fClientInputSocket) {
00406
00407
00408 unsigned numBytesToDecode = fBase64RemainderCount + newBytesRead;
00409 unsigned newBase64RemainderCount = numBytesToDecode%4;
00410 numBytesToDecode -= newBase64RemainderCount;
00411 if (numBytesToDecode > 0) {
00412 ptr[newBytesRead] = '\0';
00413 unsigned decodedSize;
00414 unsigned char* decodedBytes = base64Decode((char const*)(ptr-fBase64RemainderCount), decodedSize);
00415 #ifdef DEBUG
00416 fprintf(stderr, "Base64-decoded %d input bytes into %d new bytes:", numBytesToDecode, decodedSize);
00417 for (unsigned k = 0; k < decodedSize; ++k) fprintf(stderr, "%c", decodedBytes[k]);
00418 fprintf(stderr, "\n");
00419 #endif
00420
00421
00422 unsigned char* to = ptr-fBase64RemainderCount;
00423 for (unsigned i = 0; i < decodedSize; ++i) *to++ = decodedBytes[i];
00424
00425
00426 for (unsigned j = 0; j < newBase64RemainderCount; ++j) *to++ = (ptr-fBase64RemainderCount+numBytesToDecode)[j];
00427
00428 newBytesRead = decodedSize + newBase64RemainderCount;
00429 delete[] decodedBytes;
00430 }
00431 fBase64RemainderCount = newBase64RemainderCount;
00432 if (fBase64RemainderCount > 0) break;
00433 }
00434
00435
00436 unsigned char *tmpPtr = fLastCRLF + 2;
00437 if (tmpPtr < fRequestBuffer) tmpPtr = fRequestBuffer;
00438 while (tmpPtr < &ptr[newBytesRead-1]) {
00439 if (*tmpPtr == '\r' && *(tmpPtr+1) == '\n') {
00440 if (tmpPtr - fLastCRLF == 2) {
00441 endOfMsg = True;
00442 break;
00443 }
00444 fLastCRLF = tmpPtr;
00445 }
00446 ++tmpPtr;
00447 }
00448
00449 fRequestBufferBytesLeft -= newBytesRead;
00450 fRequestBytesAlreadySeen += newBytesRead;
00451
00452 if (!endOfMsg) break;
00453
00454
00455 fRequestBuffer[fRequestBytesAlreadySeen] = '\0';
00456 char cmdName[RTSP_PARAM_STRING_MAX];
00457 char urlPreSuffix[RTSP_PARAM_STRING_MAX];
00458 char urlSuffix[RTSP_PARAM_STRING_MAX];
00459 char cseq[RTSP_PARAM_STRING_MAX];
00460 unsigned contentLength;
00461 *fLastCRLF = '\0';
00462 Boolean parseSucceeded = parseRTSPRequestString((char*)fRequestBuffer, fRequestBytesAlreadySeen,
00463 cmdName, sizeof cmdName,
00464 urlPreSuffix, sizeof urlPreSuffix,
00465 urlSuffix, sizeof urlSuffix,
00466 cseq, sizeof cseq,
00467 contentLength);
00468 *fLastCRLF = '\r';
00469 if (parseSucceeded) {
00470 #ifdef DEBUG
00471 fprintf(stderr, "parseRTSPRequestString() succeeded, returning cmdName \"%s\", urlPreSuffix \"%s\", urlSuffix \"%s\", CSeq \"%s\", Content-Length %u, with %d bytes following the message.\n", cmdName, urlPreSuffix, urlSuffix, cseq, contentLength, ptr + newBytesRead - (tmpPtr + 2));
00472 #endif
00473
00474 if (ptr + newBytesRead < tmpPtr + 2 + contentLength) break;
00475
00476 if (strcmp(cmdName, "OPTIONS") == 0) {
00477 handleCmd_OPTIONS(cseq);
00478 } else if (strcmp(cmdName, "DESCRIBE") == 0) {
00479 handleCmd_DESCRIBE(cseq, urlPreSuffix, urlSuffix, (char const*)fRequestBuffer);
00480 } else if (strcmp(cmdName, "SETUP") == 0) {
00481 handleCmd_SETUP(cseq, urlPreSuffix, urlSuffix, (char const*)fRequestBuffer);
00482 } else if (strcmp(cmdName, "TEARDOWN") == 0
00483 || strcmp(cmdName, "PLAY") == 0
00484 || strcmp(cmdName, "PAUSE") == 0
00485 || strcmp(cmdName, "GET_PARAMETER") == 0
00486 || strcmp(cmdName, "SET_PARAMETER") == 0) {
00487 handleCmd_withinSession(cmdName, urlPreSuffix, urlSuffix, cseq, (char const*)fRequestBuffer);
00488 } else {
00489 handleCmd_notSupported(cseq);
00490 }
00491 } else {
00492 #ifdef DEBUG
00493 fprintf(stderr, "parseRTSPRequestString() failed\n");
00494 #endif
00495
00496 char sessionCookie[RTSP_PARAM_STRING_MAX];
00497 char acceptStr[RTSP_PARAM_STRING_MAX];
00498 *fLastCRLF = '\0';
00499 parseSucceeded = parseHTTPRequestString(cmdName, sizeof cmdName,
00500 urlSuffix, sizeof urlPreSuffix,
00501 sessionCookie, sizeof sessionCookie,
00502 acceptStr, sizeof acceptStr);
00503 *fLastCRLF = '\r';
00504 if (parseSucceeded) {
00505 #ifdef DEBUG
00506 fprintf(stderr, "parseHTTPRequestString() succeeded, returning cmdName \"%s\", urlSuffix \"%s\", sessionCookie \"%s\", acceptStr \"%s\"\n", cmdName, urlSuffix, sessionCookie, acceptStr);
00507 #endif
00508
00509 Boolean isValidHTTPCmd = True;
00510 if (sessionCookie[0] == '\0') {
00511
00512
00513 if (strcmp(acceptStr, "application/x-rtsp-tunnelled") == 0) {
00514 isValidHTTPCmd = False;
00515 } else {
00516 handleHTTPCmd_StreamingGET(urlSuffix, (char const*)fRequestBuffer);
00517 }
00518 } else if (strcmp(cmdName, "GET") == 0) {
00519 handleHTTPCmd_TunnelingGET(sessionCookie);
00520 } else if (strcmp(cmdName, "POST") == 0) {
00521
00522
00523 unsigned char const* extraData = fLastCRLF+4;
00524 unsigned extraDataSize = &fRequestBuffer[fRequestBytesAlreadySeen] - extraData;
00525 if (handleHTTPCmd_TunnelingPOST(sessionCookie, extraData, extraDataSize)) {
00526
00527 fSessionIsActive = False;
00528 break;
00529 }
00530 } else {
00531 isValidHTTPCmd = False;
00532 }
00533 if (!isValidHTTPCmd) {
00534 handleHTTPCmd_notSupported();
00535 }
00536 } else {
00537 #ifdef DEBUG
00538 fprintf(stderr, "parseHTTPRequestString() failed!\n");
00539 #endif
00540 handleCmd_bad(cseq);
00541 }
00542 }
00543
00544 #ifdef DEBUG
00545 fprintf(stderr, "sending response: %s", fResponseBuffer);
00546 #endif
00547 send(fClientOutputSocket, (char const*)fResponseBuffer, strlen((char*)fResponseBuffer), 0);
00548
00549 if (strcmp(cmdName, "SETUP") == 0 && fStreamAfterSETUP) {
00550
00551
00552 handleCmd_withinSession("PLAY", urlPreSuffix, urlSuffix, cseq,
00553 (char const*)fRequestBuffer);
00554 }
00555
00556
00557
00558 unsigned requestSize = (fLastCRLF+4-fRequestBuffer) + contentLength;
00559 numBytesRemaining = fRequestBytesAlreadySeen - requestSize;
00560 resetRequestBuffer();
00561
00562 if (numBytesRemaining > 0) {
00563 memmove(fRequestBuffer, &fRequestBuffer[requestSize], numBytesRemaining);
00564 newBytesRead = numBytesRemaining;
00565 }
00566 } while (numBytesRemaining > 0);
00567
00568 --fRecursionCount;
00569 if (!fSessionIsActive) {
00570 if (fRecursionCount > 0) closeSockets(); else delete this;
00571
00572
00573 }
00574 }
00575
00576
00577
00578 static char const* allowedCommandNames
00579 = "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, GET_PARAMETER, SET_PARAMETER";
00580
00581 void RTSPServer::RTSPClientSession::handleCmd_bad(char const* ) {
00582
00583 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00584 "RTSP/1.0 400 Bad Request\r\n%sAllow: %s\r\n\r\n",
00585 dateHeader(), allowedCommandNames);
00586 }
00587
00588 void RTSPServer::RTSPClientSession::handleCmd_notSupported(char const* cseq) {
00589 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00590 "RTSP/1.0 405 Method Not Allowed\r\nCSeq: %s\r\n%sAllow: %s\r\n\r\n",
00591 cseq, dateHeader(), allowedCommandNames);
00592 }
00593
00594 void RTSPServer::RTSPClientSession::handleCmd_notFound(char const* cseq) {
00595 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00596 "RTSP/1.0 404 Stream Not Found\r\nCSeq: %s\r\n%s\r\n",
00597 cseq, dateHeader());
00598 fSessionIsActive = False;
00599 }
00600
00601 void RTSPServer::RTSPClientSession::handleCmd_unsupportedTransport(char const* cseq) {
00602 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00603 "RTSP/1.0 461 Unsupported Transport\r\nCSeq: %s\r\n%s\r\n",
00604 cseq, dateHeader());
00605 fSessionIsActive = False;
00606 }
00607
00608 void RTSPServer::RTSPClientSession::handleCmd_OPTIONS(char const* cseq) {
00609 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00610 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sPublic: %s\r\n\r\n",
00611 cseq, dateHeader(), allowedCommandNames);
00612 }
00613
00614 void RTSPServer::RTSPClientSession
00615 ::handleCmd_DESCRIBE(char const* cseq,
00616 char const* urlPreSuffix, char const* urlSuffix,
00617 char const* fullRequestStr) {
00618 char* sdpDescription = NULL;
00619 char* rtspURL = NULL;
00620 do {
00621 char urlTotalSuffix[RTSP_PARAM_STRING_MAX];
00622 if (strlen(urlPreSuffix) + strlen(urlSuffix) + 2 > sizeof urlTotalSuffix) {
00623 handleCmd_bad(cseq);
00624 break;
00625 }
00626 urlTotalSuffix[0] = '\0';
00627 if (urlPreSuffix[0] != '\0') {
00628 strcat(urlTotalSuffix, urlPreSuffix);
00629 strcat(urlTotalSuffix, "/");
00630 }
00631 strcat(urlTotalSuffix, urlSuffix);
00632
00633 if (!authenticationOK("DESCRIBE", cseq, urlTotalSuffix, fullRequestStr)) break;
00634
00635
00636
00637
00638
00639 ServerMediaSession* session = fOurServer.lookupServerMediaSession(urlTotalSuffix);
00640 if (session == NULL) {
00641 handleCmd_notFound(cseq);
00642 break;
00643 }
00644
00645
00646 sdpDescription = session->generateSDPDescription();
00647 if (sdpDescription == NULL) {
00648
00649
00650 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00651 "RTSP/1.0 404 File Not Found, Or In Incorrect Format\r\n"
00652 "CSeq: %s\r\n"
00653 "%s\r\n",
00654 cseq,
00655 dateHeader());
00656 break;
00657 }
00658 unsigned sdpDescriptionSize = strlen(sdpDescription);
00659
00660
00661
00662
00663 rtspURL = fOurServer.rtspURL(session, fClientInputSocket);
00664
00665 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00666 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n"
00667 "%s"
00668 "Content-Base: %s/\r\n"
00669 "Content-Type: application/sdp\r\n"
00670 "Content-Length: %d\r\n\r\n"
00671 "%s",
00672 cseq,
00673 dateHeader(),
00674 rtspURL,
00675 sdpDescriptionSize,
00676 sdpDescription);
00677 } while (0);
00678
00679 delete[] sdpDescription;
00680 delete[] rtspURL;
00681 }
00682
00683 typedef enum StreamingMode {
00684 RTP_UDP,
00685 RTP_TCP,
00686 RAW_UDP
00687 } StreamingMode;
00688
00689 static void parseTransportHeader(char const* buf,
00690 StreamingMode& streamingMode,
00691 char*& streamingModeString,
00692 char*& destinationAddressStr,
00693 u_int8_t& destinationTTL,
00694 portNumBits& clientRTPPortNum,
00695 portNumBits& clientRTCPPortNum,
00696 unsigned char& rtpChannelId,
00697 unsigned char& rtcpChannelId
00698 ) {
00699
00700 streamingMode = RTP_UDP;
00701 streamingModeString = NULL;
00702 destinationAddressStr = NULL;
00703 destinationTTL = 255;
00704 clientRTPPortNum = 0;
00705 clientRTCPPortNum = 1;
00706 rtpChannelId = rtcpChannelId = 0xFF;
00707
00708 portNumBits p1, p2;
00709 unsigned ttl, rtpCid, rtcpCid;
00710
00711
00712 while (1) {
00713 if (*buf == '\0') return;
00714 if (*buf == '\r' && *(buf+1) == '\n' && *(buf+2) == '\r') return;
00715 if (_strncasecmp(buf, "Transport: ", 11) == 0) break;
00716 ++buf;
00717 }
00718
00719
00720 char const* fields = buf + 11;
00721 char* field = strDupSize(fields);
00722 while (sscanf(fields, "%[^;\r\n]", field) == 1) {
00723 if (strcmp(field, "RTP/AVP/TCP") == 0) {
00724 streamingMode = RTP_TCP;
00725 } else if (strcmp(field, "RAW/RAW/UDP") == 0 ||
00726 strcmp(field, "MP2T/H2221/UDP") == 0) {
00727 streamingMode = RAW_UDP;
00728 streamingModeString = strDup(field);
00729 } else if (_strncasecmp(field, "destination=", 12) == 0) {
00730 delete[] destinationAddressStr;
00731 destinationAddressStr = strDup(field+12);
00732 } else if (sscanf(field, "ttl%u", &ttl) == 1) {
00733 destinationTTL = (u_int8_t)ttl;
00734 } else if (sscanf(field, "client_port=%hu-%hu", &p1, &p2) == 2) {
00735 clientRTPPortNum = p1;
00736 clientRTCPPortNum = streamingMode == RAW_UDP ? 0 : p2;
00737 } else if (sscanf(field, "client_port=%hu", &p1) == 1) {
00738 clientRTPPortNum = p1;
00739 clientRTCPPortNum = streamingMode == RAW_UDP ? 0 : p1 + 1;
00740 } else if (sscanf(field, "interleaved=%u-%u", &rtpCid, &rtcpCid) == 2) {
00741 rtpChannelId = (unsigned char)rtpCid;
00742 rtcpChannelId = (unsigned char)rtcpCid;
00743 }
00744
00745 fields += strlen(field);
00746 while (*fields == ';') ++fields;
00747 if (*fields == '\0' || *fields == '\r' || *fields == '\n') break;
00748 }
00749 delete[] field;
00750 }
00751
00752 static Boolean parsePlayNowHeader(char const* buf) {
00753
00754 while (1) {
00755 if (*buf == '\0') return False;
00756 if (_strncasecmp(buf, "x-playNow:", 10) == 0) break;
00757 ++buf;
00758 }
00759
00760 return True;
00761 }
00762
00763 void RTSPServer::RTSPClientSession
00764 ::handleCmd_SETUP(char const* cseq,
00765 char const* urlPreSuffix, char const* urlSuffix,
00766 char const* fullRequestStr) {
00767
00768
00769
00770
00771
00772 char const* streamName = urlPreSuffix;
00773 char const* trackId = urlSuffix;
00774 char* concatenatedStreamName = NULL;
00775
00776 do {
00777
00778 ServerMediaSession* prevSMS = fOurServerMediaSession;
00779 fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName);
00780 if (fOurServerMediaSession == NULL) {
00781
00782 if (urlPreSuffix[0] == '\0') {
00783 streamName = urlSuffix;
00784 } else {
00785 concatenatedStreamName = new char[strlen(urlPreSuffix) + strlen(urlSuffix) + 2];
00786 sprintf(concatenatedStreamName, "%s/%s", urlPreSuffix, urlSuffix);
00787 streamName = concatenatedStreamName;
00788 }
00789 trackId = NULL;
00790
00791
00792 fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName);
00793 }
00794 if (fOurServerMediaSession == NULL) {
00795 handleCmd_notFound(cseq);
00796 break;
00797 }
00798
00799 if (fOurServerMediaSession != prevSMS) {
00800
00801 fOurServerMediaSession->incrementReferenceCount();
00802 }
00803
00804 if (fStreamStates == NULL) {
00805
00806 ServerMediaSubsessionIterator iter(*fOurServerMediaSession);
00807 for (fNumStreamStates = 0; iter.next() != NULL; ++fNumStreamStates) {}
00808
00809 fStreamStates = new struct streamState[fNumStreamStates];
00810
00811 iter.reset();
00812 ServerMediaSubsession* subsession;
00813 for (unsigned i = 0; i < fNumStreamStates; ++i) {
00814 subsession = iter.next();
00815 fStreamStates[i].subsession = subsession;
00816 fStreamStates[i].streamToken = NULL;
00817 }
00818 }
00819
00820
00821 ServerMediaSubsession* subsession = NULL;
00822 unsigned streamNum;
00823 if (trackId != NULL && trackId[0] != '\0') {
00824 for (streamNum = 0; streamNum < fNumStreamStates; ++streamNum) {
00825 subsession = fStreamStates[streamNum].subsession;
00826 if (subsession != NULL && strcmp(trackId, subsession->trackId()) == 0) break;
00827 }
00828 if (streamNum >= fNumStreamStates) {
00829
00830 handleCmd_notFound(cseq);
00831 break;
00832 }
00833 } else {
00834
00835
00836 if (fNumStreamStates != 1) {
00837 handleCmd_bad(cseq);
00838 break;
00839 }
00840 streamNum = 0;
00841 subsession = fStreamStates[streamNum].subsession;
00842 }
00843
00844
00845
00846 StreamingMode streamingMode;
00847 char* streamingModeString = NULL;
00848 char* clientsDestinationAddressStr;
00849 u_int8_t clientsDestinationTTL;
00850 portNumBits clientRTPPortNum, clientRTCPPortNum;
00851 unsigned char rtpChannelId, rtcpChannelId;
00852 parseTransportHeader(fullRequestStr, streamingMode, streamingModeString,
00853 clientsDestinationAddressStr, clientsDestinationTTL,
00854 clientRTPPortNum, clientRTCPPortNum,
00855 rtpChannelId, rtcpChannelId);
00856 if (streamingMode == RTP_TCP && rtpChannelId == 0xFF ||
00857 streamingMode != RTP_TCP && fClientOutputSocket != fClientInputSocket) {
00858
00859
00860
00861
00862 streamingMode = RTP_TCP;
00863 rtpChannelId = fTCPStreamIdCount; rtcpChannelId = fTCPStreamIdCount+1;
00864 }
00865 fTCPStreamIdCount += 2;
00866
00867 Port clientRTPPort(clientRTPPortNum);
00868 Port clientRTCPPort(clientRTCPPortNum);
00869
00870
00871
00872 double rangeStart = 0.0, rangeEnd = 0.0;
00873 fStreamAfterSETUP = parseRangeHeader(fullRequestStr, rangeStart, rangeEnd) || parsePlayNowHeader(fullRequestStr);
00874
00875
00876 int tcpSocketNum = streamingMode == RTP_TCP ? fClientOutputSocket : -1;
00877 netAddressBits destinationAddress = 0;
00878 u_int8_t destinationTTL = 255;
00879 #ifdef RTSP_ALLOW_CLIENT_DESTINATION_SETTING
00880 if (clientsDestinationAddressStr != NULL) {
00881
00882
00883
00884
00885 destinationAddress = our_inet_addr(clientsDestinationAddressStr);
00886 }
00887
00888 destinationTTL = clientsDestinationTTL;
00889 #endif
00890 delete[] clientsDestinationAddressStr;
00891 Port serverRTPPort(0);
00892 Port serverRTCPPort(0);
00893
00894
00895 struct sockaddr_in sourceAddr; SOCKLEN_T namelen = sizeof sourceAddr;
00896 getsockname(fClientInputSocket, (struct sockaddr*)&sourceAddr, &namelen);
00897 netAddressBits origSendingInterfaceAddr = SendingInterfaceAddr;
00898 netAddressBits origReceivingInterfaceAddr = ReceivingInterfaceAddr;
00899
00900 #ifdef HACK_FOR_MULTIHOMED_SERVERS
00901 ReceivingInterfaceAddr = SendingInterfaceAddr = sourceAddr.sin_addr.s_addr;
00902 #endif
00903
00904 subsession->getStreamParameters(fOurSessionId, fClientAddr.sin_addr.s_addr,
00905 clientRTPPort, clientRTCPPort,
00906 tcpSocketNum, rtpChannelId, rtcpChannelId,
00907 destinationAddress, destinationTTL, fIsMulticast,
00908 serverRTPPort, serverRTCPPort,
00909 fStreamStates[streamNum].streamToken);
00910 SendingInterfaceAddr = origSendingInterfaceAddr;
00911 ReceivingInterfaceAddr = origReceivingInterfaceAddr;
00912
00913 AddressString destAddrStr(destinationAddress);
00914 AddressString sourceAddrStr(sourceAddr);
00915 if (fIsMulticast) {
00916 switch (streamingMode) {
00917 case RTP_UDP:
00918 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00919 "RTSP/1.0 200 OK\r\n"
00920 "CSeq: %s\r\n"
00921 "%s"
00922 "Transport: RTP/AVP;multicast;destination=%s;source=%s;port=%d-%d;ttl=%d\r\n"
00923 "Session: %08X\r\n\r\n",
00924 cseq,
00925 dateHeader(),
00926 destAddrStr.val(), sourceAddrStr.val(), ntohs(serverRTPPort.num()), ntohs(serverRTCPPort.num()), destinationTTL,
00927 fOurSessionId);
00928 break;
00929 case RTP_TCP:
00930
00931 handleCmd_unsupportedTransport(cseq);
00932 break;
00933 case RAW_UDP:
00934 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00935 "RTSP/1.0 200 OK\r\n"
00936 "CSeq: %s\r\n"
00937 "%s"
00938 "Transport: %s;multicast;destination=%s;source=%s;port=%d;ttl=%d\r\n"
00939 "Session: %08X\r\n\r\n",
00940 cseq,
00941 dateHeader(),
00942 streamingModeString, destAddrStr.val(), sourceAddrStr.val(), ntohs(serverRTPPort.num()), destinationTTL,
00943 fOurSessionId);
00944 break;
00945 }
00946 } else {
00947 switch (streamingMode) {
00948 case RTP_UDP: {
00949 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00950 "RTSP/1.0 200 OK\r\n"
00951 "CSeq: %s\r\n"
00952 "%s"
00953 "Transport: RTP/AVP;unicast;destination=%s;source=%s;client_port=%d-%d;server_port=%d-%d\r\n"
00954 "Session: %08X\r\n\r\n",
00955 cseq,
00956 dateHeader(),
00957 destAddrStr.val(), sourceAddrStr.val(), ntohs(clientRTPPort.num()), ntohs(clientRTCPPort.num()), ntohs(serverRTPPort.num()), ntohs(serverRTCPPort.num()),
00958 fOurSessionId);
00959 break;
00960 }
00961 case RTP_TCP: {
00962 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00963 "RTSP/1.0 200 OK\r\n"
00964 "CSeq: %s\r\n"
00965 "%s"
00966 "Transport: RTP/AVP/TCP;unicast;destination=%s;source=%s;interleaved=%d-%d\r\n"
00967 "Session: %08X\r\n\r\n",
00968 cseq,
00969 dateHeader(),
00970 destAddrStr.val(), sourceAddrStr.val(), rtpChannelId, rtcpChannelId,
00971 fOurSessionId);
00972 break;
00973 }
00974 case RAW_UDP: {
00975 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00976 "RTSP/1.0 200 OK\r\n"
00977 "CSeq: %s\r\n"
00978 "%s"
00979 "Transport: %s;unicast;destination=%s;source=%s;client_port=%d;server_port=%d\r\n"
00980 "Session: %08X\r\n\r\n",
00981 cseq,
00982 dateHeader(),
00983 streamingModeString, destAddrStr.val(), sourceAddrStr.val(), ntohs(clientRTPPort.num()), ntohs(serverRTPPort.num()),
00984 fOurSessionId);
00985 break;
00986 }
00987 }
00988 }
00989 delete[] streamingModeString;
00990 } while (0);
00991
00992 delete[] concatenatedStreamName;
00993 }
00994
00995 void RTSPServer::RTSPClientSession
00996 ::handleCmd_withinSession(char const* cmdName,
00997 char const* urlPreSuffix, char const* urlSuffix,
00998 char const* cseq, char const* fullRequestStr) {
00999
01000
01001
01002
01003
01004
01005
01006
01007 ServerMediaSubsession* subsession;
01008 if (urlPreSuffix[0] == '\0' && urlSuffix[0] == '*' && urlSuffix[1] == '\0') {
01009
01010 if (strcmp(cmdName, "GET_PARAMETER") == 0) {
01011 handleCmd_GET_PARAMETER(NULL, cseq, fullRequestStr);
01012 } else if (strcmp(cmdName, "SET_PARAMETER") == 0) {
01013 handleCmd_SET_PARAMETER(NULL, cseq, fullRequestStr);
01014 } else {
01015 handleCmd_notSupported(cseq);
01016 }
01017 return;
01018 } else if (fOurServerMediaSession == NULL) {
01019 handleCmd_notSupported(cseq);
01020 return;
01021 } else if (urlSuffix[0] != '\0' && strcmp(fOurServerMediaSession->streamName(), urlPreSuffix) == 0) {
01022
01023
01024 ServerMediaSubsessionIterator iter(*fOurServerMediaSession);
01025 while ((subsession = iter.next()) != NULL) {
01026 if (strcmp(subsession->trackId(), urlSuffix) == 0) break;
01027 }
01028 if (subsession == NULL) {
01029 handleCmd_notFound(cseq);
01030 return;
01031 }
01032 } else if (strcmp(fOurServerMediaSession->streamName(), urlSuffix) == 0 ||
01033 (urlSuffix[0] == '\0' && strcmp(fOurServerMediaSession->streamName(), urlPreSuffix) == 0)) {
01034
01035 subsession = NULL;
01036 } else if (urlPreSuffix[0] != '\0' && urlSuffix[0] != '\0') {
01037
01038 unsigned const urlPreSuffixLen = strlen(urlPreSuffix);
01039 if (strncmp(fOurServerMediaSession->streamName(), urlPreSuffix, urlPreSuffixLen) == 0 &&
01040 fOurServerMediaSession->streamName()[urlPreSuffixLen] == '/' &&
01041 strcmp(&(fOurServerMediaSession->streamName())[urlPreSuffixLen+1], urlSuffix) == 0) {
01042 subsession = NULL;
01043 } else {
01044 handleCmd_notFound(cseq);
01045 return;
01046 }
01047 } else {
01048 handleCmd_notFound(cseq);
01049 return;
01050 }
01051
01052 if (strcmp(cmdName, "TEARDOWN") == 0) {
01053 handleCmd_TEARDOWN(subsession, cseq);
01054 } else if (strcmp(cmdName, "PLAY") == 0) {
01055 handleCmd_PLAY(subsession, cseq, fullRequestStr);
01056 } else if (strcmp(cmdName, "PAUSE") == 0) {
01057 handleCmd_PAUSE(subsession, cseq);
01058 } else if (strcmp(cmdName, "GET_PARAMETER") == 0) {
01059 handleCmd_GET_PARAMETER(subsession, cseq, fullRequestStr);
01060 } else if (strcmp(cmdName, "SET_PARAMETER") == 0) {
01061 handleCmd_SET_PARAMETER(subsession, cseq, fullRequestStr);
01062 }
01063 }
01064
01065 void RTSPServer::RTSPClientSession
01066 ::handleCmd_TEARDOWN(ServerMediaSubsession* , char const* cseq) {
01067 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
01068 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%s\r\n",
01069 cseq, dateHeader());
01070 fSessionIsActive = False;
01071 }
01072
01073 static Boolean parseScaleHeader(char const* buf, float& scale) {
01074
01075 scale = 1.0;
01076
01077
01078 while (1) {
01079 if (*buf == '\0') return False;
01080 if (_strncasecmp(buf, "Scale: ", 7) == 0) break;
01081 ++buf;
01082 }
01083
01084
01085 char const* fields = buf + 7;
01086 while (*fields == ' ') ++fields;
01087 float sc;
01088 if (sscanf(fields, "%f", &sc) == 1) {
01089 scale = sc;
01090 } else {
01091 return False;
01092 }
01093
01094 return True;
01095 }
01096
01097 void RTSPServer::RTSPClientSession
01098 ::handleCmd_PLAY(ServerMediaSubsession* subsession, char const* cseq,
01099 char const* fullRequestStr) {
01100 char* rtspURL = fOurServer.rtspURL(fOurServerMediaSession, fClientInputSocket);
01101 unsigned rtspURLSize = strlen(rtspURL);
01102
01103
01104 float scale;
01105 Boolean sawScaleHeader = parseScaleHeader(fullRequestStr, scale);
01106
01107
01108 if (subsession == NULL ) {
01109 fOurServerMediaSession->testScaleFactor(scale);
01110 } else {
01111 subsession->testScaleFactor(scale);
01112 }
01113
01114 char buf[100];
01115 char* scaleHeader;
01116 if (!sawScaleHeader) {
01117 buf[0] = '\0';
01118 } else {
01119 sprintf(buf, "Scale: %f\r\n", scale);
01120 }
01121 scaleHeader = strDup(buf);
01122
01123
01124 double rangeStart = 0.0, rangeEnd = 0.0;
01125 Boolean sawRangeHeader = parseRangeHeader(fullRequestStr, rangeStart, rangeEnd);
01126
01127
01128
01129 float duration = subsession == NULL
01130 ? fOurServerMediaSession->duration() : subsession->duration();
01131 if (duration < 0.0) {
01132
01133
01134 duration = -duration;
01135 }
01136
01137
01138
01139 if (rangeStart < 0.0) rangeStart = 0.0;
01140 else if (rangeStart > duration) rangeStart = duration;
01141 if (rangeEnd < 0.0) rangeEnd = 0.0;
01142 else if (rangeEnd > duration) rangeEnd = duration;
01143 if ((scale > 0.0 && rangeStart > rangeEnd && rangeEnd > 0.0) ||
01144 (scale < 0.0 && rangeStart < rangeEnd)) {
01145
01146 double tmp = rangeStart;
01147 rangeStart = rangeEnd;
01148 rangeEnd = tmp;
01149 }
01150
01151
01152 char const* rtpInfoFmt =
01153 "%s"
01154 "%s"
01155 "url=%s/%s"
01156 ";seq=%d"
01157 ";rtptime=%u"
01158 ;
01159 unsigned rtpInfoFmtSize = strlen(rtpInfoFmt);
01160 char* rtpInfo = strDup("RTP-Info: ");
01161 unsigned i, numRTPInfoItems = 0;
01162
01163
01164
01165
01166 for (i = 0; i < fNumStreamStates; ++i) {
01167 if (subsession == NULL || fNumStreamStates == 1) {
01168 if (sawScaleHeader) {
01169 fStreamStates[i].subsession->setStreamScale(fOurSessionId,
01170 fStreamStates[i].streamToken,
01171 scale);
01172 }
01173 if (sawRangeHeader) {
01174 double streamDuration = 0.0;
01175 if (rangeEnd > 0.0 && (rangeEnd+0.001) < duration) {
01176
01177 streamDuration = rangeEnd - rangeStart;
01178 if (streamDuration < 0.0) streamDuration = -streamDuration;
01179 }
01180 u_int64_t numBytes;
01181 fStreamStates[i].subsession->seekStream(fOurSessionId,
01182 fStreamStates[i].streamToken,
01183 rangeStart, streamDuration, numBytes);
01184 }
01185 }
01186 }
01187
01188
01189
01190 char* rangeHeader;
01191 if (!sawRangeHeader) {
01192 buf[0] = '\0';
01193 } else if (rangeEnd == 0.0 && scale >= 0.0) {
01194 sprintf(buf, "Range: npt=%.3f-\r\n", rangeStart);
01195 } else {
01196 sprintf(buf, "Range: npt=%.3f-%.3f\r\n", rangeStart, rangeEnd);
01197 }
01198 rangeHeader = strDup(buf);
01199
01200
01201 for (i = 0; i < fNumStreamStates; ++i) {
01202 if (subsession == NULL
01203 || subsession == fStreamStates[i].subsession) {
01204 unsigned short rtpSeqNum = 0;
01205 unsigned rtpTimestamp = 0;
01206 fStreamStates[i].subsession->startStream(fOurSessionId,
01207 fStreamStates[i].streamToken,
01208 (TaskFunc*)noteClientLiveness, this,
01209 rtpSeqNum, rtpTimestamp,
01210 handleAlternativeRequestByte, this);
01211 const char *urlSuffix = fStreamStates[i].subsession->trackId();
01212 char* prevRTPInfo = rtpInfo;
01213 unsigned rtpInfoSize = rtpInfoFmtSize
01214 + strlen(prevRTPInfo)
01215 + 1
01216 + rtspURLSize + strlen(urlSuffix)
01217 + 5
01218 + 10
01219 + 2 ;
01220 rtpInfo = new char[rtpInfoSize];
01221 sprintf(rtpInfo, rtpInfoFmt,
01222 prevRTPInfo,
01223 numRTPInfoItems++ == 0 ? "" : ",",
01224 rtspURL, urlSuffix,
01225 rtpSeqNum,
01226 rtpTimestamp
01227 );
01228 delete[] prevRTPInfo;
01229 }
01230 }
01231 if (numRTPInfoItems == 0) {
01232 rtpInfo[0] = '\0';
01233 } else {
01234 unsigned rtpInfoLen = strlen(rtpInfo);
01235 rtpInfo[rtpInfoLen] = '\r';
01236 rtpInfo[rtpInfoLen+1] = '\n';
01237 rtpInfo[rtpInfoLen+2] = '\0';
01238 }
01239
01240
01241 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
01242 "RTSP/1.0 200 OK\r\n"
01243 "CSeq: %s\r\n"
01244 "%s"
01245 "%s"
01246 "%s"
01247 "Session: %08X\r\n"
01248 "%s\r\n",
01249 cseq,
01250 dateHeader(),
01251 scaleHeader,
01252 rangeHeader,
01253 fOurSessionId,
01254 rtpInfo);
01255 delete[] rtpInfo; delete[] rangeHeader;
01256 delete[] scaleHeader; delete[] rtspURL;
01257 }
01258
01259 void RTSPServer::RTSPClientSession
01260 ::handleCmd_PAUSE(ServerMediaSubsession* subsession, char const* cseq) {
01261 for (unsigned i = 0; i < fNumStreamStates; ++i) {
01262 if (subsession == NULL
01263 || subsession == fStreamStates[i].subsession) {
01264 fStreamStates[i].subsession->pauseStream(fOurSessionId,
01265 fStreamStates[i].streamToken);
01266 }
01267 }
01268 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
01269 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sSession: %08X\r\n\r\n",
01270 cseq, dateHeader(), fOurSessionId);
01271 }
01272
01273 void RTSPServer::RTSPClientSession
01274 ::handleCmd_GET_PARAMETER(ServerMediaSubsession* , char const* cseq,
01275 char const* ) {
01276
01277
01278
01279 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
01280 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sSession: %08X\r\n\r\n",
01281 cseq, dateHeader(), fOurSessionId);
01282 }
01283
01284 void RTSPServer::RTSPClientSession
01285 ::handleCmd_SET_PARAMETER(ServerMediaSubsession* , char const* cseq,
01286 char const* ) {
01287
01288
01289
01290 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
01291 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sSession: %08X\r\n\r\n",
01292 cseq, dateHeader(), fOurSessionId);
01293 }
01294
01295 static void lookForHeader(char const* headerName, char const* source, unsigned sourceLen, char* resultStr, unsigned resultMaxSize) {
01296 resultStr[0] = '\0';
01297 unsigned headerNameLen = strlen(headerName);
01298 for (int i = 0; i < (int)(sourceLen-headerNameLen); ++i) {
01299 if (strncmp(&source[i], headerName, headerNameLen) == 0 && source[i+headerNameLen] == ':') {
01300
01301 for (i += headerNameLen+1; i < (int)sourceLen && (source[i] == ' ' || source[i] == '\t'); ++i) {}
01302 for (unsigned j = i; j < sourceLen; ++j) {
01303 if (source[j] == '\r' || source[j] == '\n') {
01304
01305 if (j-i+1 > resultMaxSize) break;
01306 char const* resultSource = &source[i];
01307 char const* resultSourceEnd = &source[j];
01308 while (resultSource < resultSourceEnd) *resultStr++ = *resultSource++;
01309 *resultStr = '\0';
01310 break;
01311 }
01312 }
01313 }
01314 }
01315 }
01316
01317 Boolean RTSPServer::RTSPClientSession::parseHTTPRequestString(char* resultCmdName, unsigned resultCmdNameMaxSize,
01318 char* urlSuffix, unsigned urlSuffixMaxSize,
01319 char* sessionCookie, unsigned sessionCookieMaxSize,
01320 char* acceptStr, unsigned acceptStrMaxSize) {
01321
01322
01323 char const* reqStr = (char const*)fRequestBuffer;
01324 unsigned const reqStrSize = fRequestBytesAlreadySeen;
01325
01326
01327 Boolean parseSucceeded = False;
01328 unsigned i;
01329 for (i = 0; i < resultCmdNameMaxSize-1 && i < reqStrSize; ++i) {
01330 char c = reqStr[i];
01331 if (c == ' ' || c == '\t') {
01332 parseSucceeded = True;
01333 break;
01334 }
01335
01336 resultCmdName[i] = c;
01337 }
01338 resultCmdName[i] = '\0';
01339 if (!parseSucceeded) return False;
01340
01341
01342 parseSucceeded = False;
01343 for (; i < reqStrSize-5 && reqStr[i] != '\r' && reqStr[i] != '\n'; ++i) {
01344 if (reqStr[i] == 'H' && reqStr[i+1] == 'T' && reqStr[i+2]== 'T' && reqStr[i+3]== 'P' && reqStr[i+4]== '/') {
01345 i += 5;
01346 parseSucceeded = True;
01347 break;
01348 }
01349 }
01350 if (!parseSucceeded) return False;
01351
01352
01353 unsigned k = i-6;
01354 while (k > 0 && reqStr[k] == ' ') --k;
01355 unsigned j = k;
01356 while (j > 0 && reqStr[j] != ' ' && reqStr[j] != '/') --j;
01357
01358 if (k - j + 1 > urlSuffixMaxSize) return False;
01359 unsigned n = 0;
01360 while (++j <= k) urlSuffix[n++] = reqStr[j];
01361 urlSuffix[n] = '\0';
01362
01363
01364 lookForHeader("x-sessioncookie", &reqStr[i], reqStrSize-i, sessionCookie, sessionCookieMaxSize);
01365 lookForHeader("Accept", &reqStr[i], reqStrSize-i, acceptStr, acceptStrMaxSize);
01366
01367 return True;
01368 }
01369
01370 void RTSPServer::RTSPClientSession::handleHTTPCmd_notSupported() {
01371 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
01372 "HTTP/1.0 405 Method Not Allowed\r\n%s\r\n\r\n",
01373 dateHeader());
01374 }
01375
01376 void RTSPServer::RTSPClientSession::handleHTTPCmd_notFound() {
01377 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
01378 "HTTP/1.0 404 Not Found\r\n%s\r\n\r\n",
01379 dateHeader());
01380 }
01381
01382 void RTSPServer::RTSPClientSession::handleHTTPCmd_TunnelingGET(char const* sessionCookie) {
01383
01384
01385 if (fOurServer.fClientSessionsForHTTPTunneling == NULL) {
01386 fOurServer.fClientSessionsForHTTPTunneling = HashTable::create(STRING_HASH_KEYS);
01387 }
01388 fOurServer.fClientSessionsForHTTPTunneling->Add(sessionCookie, (void*)this);
01389 #ifdef DEBUG
01390 fprintf(stderr, "Handled HTTP \"GET\" request (client output socket: %d)\n", fClientOutputSocket);
01391 #endif
01392
01393
01394 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
01395 "HTTP/1.0 200 OK\r\n"
01396 "Date: Thu, 19 Aug 1982 18:30:00 GMT\r\n"
01397 "Cache-Control: no-cache\r\n"
01398 "Pragma: no-cache\r\n"
01399 "Content-Type: application/x-rtsp-tunnelled\r\n"
01400 "\r\n");
01401 }
01402
01403 Boolean RTSPServer::RTSPClientSession
01404 ::handleHTTPCmd_TunnelingPOST(char const* sessionCookie, unsigned char const* extraData, unsigned extraDataSize) {
01405
01406
01407 RTSPServer::RTSPClientSession* prevClientSession
01408 = (RTSPServer::RTSPClientSession*)(fOurServer.fClientSessionsForHTTPTunneling->Lookup(sessionCookie));
01409 if (prevClientSession == NULL) {
01410
01411 handleHTTPCmd_notSupported();
01412 fSessionIsActive = False;
01413 return False;
01414 }
01415 #ifdef DEBUG
01416 fprintf(stderr, "Handled HTTP \"POST\" request (client input socket: %d)\n", fClientInputSocket);
01417 #endif
01418
01419
01420 prevClientSession->changeClientInputSocket(fClientInputSocket, extraData, extraDataSize);
01421 fClientInputSocket = fClientOutputSocket = -1;
01422 return True;
01423 }
01424
01425 void RTSPServer::RTSPClientSession::handleHTTPCmd_StreamingGET(char const* , char const* ) {
01426
01427 handleHTTPCmd_notSupported();
01428 }
01429
01430 static Boolean parseAuthorizationHeader(char const* buf,
01431 char const*& username,
01432 char const*& realm,
01433 char const*& nonce, char const*& uri,
01434 char const*& response) {
01435
01436 username = realm = nonce = uri = response = NULL;
01437
01438
01439 while (1) {
01440 if (*buf == '\0') return False;
01441 if (_strncasecmp(buf, "Authorization: Digest ", 22) == 0) break;
01442 ++buf;
01443 }
01444
01445
01446 char const* fields = buf + 22;
01447 while (*fields == ' ') ++fields;
01448 char* parameter = strDupSize(fields);
01449 char* value = strDupSize(fields);
01450 while (1) {
01451 value[0] = '\0';
01452 if (sscanf(fields, "%[^=]=\"%[^\"]\"", parameter, value) != 2 &&
01453 sscanf(fields, "%[^=]=\"\"", parameter) != 1) {
01454 break;
01455 }
01456 if (strcmp(parameter, "username") == 0) {
01457 username = strDup(value);
01458 } else if (strcmp(parameter, "realm") == 0) {
01459 realm = strDup(value);
01460 } else if (strcmp(parameter, "nonce") == 0) {
01461 nonce = strDup(value);
01462 } else if (strcmp(parameter, "uri") == 0) {
01463 uri = strDup(value);
01464 } else if (strcmp(parameter, "response") == 0) {
01465 response = strDup(value);
01466 }
01467
01468 fields += strlen(parameter) + 2 + strlen(value) + 1 ;
01469 while (*fields == ',' || *fields == ' ') ++fields;
01470
01471 if (*fields == '\0' || *fields == '\r' || *fields == '\n') break;
01472 }
01473 delete[] parameter; delete[] value;
01474 return True;
01475 }
01476
01477 Boolean RTSPServer::RTSPClientSession
01478 ::authenticationOK(char const* cmdName, char const* cseq,
01479 char const* urlSuffix, char const* fullRequestStr) {
01480
01481 if (!fOurServer.specialClientAccessCheck(fClientInputSocket, fClientAddr, urlSuffix)) {
01482 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
01483 "RTSP/1.0 401 Unauthorized\r\n"
01484 "CSeq: %s\r\n"
01485 "%s"
01486 "\r\n",
01487 cseq, dateHeader());
01488 return False;
01489 }
01490
01491
01492 if (fOurServer.fAuthDB == NULL) return True;
01493
01494 char const* username = NULL; char const* realm = NULL; char const* nonce = NULL;
01495 char const* uri = NULL; char const* response = NULL;
01496 Boolean success = False;
01497
01498 do {
01499
01500
01501 if (fCurrentAuthenticator.nonce() == NULL) break;
01502
01503
01504
01505
01506 if (!parseAuthorizationHeader(fullRequestStr,
01507 username, realm, nonce, uri, response)
01508 || username == NULL
01509 || realm == NULL || strcmp(realm, fCurrentAuthenticator.realm()) != 0
01510 || nonce == NULL || strcmp(nonce, fCurrentAuthenticator.nonce()) != 0
01511 || uri == NULL || response == NULL) {
01512 break;
01513 }
01514
01515
01516 char const* password = fOurServer.fAuthDB->lookupPassword(username);
01517 #ifdef DEBUG
01518 fprintf(stderr, "lookupPassword(%s) returned password %s\n", username, password);
01519 #endif
01520 if (password == NULL) break;
01521 fCurrentAuthenticator.
01522 setUsernameAndPassword(username, password,
01523 fOurServer.fAuthDB->passwordsAreMD5());
01524
01525
01526
01527 char const* ourResponse
01528 = fCurrentAuthenticator.computeDigestResponse(cmdName, uri);
01529 success = (strcmp(ourResponse, response) == 0);
01530 fCurrentAuthenticator.reclaimDigestResponse(ourResponse);
01531 } while (0);
01532
01533 delete[] (char*)username; delete[] (char*)realm; delete[] (char*)nonce;
01534 delete[] (char*)uri; delete[] (char*)response;
01535 if (success) return True;
01536
01537
01538
01539 fCurrentAuthenticator.setRealmAndRandomNonce(fOurServer.fAuthDB->realm());
01540 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
01541 "RTSP/1.0 401 Unauthorized\r\n"
01542 "CSeq: %s\r\n"
01543 "%s"
01544 "WWW-Authenticate: Digest realm=\"%s\", nonce=\"%s\"\r\n\r\n",
01545 cseq,
01546 dateHeader(),
01547 fCurrentAuthenticator.realm(), fCurrentAuthenticator.nonce());
01548 return False;
01549 }
01550
01551 void RTSPServer::RTSPClientSession::noteLiveness() {
01552 #ifdef DEBUG
01553 fprintf(stderr, "Liveness indication from client at %s\n", AddressString(fClientAddr).val());
01554 #endif
01555 if (fOurServer.fReclamationTestSeconds > 0) {
01556 envir().taskScheduler()
01557 .rescheduleDelayedTask(fLivenessCheckTask,
01558 fOurServer.fReclamationTestSeconds*1000000,
01559 (TaskFunc*)livenessTimeoutTask, this);
01560 }
01561 }
01562
01563 void RTSPServer::RTSPClientSession
01564 ::noteClientLiveness(RTSPClientSession* clientSession) {
01565 clientSession->noteLiveness();
01566 }
01567
01568 void RTSPServer::RTSPClientSession
01569 ::livenessTimeoutTask(RTSPClientSession* clientSession) {
01570
01571
01572 #ifdef DEBUG
01573 fprintf(stderr, "RTSP client session from %s has timed out (due to inactivity)\n", AddressString(clientSession->fClientAddr).val());
01574 #endif
01575 delete clientSession;
01576 }
01577
01578 RTSPServer::RTSPClientSession*
01579 RTSPServer::createNewClientSession(unsigned sessionId, int clientSocket, struct sockaddr_in clientAddr) {
01580 return new RTSPClientSession(*this, sessionId, clientSocket, clientAddr);
01581 }
01582
01583 void RTSPServer::RTSPClientSession
01584 ::changeClientInputSocket(int newSocketNum, unsigned char const* extraData, unsigned extraDataSize) {
01585 envir().taskScheduler().turnOffBackgroundReadHandling(fClientInputSocket);
01586 fClientInputSocket = newSocketNum;
01587 envir().taskScheduler().turnOnBackgroundReadHandling(fClientInputSocket,
01588 (TaskScheduler::BackgroundHandlerProc*)&incomingRequestHandler, this);
01589
01590
01591 if (extraDataSize > 0 && extraDataSize <= fRequestBufferBytesLeft) {
01592 unsigned char* ptr = &fRequestBuffer[fRequestBytesAlreadySeen];
01593 for (unsigned i = 0; i < extraDataSize; ++i) {
01594 ptr[i] = extraData[i];
01595 }
01596 handleRequestBytes(extraDataSize);
01597 }
01598 }
01599
01600
01602
01603 RTSPServer::ServerMediaSessionIterator
01604 ::ServerMediaSessionIterator(RTSPServer& server)
01605 : fOurIterator((server.fServerMediaSessions == NULL)
01606 ? NULL : HashTable::Iterator::create(*server.fServerMediaSessions)) {
01607 }
01608
01609 RTSPServer::ServerMediaSessionIterator::~ServerMediaSessionIterator() {
01610 delete fOurIterator;
01611 }
01612
01613 ServerMediaSession* RTSPServer::ServerMediaSessionIterator::next() {
01614 if (fOurIterator == NULL) return NULL;
01615
01616 char const* key;
01617 return (ServerMediaSession*)(fOurIterator->next(key));
01618 }
01619
01620
01622
01623 UserAuthenticationDatabase::UserAuthenticationDatabase(char const* realm,
01624 Boolean passwordsAreMD5)
01625 : fTable(HashTable::create(STRING_HASH_KEYS)),
01626 fRealm(strDup(realm == NULL ? "LIVE555 Streaming Media" : realm)),
01627 fPasswordsAreMD5(passwordsAreMD5) {
01628 }
01629
01630 UserAuthenticationDatabase::~UserAuthenticationDatabase() {
01631 delete[] fRealm;
01632
01633
01634 char* password;
01635 while ((password = (char*)fTable->RemoveNext()) != NULL) {
01636 delete[] password;
01637 }
01638 delete fTable;
01639 }
01640
01641 void UserAuthenticationDatabase::addUserRecord(char const* username,
01642 char const* password) {
01643 fTable->Add(username, (void*)(strDup(password)));
01644 }
01645
01646 void UserAuthenticationDatabase::removeUserRecord(char const* username) {
01647 char* password = (char*)(fTable->Lookup(username));
01648 fTable->Remove(username);
01649 delete[] password;
01650 }
01651
01652 char const* UserAuthenticationDatabase::lookupPassword(char const* username) {
01653 return (char const*)(fTable->Lookup(username));
01654 }