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