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 <GroupsockHelper.hh>
00024
00025 #if defined(__WIN32__) || defined(_WIN32) || defined(_QNX4)
00026 #else
00027 #include <signal.h>
00028 #define USE_SIGNALS 1
00029 #endif
00030 #include <time.h>
00031
00032 #define RTPINFO_INCLUDE_RTPTIME 1
00033
00035
00036 RTSPServer*
00037 RTSPServer::createNew(UsageEnvironment& env, Port ourPort,
00038 UserAuthenticationDatabase* authDatabase,
00039 unsigned reclamationTestSeconds) {
00040 int ourSocket = -1;
00041
00042 do {
00043 int ourSocket = setUpOurSocket(env, ourPort);
00044 if (ourSocket == -1) break;
00045
00046 return new RTSPServer(env, ourSocket, ourPort, authDatabase,
00047 reclamationTestSeconds);
00048 } while (0);
00049
00050 if (ourSocket != -1) ::closeSocket(ourSocket);
00051 return NULL;
00052 }
00053
00054 Boolean RTSPServer::lookupByName(UsageEnvironment& env,
00055 char const* name,
00056 RTSPServer*& resultServer) {
00057 resultServer = NULL;
00058
00059 Medium* medium;
00060 if (!Medium::lookupByName(env, name, medium)) return False;
00061
00062 if (!medium->isRTSPServer()) {
00063 env.setResultMsg(name, " is not a RTSP server");
00064 return False;
00065 }
00066
00067 resultServer = (RTSPServer*)medium;
00068 return True;
00069 }
00070
00071 void RTSPServer::addServerMediaSession(ServerMediaSession* serverMediaSession) {
00072 if (serverMediaSession == NULL) return;
00073
00074 char const* sessionName = serverMediaSession->streamName();
00075 if (sessionName == NULL) sessionName = "";
00076 ServerMediaSession* existingSession
00077 = (ServerMediaSession*)
00078 (fServerMediaSessions->Add(sessionName,
00079 (void*)serverMediaSession));
00080 removeServerMediaSession(existingSession);
00081 }
00082
00083 ServerMediaSession* RTSPServer::lookupServerMediaSession(char const* streamName) {
00084 return (ServerMediaSession*)(fServerMediaSessions->Lookup(streamName));
00085 }
00086
00087 void RTSPServer::removeServerMediaSession(ServerMediaSession* serverMediaSession) {
00088 if (serverMediaSession == NULL) return;
00089
00090 fServerMediaSessions->Remove(serverMediaSession->streamName());
00091 if (serverMediaSession->referenceCount() == 0) {
00092 Medium::close(serverMediaSession);
00093 } else {
00094 serverMediaSession->deleteWhenUnreferenced() = True;
00095 }
00096 }
00097
00098 void RTSPServer::removeServerMediaSession(char const* streamName) {
00099 removeServerMediaSession(lookupServerMediaSession(streamName));
00100 }
00101
00102 char* RTSPServer
00103 ::rtspURL(ServerMediaSession const* serverMediaSession) const {
00104 struct in_addr ourAddress;
00105 ourAddress.s_addr = ReceivingInterfaceAddr != 0
00106 ? ReceivingInterfaceAddr
00107 : ourSourceAddressForMulticast(envir());
00108
00109 char const* sessionName = serverMediaSession->streamName();
00110 unsigned sessionNameLength = strlen(sessionName);
00111
00112 char* urlBuffer = new char[100 + sessionNameLength];
00113 char* resultURL;
00114
00115 portNumBits portNumHostOrder = ntohs(fServerPort.num());
00116 if (portNumHostOrder == 554 ) {
00117 sprintf(urlBuffer, "rtsp://%s/%s", our_inet_ntoa(ourAddress),
00118 sessionName);
00119 } else {
00120 sprintf(urlBuffer, "rtsp://%s:%hu/%s",
00121 our_inet_ntoa(ourAddress), portNumHostOrder,
00122 sessionName);
00123 }
00124
00125 resultURL = strDup(urlBuffer);
00126 delete[] urlBuffer;
00127 return resultURL;
00128 }
00129
00130 #define LISTEN_BACKLOG_SIZE 20
00131
00132 int RTSPServer::setUpOurSocket(UsageEnvironment& env, Port& ourPort) {
00133 int ourSocket = -1;
00134
00135 do {
00136 ourSocket = setupStreamSocket(env, ourPort);
00137 if (ourSocket < 0) break;
00138
00139
00140 if (!increaseSendBufferTo(env, ourSocket, 50*1024)) break;
00141
00142
00143 if (listen(ourSocket, LISTEN_BACKLOG_SIZE) < 0) {
00144 env.setResultErrMsg("listen() failed: ");
00145 break;
00146 }
00147
00148 if (ourPort.num() == 0) {
00149
00150 if (!getSourcePort(env, ourSocket, ourPort)) break;
00151 }
00152
00153 return ourSocket;
00154 } while (0);
00155
00156 if (ourSocket != -1) ::closeSocket(ourSocket);
00157 return -1;
00158 }
00159
00160 RTSPServer::RTSPServer(UsageEnvironment& env,
00161 int ourSocket, Port ourPort,
00162 UserAuthenticationDatabase* authDatabase,
00163 unsigned reclamationTestSeconds)
00164 : Medium(env),
00165 fServerSocket(ourSocket), fServerPort(ourPort),
00166 fAuthDB(authDatabase), fReclamationTestSeconds(reclamationTestSeconds),
00167 fServerMediaSessions(HashTable::create(STRING_HASH_KEYS)),
00168 fSessionIdCounter(0) {
00169 #ifdef USE_SIGNALS
00170
00171
00172 signal(SIGPIPE, SIG_IGN);
00173 #endif
00174
00175
00176 env.taskScheduler().turnOnBackgroundReadHandling(fServerSocket,
00177 (TaskScheduler::BackgroundHandlerProc*)&incomingConnectionHandler,
00178 this);
00179 }
00180
00181 RTSPServer::~RTSPServer() {
00182
00183 envir().taskScheduler().turnOffBackgroundReadHandling(fServerSocket);
00184
00185 ::closeSocket(fServerSocket);
00186
00187
00188 while (1) {
00189 ServerMediaSession* serverMediaSession
00190 = (ServerMediaSession*)fServerMediaSessions->RemoveNext();
00191 if (serverMediaSession == NULL) break;
00192 removeServerMediaSession(serverMediaSession);
00193 }
00194
00195
00196 delete fServerMediaSessions;
00197 }
00198
00199 Boolean RTSPServer::isRTSPServer() const {
00200 return True;
00201 }
00202
00203 void RTSPServer::incomingConnectionHandler(void* instance, int ) {
00204 RTSPServer* server = (RTSPServer*)instance;
00205 server->incomingConnectionHandler1();
00206 }
00207
00208 void RTSPServer::incomingConnectionHandler1() {
00209 struct sockaddr_in clientAddr;
00210 SOCKLEN_T clientAddrLen = sizeof clientAddr;
00211 int clientSocket = accept(fServerSocket, (struct sockaddr*)&clientAddr,
00212 &clientAddrLen);
00213 if (clientSocket < 0) {
00214 int err = envir().getErrno();
00215 if (err != EWOULDBLOCK) {
00216 envir().setResultErrMsg("accept() failed: ");
00217 }
00218 return;
00219 }
00220 #if defined(DEBUG) || defined(DEBUG_CONNECTIONS)
00221 fprintf(stderr, "accept()ed connection from %s\n", our_inet_ntoa(clientAddr.sin_addr));
00222 #endif
00223
00224
00225 new RTSPClientSession(*this, ++fSessionIdCounter,
00226 clientSocket, clientAddr);
00227 }
00228
00229
00231
00232 RTSPServer::RTSPClientSession
00233 ::RTSPClientSession(RTSPServer& ourServer, unsigned sessionId,
00234 int clientSocket, struct sockaddr_in clientAddr)
00235 : fOurServer(ourServer), fOurSessionId(sessionId),
00236 fOurServerMediaSession(NULL),
00237 fClientSocket(clientSocket), fClientAddr(clientAddr),
00238 fLivenessCheckTask(NULL),
00239 fIsMulticast(False), fSessionIsActive(True), fStreamAfterSETUP(False),
00240 fTCPStreamIdCount(0), fNumStreamStates(0), fStreamStates(NULL) {
00241
00242 envir().taskScheduler().turnOnBackgroundReadHandling(fClientSocket,
00243 (TaskScheduler::BackgroundHandlerProc*)&incomingRequestHandler, this);
00244 noteLiveness();
00245 }
00246
00247 RTSPServer::RTSPClientSession::~RTSPClientSession() {
00248
00249 envir().taskScheduler().unscheduleDelayedTask(fLivenessCheckTask);
00250
00251
00252 envir().taskScheduler().turnOffBackgroundReadHandling(fClientSocket);
00253
00254 ::closeSocket(fClientSocket);
00255
00256 reclaimStreamStates();
00257
00258 if (fOurServerMediaSession != NULL) {
00259 fOurServerMediaSession->decrementReferenceCount();
00260 if (fOurServerMediaSession->referenceCount() == 0
00261 && fOurServerMediaSession->deleteWhenUnreferenced()) {
00262 fOurServer.removeServerMediaSession(fOurServerMediaSession);
00263 }
00264 }
00265 }
00266
00267 void RTSPServer::RTSPClientSession::reclaimStreamStates() {
00268 for (unsigned i = 0; i < fNumStreamStates; ++i) {
00269 if (fStreamStates[i].subsession != NULL) {
00270 fStreamStates[i].subsession->deleteStream(fOurSessionId,
00271 fStreamStates[i].streamToken);
00272 }
00273 }
00274 delete[] fStreamStates; fStreamStates = NULL;
00275 fNumStreamStates = 0;
00276 }
00277
00278 void RTSPServer::RTSPClientSession
00279 ::incomingRequestHandler(void* instance, int ) {
00280 RTSPClientSession* session = (RTSPClientSession*)instance;
00281 session->incomingRequestHandler1();
00282 }
00283
00284 void RTSPServer::RTSPClientSession::incomingRequestHandler1() {
00285 noteLiveness();
00286
00287 struct sockaddr_in dummy;
00288 int bytesLeft = sizeof fBuffer;
00289 int totalBytes = 0;
00290 Boolean endOfMsg = False;
00291 unsigned char* ptr = fBuffer;
00292 unsigned char* lastCRLF = ptr-3;
00293
00294 while (!endOfMsg) {
00295 if (bytesLeft <= 0) {
00296
00297 delete this;
00298 return;
00299 }
00300
00301 int bytesRead = readSocket(envir(), fClientSocket,
00302 ptr, bytesLeft, dummy);
00303 if (bytesRead <= 0) {
00304
00305 delete this;
00306 return;
00307 }
00308 #ifdef DEBUG
00309 ptr[bytesRead] = '\0';
00310 fprintf(stderr, "RTSPClientSession[%p]::incomingRequestHandler1() read %d bytes:%s\n", this, bytesRead, ptr);
00311 #endif
00312
00313
00314 unsigned char *tmpPtr = ptr;
00315 if (totalBytes > 0) --tmpPtr;
00316 while (tmpPtr < &ptr[bytesRead-1]) {
00317 if (*tmpPtr == '\r' && *(tmpPtr+1) == '\n') {
00318 if (tmpPtr - lastCRLF == 2) {
00319 endOfMsg = 1;
00320 break;
00321 }
00322 lastCRLF = tmpPtr;
00323 }
00324 ++tmpPtr;
00325 }
00326
00327 bytesLeft -= bytesRead;
00328 totalBytes += bytesRead;
00329 ptr += bytesRead;
00330 }
00331 fBuffer[totalBytes] = '\0';
00332
00333
00334
00335 char cmdName[RTSP_PARAM_STRING_MAX];
00336 char urlPreSuffix[RTSP_PARAM_STRING_MAX];
00337 char urlSuffix[RTSP_PARAM_STRING_MAX];
00338 char cseq[RTSP_PARAM_STRING_MAX];
00339 if (!parseRTSPRequestString((char*)fBuffer, totalBytes,
00340 cmdName, sizeof cmdName,
00341 urlPreSuffix, sizeof urlPreSuffix,
00342 urlSuffix, sizeof urlSuffix,
00343 cseq, sizeof cseq)) {
00344 #ifdef DEBUG
00345 fprintf(stderr, "parseRTSPRequestString() failed!\n");
00346 #endif
00347 handleCmd_bad(cseq);
00348 } else {
00349 #ifdef DEBUG
00350 fprintf(stderr, "parseRTSPRequestString() returned cmdName \"%s\", urlPreSuffix \"%s\", urlSuffix \"%s\"\n", cmdName, urlPreSuffix, urlSuffix);
00351 #endif
00352 if (strcmp(cmdName, "OPTIONS") == 0) {
00353 handleCmd_OPTIONS(cseq);
00354 } else if (strcmp(cmdName, "DESCRIBE") == 0) {
00355 handleCmd_DESCRIBE(cseq, urlSuffix, (char const*)fBuffer);
00356 } else if (strcmp(cmdName, "SETUP") == 0) {
00357 handleCmd_SETUP(cseq, urlPreSuffix, urlSuffix, (char const*)fBuffer);
00358 } else if (strcmp(cmdName, "TEARDOWN") == 0
00359 || strcmp(cmdName, "PLAY") == 0
00360 || strcmp(cmdName, "PAUSE") == 0
00361 || strcmp(cmdName, "GET_PARAMETER") == 0) {
00362 handleCmd_withinSession(cmdName, urlPreSuffix, urlSuffix, cseq,
00363 (char const*)fBuffer);
00364 } else {
00365 handleCmd_notSupported(cseq);
00366 }
00367 }
00368
00369 #ifdef DEBUG
00370 fprintf(stderr, "sending response: %s", fResponseBuffer);
00371 #endif
00372 send(fClientSocket, (char const*)fResponseBuffer, strlen((char*)fResponseBuffer), 0);
00373
00374 if (strcmp(cmdName, "SETUP") == 0 && fStreamAfterSETUP) {
00375
00376
00377 handleCmd_withinSession("PLAY", urlPreSuffix, urlSuffix, cseq,
00378 (char const*)fBuffer);
00379 }
00380 if (!fSessionIsActive) delete this;
00381 }
00382
00383
00384
00385
00386 static char const* dateHeader() {
00387 static char buf[200];
00388 #if !defined(_WIN32_WCE)
00389 time_t tt = time(NULL);
00390 strftime(buf, sizeof buf, "Date: %a, %b %d %Y %H:%M:%S GMT\r\n", gmtime(&tt));
00391 #else
00392
00393
00394
00395 SYSTEMTIME SystemTime;
00396 GetSystemTime(&SystemTime);
00397 WCHAR dateFormat[] = L"ddd, MMM dd yyyy";
00398 WCHAR timeFormat[] = L"HH:mm:ss GMT\r\n";
00399 WCHAR inBuf[200];
00400 DWORD locale = LOCALE_NEUTRAL;
00401
00402 int ret = GetDateFormat(locale, 0, &SystemTime,
00403 (LPTSTR)dateFormat, (LPTSTR)inBuf, sizeof inBuf);
00404 inBuf[ret - 1] = ' ';
00405 ret = GetTimeFormat(locale, 0, &SystemTime,
00406 (LPTSTR)timeFormat,
00407 (LPTSTR)inBuf + ret, (sizeof inBuf) - ret);
00408 wcstombs(buf, inBuf, wcslen(inBuf));
00409 #endif
00410 return buf;
00411 }
00412
00413 static char const* allowedCommandNames
00414 = "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE";
00415
00416 void RTSPServer::RTSPClientSession::handleCmd_bad(char const* ) {
00417
00418 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00419 "RTSP/1.0 400 Bad Request\r\n%sAllow: %s\r\n\r\n",
00420 dateHeader(), allowedCommandNames);
00421 fSessionIsActive = False;
00422 }
00423
00424 void RTSPServer::RTSPClientSession::handleCmd_notSupported(char const* cseq) {
00425 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00426 "RTSP/1.0 405 Method Not Allowed\r\nCSeq: %s\r\n%sAllow: %s\r\n\r\n",
00427 cseq, dateHeader(), allowedCommandNames);
00428 fSessionIsActive = False;
00429 }
00430
00431 void RTSPServer::RTSPClientSession::handleCmd_notFound(char const* cseq) {
00432 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00433 "RTSP/1.0 404 Stream Not Found\r\nCSeq: %s\r\n%s\r\n",
00434 cseq, dateHeader());
00435 fSessionIsActive = False;
00436 }
00437
00438 void RTSPServer::RTSPClientSession::handleCmd_unsupportedTransport(char const* cseq) {
00439 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00440 "RTSP/1.0 461 Unsupported Transport\r\nCSeq: %s\r\n%s\r\n",
00441 cseq, dateHeader());
00442 fSessionIsActive = False;
00443 }
00444
00445 void RTSPServer::RTSPClientSession::handleCmd_OPTIONS(char const* cseq) {
00446 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00447 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sPublic: %s\r\n\r\n",
00448 cseq, dateHeader(), allowedCommandNames);
00449 }
00450
00451 void RTSPServer::RTSPClientSession
00452 ::handleCmd_DESCRIBE(char const* cseq, char const* urlSuffix,
00453 char const* fullRequestStr) {
00454 char* sdpDescription = NULL;
00455 char* rtspURL = NULL;
00456 do {
00457 if (!authenticationOK("DESCRIBE", cseq, fullRequestStr)) break;
00458
00459
00460
00461
00462
00463
00464 ServerMediaSession* session = fOurServer.lookupServerMediaSession(urlSuffix);
00465 if (session == NULL) {
00466 handleCmd_notFound(cseq);
00467 break;
00468 }
00469
00470
00471 sdpDescription = session->generateSDPDescription();
00472 if (sdpDescription == NULL) {
00473
00474
00475 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00476 "RTSP/1.0 404 File Not Found, Or In Incorrect Format\r\n"
00477 "CSeq: %s\r\n"
00478 "%s\r\n",
00479 cseq,
00480 dateHeader());
00481 break;
00482 }
00483 unsigned sdpDescriptionSize = strlen(sdpDescription);
00484
00485
00486
00487
00488 rtspURL = fOurServer.rtspURL(session);
00489
00490 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00491 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n"
00492 "%s"
00493 "Content-Base: %s/\r\n"
00494 "Content-Type: application/sdp\r\n"
00495 "Content-Length: %d\r\n\r\n"
00496 "%s",
00497 cseq,
00498 dateHeader(),
00499 rtspURL,
00500 sdpDescriptionSize,
00501 sdpDescription);
00502 } while (0);
00503
00504 delete[] sdpDescription;
00505 delete[] rtspURL;
00506 }
00507
00508 typedef enum StreamingMode {
00509 RTP_UDP,
00510 RTP_TCP,
00511 RAW_UDP
00512 };
00513
00514 static void parseTransportHeader(char const* buf,
00515 StreamingMode& streamingMode,
00516 char*& streamingModeString,
00517 char*& destinationAddressStr,
00518 u_int8_t& destinationTTL,
00519 portNumBits& clientRTPPortNum,
00520 portNumBits& clientRTCPPortNum,
00521 unsigned char& rtpChannelId,
00522 unsigned char& rtcpChannelId
00523 ) {
00524
00525 streamingMode = RTP_UDP;
00526 streamingModeString = NULL;
00527 destinationAddressStr = NULL;
00528 destinationTTL = 255;
00529 clientRTPPortNum = 0;
00530 clientRTCPPortNum = 1;
00531 rtpChannelId = rtcpChannelId = 0xFF;
00532
00533 portNumBits p1, p2;
00534 unsigned ttl, rtpCid, rtcpCid;
00535
00536
00537 while (1) {
00538 if (*buf == '\0') return;
00539 if (_strncasecmp(buf, "Transport: ", 11) == 0) break;
00540 ++buf;
00541 }
00542
00543
00544 char const* fields = buf + 11;
00545 char* field = strDupSize(fields);
00546 while (sscanf(fields, "%[^;]", field) == 1) {
00547 if (strcmp(field, "RTP/AVP/TCP") == 0) {
00548 streamingMode = RTP_TCP;
00549 } else if (strcmp(field, "RAW/RAW/UDP") == 0 ||
00550 strcmp(field, "MP2T/H2221/UDP") == 0) {
00551 streamingMode = RAW_UDP;
00552 streamingModeString = strDup(field);
00553 } else if (_strncasecmp(field, "destination=", 12) == 0) {
00554 delete[] destinationAddressStr;
00555 destinationAddressStr = strDup(field+12);
00556 } else if (sscanf(field, "ttl%u", &ttl) == 1) {
00557 destinationTTL = (u_int8_t)ttl;
00558 } else if (sscanf(field, "client_port=%hu-%hu", &p1, &p2) == 2) {
00559 clientRTPPortNum = p1;
00560 clientRTCPPortNum = p2;
00561 } else if (sscanf(field, "client_port=%hu", &p1) == 1) {
00562 clientRTPPortNum = p1;
00563 clientRTCPPortNum = streamingMode == RAW_UDP ? 0 : p1 + 1;
00564 } else if (sscanf(field, "interleaved=%u-%u", &rtpCid, &rtcpCid) == 2) {
00565 rtpChannelId = (unsigned char)rtpCid;
00566 rtcpChannelId = (unsigned char)rtcpCid;
00567 }
00568
00569 fields += strlen(field);
00570 while (*fields == ';') ++fields;
00571 if (*fields == '\0' || *fields == '\r' || *fields == '\n') break;
00572 }
00573 delete[] field;
00574 }
00575
00576 static Boolean parseRangeHeader(char const* buf, float& rangeStart, float& rangeEnd) {
00577
00578 rangeStart = rangeEnd = 0.0;
00579
00580
00581 while (1) {
00582 if (*buf == '\0') return False;
00583 if (_strncasecmp(buf, "Range: ", 7) == 0) break;
00584 ++buf;
00585 }
00586
00587
00588 char const* fields = buf + 7;
00589 while (*fields == ' ') ++fields;
00590 float start, end;
00591 if (sscanf(fields, "npt = %f - %f", &start, &end) == 2) {
00592 rangeStart = start;
00593 rangeEnd = end;
00594 } else if (sscanf(fields, "npt = %f -", &start) == 1) {
00595 rangeStart = start;
00596 } else {
00597 return False;
00598 }
00599
00600 return True;
00601 }
00602
00603 void RTSPServer::RTSPClientSession
00604 ::handleCmd_SETUP(char const* cseq,
00605 char const* urlPreSuffix, char const* urlSuffix,
00606 char const* fullRequestStr) {
00607
00608
00609 char const* streamName = urlPreSuffix;
00610 char const* trackId = urlSuffix;
00611
00612
00613
00614
00615 if (fOurServerMediaSession != NULL
00616 && strcmp(streamName, fOurServerMediaSession->streamName()) != 0) {
00617 fOurServerMediaSession = NULL;
00618 }
00619 if (fOurServerMediaSession == NULL) {
00620
00621
00622
00623 if (streamName[0] != '\0' ||
00624 fOurServer.lookupServerMediaSession("") != NULL) {
00625 } else {
00626 streamName = urlSuffix;
00627 trackId = NULL;
00628 }
00629 fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName);
00630 if (fOurServerMediaSession == NULL) {
00631 handleCmd_notFound(cseq);
00632 return;
00633 }
00634
00635 fOurServerMediaSession->incrementReferenceCount();
00636
00637
00638 reclaimStreamStates();
00639 ServerMediaSubsessionIterator iter(*fOurServerMediaSession);
00640 for (fNumStreamStates = 0; iter.next() != NULL; ++fNumStreamStates) {}
00641 fStreamStates = new struct streamState[fNumStreamStates];
00642 iter.reset();
00643 ServerMediaSubsession* subsession;
00644 for (unsigned i = 0; i < fNumStreamStates; ++i) {
00645 subsession = iter.next();
00646 fStreamStates[i].subsession = subsession;
00647 fStreamStates[i].streamToken = NULL;
00648 }
00649 }
00650
00651
00652 ServerMediaSubsession* subsession = NULL;
00653 unsigned streamNum;
00654 if (trackId != NULL && trackId[0] != '\0') {
00655 for (streamNum = 0; streamNum < fNumStreamStates; ++streamNum) {
00656 subsession = fStreamStates[streamNum].subsession;
00657 if (subsession != NULL && strcmp(trackId, subsession->trackId()) == 0) break;
00658 }
00659 if (streamNum >= fNumStreamStates) {
00660
00661 handleCmd_notFound(cseq);
00662 return;
00663 }
00664 } else {
00665
00666
00667 if (fNumStreamStates != 1) {
00668 handleCmd_bad(cseq);
00669 return;
00670 }
00671 streamNum = 0;
00672 subsession = fStreamStates[streamNum].subsession;
00673 }
00674
00675
00676
00677
00678 StreamingMode streamingMode;
00679 char* streamingModeString;
00680 char* clientsDestinationAddressStr;
00681 u_int8_t clientsDestinationTTL;
00682 portNumBits clientRTPPortNum, clientRTCPPortNum;
00683 unsigned char rtpChannelId, rtcpChannelId;
00684 parseTransportHeader(fullRequestStr, streamingMode, streamingModeString,
00685 clientsDestinationAddressStr, clientsDestinationTTL,
00686 clientRTPPortNum, clientRTCPPortNum,
00687 rtpChannelId, rtcpChannelId);
00688 if (streamingMode == RTP_TCP && rtpChannelId == 0xFF) {
00689
00690
00691
00692 rtpChannelId = fTCPStreamIdCount; rtcpChannelId = fTCPStreamIdCount+1;
00693 }
00694 fTCPStreamIdCount += 2;
00695
00696 Port clientRTPPort(clientRTPPortNum);
00697 Port clientRTCPPort(clientRTCPPortNum);
00698
00699
00700
00701 float rangeStart, rangeEnd;
00702 fStreamAfterSETUP = parseRangeHeader(fullRequestStr, rangeStart, rangeEnd);
00703
00704
00705 int tcpSocketNum = streamingMode == RTP_TCP ? fClientSocket : -1;
00706 netAddressBits destinationAddress = 0;
00707 u_int8_t destinationTTL = 255;
00708 #ifdef RTSP_ALLOW_CLIENT_DESTINATION_SETTING
00709 if (clientsDestinationAddressStr != NULL) {
00710
00711
00712
00713
00714 destinationAddress = our_inet_addr(clientsDestinationAddressStr);
00715 }
00716
00717 destinationTTL = clientsDestinationTTL;
00718 #endif
00719 delete[] clientsDestinationAddressStr;
00720 Port serverRTPPort(0);
00721 Port serverRTCPPort(0);
00722 subsession->getStreamParameters(fOurSessionId, fClientAddr.sin_addr.s_addr,
00723 clientRTPPort, clientRTCPPort,
00724 tcpSocketNum, rtpChannelId, rtcpChannelId,
00725 destinationAddress, destinationTTL, fIsMulticast,
00726 serverRTPPort, serverRTCPPort,
00727 fStreamStates[streamNum].streamToken);
00728 struct in_addr destinationAddr; destinationAddr.s_addr = destinationAddress;
00729 if (fIsMulticast) {
00730 if (streamingMode == RTP_TCP) {
00731
00732 handleCmd_unsupportedTransport(cseq);
00733 return;
00734 }
00735 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00736 "RTSP/1.0 200 OK\r\n"
00737 "CSeq: %s\r\n"
00738 "%s"
00739 "Transport: RTP/AVP;multicast;destination=%s;port=%d-%d;ttl=%d\r\n"
00740 "Session: %d\r\n\r\n",
00741 cseq,
00742 dateHeader(),
00743 our_inet_ntoa(destinationAddr), ntohs(serverRTPPort.num()), ntohs(serverRTCPPort.num()), destinationTTL,
00744 fOurSessionId);
00745 } else {
00746 switch (streamingMode) {
00747 case RTP_UDP: {
00748 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00749 "RTSP/1.0 200 OK\r\n"
00750 "CSeq: %s\r\n"
00751 "%s"
00752 "Transport: RTP/AVP;unicast;destination=%s;client_port=%d-%d;server_port=%d-%d\r\n"
00753 "Session: %d\r\n\r\n",
00754 cseq,
00755 dateHeader(),
00756 our_inet_ntoa(destinationAddr), ntohs(clientRTPPort.num()), ntohs(clientRTCPPort.num()), ntohs(serverRTPPort.num()), ntohs(serverRTCPPort.num()),
00757 fOurSessionId);
00758 break;
00759 }
00760 case RTP_TCP: {
00761 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00762 "RTSP/1.0 200 OK\r\n"
00763 "CSeq: %s\r\n"
00764 "%s"
00765 "Transport: RTP/AVP/TCP;unicast;destination=%s;interleaved=%d-%d\r\n"
00766 "Session: %d\r\n\r\n",
00767 cseq,
00768 dateHeader(),
00769 our_inet_ntoa(destinationAddr), rtpChannelId, rtcpChannelId,
00770 fOurSessionId);
00771 break;
00772 }
00773 case RAW_UDP: {
00774 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00775 "RTSP/1.0 200 OK\r\n"
00776 "CSeq: %s\r\n"
00777 "%s"
00778 "Transport: %s;unicast;destination=%s;client_port=%d;server_port=%d\r\n"
00779 "Session: %d\r\n\r\n",
00780 cseq,
00781 dateHeader(),
00782 streamingModeString, our_inet_ntoa(destinationAddr), ntohs(clientRTPPort.num()), ntohs(serverRTPPort.num()),
00783 fOurSessionId);
00784 delete[] streamingModeString;
00785 break;
00786 }
00787 }
00788 }
00789 }
00790
00791 void RTSPServer::RTSPClientSession
00792 ::handleCmd_withinSession(char const* cmdName,
00793 char const* urlPreSuffix, char const* urlSuffix,
00794 char const* cseq, char const* fullRequestStr) {
00795
00796
00797
00798
00799
00800
00801
00802 if (fOurServerMediaSession == NULL) {
00803 handleCmd_notSupported(cseq);
00804 return;
00805 }
00806 ServerMediaSubsession* subsession;
00807 if (urlSuffix[0] != '\0' &&
00808 strcmp(fOurServerMediaSession->streamName(), urlPreSuffix) == 0) {
00809
00810
00811 ServerMediaSubsessionIterator iter(*fOurServerMediaSession);
00812 while ((subsession = iter.next()) != NULL) {
00813 if (strcmp(subsession->trackId(), urlSuffix) == 0) break;
00814 }
00815 if (subsession == NULL) {
00816 handleCmd_notFound(cseq);
00817 return;
00818 }
00819 } else if (strcmp(fOurServerMediaSession->streamName(), urlSuffix) == 0 ||
00820 strcmp(fOurServerMediaSession->streamName(), urlPreSuffix) == 0) {
00821
00822 subsession = NULL;
00823 } else {
00824 handleCmd_notFound(cseq);
00825 return;
00826 }
00827
00828 if (strcmp(cmdName, "TEARDOWN") == 0) {
00829 handleCmd_TEARDOWN(subsession, cseq);
00830 } else if (strcmp(cmdName, "PLAY") == 0) {
00831 handleCmd_PLAY(subsession, cseq, fullRequestStr);
00832 } else if (strcmp(cmdName, "PAUSE") == 0) {
00833 handleCmd_PAUSE(subsession, cseq);
00834 } else if (strcmp(cmdName, "GET_PARAMETER") == 0) {
00835 handleCmd_GET_PARAMETER(subsession, cseq, fullRequestStr);
00836 }
00837 }
00838
00839 void RTSPServer::RTSPClientSession
00840 ::handleCmd_TEARDOWN(ServerMediaSubsession* , char const* cseq) {
00841 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
00842 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%s\r\n",
00843 cseq, dateHeader());
00844 fSessionIsActive = False;
00845 }
00846
00847 static Boolean parseScaleHeader(char const* buf, float& scale) {
00848
00849 scale = 1.0;
00850
00851
00852 while (1) {
00853 if (*buf == '\0') return False;
00854 if (_strncasecmp(buf, "Scale: ", 7) == 0) break;
00855 ++buf;
00856 }
00857
00858
00859 char const* fields = buf + 7;
00860 while (*fields == ' ') ++fields;
00861 float sc;
00862 if (sscanf(fields, "%f", &sc) == 1) {
00863 scale = sc;
00864 } else {
00865 return False;
00866 }
00867
00868 return True;
00869 }
00870
00871 void RTSPServer::RTSPClientSession
00872 ::handleCmd_PLAY(ServerMediaSubsession* subsession, char const* cseq,
00873 char const* fullRequestStr) {
00874 char* rtspURL = fOurServer.rtspURL(fOurServerMediaSession);
00875 unsigned rtspURLSize = strlen(rtspURL);
00876
00878 float scale;
00879 Boolean sawScaleHeader = parseScaleHeader(fullRequestStr, scale);
00880
00881
00882 if (subsession == NULL ) {
00883 fOurServerMediaSession->testScaleFactor(scale);
00884 } else {
00885 subsession->testScaleFactor(scale);
00886 }
00887
00888 char buf[100];
00889 char* scaleHeader;
00890 if (!sawScaleHeader) {
00891 buf[0] = '\0';
00892 } else {
00893 sprintf(buf, "Scale: %f\r\n", scale);
00894 }
00895 scaleHeader = strDup(buf);
00896
00898 float rangeStart, rangeEnd;
00899 Boolean sawRangeHeader = parseRangeHeader(fullRequestStr, rangeStart, rangeEnd);
00900
00901
00902
00903 float duration = subsession == NULL
00904 ? fOurServerMediaSession->duration() : subsession->duration();
00905 if (duration < 0.0) {
00906
00907
00908 duration = -duration;
00909 }
00910
00911 if (rangeEnd < 0.0 || rangeEnd > duration) rangeEnd = duration;
00912 if (rangeStart < 0.0) {
00913 rangeStart = 0.0;
00914 } else if (rangeEnd > 0.0 && scale > 0.0 && rangeStart > rangeEnd) {
00915 rangeStart = rangeEnd;
00916 }
00917
00918 char* rangeHeader;
00919 if (!sawRangeHeader) {
00920 buf[0] = '\0';
00921 } else if (rangeEnd == 0.0 && scale >= 0.0) {
00922 sprintf(buf, "Range: npt=%.3f-\r\n", rangeStart);
00923 } else {
00924 sprintf(buf, "Range: npt=%.3f-%.3f\r\n", rangeStart, rangeEnd);
00925 }
00926 rangeHeader = strDup(buf);
00927
00928
00929 char const* rtpInfoFmt =
00930 "%s"
00931 "%s"
00932 "url=%s/%s"
00933 ";seq=%d"
00934 #ifdef RTPINFO_INCLUDE_RTPTIME
00935 ";rtptime=%u"
00936 #endif
00937 ;
00938 unsigned rtpInfoFmtSize = strlen(rtpInfoFmt);
00939 char* rtpInfo = strDup("RTP-Info: ");
00940 unsigned i, numRTPInfoItems = 0;
00941
00942
00943 for (i = 0; i < fNumStreamStates; ++i) {
00944 if (subsession == NULL
00945 || subsession == fStreamStates[i].subsession) {
00946 if (sawScaleHeader) {
00947 fStreamStates[i].subsession->setStreamScale(fOurSessionId,
00948 fStreamStates[i].streamToken,
00949 scale);
00950 }
00951 if (sawRangeHeader) {
00952 fStreamStates[i].subsession->seekStream(fOurSessionId,
00953 fStreamStates[i].streamToken,
00954 rangeStart);
00955 }
00956 }
00957 }
00958
00959
00960 for (i = 0; i < fNumStreamStates; ++i) {
00961 if (subsession == NULL
00962 || subsession == fStreamStates[i].subsession) {
00963 unsigned short rtpSeqNum = 0;
00964 unsigned rtpTimestamp = 0;
00965 fStreamStates[i].subsession->startStream(fOurSessionId,
00966 fStreamStates[i].streamToken,
00967 (TaskFunc*)noteClientLiveness,
00968 this,
00969 rtpSeqNum, rtpTimestamp);
00970 const char *urlSuffix = fStreamStates[i].subsession->trackId();
00971 char* prevRTPInfo = rtpInfo;
00972 unsigned rtpInfoSize = rtpInfoFmtSize
00973 + strlen(prevRTPInfo)
00974 + 1
00975 + rtspURLSize + strlen(urlSuffix)
00976 + 5
00977 #ifdef RTPINFO_INCLUDE_RTPTIME
00978 + 10
00979 #endif
00980 + 2 ;
00981 rtpInfo = new char[rtpInfoSize];
00982 sprintf(rtpInfo, rtpInfoFmt,
00983 prevRTPInfo,
00984 numRTPInfoItems++ == 0 ? "" : ",",
00985 rtspURL, urlSuffix,
00986 rtpSeqNum
00987 #ifdef RTPINFO_INCLUDE_RTPTIME
00988 ,rtpTimestamp
00989 #endif
00990 );
00991 delete[] prevRTPInfo;
00992 }
00993 }
00994 if (numRTPInfoItems == 0) {
00995 rtpInfo[0] = '\0';
00996 } else {
00997 unsigned rtpInfoLen = strlen(rtpInfo);
00998 rtpInfo[rtpInfoLen] = '\r';
00999 rtpInfo[rtpInfoLen+1] = '\n';
01000 rtpInfo[rtpInfoLen+2] = '\0';
01001 }
01002
01003
01004 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
01005 "RTSP/1.0 200 OK\r\n"
01006 "CSeq: %s\r\n"
01007 "%s"
01008 "%s"
01009 "%s"
01010 "Session: %d\r\n"
01011 "%s\r\n",
01012 cseq,
01013 dateHeader(),
01014 scaleHeader,
01015 rangeHeader,
01016 fOurSessionId,
01017 rtpInfo);
01018 delete[] rtpInfo; delete[] rangeHeader;
01019 delete[] scaleHeader; delete[] rtspURL;
01020 }
01021
01022 void RTSPServer::RTSPClientSession
01023 ::handleCmd_PAUSE(ServerMediaSubsession* subsession, char const* cseq) {
01024 for (unsigned i = 0; i < fNumStreamStates; ++i) {
01025 if (subsession == NULL
01026 || subsession == fStreamStates[i].subsession) {
01027 fStreamStates[i].subsession->pauseStream(fOurSessionId,
01028 fStreamStates[i].streamToken);
01029 }
01030 }
01031 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
01032 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sSession: %d\r\n\r\n",
01033 cseq, dateHeader(), fOurSessionId);
01034 }
01035
01036 void RTSPServer::RTSPClientSession
01037 ::handleCmd_GET_PARAMETER(ServerMediaSubsession* subsession, char const* cseq,
01038 char const* ) {
01039
01040
01041 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
01042 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sSession: %d\r\n\r\n",
01043 cseq, dateHeader(), fOurSessionId);
01044 }
01045
01046 static Boolean parseAuthorizationHeader(char const* buf,
01047 char const*& username,
01048 char const*& realm,
01049 char const*& nonce, char const*& uri,
01050 char const*& response) {
01051
01052 username = realm = nonce = uri = response = NULL;
01053
01054
01055 while (1) {
01056 if (*buf == '\0') return False;
01057 if (_strncasecmp(buf, "Authorization: Digest ", 22) == 0) break;
01058 ++buf;
01059 }
01060
01061
01062 char const* fields = buf + 22;
01063 while (*fields == ' ') ++fields;
01064 char* parameter = strDupSize(fields);
01065 char* value = strDupSize(fields);
01066 while (1) {
01067 value[0] = '\0';
01068 if (sscanf(fields, "%[^=]=\"%[^\"]\"", parameter, value) != 2 &&
01069 sscanf(fields, "%[^=]=\"\"", parameter) != 1) {
01070 break;
01071 }
01072 if (strcmp(parameter, "username") == 0) {
01073 username = strDup(value);
01074 } else if (strcmp(parameter, "realm") == 0) {
01075 realm = strDup(value);
01076 } else if (strcmp(parameter, "nonce") == 0) {
01077 nonce = strDup(value);
01078 } else if (strcmp(parameter, "uri") == 0) {
01079 uri = strDup(value);
01080 } else if (strcmp(parameter, "response") == 0) {
01081 response = strDup(value);
01082 }
01083
01084 fields += strlen(parameter) + 2 + strlen(value) + 1 ;
01085 while (*fields == ',' || *fields == ' ') ++fields;
01086
01087 if (*fields == '\0' || *fields == '\r' || *fields == '\n') break;
01088 }
01089 delete[] parameter; delete[] value;
01090 return True;
01091 }
01092
01093 Boolean RTSPServer::RTSPClientSession
01094 ::authenticationOK(char const* cmdName, char const* cseq,
01095 char const* fullRequestStr) {
01096
01097 if (fOurServer.fAuthDB == NULL) return True;
01098
01099 char const* username = NULL; char const* realm = NULL; char const* nonce = NULL;
01100 char const* uri = NULL; char const* response = NULL;
01101 Boolean success = False;
01102
01103 do {
01104
01105
01106 if (fCurrentAuthenticator.nonce() == NULL) break;
01107
01108
01109
01110
01111 if (!parseAuthorizationHeader(fullRequestStr,
01112 username, realm, nonce, uri, response)
01113 || username == NULL
01114 || realm == NULL || strcmp(realm, fCurrentAuthenticator.realm()) != 0
01115 || nonce == NULL || strcmp(nonce, fCurrentAuthenticator.nonce()) != 0
01116 || uri == NULL || response == NULL) {
01117 break;
01118 }
01119
01120
01121 char const* password = fOurServer.fAuthDB->lookupPassword(username);
01122 #ifdef DEBUG
01123 fprintf(stderr, "lookupPassword(%s) returned password %s\n", username, password);
01124 #endif
01125 if (password == NULL) break;
01126 fCurrentAuthenticator.
01127 setUsernameAndPassword(username, password,
01128 fOurServer.fAuthDB->passwordsAreMD5());
01129
01130
01131
01132 char const* ourResponse
01133 = fCurrentAuthenticator.computeDigestResponse(cmdName, uri);
01134 success = (strcmp(ourResponse, response) == 0);
01135 fCurrentAuthenticator.reclaimDigestResponse(ourResponse);
01136 } while (0);
01137
01138 delete[] (char*)username; delete[] (char*)realm; delete[] (char*)nonce;
01139 delete[] (char*)uri; delete[] (char*)response;
01140 if (success) return True;
01141
01142
01143
01144 fCurrentAuthenticator.setRealmAndRandomNonce(fOurServer.fAuthDB->realm());
01145 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
01146 "RTSP/1.0 401 Unauthorized\r\n"
01147 "CSeq: %s\r\n"
01148 "%s"
01149 "WWW-Authenticate: Digest realm=\"%s\", nonce=\"%s\"\r\n\r\n",
01150 cseq,
01151 dateHeader(),
01152 fCurrentAuthenticator.realm(), fCurrentAuthenticator.nonce());
01153 return False;
01154 }
01155
01156 void RTSPServer::RTSPClientSession::noteLiveness() {
01157 if (fOurServer.fReclamationTestSeconds > 0) {
01158 envir().taskScheduler()
01159 .rescheduleDelayedTask(fLivenessCheckTask,
01160 fOurServer.fReclamationTestSeconds*1000000,
01161 (TaskFunc*)livenessTimeoutTask, this);
01162 }
01163 }
01164
01165 void RTSPServer::RTSPClientSession
01166 ::noteClientLiveness(RTSPClientSession* clientSession) {
01167 clientSession->noteLiveness();
01168 }
01169
01170 void RTSPServer::RTSPClientSession
01171 ::livenessTimeoutTask(RTSPClientSession* clientSession) {
01172
01173
01174
01175
01176
01177
01178 if (clientSession->isMulticast()) return;
01179
01180 #ifdef DEBUG
01181 fprintf(stderr, "RTSP client session from %s has timed out (due to inactivity)\n", our_inet_ntoa(clientSession->fClientAddr.sin_addr));
01182 #endif
01183 delete clientSession;
01184 }
01185
01186
01188
01189 UserAuthenticationDatabase::UserAuthenticationDatabase(char const* realm,
01190 Boolean passwordsAreMD5)
01191 : fTable(HashTable::create(STRING_HASH_KEYS)),
01192 fRealm(strDup(realm == NULL ? "LIVE555 Streaming Media" : realm)),
01193 fPasswordsAreMD5(passwordsAreMD5) {
01194 }
01195
01196 UserAuthenticationDatabase::~UserAuthenticationDatabase() {
01197 delete[] fRealm;
01198 delete fTable;
01199 }
01200
01201 void UserAuthenticationDatabase::addUserRecord(char const* username,
01202 char const* password) {
01203 fTable->Add(username, (void*)(strDup(password)));
01204 }
01205
01206 void UserAuthenticationDatabase::removeUserRecord(char const* username) {
01207 char* password = (char*)(fTable->Lookup(username));
01208 fTable->Remove(username);
01209 delete[] password;
01210 }
01211
01212 char const* UserAuthenticationDatabase::lookupPassword(char const* username) {
01213 return (char const*)(fTable->Lookup(username));
01214 }