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