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