
Public Member Functions | |
| RTSPClientSession (RTSPServer &ourServer, unsigned sessionId, int clientSocket, struct sockaddr_in clientAddr) | |
| virtual | ~RTSPClientSession () |
Private Member Functions | |
| UsageEnvironment & | envir () |
| void | reclaimStreamStates () |
| void | resetRequestBuffer () |
| void | incomingRequestHandler1 () |
| void | handleCmd_bad (char const *cseq) |
| void | handleCmd_notSupported (char const *cseq) |
| void | handleCmd_notFound (char const *cseq) |
| void | handleCmd_unsupportedTransport (char const *cseq) |
| void | handleCmd_OPTIONS (char const *cseq) |
| void | handleCmd_DESCRIBE (char const *cseq, char const *urlSuffix, char const *fullRequestStr) |
| void | handleCmd_SETUP (char const *cseq, char const *urlPreSuffix, char const *urlSuffix, char const *fullRequestStr) |
| void | handleCmd_withinSession (char const *cmdName, char const *urlPreSuffix, char const *urlSuffix, char const *cseq, char const *fullRequestStr) |
| void | handleCmd_TEARDOWN (ServerMediaSubsession *subsession, char const *cseq) |
| void | handleCmd_PLAY (ServerMediaSubsession *subsession, char const *cseq, char const *fullRequestStr) |
| void | handleCmd_PAUSE (ServerMediaSubsession *subsession, char const *cseq) |
| void | handleCmd_GET_PARAMETER (ServerMediaSubsession *subsession, char const *cseq, char const *fullRequestStr) |
| Boolean | authenticationOK (char const *cmdName, char const *cseq, char const *urlSuffix, char const *fullRequestStr) |
| void | noteLiveness () |
| Boolean | isMulticast () const |
Static Private Member Functions | |
| static void | incomingRequestHandler (void *, int) |
| static void | noteClientLiveness (RTSPClientSession *clientSession) |
| static void | livenessTimeoutTask (RTSPClientSession *clientSession) |
Private Attributes | |
| RTSPServer & | fOurServer |
| unsigned | fOurSessionId |
| ServerMediaSession * | fOurServerMediaSession |
| int | fClientSocket |
| sockaddr_in | fClientAddr |
| TaskToken | fLivenessCheckTask |
| unsigned char | fRequestBuffer [RTSP_BUFFER_SIZE] |
| unsigned | fRequestBytesAlreadySeen |
| unsigned | fRequestBufferBytesLeft |
| unsigned char * | fLastCRLF |
| unsigned char | fResponseBuffer [RTSP_BUFFER_SIZE] |
| Boolean | fIsMulticast |
| Boolean | fSessionIsActive |
| Boolean | fStreamAfterSETUP |
| Authenticator | fCurrentAuthenticator |
| unsigned char | fTCPStreamIdCount |
| unsigned | fNumStreamStates |
| RTSPServer::RTSPClientSession::streamState * | fStreamStates |
Data Structures | |
| struct | streamState |
Definition at line 117 of file RTSPServer.hh.
| RTSPServer::RTSPClientSession::RTSPClientSession | ( | RTSPServer & | ourServer, | |
| unsigned | sessionId, | |||
| int | clientSocket, | |||
| struct sockaddr_in | clientAddr | |||
| ) |
Definition at line 251 of file RTSPServer.cpp.
References envir(), fClientSocket, incomingRequestHandler(), noteLiveness(), resetRequestBuffer(), UsageEnvironment::taskScheduler(), and TaskScheduler::turnOnBackgroundReadHandling().
00253 : fOurServer(ourServer), fOurSessionId(sessionId), 00254 fOurServerMediaSession(NULL), 00255 fClientSocket(clientSocket), fClientAddr(clientAddr), 00256 fLivenessCheckTask(NULL), 00257 fIsMulticast(False), fSessionIsActive(True), fStreamAfterSETUP(False), 00258 fTCPStreamIdCount(0), fNumStreamStates(0), fStreamStates(NULL) { 00259 // Arrange to handle incoming requests: 00260 resetRequestBuffer(); 00261 envir().taskScheduler().turnOnBackgroundReadHandling(fClientSocket, 00262 (TaskScheduler::BackgroundHandlerProc*)&incomingRequestHandler, this); 00263 noteLiveness(); 00264 }
| RTSPServer::RTSPClientSession::~RTSPClientSession | ( | ) | [virtual] |
Definition at line 266 of file RTSPServer.cpp.
References closeSocket, ServerMediaSession::decrementReferenceCount(), ServerMediaSession::deleteWhenUnreferenced(), envir(), fClientSocket, fLivenessCheckTask, fOurServer, fOurServerMediaSession, NULL, reclaimStreamStates(), ServerMediaSession::referenceCount(), RTSPServer::removeServerMediaSession(), UsageEnvironment::taskScheduler(), TaskScheduler::turnOffBackgroundReadHandling(), and TaskScheduler::unscheduleDelayedTask().
00266 { 00267 // Turn off any liveness checking: 00268 envir().taskScheduler().unscheduleDelayedTask(fLivenessCheckTask); 00269 00270 // Turn off background read handling: 00271 envir().taskScheduler().turnOffBackgroundReadHandling(fClientSocket); 00272 00273 ::closeSocket(fClientSocket); 00274 00275 reclaimStreamStates(); 00276 00277 if (fOurServerMediaSession != NULL) { 00278 fOurServerMediaSession->decrementReferenceCount(); 00279 if (fOurServerMediaSession->referenceCount() == 0 00280 && fOurServerMediaSession->deleteWhenUnreferenced()) { 00281 fOurServer.removeServerMediaSession(fOurServerMediaSession); 00282 } 00283 } 00284 }
| UsageEnvironment& RTSPServer::RTSPClientSession::envir | ( | ) | [inline, private] |
Definition at line 123 of file RTSPServer.hh.
References Medium::envir(), and fOurServer.
Referenced by incomingRequestHandler1(), noteLiveness(), RTSPClientSession(), and ~RTSPClientSession().
00123 { return fOurServer.envir(); }
| void RTSPServer::RTSPClientSession::reclaimStreamStates | ( | ) | [private] |
Definition at line 286 of file RTSPServer.cpp.
References fNumStreamStates, fOurSessionId, fStreamStates, NULL, RTSPServer::RTSPClientSession::streamState::streamToken, and subsession.
Referenced by ~RTSPClientSession().
00286 { 00287 for (unsigned i = 0; i < fNumStreamStates; ++i) { 00288 if (fStreamStates[i].subsession != NULL) { 00289 fStreamStates[i].subsession->deleteStream(fOurSessionId, 00290 fStreamStates[i].streamToken); 00291 } 00292 } 00293 delete[] fStreamStates; fStreamStates = NULL; 00294 fNumStreamStates = 0; 00295 }
| void RTSPServer::RTSPClientSession::resetRequestBuffer | ( | ) | [private] |
Definition at line 297 of file RTSPServer.cpp.
References fLastCRLF, fRequestBuffer, fRequestBufferBytesLeft, and fRequestBytesAlreadySeen.
Referenced by incomingRequestHandler1(), and RTSPClientSession().
00297 { 00298 fRequestBytesAlreadySeen = 0; 00299 fRequestBufferBytesLeft = sizeof fRequestBuffer; 00300 fLastCRLF = &fRequestBuffer[-3]; // hack 00301 }
| void RTSPServer::RTSPClientSession::incomingRequestHandler | ( | void * | , | |
| int | ||||
| ) | [static, private] |
Definition at line 304 of file RTSPServer.cpp.
References session.
Referenced by RTSPClientSession().
00304 { 00305 RTSPClientSession* session = (RTSPClientSession*)instance; 00306 session->incomingRequestHandler1(); 00307 }
| void RTSPServer::RTSPClientSession::incomingRequestHandler1 | ( | ) | [private] |
Definition at line 309 of file RTSPServer.cpp.
References envir(), False, fClientSocket, fLastCRLF, fRequestBuffer, fRequestBufferBytesLeft, fRequestBytesAlreadySeen, fResponseBuffer, fSessionIsActive, fStreamAfterSETUP, handleCmd_bad(), handleCmd_DESCRIBE(), handleCmd_notSupported(), handleCmd_OPTIONS(), handleCmd_SETUP(), handleCmd_withinSession(), noteLiveness(), parseRTSPRequestString(), readSocket(), resetRequestBuffer(), and RTSP_PARAM_STRING_MAX.
00309 { 00310 noteLiveness(); 00311 00312 struct sockaddr_in dummy; // 'from' address, meaningless in this case 00313 Boolean endOfMsg = False; 00314 unsigned char* ptr = &fRequestBuffer[fRequestBytesAlreadySeen]; 00315 00316 int bytesRead = readSocket(envir(), fClientSocket, 00317 ptr, fRequestBufferBytesLeft, dummy); 00318 if (bytesRead <= 0 || (unsigned)bytesRead >= fRequestBufferBytesLeft) { 00319 // Either the client socket has died, or the request was too big for us. 00320 // Terminate this connection: 00321 #ifdef DEBUG 00322 fprintf(stderr, "RTSPClientSession[%p]::incomingRequestHandler1() read %d bytes (of %d); terminating connection!\n", this, bytesRead, fRequestBufferBytesLeft); 00323 #endif 00324 delete this; 00325 return; 00326 } 00327 #ifdef DEBUG 00328 ptr[bytesRead] = '\0'; 00329 fprintf(stderr, "RTSPClientSession[%p]::incomingRequestHandler1() read %d bytes:%s\n", this, bytesRead, ptr); 00330 #endif 00331 00332 // Look for the end of the message: <CR><LF><CR><LF> 00333 unsigned char *tmpPtr = ptr; 00334 if (fRequestBytesAlreadySeen > 0) --tmpPtr; 00335 // in case the last read ended with a <CR> 00336 while (tmpPtr < &ptr[bytesRead-1]) { 00337 if (*tmpPtr == '\r' && *(tmpPtr+1) == '\n') { 00338 if (tmpPtr - fLastCRLF == 2) { // This is it: 00339 endOfMsg = 1; 00340 break; 00341 } 00342 fLastCRLF = tmpPtr; 00343 } 00344 ++tmpPtr; 00345 } 00346 00347 fRequestBufferBytesLeft -= bytesRead; 00348 fRequestBytesAlreadySeen += bytesRead; 00349 00350 if (!endOfMsg) return; // subsequent reads will be needed to complete the request 00351 00352 // Parse the request string into command name and 'CSeq', 00353 // then handle the command: 00354 fRequestBuffer[fRequestBytesAlreadySeen] = '\0'; 00355 char cmdName[RTSP_PARAM_STRING_MAX]; 00356 char urlPreSuffix[RTSP_PARAM_STRING_MAX]; 00357 char urlSuffix[RTSP_PARAM_STRING_MAX]; 00358 char cseq[RTSP_PARAM_STRING_MAX]; 00359 if (!parseRTSPRequestString((char*)fRequestBuffer, fRequestBytesAlreadySeen, 00360 cmdName, sizeof cmdName, 00361 urlPreSuffix, sizeof urlPreSuffix, 00362 urlSuffix, sizeof urlSuffix, 00363 cseq, sizeof cseq)) { 00364 #ifdef DEBUG 00365 fprintf(stderr, "parseRTSPRequestString() failed!\n"); 00366 #endif 00367 handleCmd_bad(cseq); 00368 } else { 00369 #ifdef DEBUG 00370 fprintf(stderr, "parseRTSPRequestString() returned cmdName \"%s\", urlPreSuffix \"%s\", urlSuffix \"%s\"\n", cmdName, urlPreSuffix, urlSuffix); 00371 #endif 00372 if (strcmp(cmdName, "OPTIONS") == 0) { 00373 handleCmd_OPTIONS(cseq); 00374 } else if (strcmp(cmdName, "DESCRIBE") == 0) { 00375 handleCmd_DESCRIBE(cseq, urlSuffix, (char const*)fRequestBuffer); 00376 } else if (strcmp(cmdName, "SETUP") == 0) { 00377 handleCmd_SETUP(cseq, urlPreSuffix, urlSuffix, (char const*)fRequestBuffer); 00378 } else if (strcmp(cmdName, "TEARDOWN") == 0 00379 || strcmp(cmdName, "PLAY") == 0 00380 || strcmp(cmdName, "PAUSE") == 0 00381 || strcmp(cmdName, "GET_PARAMETER") == 0) { 00382 handleCmd_withinSession(cmdName, urlPreSuffix, urlSuffix, cseq, 00383 (char const*)fRequestBuffer); 00384 } else { 00385 handleCmd_notSupported(cseq); 00386 } 00387 } 00388 00389 #ifdef DEBUG 00390 fprintf(stderr, "sending response: %s", fResponseBuffer); 00391 #endif 00392 send(fClientSocket, (char const*)fResponseBuffer, strlen((char*)fResponseBuffer), 0); 00393 00394 if (strcmp(cmdName, "SETUP") == 0 && fStreamAfterSETUP) { 00395 // The client has asked for streaming to commence now, rather than after a 00396 // subsequent "PLAY" command. So, simulate the effect of a "PLAY" command: 00397 handleCmd_withinSession("PLAY", urlPreSuffix, urlSuffix, cseq, 00398 (char const*)fRequestBuffer); 00399 } 00400 00401 resetRequestBuffer(); // to prepare for any subsequent request 00402 if (!fSessionIsActive) delete this; 00403 }
| void RTSPServer::RTSPClientSession::handleCmd_bad | ( | char const * | cseq | ) | [private] |
Definition at line 438 of file RTSPServer.cpp.
References allowedCommandNames, dateHeader(), and fResponseBuffer.
Referenced by incomingRequestHandler1().
00438 { 00439 // Don't do anything with "cseq", because it might be nonsense 00440 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00441 "RTSP/1.0 400 Bad Request\r\n%sAllow: %s\r\n\r\n", 00442 dateHeader(), allowedCommandNames); 00443 }
| void RTSPServer::RTSPClientSession::handleCmd_notSupported | ( | char const * | cseq | ) | [private] |
Definition at line 445 of file RTSPServer.cpp.
References allowedCommandNames, dateHeader(), and fResponseBuffer.
Referenced by incomingRequestHandler1().
00445 { 00446 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00447 "RTSP/1.0 405 Method Not Allowed\r\nCSeq: %s\r\n%sAllow: %s\r\n\r\n", 00448 cseq, dateHeader(), allowedCommandNames); 00449 }
| void RTSPServer::RTSPClientSession::handleCmd_notFound | ( | char const * | cseq | ) | [private] |
Definition at line 451 of file RTSPServer.cpp.
References dateHeader(), False, fResponseBuffer, and fSessionIsActive.
00451 { 00452 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00453 "RTSP/1.0 404 Stream Not Found\r\nCSeq: %s\r\n%s\r\n", 00454 cseq, dateHeader()); 00455 fSessionIsActive = False; // triggers deletion of ourself after responding 00456 }
| void RTSPServer::RTSPClientSession::handleCmd_unsupportedTransport | ( | char const * | cseq | ) | [private] |
Definition at line 458 of file RTSPServer.cpp.
References dateHeader(), False, fResponseBuffer, and fSessionIsActive.
00458 { 00459 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00460 "RTSP/1.0 461 Unsupported Transport\r\nCSeq: %s\r\n%s\r\n", 00461 cseq, dateHeader()); 00462 fSessionIsActive = False; // triggers deletion of ourself after responding 00463 }
| void RTSPServer::RTSPClientSession::handleCmd_OPTIONS | ( | char const * | cseq | ) | [private] |
Definition at line 465 of file RTSPServer.cpp.
References allowedCommandNames, dateHeader(), and fResponseBuffer.
Referenced by incomingRequestHandler1().
00465 { 00466 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00467 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sPublic: %s\r\n\r\n", 00468 cseq, dateHeader(), allowedCommandNames); 00469 }
| void RTSPServer::RTSPClientSession::handleCmd_DESCRIBE | ( | char const * | cseq, | |
| char const * | urlSuffix, | |||
| char const * | fullRequestStr | |||
| ) | [private] |
Definition at line 472 of file RTSPServer.cpp.
References dateHeader(), NULL, RTSPServer::rtspURL(), and session.
Referenced by incomingRequestHandler1().
00473 { 00474 char* sdpDescription = NULL; 00475 char* rtspURL = NULL; 00476 do { 00477 if (!authenticationOK("DESCRIBE", cseq, urlSuffix, fullRequestStr)) 00478 break; 00479 00480 // We should really check that the request contains an "Accept:" ##### 00481 // for "application/sdp", because that's what we're sending back ##### 00482 00483 // Begin by looking up the "ServerMediaSession" object for the 00484 // specified "urlSuffix": 00485 ServerMediaSession* session = fOurServer.lookupServerMediaSession(urlSuffix); 00486 if (session == NULL) { 00487 handleCmd_notFound(cseq); 00488 break; 00489 } 00490 00491 // Then, assemble a SDP description for this session: 00492 sdpDescription = session->generateSDPDescription(); 00493 if (sdpDescription == NULL) { 00494 // This usually means that a file name that was specified for a 00495 // "ServerMediaSubsession" does not exist. 00496 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00497 "RTSP/1.0 404 File Not Found, Or In Incorrect Format\r\n" 00498 "CSeq: %s\r\n" 00499 "%s\r\n", 00500 cseq, 00501 dateHeader()); 00502 break; 00503 } 00504 unsigned sdpDescriptionSize = strlen(sdpDescription); 00505 00506 // Also, generate our RTSP URL, for the "Content-Base:" header 00507 // (which is necessary to ensure that the correct URL gets used in 00508 // subsequent "SETUP" requests). 00509 rtspURL = fOurServer.rtspURL(session, fClientSocket); 00510 00511 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00512 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n" 00513 "%s" 00514 "Content-Base: %s/\r\n" 00515 "Content-Type: application/sdp\r\n" 00516 "Content-Length: %d\r\n\r\n" 00517 "%s", 00518 cseq, 00519 dateHeader(), 00520 rtspURL, 00521 sdpDescriptionSize, 00522 sdpDescription); 00523 } while (0); 00524 00525 delete[] sdpDescription; 00526 delete[] rtspURL; 00527 }
| void RTSPServer::RTSPClientSession::handleCmd_SETUP | ( | char const * | cseq, | |
| char const * | urlPreSuffix, | |||
| char const * | urlSuffix, | |||
| char const * | fullRequestStr | |||
| ) | [private] |
Definition at line 609 of file RTSPServer.cpp.
References dateHeader(), handleCmd_withinSession(), iter, MediaSubsessionIterator::next(), NULL, Port::num(), our_inet_addr(), our_inet_ntoa(), parsePlayNowHeader(), parseRangeHeader(), parseTransportHeader(), RAW_UDP, MediaSubsessionIterator::reset(), RTP_TCP, RTP_UDP, SOCKLEN_T, strDup(), and subsession.
Referenced by incomingRequestHandler1().
00611 { 00612 // "urlPreSuffix" should be the session (stream) name, and 00613 // "urlSuffix" should be the subsession (track) name. 00614 char const* streamName = urlPreSuffix; 00615 char const* trackId = urlSuffix; 00616 00617 // Check whether we have existing session state, and, if so, whether it's 00618 // for the session that's named in "streamName". (Note that we don't 00619 // support more than one concurrent session on the same client connection.) ##### 00620 if (fOurServerMediaSession != NULL 00621 && strcmp(streamName, fOurServerMediaSession->streamName()) != 0) { 00622 fOurServerMediaSession = NULL; 00623 } 00624 if (fOurServerMediaSession == NULL) { 00625 // Set up this session's state. 00626 00627 // Look up the "ServerMediaSession" object for the specified stream: 00628 if (streamName[0] != '\0' || 00629 fOurServer.lookupServerMediaSession("") != NULL) { // normal case 00630 } else { // weird case: there was no track id in the URL 00631 streamName = urlSuffix; 00632 trackId = NULL; 00633 } 00634 fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName); 00635 if (fOurServerMediaSession == NULL) { 00636 handleCmd_notFound(cseq); 00637 return; 00638 } 00639 00640 fOurServerMediaSession->incrementReferenceCount(); 00641 00642 // Set up our array of states for this session's subsessions (tracks): 00643 reclaimStreamStates(); 00644 ServerMediaSubsessionIterator iter(*fOurServerMediaSession); 00645 for (fNumStreamStates = 0; iter.next() != NULL; ++fNumStreamStates) {} 00646 fStreamStates = new struct streamState[fNumStreamStates]; 00647 iter.reset(); 00648 ServerMediaSubsession* subsession; 00649 for (unsigned i = 0; i < fNumStreamStates; ++i) { 00650 subsession = iter.next(); 00651 fStreamStates[i].subsession = subsession; 00652 fStreamStates[i].streamToken = NULL; // for now; reset by SETUP later 00653 } 00654 } 00655 00656 // Look up information for the specified subsession (track): 00657 ServerMediaSubsession* subsession = NULL; 00658 unsigned streamNum; 00659 if (trackId != NULL && trackId[0] != '\0') { // normal case 00660 for (streamNum = 0; streamNum < fNumStreamStates; ++streamNum) { 00661 subsession = fStreamStates[streamNum].subsession; 00662 if (subsession != NULL && strcmp(trackId, subsession->trackId()) == 0) break; 00663 } 00664 if (streamNum >= fNumStreamStates) { 00665 // The specified track id doesn't exist, so this request fails: 00666 handleCmd_notFound(cseq); 00667 return; 00668 } 00669 } else { 00670 // Weird case: there was no track id in the URL. 00671 // This works only if we have only one subsession: 00672 if (fNumStreamStates != 1) { 00673 handleCmd_bad(cseq); 00674 return; 00675 } 00676 streamNum = 0; 00677 subsession = fStreamStates[streamNum].subsession; 00678 } 00679 // ASSERT: subsession != NULL 00680 00681 // Look for a "Transport:" header in the request string, 00682 // to extract client parameters: 00683 StreamingMode streamingMode; 00684 char* streamingModeString = NULL; // set when RAW_UDP streaming is specified 00685 char* clientsDestinationAddressStr; 00686 u_int8_t clientsDestinationTTL; 00687 portNumBits clientRTPPortNum, clientRTCPPortNum; 00688 unsigned char rtpChannelId, rtcpChannelId; 00689 parseTransportHeader(fullRequestStr, streamingMode, streamingModeString, 00690 clientsDestinationAddressStr, clientsDestinationTTL, 00691 clientRTPPortNum, clientRTCPPortNum, 00692 rtpChannelId, rtcpChannelId); 00693 if (streamingMode == RTP_TCP && rtpChannelId == 0xFF) { 00694 // TCP streaming was requested, but with no "interleaving=" fields. 00695 // (QuickTime Player sometimes does this.) Set the RTP and RTCP channel ids to 00696 // proper values: 00697 rtpChannelId = fTCPStreamIdCount; rtcpChannelId = fTCPStreamIdCount+1; 00698 } 00699 fTCPStreamIdCount += 2; 00700 00701 Port clientRTPPort(clientRTPPortNum); 00702 Port clientRTCPPort(clientRTCPPortNum); 00703 00704 // Next, check whether a "Range:" header is present in the request. 00705 // This isn't legal, but some clients do this to combine "SETUP" and "PLAY": 00706 float rangeStart = 0.0, rangeEnd = 0.0; 00707 fStreamAfterSETUP = parseRangeHeader(fullRequestStr, rangeStart, rangeEnd) || 00708 parsePlayNowHeader(fullRequestStr); 00709 00710 // Then, get server parameters from the 'subsession': 00711 int tcpSocketNum = streamingMode == RTP_TCP ? fClientSocket : -1; 00712 netAddressBits destinationAddress = 0; 00713 u_int8_t destinationTTL = 255; 00714 #ifdef RTSP_ALLOW_CLIENT_DESTINATION_SETTING 00715 if (clientsDestinationAddressStr != NULL) { 00716 // Use the client-provided "destination" address. 00717 // Note: This potentially allows the server to be used in denial-of-service 00718 // attacks, so don't enable this code unless you're sure that clients are 00719 // trusted. 00720 destinationAddress = our_inet_addr(clientsDestinationAddressStr); 00721 } 00722 // Also use the client-provided TTL. 00723 destinationTTL = clientsDestinationTTL; 00724 #endif 00725 delete[] clientsDestinationAddressStr; 00726 Port serverRTPPort(0); 00727 Port serverRTCPPort(0); 00728 subsession->getStreamParameters(fOurSessionId, fClientAddr.sin_addr.s_addr, 00729 clientRTPPort, clientRTCPPort, 00730 tcpSocketNum, rtpChannelId, rtcpChannelId, 00731 destinationAddress, destinationTTL, fIsMulticast, 00732 serverRTPPort, serverRTCPPort, 00733 fStreamStates[streamNum].streamToken); 00734 struct in_addr destinationAddr; destinationAddr.s_addr = destinationAddress; 00735 char* destAddrStr = strDup(our_inet_ntoa(destinationAddr)); 00736 struct sockaddr_in sourceAddr; SOCKLEN_T namelen = sizeof sourceAddr; 00737 getsockname(fClientSocket, (struct sockaddr*)&sourceAddr, &namelen); 00738 char* sourceAddrStr = strDup(our_inet_ntoa(sourceAddr.sin_addr)); 00739 if (fIsMulticast) { 00740 switch (streamingMode) { 00741 case RTP_UDP: 00742 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00743 "RTSP/1.0 200 OK\r\n" 00744 "CSeq: %s\r\n" 00745 "%s" 00746 "Transport: RTP/AVP;multicast;destination=%s;source=%s;port=%d-%d;ttl=%d\r\n" 00747 "Session: %d\r\n\r\n", 00748 cseq, 00749 dateHeader(), 00750 destAddrStr, sourceAddrStr, ntohs(serverRTPPort.num()), ntohs(serverRTCPPort.num()), destinationTTL, 00751 fOurSessionId); 00752 break; 00753 case RTP_TCP: 00754 // multicast streams can't be sent via TCP 00755 handleCmd_unsupportedTransport(cseq); 00756 break; 00757 case RAW_UDP: 00758 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00759 "RTSP/1.0 200 OK\r\n" 00760 "CSeq: %s\r\n" 00761 "%s" 00762 "Transport: %s;multicast;destination=%s;source=%s;port=%d;ttl=%d\r\n" 00763 "Session: %d\r\n\r\n", 00764 cseq, 00765 dateHeader(), 00766 streamingModeString, destAddrStr, sourceAddrStr, ntohs(serverRTPPort.num()), destinationTTL, 00767 fOurSessionId); 00768 break; 00769 } 00770 } else { 00771 switch (streamingMode) { 00772 case RTP_UDP: { 00773 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00774 "RTSP/1.0 200 OK\r\n" 00775 "CSeq: %s\r\n" 00776 "%s" 00777 "Transport: RTP/AVP;unicast;destination=%s;source=%s;client_port=%d-%d;server_port=%d-%d\r\n" 00778 "Session: %d\r\n\r\n", 00779 cseq, 00780 dateHeader(), 00781 destAddrStr, sourceAddrStr, ntohs(clientRTPPort.num()), ntohs(clientRTCPPort.num()), ntohs(serverRTPPort.num()), ntohs(serverRTCPPort.num()), 00782 fOurSessionId); 00783 break; 00784 } 00785 case RTP_TCP: { 00786 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00787 "RTSP/1.0 200 OK\r\n" 00788 "CSeq: %s\r\n" 00789 "%s" 00790 "Transport: RTP/AVP/TCP;unicast;destination=%s;source=%s;interleaved=%d-%d\r\n" 00791 "Session: %d\r\n\r\n", 00792 cseq, 00793 dateHeader(), 00794 destAddrStr, sourceAddrStr, rtpChannelId, rtcpChannelId, 00795 fOurSessionId); 00796 break; 00797 } 00798 case RAW_UDP: { 00799 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00800 "RTSP/1.0 200 OK\r\n" 00801 "CSeq: %s\r\n" 00802 "%s" 00803 "Transport: %s;unicast;destination=%s;source=%s;client_port=%d;server_port=%d\r\n" 00804 "Session: %d\r\n\r\n", 00805 cseq, 00806 dateHeader(), 00807 streamingModeString, destAddrStr, sourceAddrStr, ntohs(clientRTPPort.num()), ntohs(serverRTPPort.num()), 00808 fOurSessionId); 00809 break; 00810 } 00811 } 00812 } 00813 delete[] destAddrStr; delete[] sourceAddrStr; delete[] streamingModeString; 00814 }
| void RTSPServer::RTSPClientSession::handleCmd_withinSession | ( | char const * | cmdName, | |
| char const * | urlPreSuffix, | |||
| char const * | urlSuffix, | |||
| char const * | cseq, | |||
| char const * | fullRequestStr | |||
| ) | [private] |
Definition at line 817 of file RTSPServer.cpp.
References iter, MediaSubsessionIterator::next(), NULL, and subsession.
Referenced by handleCmd_SETUP(), and incomingRequestHandler1().
00819 { 00820 // This will either be: 00821 // - a non-aggregated operation, if "urlPreSuffix" is the session (stream) 00822 // name and "urlSuffix" is the subsession (track) name, or 00823 // - a aggregated operation, if "urlSuffix" is the session (stream) name, 00824 // or "urlPreSuffix" is the session (stream) name, and "urlSuffix" 00825 // is empty. 00826 // First, figure out which of these it is: 00827 if (fOurServerMediaSession == NULL) { // There wasn't a previous SETUP! 00828 handleCmd_notSupported(cseq); 00829 return; 00830 } 00831 ServerMediaSubsession* subsession; 00832 if (urlSuffix[0] != '\0' && 00833 strcmp(fOurServerMediaSession->streamName(), urlPreSuffix) == 0) { 00834 // Non-aggregated operation. 00835 // Look up the media subsession whose track id is "urlSuffix": 00836 ServerMediaSubsessionIterator iter(*fOurServerMediaSession); 00837 while ((subsession = iter.next()) != NULL) { 00838 if (strcmp(subsession->trackId(), urlSuffix) == 0) break; // success 00839 } 00840 if (subsession == NULL) { // no such track! 00841 handleCmd_notFound(cseq); 00842 return; 00843 } 00844 } else if (strcmp(fOurServerMediaSession->streamName(), urlSuffix) == 0 || 00845 strcmp(fOurServerMediaSession->streamName(), urlPreSuffix) == 0) { 00846 // Aggregated operation 00847 subsession = NULL; 00848 } else { // the request doesn't match a known stream and/or track at all! 00849 handleCmd_notFound(cseq); 00850 return; 00851 } 00852 00853 if (strcmp(cmdName, "TEARDOWN") == 0) { 00854 handleCmd_TEARDOWN(subsession, cseq); 00855 } else if (strcmp(cmdName, "PLAY") == 0) { 00856 handleCmd_PLAY(subsession, cseq, fullRequestStr); 00857 } else if (strcmp(cmdName, "PAUSE") == 0) { 00858 handleCmd_PAUSE(subsession, cseq); 00859 } else if (strcmp(cmdName, "GET_PARAMETER") == 0) { 00860 handleCmd_GET_PARAMETER(subsession, cseq, fullRequestStr); 00861 } 00862 }
| void RTSPServer::RTSPClientSession::handleCmd_TEARDOWN | ( | ServerMediaSubsession * | subsession, | |
| char const * | cseq | |||
| ) | [private] |
Definition at line 865 of file RTSPServer.cpp.
References dateHeader(), and False.
00865 { 00866 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00867 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%s\r\n", 00868 cseq, dateHeader()); 00869 fSessionIsActive = False; // triggers deletion of ourself after responding 00870 }
| void RTSPServer::RTSPClientSession::handleCmd_PLAY | ( | ServerMediaSubsession * | subsession, | |
| char const * | cseq, | |||
| char const * | fullRequestStr | |||
| ) | [private] |
Definition at line 897 of file RTSPServer.cpp.
References dateHeader(), duration, NULL, parseRangeHeader(), parseScaleHeader(), RTPINFO_INCLUDE_RTPTIME, RTSPServer::rtspURL(), scale, strDup(), and subsession.
00898 { 00899 char* rtspURL = fOurServer.rtspURL(fOurServerMediaSession, fClientSocket); 00900 unsigned rtspURLSize = strlen(rtspURL); 00901 00903 float scale; 00904 Boolean sawScaleHeader = parseScaleHeader(fullRequestStr, scale); 00905 00906 // Try to set the stream's scale factor to this value: 00907 if (subsession == NULL /*aggregate op*/) { 00908 fOurServerMediaSession->testScaleFactor(scale); 00909 } else { 00910 subsession->testScaleFactor(scale); 00911 } 00912 00913 char buf[100]; 00914 char* scaleHeader; 00915 if (!sawScaleHeader) { 00916 buf[0] = '\0'; // Because we didn't see a Scale: header, don't send one back 00917 } else { 00918 sprintf(buf, "Scale: %f\r\n", scale); 00919 } 00920 scaleHeader = strDup(buf); 00921 00923 float rangeStart = 0.0, rangeEnd = 0.0; 00924 Boolean sawRangeHeader = parseRangeHeader(fullRequestStr, rangeStart, rangeEnd); 00925 00926 // Use this information, plus the stream's duration (if known), to create 00927 // our own "Range:" header, for the response: 00928 float duration = subsession == NULL /*aggregate op*/ 00929 ? fOurServerMediaSession->duration() : subsession->duration(); 00930 if (duration < 0.0) { 00931 // We're an aggregate PLAY, but the subsessions have different durations. 00932 // Use the largest of these durations in our header 00933 duration = -duration; 00934 } 00935 00936 if (rangeEnd < 0.0 || rangeEnd > duration) rangeEnd = duration; 00937 if (rangeStart < 0.0) { 00938 rangeStart = 0.0; 00939 } else if (rangeEnd > 0.0 && scale > 0.0 && rangeStart > rangeEnd) { 00940 rangeStart = rangeEnd; 00941 } 00942 00943 char* rangeHeader; 00944 if (!sawRangeHeader) { 00945 buf[0] = '\0'; // Because we didn't see a Range: header, don't send one back 00946 } else if (rangeEnd == 0.0 && scale >= 0.0) { 00947 sprintf(buf, "Range: npt=%.3f-\r\n", rangeStart); 00948 } else { 00949 sprintf(buf, "Range: npt=%.3f-%.3f\r\n", rangeStart, rangeEnd); 00950 } 00951 rangeHeader = strDup(buf); 00952 00953 // Create a "RTP-Info:" line. It will get filled in from each subsession's state: 00954 char const* rtpInfoFmt = 00955 "%s" // "RTP-Info:", plus any preceding rtpInfo items 00956 "%s" // comma separator, if needed 00957 "url=%s/%s" 00958 ";seq=%d" 00959 #ifdef RTPINFO_INCLUDE_RTPTIME 00960 ";rtptime=%u" 00961 #endif 00962 ; 00963 unsigned rtpInfoFmtSize = strlen(rtpInfoFmt); 00964 char* rtpInfo = strDup("RTP-Info: "); 00965 unsigned i, numRTPInfoItems = 0; 00966 00967 // Do any required seeking/scaling on each subsession, before starting streaming: 00968 for (i = 0; i < fNumStreamStates; ++i) { 00969 if (subsession == NULL /* means: aggregated operation */ 00970 || subsession == fStreamStates[i].subsession) { 00971 if (sawScaleHeader) { 00972 fStreamStates[i].subsession->setStreamScale(fOurSessionId, 00973 fStreamStates[i].streamToken, 00974 scale); 00975 } 00976 if (sawRangeHeader) { 00977 fStreamStates[i].subsession->seekStream(fOurSessionId,