#include <RTSPServer.hh>
Inheritance diagram for RTSPServer::RTSPClientSession:


Public Member Functions | |
| RTSPClientSession (RTSPServer &ourServer, unsigned sessionId, int clientSocket, struct sockaddr_in clientAddr) | |
| virtual | ~RTSPClientSession () |
Protected Member Functions | |
| virtual void | handleCmd_bad (char const *cseq) |
| virtual void | handleCmd_notSupported (char const *cseq) |
| virtual void | handleCmd_notFound (char const *cseq) |
| virtual void | handleCmd_unsupportedTransport (char const *cseq) |
| virtual void | handleCmd_OPTIONS (char const *cseq) |
| virtual void | handleCmd_DESCRIBE (char const *cseq, char const *urlPreSuffix, char const *urlSuffix, char const *fullRequestStr) |
| virtual void | handleCmd_SETUP (char const *cseq, char const *urlPreSuffix, char const *urlSuffix, char const *fullRequestStr) |
| virtual void | handleCmd_withinSession (char const *cmdName, char const *urlPreSuffix, char const *urlSuffix, char const *cseq, char const *fullRequestStr) |
| virtual void | handleCmd_TEARDOWN (ServerMediaSubsession *subsession, char const *cseq) |
| virtual void | handleCmd_PLAY (ServerMediaSubsession *subsession, char const *cseq, char const *fullRequestStr) |
| virtual void | handleCmd_PAUSE (ServerMediaSubsession *subsession, char const *cseq) |
| virtual void | handleCmd_GET_PARAMETER (ServerMediaSubsession *subsession, char const *cseq, char const *fullRequestStr) |
| virtual void | handleCmd_SET_PARAMETER (ServerMediaSubsession *subsession, char const *cseq, char const *fullRequestStr) |
| virtual Boolean | parseHTTPRequestString (char *resultCmdName, unsigned resultCmdNameMaxSize, char *urlSuffix, unsigned urlSuffixMaxSize, char *sessionCookie, unsigned sessionCookieMaxSize, char *acceptStr, unsigned acceptStrMaxSize) |
| virtual void | handleHTTPCmd_notSupported () |
| virtual void | handleHTTPCmd_notFound () |
| virtual void | handleHTTPCmd_TunnelingGET (char const *sessionCookie) |
| virtual Boolean | handleHTTPCmd_TunnelingPOST (char const *sessionCookie, unsigned char const *extraData, unsigned extraDataSize) |
| virtual void | handleHTTPCmd_StreamingGET (char const *urlSuffix, char const *fullRequestStr) |
| UsageEnvironment & | envir () |
| void | closeSockets () |
| void | reclaimStreamStates () |
| void | resetRequestBuffer () |
| Boolean | authenticationOK (char const *cmdName, char const *cseq, char const *urlSuffix, char const *fullRequestStr) |
| Boolean | isMulticast () const |
| void | incomingRequestHandler1 () |
| void | handleAlternativeRequestByte1 (u_int8_t requestByte) |
| void | handleRequestBytes (int newBytesRead) |
| void | noteLiveness () |
| void | changeClientInputSocket (int newSocketNum, unsigned char const *extraData, unsigned extraDataSize) |
Static Protected Member Functions | |
| static void | incomingRequestHandler (void *, int) |
| static void | handleAlternativeRequestByte (void *, u_int8_t requestByte) |
| static void | noteClientLiveness (RTSPClientSession *clientSession) |
| static void | livenessTimeoutTask (RTSPClientSession *clientSession) |
Protected Attributes | |
| RTSPServer & | fOurServer |
| unsigned | fOurSessionId |
| ServerMediaSession * | fOurServerMediaSession |
| int | fClientInputSocket |
| int | fClientOutputSocket |
| sockaddr_in | fClientAddr |
| char * | fSessionCookie |
| TaskToken | fLivenessCheckTask |
| unsigned char | fRequestBuffer [RTSP_BUFFER_SIZE] |
| unsigned | fRequestBytesAlreadySeen |
| unsigned | fRequestBufferBytesLeft |
| unsigned char * | fLastCRLF |
| unsigned | fBase64RemainderCount |
| unsigned char | fResponseBuffer [RTSP_BUFFER_SIZE] |
| Boolean | fIsMulticast |
| Boolean | fSessionIsActive |
| Boolean | fStreamAfterSETUP |
| Authenticator | fCurrentAuthenticator |
| unsigned char | fTCPStreamIdCount |
| unsigned | fNumStreamStates |
| RTSPServer::RTSPClientSession::streamState * | fStreamStates |
| unsigned | fRecursionCount |
Data Structures | |
| struct | streamState |
Definition at line 124 of file RTSPServer.hh.
| RTSPServer::RTSPClientSession::RTSPClientSession | ( | RTSPServer & | ourServer, | |
| unsigned | sessionId, | |||
| int | clientSocket, | |||
| struct sockaddr_in | clientAddr | |||
| ) |
Definition at line 285 of file RTSPServer.cpp.
References envir(), fClientInputSocket, incomingRequestHandler(), noteLiveness(), resetRequestBuffer(), UsageEnvironment::taskScheduler(), and TaskScheduler::turnOnBackgroundReadHandling().
00286 : fOurServer(ourServer), fOurSessionId(sessionId), 00287 fOurServerMediaSession(NULL), 00288 fClientInputSocket(clientSocket), fClientOutputSocket(clientSocket), fClientAddr(clientAddr), 00289 fSessionCookie(NULL), fLivenessCheckTask(NULL), 00290 fIsMulticast(False), fSessionIsActive(True), fStreamAfterSETUP(False), 00291 fTCPStreamIdCount(0), fNumStreamStates(0), fStreamStates(NULL), fRecursionCount(0) { 00292 // Arrange to handle incoming requests: 00293 resetRequestBuffer(); 00294 envir().taskScheduler().turnOnBackgroundReadHandling(fClientInputSocket, 00295 (TaskScheduler::BackgroundHandlerProc*)&incomingRequestHandler, this); 00296 noteLiveness(); 00297 }
| RTSPServer::RTSPClientSession::~RTSPClientSession | ( | ) | [virtual] |
Definition at line 299 of file RTSPServer.cpp.
References closeSockets(), ServerMediaSession::decrementReferenceCount(), ServerMediaSession::deleteWhenUnreferenced(), RTSPServer::fClientSessionsForHTTPTunneling, fOurServer, fOurServerMediaSession, fSessionCookie, NULL, reclaimStreamStates(), ServerMediaSession::referenceCount(), HashTable::Remove(), and RTSPServer::removeServerMediaSession().
00299 { 00300 closeSockets(); 00301 00302 if (fSessionCookie != NULL) { 00303 // We were being used for RTSP-over-HTTP tunneling. Remove ourselves from the 'session cookie' hash table before we go: 00304 fOurServer.fClientSessionsForHTTPTunneling->Remove(fSessionCookie); 00305 delete[] fSessionCookie; 00306 } 00307 00308 reclaimStreamStates(); 00309 00310 if (fOurServerMediaSession != NULL) { 00311 fOurServerMediaSession->decrementReferenceCount(); 00312 if (fOurServerMediaSession->referenceCount() == 0 00313 && fOurServerMediaSession->deleteWhenUnreferenced()) { 00314 fOurServer.removeServerMediaSession(fOurServerMediaSession); 00315 fOurServerMediaSession = NULL; 00316 } 00317 } 00318 }
| void RTSPServer::RTSPClientSession::handleCmd_bad | ( | char const * | cseq | ) | [protected, virtual] |
Definition at line 559 of file RTSPServer.cpp.
References allowedCommandNames, dateHeader(), and fResponseBuffer.
Referenced by handleRequestBytes().
00559 { 00560 // Don't do anything with "cseq", because it might be nonsense 00561 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00562 "RTSP/1.0 400 Bad Request\r\n%sAllow: %s\r\n\r\n", 00563 dateHeader(), allowedCommandNames); 00564 }
| void RTSPServer::RTSPClientSession::handleCmd_notSupported | ( | char const * | cseq | ) | [protected, virtual] |
Definition at line 566 of file RTSPServer.cpp.
References allowedCommandNames, dateHeader(), and fResponseBuffer.
Referenced by handleRequestBytes().
00566 { 00567 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00568 "RTSP/1.0 405 Method Not Allowed\r\nCSeq: %s\r\n%sAllow: %s\r\n\r\n", 00569 cseq, dateHeader(), allowedCommandNames); 00570 }
| void RTSPServer::RTSPClientSession::handleCmd_notFound | ( | char const * | cseq | ) | [protected, virtual] |
Definition at line 572 of file RTSPServer.cpp.
References dateHeader(), False, fResponseBuffer, and fSessionIsActive.
00572 { 00573 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00574 "RTSP/1.0 404 Stream Not Found\r\nCSeq: %s\r\n%s\r\n", 00575 cseq, dateHeader()); 00576 fSessionIsActive = False; // triggers deletion of ourself after responding 00577 }
| void RTSPServer::RTSPClientSession::handleCmd_unsupportedTransport | ( | char const * | cseq | ) | [protected, virtual] |
Definition at line 579 of file RTSPServer.cpp.
References dateHeader(), False, fResponseBuffer, and fSessionIsActive.
00579 { 00580 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00581 "RTSP/1.0 461 Unsupported Transport\r\nCSeq: %s\r\n%s\r\n", 00582 cseq, dateHeader()); 00583 fSessionIsActive = False; // triggers deletion of ourself after responding 00584 }
| void RTSPServer::RTSPClientSession::handleCmd_OPTIONS | ( | char const * | cseq | ) | [protected, virtual] |
Definition at line 586 of file RTSPServer.cpp.
References allowedCommandNames, dateHeader(), and fResponseBuffer.
Referenced by handleRequestBytes().
00586 { 00587 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00588 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sPublic: %s\r\n\r\n", 00589 cseq, dateHeader(), allowedCommandNames); 00590 }
| void RTSPServer::RTSPClientSession::handleCmd_DESCRIBE | ( | char const * | cseq, | |
| char const * | urlPreSuffix, | |||
| char const * | urlSuffix, | |||
| char const * | fullRequestStr | |||
| ) | [protected, virtual] |
Definition at line 593 of file RTSPServer.cpp.
References dateHeader(), NULL, RTSP_PARAM_STRING_MAX, RTSPServer::rtspURL(), and session.
Referenced by handleRequestBytes().
00595 { 00596 char* sdpDescription = NULL; 00597 char* rtspURL = NULL; 00598 do { 00599 char urlTotalSuffix[RTSP_PARAM_STRING_MAX]; 00600 if (strlen(urlPreSuffix) + strlen(urlSuffix) + 2 > sizeof urlTotalSuffix) { 00601 handleCmd_bad(cseq); 00602 break; 00603 } 00604 urlTotalSuffix[0] = '\0'; 00605 if (urlPreSuffix[0] != '\0') { 00606 strcat(urlTotalSuffix, urlPreSuffix); 00607 strcat(urlTotalSuffix, "/"); 00608 } 00609 strcat(urlTotalSuffix, urlSuffix); 00610 00611 if (!authenticationOK("DESCRIBE", cseq, urlTotalSuffix, fullRequestStr)) break; 00612 00613 // We should really check that the request contains an "Accept:" ##### 00614 // for "application/sdp", because that's what we're sending back ##### 00615 00616 // Begin by looking up the "ServerMediaSession" object for the specified "urlTotalSuffix": 00617 ServerMediaSession* session = fOurServer.lookupServerMediaSession(urlTotalSuffix); 00618 if (session == NULL) { 00619 handleCmd_notFound(cseq); 00620 break; 00621 } 00622 00623 // Then, assemble a SDP description for this session: 00624 sdpDescription = session->generateSDPDescription(); 00625 if (sdpDescription == NULL) { 00626 // This usually means that a file name that was specified for a 00627 // "ServerMediaSubsession" does not exist. 00628 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00629 "RTSP/1.0 404 File Not Found, Or In Incorrect Format\r\n" 00630 "CSeq: %s\r\n" 00631 "%s\r\n", 00632 cseq, 00633 dateHeader()); 00634 break; 00635 } 00636 unsigned sdpDescriptionSize = strlen(sdpDescription); 00637 00638 // Also, generate our RTSP URL, for the "Content-Base:" header 00639 // (which is necessary to ensure that the correct URL gets used in 00640 // subsequent "SETUP" requests). 00641 rtspURL = fOurServer.rtspURL(session, fClientInputSocket); 00642 00643 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00644 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n" 00645 "%s" 00646 "Content-Base: %s/\r\n" 00647 "Content-Type: application/sdp\r\n" 00648 "Content-Length: %d\r\n\r\n" 00649 "%s", 00650 cseq, 00651 dateHeader(), 00652 rtspURL, 00653 sdpDescriptionSize, 00654 sdpDescription); 00655 } while (0); 00656 00657 delete[] sdpDescription; 00658 delete[] rtspURL; 00659 }
| void RTSPServer::RTSPClientSession::handleCmd_SETUP | ( | char const * | cseq, | |
| char const * | urlPreSuffix, | |||
| char const * | urlSuffix, | |||
| char const * | fullRequestStr | |||
| ) | [protected, virtual] |
Definition at line 741 of file RTSPServer.cpp.
References dateHeader(), handleCmd_withinSession(), iter, MediaSubsessionIterator::next(), NULL, Port::num(), our_inet_addr(), parsePlayNowHeader(), parseRangeHeader(), parseTransportHeader(), RAW_UDP, ReceivingInterfaceAddr, MediaSubsessionIterator::reset(), RTP_TCP, RTP_UDP, SendingInterfaceAddr, SOCKLEN_T, subsession, and AddressString::val().
Referenced by handleRequestBytes().
00743 { 00744 // Normally, "urlPreSuffix" should be the session (stream) name, and "urlSuffix" should be the subsession (track) name. 00745 // However (being "liberal in what we accept"), we also handle 'aggregate' SETUP requests (i.e., without a track name), 00746 // in the special case where we have only a single track. I.e., in this case, we also handle: 00747 // "urlPreSuffix" is empty and "urlSuffix" is the session (stream) name, or 00748 // "urlPreSuffix" concatenated with "urlSuffix" (with "/" inbetween) is the session (stream) name. 00749 char const* streamName = urlPreSuffix; // in the normal case 00750 char const* trackId = urlSuffix; // in the normal case 00751 char* concatenatedStreamName = NULL; // in the normal case 00752 00753 do { 00754 // First, make sure the specified stream name exists: 00755 fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName); 00756 if (fOurServerMediaSession == NULL) { 00757 // Check for the special case (noted above), before we up: 00758 if (urlPreSuffix[0] == '\0') { 00759 streamName = urlSuffix; 00760 } else { 00761 concatenatedStreamName = new char[strlen(urlPreSuffix) + strlen(urlSuffix) + 2]; // allow for the "/" and the trailing '\0' 00762 sprintf(concatenatedStreamName, "%s/%s", urlPreSuffix, urlSuffix); 00763 streamName = concatenatedStreamName; 00764 } 00765 trackId = NULL; 00766 00767 // Check again: 00768 fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName); 00769 } 00770 if (fOurServerMediaSession == NULL) { 00771 handleCmd_notFound(cseq); 00772 break; 00773 } 00774 00775 fOurServerMediaSession->incrementReferenceCount(); 00776 00777 if (fStreamStates == NULL) { 00778 // This is the first "SETUP" for this session. Set up our array of states for all of this session's subsessions (tracks): 00779 ServerMediaSubsessionIterator iter(*fOurServerMediaSession); 00780 for (fNumStreamStates = 0; iter.next() != NULL; ++fNumStreamStates) {} // begin by counting the number of subsessions (tracks) 00781 00782 fStreamStates = new struct streamState[fNumStreamStates]; 00783 00784 iter.reset(); 00785 ServerMediaSubsession* subsession; 00786 for (unsigned i = 0; i < fNumStreamStates; ++i) { 00787 subsession = iter.next(); 00788 fStreamStates[i].subsession = subsession; 00789 fStreamStates[i].streamToken = NULL; // for now; it may be changed by the "getStreamParameters()" call that comes later 00790 } 00791 } 00792 00793 // Look up information for the specified subsession (track): 00794 ServerMediaSubsession* subsession = NULL; 00795 unsigned streamNum; 00796 if (trackId != NULL && trackId[0] != '\0') { // normal case 00797 for (streamNum = 0; streamNum < fNumStreamStates; ++streamNum) { 00798 subsession = fStreamStates[streamNum].subsession; 00799 if (subsession != NULL && strcmp(trackId, subsession->trackId()) == 0) break; 00800 } 00801 if (streamNum >= fNumStreamStates) { 00802 // The specified track id doesn't exist, so this request fails: 00803 handleCmd_notFound(cseq); 00804 break; 00805 } 00806 } else { 00807 // Weird case: there was no track id in the URL. 00808 // This works only if we have only one subsession: 00809 if (fNumStreamStates != 1) { 00810 handleCmd_bad(cseq); 00811 break; 00812 } 00813 streamNum = 0; 00814 subsession = fStreamStates[streamNum].subsession; 00815 } 00816 // ASSERT: subsession != NULL 00817 00818 // Look for a "Transport:" header in the request string, to extract client parameters: 00819 StreamingMode streamingMode; 00820 char* streamingModeString = NULL; // set when RAW_UDP streaming is specified 00821 char* clientsDestinationAddressStr; 00822 u_int8_t clientsDestinationTTL; 00823 portNumBits clientRTPPortNum, clientRTCPPortNum; 00824 unsigned char rtpChannelId, rtcpChannelId; 00825 parseTransportHeader(fullRequestStr, streamingMode, streamingModeString, 00826 clientsDestinationAddressStr, clientsDestinationTTL, 00827 clientRTPPortNum, clientRTCPPortNum, 00828 rtpChannelId, rtcpChannelId); 00829 if (streamingMode == RTP_TCP && rtpChannelId == 0xFF || 00830 streamingMode != RTP_TCP && fClientOutputSocket != fClientInputSocket) { 00831 // An anomolous situation, caused by a buggy client. Either: 00832 // 1/ TCP streaming was requested, but with no "interleaving=" fields. (QuickTime Player sometimes does this.), or 00833 // 2/ TCP streaming was not requested, but we're doing RTSP-over-HTTP tunneling (which implies TCP streaming). 00834 // In either case, we assume TCP streaming, and set the RTP and RTCP channel ids to proper values: 00835 streamingMode = RTP_TCP; 00836 rtpChannelId = fTCPStreamIdCount; rtcpChannelId = fTCPStreamIdCount+1; 00837 } 00838 fTCPStreamIdCount += 2; 00839 00840 Port clientRTPPort(clientRTPPortNum); 00841 Port clientRTCPPort(clientRTCPPortNum); 00842 00843 // Next, check whether a "Range:" header is present in the request. 00844 // This isn't legal, but some clients do this to combine "SETUP" and "PLAY": 00845 double rangeStart = 0.0, rangeEnd = 0.0; 00846 fStreamAfterSETUP = parseRangeHeader(fullRequestStr, rangeStart, rangeEnd) || parsePlayNowHeader(fullRequestStr); 00847 00848 // Then, get server parameters from the 'subsession': 00849 int tcpSocketNum = streamingMode == RTP_TCP ? fClientOutputSocket : -1; 00850 netAddressBits destinationAddress = 0; 00851 u_int8_t destinationTTL = 255; 00852 #ifdef RTSP_ALLOW_CLIENT_DESTINATION_SETTING 00853 if (clientsDestinationAddressStr != NULL) { 00854 // Use the client-provided "destination" address. 00855 // Note: This potentially allows the server to be used in denial-of-service 00856 // attacks, so don't enable this code unless you're sure that clients are 00857 // trusted. 00858 destinationAddress = our_inet_addr(clientsDestinationAddressStr); 00859 } 00860 // Also use the client-provided TTL. 00861 destinationTTL = clientsDestinationTTL; 00862 #endif 00863 delete[] clientsDestinationAddressStr; 00864 Port serverRTPPort(0); 00865 Port serverRTCPPort(0); 00866 00867 // Make sure that we transmit on the same interface that's used by the client (in case we're a multi-homed server): 00868 struct sockaddr_in sourceAddr; SOCKLEN_T namelen = sizeof sourceAddr; 00869 getsockname(fClientInputSocket, (struct sockaddr*)&sourceAddr, &namelen); 00870 netAddressBits origSendingInterfaceAddr = SendingInterfaceAddr; 00871 netAddressBits origReceivingInterfaceAddr = ReceivingInterfaceAddr; 00872 // NOTE: The following might not work properly, so we ifdef it out for now: 00873 #ifdef HACK_FOR_MULTIHOMED_SERVERS 00874 ReceivingInterfaceAddr = SendingInterfaceAddr = sourceAddr.sin_addr.s_addr; 00875 #endif 00876 00877 subsession->getStreamParameters(fOurSessionId, fClientAddr.sin_addr.s_addr, 00878 clientRTPPort, clientRTCPPort, 00879 tcpSocketNum, rtpChannelId, rtcpChannelId, 00880 destinationAddress, destinationTTL, fIsMulticast, 00881 serverRTPPort, serverRTCPPort, 00882 fStreamStates[streamNum].streamToken); 00883 SendingInterfaceAddr = origSendingInterfaceAddr; 00884 ReceivingInterfaceAddr = origReceivingInterfaceAddr; 00885 00886 AddressString destAddrStr(destinationAddress); 00887 AddressString sourceAddrStr(sourceAddr); 00888 if (fIsMulticast) { 00889 switch (streamingMode) { 00890 case RTP_UDP: 00891 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00892 "RTSP/1.0 200 OK\r\n" 00893 "CSeq: %s\r\n" 00894 "%s" 00895 "Transport: RTP/AVP;multicast;destination=%s;source=%s;port=%d-%d;ttl=%d\r\n" 00896 "Session: %08X\r\n\r\n", 00897 cseq, 00898 dateHeader(), 00899 destAddrStr.val(), sourceAddrStr.val(), ntohs(serverRTPPort.num()), ntohs(serverRTCPPort.num()), destinationTTL, 00900 fOurSessionId); 00901 break; 00902 case RTP_TCP: 00903 // multicast streams can't be sent via TCP 00904 handleCmd_unsupportedTransport(cseq); 00905 break; 00906 case RAW_UDP: 00907 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00908 "RTSP/1.0 200 OK\r\n" 00909 "CSeq: %s\r\n" 00910 "%s" 00911 "Transport: %s;multicast;destination=%s;source=%s;port=%d;ttl=%d\r\n" 00912 "Session: %08X\r\n\r\n", 00913 cseq, 00914 dateHeader(), 00915 streamingModeString, destAddrStr.val(), sourceAddrStr.val(), ntohs(serverRTPPort.num()), destinationTTL, 00916 fOurSessionId); 00917 break; 00918 } 00919 } else { 00920 switch (streamingMode) { 00921 case RTP_UDP: { 00922 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00923 "RTSP/1.0 200 OK\r\n" 00924 "CSeq: %s\r\n" 00925 "%s" 00926 "Transport: RTP/AVP;unicast;destination=%s;source=%s;client_port=%d-%d;server_port=%d-%d\r\n" 00927 "Session: %08X\r\n\r\n", 00928 cseq, 00929 dateHeader(), 00930 destAddrStr.val(), sourceAddrStr.val(), ntohs(clientRTPPort.num()), ntohs(clientRTCPPort.num()), ntohs(serverRTPPort.num()), ntohs(serverRTCPPort.num()), 00931 fOurSessionId); 00932 break; 00933 } 00934 case RTP_TCP: { 00935 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00936 "RTSP/1.0 200 OK\r\n" 00937 "CSeq: %s\r\n" 00938 "%s" 00939 "Transport: RTP/AVP/TCP;unicast;destination=%s;source=%s;interleaved=%d-%d\r\n" 00940 "Session: %08X\r\n\r\n", 00941 cseq, 00942 dateHeader(), 00943 destAddrStr.val(), sourceAddrStr.val(), rtpChannelId, rtcpChannelId, 00944 fOurSessionId); 00945 break; 00946 } 00947 case RAW_UDP: { 00948 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 00949 "RTSP/1.0 200 OK\r\n" 00950 "CSeq: %s\r\n" 00951 "%s" 00952 "Transport: %s;unicast;destination=%s;source=%s;client_port=%d;server_port=%d\r\n" 00953 "Session: %08X\r\n\r\n", 00954 cseq, 00955 dateHeader(), 00956 streamingModeString, destAddrStr.val(), sourceAddrStr.val(), ntohs(clientRTPPort.num()), ntohs(serverRTPPort.num()), 00957 fOurSessionId); 00958 break; 00959 } 00960 } 00961 } 00962 delete[] streamingModeString; 00963 } while (0); 00964 00965 delete[] concatenatedStreamName; 00966 }
| void RTSPServer::RTSPClientSession::handleCmd_withinSession | ( | char const * | cmdName, | |
| char const * | urlPreSuffix, | |||
| char const * | urlSuffix, | |||
| char const * | cseq, | |||
| char const * | fullRequestStr | |||
| ) | [protected, virtual] |
Definition at line 969 of file RTSPServer.cpp.
References iter, MediaSubsessionIterator::next(), NULL, and subsession.
Referenced by handleCmd_SETUP(), and handleRequestBytes().
00971 { 00972 // This will either be: 00973 // - an operation on the entire server, if "urlPreSuffix" is "", and "urlSuffix" is "*" (i.e., the special "*" URL), or 00974 // - a non-aggregated operation, if "urlPreSuffix" is the session (stream) 00975 // name and "urlSuffix" is the subsession (track) name, or 00976 // - an aggregated operation, if "urlSuffix" is the session (stream) name, 00977 // or "urlPreSuffix" is the session (stream) name, and "urlSuffix" is empty, 00978 // or "urlPreSuffix" and "urlSuffix" are both nonempty, but when concatenated, (with "/") form the session (stream) name. 00979 // Begin by figuring out which of these it is: 00980 ServerMediaSubsession* subsession; 00981 if (urlPreSuffix[0] == '\0' && urlSuffix[0] == '*' && urlSuffix[1] == '\0') { 00982 // An operation on the entire server. This works only for GET_PARAMETER and SET_PARAMETER: 00983 if (strcmp(cmdName, "GET_PARAMETER") == 0) { 00984 handleCmd_GET_PARAMETER(NULL, cseq, fullRequestStr); 00985 } else if (strcmp(cmdName, "SET_PARAMETER") == 0) { 00986 handleCmd_SET_PARAMETER(NULL, cseq, fullRequestStr); 00987 } else { 00988 handleCmd_notSupported(cseq); 00989 } 00990 return; 00991 } else if (fOurServerMediaSession == NULL) { // There wasn't a previous SETUP! 00992 handleCmd_notSupported(cseq); 00993 return; 00994 } else if (urlSuffix[0] != '\0' && strcmp(fOurServerMediaSession->streamName(), urlPreSuffix) == 0) { 00995 // Non-aggregated operation. 00996 // Look up the media subsession whose track id is "urlSuffix": 00997 ServerMediaSubsessionIterator iter(*fOurServerMediaSession); 00998 while ((subsession = iter.next()) != NULL) { 00999 if (strcmp(subsession->trackId(), urlSuffix) == 0) break; // success 01000 } 01001 if (subsession == NULL) { // no such track! 01002 handleCmd_notFound(cseq); 01003 return; 01004 } 01005 } else if (strcmp(fOurServerMediaSession->streamName(), urlSuffix) == 0 || 01006 (urlSuffix[0] == '\0' && strcmp(fOurServerMediaSession->streamName(), urlPreSuffix) == 0)) { 01007 // Aggregated operation 01008 subsession = NULL; 01009 } else if (urlPreSuffix[0] != '\0' && urlSuffix[0] != '\0') { 01010 // Aggregated operation, if <urlPreSuffix>/<urlSuffix> is the session (stream) name: 01011 unsigned const urlPreSuffixLen = strlen(urlPreSuffix); 01012 if (strncmp(fOurServerMediaSession->streamName(), urlPreSuffix, urlPreSuffixLen) == 0 && 01013 fOurServerMediaSession->streamName()[urlPreSuffixLen] == '/' && 01014 strcmp(&(fOurServerMediaSession->streamName())[urlPreSuffixLen+1], urlSuffix) == 0) { 01015 subsession = NULL; 01016 } else { 01017 handleCmd_notFound(cseq); 01018 return; 01019 } 01020 } else { // the request doesn't match a known stream and/or track at all! 01021 handleCmd_notFound(cseq); 01022 return; 01023 } 01024 01025 if (strcmp(cmdName, "TEARDOWN") == 0) { 01026 handleCmd_TEARDOWN(subsession, cseq); 01027 } else if (strcmp(cmdName, "PLAY") == 0) { 01028 handleCmd_PLAY(subsession, cseq, fullRequestStr); 01029 } else if (strcmp(cmdName, "PAUSE") == 0) { 01030 handleCmd_PAUSE(subsession, cseq); 01031 } else if (strcmp(cmdName, "GET_PARAMETER") == 0) { 01032 handleCmd_GET_PARAMETER(subsession, cseq, fullRequestStr); 01033 } else if (strcmp(cmdName, "SET_PARAMETER") == 0) { 01034 handleCmd_SET_PARAMETER(subsession, cseq, fullRequestStr); 01035 } 01036 }
| void RTSPServer::RTSPClientSession::handleCmd_TEARDOWN | ( | ServerMediaSubsession * | subsession, | |
| char const * | cseq | |||
| ) | [protected, virtual] |
Definition at line 1039 of file RTSPServer.cpp.
References dateHeader(), and False.
01039 { 01040 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 01041 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%s\r\n", 01042 cseq, dateHeader()); 01043 fSessionIsActive = False; // triggers deletion of ourself after responding 01044 }
| void RTSPServer::RTSPClientSession::handleCmd_PLAY | ( | ServerMediaSubsession * | subsession, | |
| char const * | cseq, | |||
| char const * | fullRequestStr | |||
| ) | [protected, virtual] |
Definition at line 1071 of file RTSPServer.cpp.
References dateHeader(), duration, NULL, parseRangeHeader(), parseScaleHeader(), RTSPServer::rtspURL(), scale, strDup(), and subsession.
01072 { 01073 char* rtspURL = fOurServer.rtspURL(fOurServerMediaSession, fClientInputSocket); 01074 unsigned rtspURLSize = strlen(rtspURL); 01075 01076 // Parse the client's "Scale:" header, if any: 01077 float scale; 01078 Boolean sawScaleHeader = parseScaleHeader(fullRequestStr, scale); 01079 01080 // Try to set the stream's scale factor to this value: 01081 if (subsession == NULL /*aggregate op*/) { 01082 fOurServerMediaSession->testScaleFactor(scale); 01083 } else { 01084 subsession->testScaleFactor(scale); 01085 } 01086 01087 char buf[100]; 01088 char* scaleHeader; 01089 if (!sawScaleHeader) { 01090 buf[0] = '\0'; // Because we didn't see a Scale: header, don't send one back 01091 } else { 01092 sprintf(buf, "Scale: %f\r\n", scale); 01093 } 01094 scaleHeader = strDup(buf); 01095 01096 // Parse the client's "Range:" header, if any: 01097 double rangeStart = 0.0, rangeEnd = 0.0; 01098 Boolean sawRangeHeader = parseRangeHeader(fullRequestStr, rangeStart, rangeEnd); 01099 01100 // Use this information, plus the stream's duration (if known), to create 01101 // our own "Range:" header, for the response: 01102 float duration = subsession == NULL /*aggregate op*/ 01103 ? fOurServerMediaSession->duration() : subsession->duration(); 01104 if (duration < 0.0) { 01105 // We're an aggregate PLAY, but the subsessions have different durations. 01106 // Use the largest of these durations in our header 01107 duration = -duration; 01108 } 01109 01110 // Make sure that "rangeStart" and "rangeEnd" (from the client's "Range:" header) have sane values 01111 // before we send back our own "Range:" header in our response: 01112 if (rangeStart < 0.0) rangeStart = 0.0; 01113 else if (rangeStart > duration) rangeStart = duration; 01114 if (rangeEnd < 0.0) rangeEnd = 0.0; 01115 else if (rangeEnd > duration) rangeEnd = duration; 01116 if ((scale > 0.0 && rangeStart > rangeEnd && rangeEnd > 0.0) || 01117 (scale < 0.0 && rangeStart < rangeEnd)) { 01118 // "rangeStart" and "rangeEnd" were the wrong way around; swap them: 01119 double tmp = rangeStart; 01120 rangeStart = rangeEnd; 01121 rangeEnd = tmp; 01122 } 01123 01124 // Create a "RTP-Info:" line. It will get filled in from each subsession's state: 01125 char const* rtpInfoFmt = 01126 "%s" // "RTP-Info:", plus any preceding rtpInfo items 01127 "%s" // comma separator, if needed 01128 "url=%s/%s" 01129 ";seq=%d" 01130 ";rtptime=%u" 01131 ; 01132 unsigned rtpInfoFmtSize = strlen(rtpInfoFmt); 01133 char* rtpInfo = strDup("RTP-Info: "); 01134 unsigned i, numRTPInfoItems = 0; 01135 01136 // Do any required seeking/scaling on each subsession, before starting streaming: 01137 for (i = 0; i < fNumStreamStates; ++i) { 01138 if (subsession == NULL /* means: aggregated operation */ 01139 || subsession == fStreamStates[i].subsession) { 01140 if (sawScaleHeader) { 01141 fStreamStates[i].subsession->setStreamScale(fOurSessionId, 01142 fStreamStates[i].streamToken, 01143 scale); 01144 } 01145 if (sawRangeHeader) { 01146 double streamDuration = 0.0; // by default; means: stream until the end of the media 01147 if (rangeEnd > 0.0 && (rangeEnd+0.001) < duration) { // the 0.001 is because we limited the values to 3 decimal places 01148 // We want the stream to end early. Set the duration we want: 01149 streamDuration = rangeEnd - rangeStart; 01150 if (streamDuration < 0.0) streamDuration = -streamDuration; // should happen only if scale < 0.0 01151 } 01152 u_int64_t numBytes; 01153 fStreamStates[i].subsession->seekStream(fOurSessionId, 01154 fStreamStates[i].streamToken, 01155 rangeStart, streamDuration, numBytes); 01156 } 01157 } 01158 } 01159 01160 // Create the "Range:" header that we'll send back in our response. 01161 // (Note that we do this after seeking, in case the seeking operation changed the range start time.) 01162 char* rangeHeader; 01163 if (!sawRangeHeader) { 01164 buf[0] = '\0'; // Because we didn't see a Range: header, don't send one back 01165 } else if (rangeEnd == 0.0 && scale >= 0.0) { 01166 sprintf(buf, "Range: npt=%.3f-\r\n", rangeStart); 01167 } else { 01168 sprintf(buf, "Range: npt=%.3f-%.3f\r\n", rangeStart, rangeEnd); 01169 } 01170 rangeHeader = strDup(buf); 01171 01172 // Now, start streaming: 01173 for (i = 0; i < fNumStreamStates; ++i) { 01174 if (subsession == NULL /* means: aggregated operation */ 01175 || subsession == fStreamStates[i].subsession) { 01176 unsigned short rtpSeqNum = 0; 01177 unsigned rtpTimestamp = 0; 01178 fStreamStates[i].subsession->startStream(fOurSessionId, 01179 fStreamStates[i].streamToken, 01180 (TaskFunc*)noteClientLiveness, this, 01181 rtpSeqNum, rtpTimestamp, 01182 handleAlternativeRequestByte, this); 01183 const char *urlSuffix = fStreamStates[i].subsession->trackId(); 01184 char* prevRTPInfo = rtpInfo; 01185 unsigned rtpInfoSize = rtpInfoFmtSize 01186 + strlen(prevRTPInfo) 01187 + 1 01188 + rtspURLSize + strlen(urlSuffix) 01189 + 5 /*max unsigned short len*/ 01190 + 10 /*max unsigned (32-bit) len*/ 01191 + 2 /*allows for trailing \r\n at final end of string*/; 01192 rtpInfo = new char[rtpInfoSize]; 01193 sprintf(rtpInfo, rtpInfoFmt, 01194 prevRTPInfo, 01195 numRTPInfoItems++ == 0 ? "" : ",", 01196 rtspURL, urlSuffix, 01197 rtpSeqNum, 01198 rtpTimestamp 01199 ); 01200 delete[] prevRTPInfo; 01201 } 01202 } 01203 if (numRTPInfoItems == 0) { 01204 rtpInfo[0] = '\0'; 01205 } else { 01206 unsigned rtpInfoLen = strlen(rtpInfo); 01207 rtpInfo[rtpInfoLen] = '\r'; 01208 rtpInfo[rtpInfoLen+1] = '\n'; 01209 rtpInfo[rtpInfoLen+2] = '\0'; 01210 } 01211 01212 // Fill in the response: 01213 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 01214 "RTSP/1.0 200 OK\r\n" 01215 "CSeq: %s\r\n" 01216 "%s" 01217 "%s" 01218 "%s" 01219 "Session: %08X\r\n" 01220 "%s\r\n", 01221 cseq, 01222 dateHeader(), 01223 scaleHeader, 01224 rangeHeader, 01225 fOurSessionId, 01226 rtpInfo); 01227 delete[] rtpInfo; delete[] rangeHeader; 01228 delete[] scaleHeader; delete[] rtspURL; 01229 }
| void RTSPServer::RTSPClientSession::handleCmd_PAUSE | ( | ServerMediaSubsession * | subsession, | |
| char const * | cseq | |||
| ) | [protected, virtual] |
Definition at line 1232 of file RTSPServer.cpp.
References dateHeader(), NULL, and subsession.
01232 { 01233 for (unsigned i = 0; i < fNumStreamStates; ++i) { 01234 if (subsession == NULL /* means: aggregated operation */ 01235 || subsession == fStreamStates[i].subsession) { 01236 fStreamStates[i].subsession->pauseStream(fOurSessionId, 01237 fStreamStates[i].streamToken); 01238 } 01239 } 01240 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 01241 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sSession: %08X\r\n\r\n", 01242 cseq, dateHeader(), fOurSessionId); 01243 }
| void RTSPServer::RTSPClientSession::handleCmd_GET_PARAMETER | ( | ServerMediaSubsession * | subsession, | |
| char const * | cseq, | |||
| char const * | fullRequestStr | |||
| ) | [protected, virtual] |
Definition at line 1246 of file RTSPServer.cpp.
References dateHeader().
01247 { 01248 // By default, we implement "GET_PARAMETER" just as a 'keep alive', and send back an empty response. 01249 // (If you want to handle "GET_PARAMETER" properly, you can do so by defining a subclass of "RTSPServer" 01250 // and "RTSPServer::RTSPClientSession", and then reimplement this virtual function in your subclass.) 01251 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 01252 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sSession: %08X\r\n\r\n", 01253 cseq, dateHeader(), fOurSessionId); 01254 }
| void RTSPServer::RTSPClientSession::handleCmd_SET_PARAMETER | ( | ServerMediaSubsession * | subsession, | |
| char const * | cseq, | |||
| char const * | fullRequestStr | |||
| ) | [protected, virtual] |
Definition at line 1257 of file RTSPServer.cpp.
References dateHeader().
01258 { 01259 // By default, we implement "SET_PARAMETER" just as a 'keep alive', and send back an empty response. 01260 // (If you want to handle "SET_PARAMETER" properly, you can do so by defining a subclass of "RTSPServer" 01261 // and "RTSPServer::RTSPClientSession", and then reimplement this virtual function in your subclass.) 01262 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 01263 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sSession: %08X\r\n\r\n", 01264 cseq, dateHeader(), fOurSessionId); 01265 }
| Boolean RTSPServer::RTSPClientSession::parseHTTPRequestString | ( | char * | resultCmdName, | |
| unsigned | resultCmdNameMaxSize, | |||
| char * | urlSuffix, | |||
| unsigned | urlSuffixMaxSize, | |||
| char * | sessionCookie, | |||
| unsigned | sessionCookieMaxSize, | |||
| char * | acceptStr, | |||
| unsigned | acceptStrMaxSize | |||
| ) | [protected, virtual] |
Definition at line 1289 of file RTSPServer.cpp.
References False, fRequestBuffer, fRequestBytesAlreadySeen, lookForHeader(), and True.
Referenced by handleRequestBytes().
01292 { 01293 // Check for the limited HTTP requests that we expect for specifying RTSP-over-HTTP tunneling. 01294 // This parser is currently rather dumb; it should be made smarter ##### 01295 char const* reqStr = (char const*)fRequestBuffer; 01296 unsigned const reqStrSize = fRequestBytesAlreadySeen; 01297 01298 // Read everything up to the first space as the command name: 01299 Boolean parseSucceeded = False; 01300 unsigned i; 01301 for (i = 0; i < resultCmdNameMaxSize-1 && i < reqStrSize; ++i) { 01302 char c = reqStr[i]; 01303 if (c == ' ' || c == '\t') { 01304 parseSucceeded = True; 01305 break; 01306 } 01307 01308 resultCmdName[i] = c; 01309 } 01310 resultCmdName[i] = '\0'; 01311 if (!parseSucceeded) return False; 01312 01313 // Look for the string "HTTP/", before the first \r or \n: 01314 parseSucceeded = False; 01315 for (; i < reqStrSize-5 && reqStr[i] != '\r' && reqStr[i] != '\n'; ++i) { 01316 if (reqStr[i] == 'H' && reqStr[i+1] == 'T' && reqStr[i+2]== 'T' && reqStr[i+3]== 'P' && reqStr[i+4]== '/') { 01317 i += 5; // to advance past the "HTTP/" 01318 parseSucceeded = True; 01319 break; 01320 } 01321 } 01322 if (!parseSucceeded) return False; 01323 01324 // Get the 'URL suffix' that occurred before this: 01325 unsigned k = i-6; 01326 while (k > 0 && reqStr[k] == ' ') --k; // back up over white space 01327 unsigned j = k; 01328 while (j > 0 && reqStr[j] != ' ' && reqStr[j] != '/') --j; 01329 // The URL suffix is in position (j,k]: 01330 if (k - j + 1 > urlSuffixMaxSize) return False; // there's no room> 01331 unsigned n = 0; 01332 while (++j <= k) urlSuffix[n++] = reqStr[j]; 01333 urlSuffix[n] = '\0'; 01334 01335 // Look for various headers that we're interested in: 01336 lookForHeader("x-sessioncookie", &reqStr[i], reqStrSize-i, sessionCookie, sessionCookieMaxSize); 01337 lookForHeader("Accept", &reqStr[i], reqStrSize-i, acceptStr, acceptStrMaxSize); 01338 01339 return True; 01340 }
| void RTSPServer::RTSPClientSession::handleHTTPCmd_notSupported | ( | ) | [protected, virtual] |
Definition at line 1342 of file RTSPServer.cpp.
References dateHeader(), and fResponseBuffer.
Referenced by handleHTTPCmd_StreamingGET(), and handleRequestBytes().
01342 { 01343 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 01344 "HTTP/1.0 405 Method Not Allowed\r\n%s\r\n\r\n", 01345 dateHeader()); 01346 }
| void RTSPServer::RTSPClientSession::handleHTTPCmd_notFound | ( | ) | [protected, virtual] |
Definition at line 1348 of file RTSPServer.cpp.
References dateHeader(), and fResponseBuffer.
01348 { 01349 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 01350 "HTTP/1.0 404 Not Found\r\n%s\r\n\r\n", 01351 dateHeader()); 01352 }
| void RTSPServer::RTSPClientSession::handleHTTPCmd_TunnelingGET | ( | char const * | sessionCookie | ) | [protected, virtual] |
Definition at line 1354 of file RTSPServer.cpp.
References HashTable::Add(), HashTable::create(), fClientOutputSocket, RTSPServer::fClientSessionsForHTTPTunneling, fOurServer, fResponseBuffer, NULL, and STRING_HASH_KEYS.
Referenced by handleRequestBytes().
01354 { 01355 // Record ourself as having this 'session cookie', so that a subsequent HTTP "POST" command (with the same 'session cookie') 01356 // can find us: 01357 if (fOurServer.fClientSessionsForHTTPTunneling == NULL) { 01358 fOurServer.fClientSessionsForHTTPTunneling = HashTable::create(STRING_HASH_KEYS); 01359 } 01360 fOurServer.fClientSessionsForHTTPTunneling->Add(sessionCookie, (void*)this); 01361 #ifdef DEBUG 01362 fprintf(stderr, "Handled HTTP \"GET\" request (client output socket: %d)\n", fClientOutputSocket); 01363 #endif 01364 01365 // Construct our response: 01366 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 01367 "HTTP/1.0 200 OK\r\n" 01368 "Date: Thu, 19 Aug 1982 18:30:00 GMT\r\n" 01369 "Cache-Control: no-cache\r\n" 01370 "Pragma: no-cache\r\n" 01371 "Content-Type: application/x-rtsp-tunnelled\r\n" 01372 "\r\n"); 01373 }
| Boolean RTSPServer::RTSPClientSession::handleHTTPCmd_TunnelingPOST | ( | char const * | sessionCookie, | |
| unsigned char const * | extraData, | |||
| unsigned | extraDataSize | |||
| ) | [protected, virtual] |
Definition at line 1376 of file RTSPServer.cpp.
References changeClientInputSocket(), False, NULL, and True.
Referenced by handleRequestBytes().
01376 { 01377 // Use the "sessionCookie" string to look up the separate "RTSPClientSession" object that should have been used to handle 01378 // an earlier HTTP "GET" request: 01379 RTSPServer::RTSPClientSession* prevClientSession 01380 = (RTSPServer::RTSPClientSession*)(fOurServer.fClientSessionsForHTTPTunneling->Lookup(sessionCookie)); 01381 if (prevClientSession == NULL) { 01382 // There was no previous HTTP "GET" request; treat this "POST" request as bad: 01383 handleHTTPCmd_notSupported(); 01384 fSessionIsActive = False; // triggers deletion of ourself 01385 return False; 01386 } 01387 #ifdef DEBUG 01388 fprintf(stderr, "Handled HTTP \"POST\" request (client input socket: %d)\n", fClientInputSocket); 01389 #endif 01390 01391 // Change the previous "RTSPClientSession" object's input socket to ours. It will be used for subsequent requests: 01392 prevClientSession->changeClientInputSocket(fClientInputSocket, extraData, extraDataSize); 01393 fClientInputSocket = fClientOutputSocket = -1; // so the socket doesn't get closed when we get deleted 01394 return True; 01395 }
| void RTSPServer::RTSPClientSession::handleHTTPCmd_StreamingGET | ( | char const * | urlSuffix, | |
| char const * | fullRequestStr | |||
| ) | [protected, virtual] |
Reimplemented in RTSPServerSupportingHTTPStreaming::RTSPClientSessionSupportingHTTPStreaming.
Definition at line 1397 of file RTSPServer.cpp.
References handleHTTPCmd_notSupported().
Referenced by handleRequestBytes().
01397 { 01398 // By default, we don't support requests to access streams via HTTP: 01399 handleHTTPCmd_notSupported(); 01400 }
| UsageEnvironment& RTSPServer::RTSPClientSession::envir | ( | ) | [inline, protected] |
Definition at line 166 of file RTSPServer.hh.
References Medium::envir(), and fOurServer.
Referenced by closeSockets(), incomingRequestHandler1(), noteLiveness(), and RTSPClientSession().
00166 { return fOurServer.envir(); }
| void RTSPServer::RTSPClientSession::closeSockets | ( | ) | [protected] |
Definition at line 320 of file RTSPServer.cpp.
References closeSocket, envir(), fClientInputSocket, fClientOutputSocket, fLivenessCheckTask, UsageEnvironment::taskScheduler(), TaskScheduler::turnOffBackgroundReadHandling(), and TaskScheduler::unscheduleDelayedTask().
Referenced by handleRequestBytes(), and ~RTSPClientSession().
00320 { 00321 // Turn off any liveness checking: 00322 envir().taskScheduler().unscheduleDelayedTask(fLivenessCheckTask); 00323 00324 // Turn off background read handling: 00325 envir().taskScheduler().turnOffBackgroundReadHandling(fClientInputSocket); 00326 00327 if (fClientOutputSocket != fClientInputSocket) ::closeSocket(fClientOutputSocket); 00328 ::closeSocket(fClientInputSocket); 00329 00330 fClientInputSocket = fClientOutputSocket = -1; 00331 }
| void RTSPServer::RTSPClientSession::reclaimStreamStates | ( | ) | [protected] |
Definition at line 333 of file RTSPServer.cpp.
References fNumStreamStates, fOurSessionId, fStreamStates, NULL, RTSPServer::RTSPClientSession::streamState::streamToken, and subsession.
Referenced by ~RTSPClientSession().
00333 { 00334 for (unsigned i = 0; i < fNumStreamStates; ++i) { 00335 if (fStreamStates[i].subsession != NULL) { 00336 fStreamStates[i].subsession->deleteStream(fOurSessionId, 00337 fStreamStates[i].streamToken); 00338 } 00339 } 00340 delete[] fStreamStates; fStreamStates = NULL; 00341 fNumStreamStates = 0; 00342 }
| void RTSPServer::RTSPClientSession::resetRequestBuffer | ( | ) | [protected] |
Definition at line 344 of file RTSPServer.cpp.
References fBase64RemainderCount, fLastCRLF, fRequestBuffer, fRequestBufferBytesLeft, and fRequestBytesAlreadySeen.
Referenced by handleRequestBytes(), and RTSPClientSession().
00344 { 00345 fRequestBytesAlreadySeen = 0; 00346 fRequestBufferBytesLeft = sizeof fRequestBuffer; 00347 fLastCRLF = &fRequestBuffer[-3]; // hack: Ensures that we don't think we have end-of-msg if the data starts with <CR><LF> 00348 fBase64RemainderCount = 0; 00349 }
| Boolean RTSPServer::RTSPClientSession::authenticationOK | ( | char const * | cmdName, | |
| char const * | cseq, | |||
| char const * | urlSuffix, | |||
| char const * | fullRequestStr | |||
| ) | [protected] |
Definition at line 1450 of file RTSPServer.cpp.
References dateHeader(), False, NULL, parseAuthorizationHeader(), password, True, and username.
01451 { 01452 01453 if (!fOurServer.specialClientAccessCheck(fClientInputSocket, fClientAddr, urlSuffix)) { 01454 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 01455 "RTSP/1.0 401 Unauthorized\r\n" 01456 "CSeq: %s\r\n" 01457 "%s" 01458 "\r\n", 01459 cseq, dateHeader()); 01460 return False; 01461 } 01462 01463 // If we weren't set up with an authentication database, we're OK: 01464 if (fOurServer.fAuthDB == NULL) return True; 01465 01466 char const* username = NULL; char const* realm = NULL; char const* nonce = NULL; 01467 char const* uri = NULL; char const* response = NULL; 01468 Boolean success = False; 01469 01470 do { 01471 // To authenticate, we first need to have a nonce set up 01472 // from a previous attempt: 01473 if (fCurrentAuthenticator.nonce() == NULL) break; 01474 01475 // Next, the request needs to contain an "Authorization:" header, 01476 // containing a username, (our) realm, (our) nonce, uri, 01477 // and response string: 01478 if (!parseAuthorizationHeader(fullRequestStr, 01479 username, realm, nonce, uri, response) 01480 || username == NULL 01481 || realm == NULL || strcmp(realm, fCurrentAuthenticator.realm()) != 0 01482 || nonce == NULL || strcmp(nonce, fCurrentAuthenticator.nonce()) != 0 01483 || uri == NULL || response == NULL) { 01484 break; 01485 } 01486 01487 // Next, the username has to be known to us: 01488 char const* password = fOurServer.fAuthDB->lookupPassword(username); 01489 #ifdef DEBUG 01490 fprintf(stderr, "lookupPassword(%s) returned password %s\n", username, password); 01491 #endif 01492 if (password == NULL) break; 01493 fCurrentAuthenticator. 01494 setUsernameAndPassword(username, password, 01495 fOurServer.fAuthDB->passwordsAreMD5()); 01496 01497 // Finally, compute a digest response from the information that we have, 01498 // and compare it to the one that we were given: 01499 char const* ourResponse 01500 = fCurrentAuthenticator.computeDigestResponse(cmdName, uri); 01501 success = (strcmp(ourResponse, response) == 0); 01502 fCurrentAuthenticator.reclaimDigestResponse(ourResponse); 01503 } while (0); 01504 01505 delete[] (char*)username; delete[] (char*)realm; delete[] (char*)nonce; 01506 delete[] (char*)uri; delete[] (char*)response; 01507 if (success) return True; 01508 01509 // If we get here, there was some kind of authentication failure. 01510 // Send back a "401 Unauthorized" response, with a new random nonce: 01511 fCurrentAuthenticator.setRealmAndRandomNonce(fOurServer.fAuthDB->realm()); 01512 snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, 01513 "RTSP/1.0 401 Unauthorized\r\n" 01514 "CSeq: %s\r\n" 01515 "%s" 01516 "WWW-Authenticate: Digest realm=\"%s\", nonce=\"%s\"\r\n\r\n", 01517 cseq, 01518 dateHeader(), 01519 fCurrentAuthenticator.realm(), fCurrentAuthenticator.nonce()); 01520 return False; 01521 }
| Boolean RTSPServer::RTSPClientSession::isMulticast | ( | ) | const [inline, protected] |
Definition at line 173 of file RTSPServer.hh.
References fIsMulticast.
00173 { return fIsMulticast; }
| void RTSPServer::RTSPClientSession::incomingRequestHandler | ( | void * | , | |
| int | ||||
| ) | [static, protected] |
Definition at line 351 of file RTSPServer.cpp.
References session.
Referenced by RTSPClientSession().
00351 { 00352 RTSPClientSession* session = (RTSPClientSession*)instance; 00353 session->incomingRequestHandler1(); 00354 }
| void RTSPServer::RTSPClientSession::incomingRequestHandler1 | ( | ) | [protected] |
Definition at line 356 of file RTSPServer.cpp.
References envir(), fClientInputSocket, fRequestBuffer, fRequestBufferBytesLeft, fRequestBytesAlreadySeen, handleRequestBytes(), and readSocket().
00356 { 00357 struct sockaddr_in dummy; // 'from' address, meaningless in this case 00358 00359 int bytesRead = readSocket(envir(), fClientInputSocket, &fRequestBuffer[fRequestBytesAlreadySeen], fRequestBufferBytesLeft, dummy); 00360 handleRequestBytes(bytesRead); 00361 }
| void RTSPServer::RTSPClientSession::handleAlternativeRequestByte | ( | void * | , | |
| u_int8_t | requestByte | |||
| ) | [static, protected] |
Definition at line 363 of file RTSPServer.cpp.
References session.
00363 { 00364 RTSPClientSession* session = (RTSPClientSession*)instance; 00365 session->handleAlternativeRequestByte1(requestByte); 00366 }
| void RTSPServer::RTSPClientSession::handleAlternativeRequestByte1 | ( | u_int8_t | requestByte | ) | [protected] |
Definition at line 368 of file RTSPServer.cpp.
References fRequestBuffer, fRequestBufferBytesLeft, fRequestBytesAlreadySeen, handleRequestBytes(), and RTSP_BUFFER_SIZE.
00368 { 00369 // Add this character to our buffer; then try to handle the data that we have buffered so far: 00370 if (fRequestBufferBytesLeft == 0|| fRequestBytesAlreadySeen >= RTSP_BUFFER_SIZE) return; 00371 fRequestBuffer[fRequestBytesAlreadySeen] = requestByte; 00372 handleRequestBytes(1); 00373 }
| void RTSPServer::RTSPClientSession::handleRequestBytes | ( | int | newBytesRead | ) | [protected] |
Definition at line 375 of file RTSPServer.cpp.
References base64Decode(), closeSockets(), False, fBase64RemainderCount, fClientInputSocket, fClientOutputSocket, fLastCRLF, fRecursionCount, fRequestBuffer, fRequestBufferBytesLeft, fRequestBytesAlreadySeen, fResponseBuffer, fSessionIsActive, fStreamAfterSETUP, handleCmd_bad(), handleCmd_DESCRIBE(), handleCmd_notSupported(), handleCmd_OPTIONS(), handleCmd_SETUP(), handleCmd_withinSession(), handleHTTPCmd_notSupported(), handleHTTPCmd_StreamingGET(), handleHTTPCmd_TunnelingGET(), handleHTTPCmd_TunnelingPOST(), noteLiveness(), parseHTTPRequestString(), parseRTSPRequestString(), resetRequestBuffer(), RTSP_PARAM_STRING_MAX, and True.
Referenced by handleAlternativeRequestByte1(), and incomingRequestHandler1().
00375 { 00376 ++fRecursionCount; 00377 00378 do { 00379 noteLiveness(); 00380 00381 if (newBytesRead <= 0 || (unsigned)newBytesRead >= fRequestBufferBytesLeft) { 00382 // Either the client socket has died, or the request was too big for us. 00383 // Terminate this connection: 00384 #ifdef DEBUG 00385 fprintf(stderr, "RTSPClientSession[%p]::handleRequestBytes() read %d new bytes (of %d); terminating connection!\n", this, newBytesRead, fRequestBufferBytesLeft); 00386 #endif 00387 fSessionIsActive = False; 00388 break; 00389 } 00390 00391 Boolean endOfMsg = False; 00392 unsigned char* ptr = &fRequestBuffer[fRequestBytesAlreadySeen]; 00393 #ifdef DEBUG 00394 ptr[newBytesRead] = '\0'; 00395 fprintf(stderr, "RTSPClientSession[%p]::handleRequestBytes() read %d new bytes:%s\n", this, newBytesRead, ptr); 00396 #endif 00397 00398 if (fClientOutputSocket != fClientInputSocket) { 00399 // We're doing RTSP-over-HTTP tunneling, and input commands are assumed to have been Base64-encoded. 00400 // We therefore Base64-decode as much of this new data as we can (i.e., up to a multiple of 4 bytes): 00401 unsigned numBytesToDecode = fBase64RemainderCount + newBytesRead; 00402 unsigned newBase64RemainderCount = numBytesToDecode%4; 00403 numBytesToDecode -= newBase64RemainderCount; 00404 if (numBytesToDecode > 0) { 00405 ptr[newBytesRead] = '\0'; 00406 unsigned decodedSize; 00407 unsigned char* decodedBytes = base64Decode((char*)(ptr-fBase64RemainderCount), decodedSize); 00408 #ifdef DEBUG 00409 fprintf(stderr, "Base64-decoded %d input bytes into %d new bytes:", numBytesToDecode, decodedSize); 00410 for (unsigned k = 0; k < decodedSize; ++k) fprintf(stderr, "%c", decodedBytes[k]); 00411 fprintf(stderr, "\n"); 00412 #endif 00413 00414 // Copy the new decoded bytes in place of the old ones (we can do this because there are fewer decoded bytes than original): 00415 unsigned char* to = ptr-fBase64RemainderCount; 00416 for (unsigned i = 0; i < decodedSize; ++i) *to++ = decodedBytes[i]; 00417 00418 // Then copy any remaining (undecoded) bytes to the end: 00419 for (unsigned j = 0; j < newBase64RemainderCount; ++j) *to++ = (ptr-fBase64RemainderCount+numBytesToDecode)[j]; 00420 00421 newBytesRead = decodedSize + newBase64RemainderCount; // adjust to allow for the size of the new decoded data (+ remainder) 00422 delete[] decodedBytes; 00423 } 00424 fBase64RemainderCount = newBase64RemainderCount; 00425 if (fBase64RemainderCount > 0) break; // because we know that we have more input bytes still to receive 00426 } 00427 00428 // Look for the end of the message: <CR><LF><CR><LF> 00429 unsigned char *tmpPtr = fLastCRLF + 2; 00430 if (tmpPtr < fRequestBuffer) tmpPtr = fRequestBuffer; 00431 while (tmpPtr < &ptr[newBytesRead-1]) { 00432 if (*tmpPtr == '\r' && *(tmpPtr+1) == '\n') { 00433 if (tmpPtr - fLastCRLF == 2) { // This is it: 00434 endOfMsg = True; 00435 break; 00436 } 00437 fLastCRLF = tmpPtr; 00438 } 00439 ++tmpPtr; 00440 } 00441 00442 fRequestBufferBytesLeft -= newBytesRead; 00443 fRequestBytesAlreadySeen += newBytesRead; 00444 00445 if (!endOfMsg) break; // subsequent reads will be needed to complete the request 00446 00447 // Parse the request string into command name and 'CSeq', then handle the command: 00448 fRequestBuffer[fRequestBytesAlreadySeen] = '\0'; 00449 char cmdName[RTSP_PARAM_STRING_MAX]; 00450 char urlPreSuffix[RTSP_PARAM_STRING_MAX]; 00451 char urlSuffix[RTSP_PARAM_STRING_MAX]; 00452 char cseq[RTSP_PARAM_STRING_MAX]; 00453 unsigned contentLength; 00454 if (parseRTSPRequestString((char*)fRequestBuffer, fRequestBytesAlreadySeen, 00455 cmdName, sizeof cmdName, 00456 urlPreSuffix, sizeof urlPreSuffix, 00457 urlSuffix, sizeof urlSuffix, 00458 cseq, sizeof cseq, 00459 contentLength)) { 00460 #ifdef DEBUG 00461 fprintf(stderr, "parseRTSPRequestString() succeeded, returning cmdName \"%s\", urlPreSuffix \"%s\", urlSuffix \"%s\", CSeq \"%s\", Content-Length %u, with %d bytes following the message.\n", cmdName, urlPreSuffix, urlSuffix, cseq, contentLength, ptr + newBytesRead - (tmpPtr + 2)); 00462 #endif 00463 // If there was a "Content-Length:" header, then make sure we've received all of the data that it specified: 00464 if (ptr + newBytesRead < tmpPtr + 2 + contentLength) break; // we still need more data; subsequent reads will give it to us 00465 00466 if (strcmp(cmdName, "OPTIONS") == 0) { 00467 handleCmd_OPTIONS(cseq); 00468 } else if (strcmp(cmdName, "DESCRIBE") == 0) { 00469 handleCmd_DESCRIBE(cseq, urlPreSuffix, urlSuffix, (char const*)fRequestBuffer); 00470 } else if (strcmp(cmdName, "SETUP") == 0) { 00471 handleCmd_SETUP(cseq, urlPreSuffix, urlSuffix, (char const*)fRequestBuffer); 00472 } else if (strcmp(cmdName, "TEARDOWN") == 0 00473 || strcmp(cmdName, "PLAY") == 0 00474 || strcmp(cmdName, "PAUSE") == 0 00475 || strcmp(cmdName, "GET_PARAMETER") == 0 00476 || strcmp(cmdName, "SET_PARAMETER") == 0) { 00477 handleCmd_withinSession(cmdName, urlPreSuffix, urlSuffix, cseq, (char const*)fRequestBuffer); 00478 } else { 00479 handleCmd_notSupported(cseq); 00480 } 00481 } else { 00482 #ifdef DEBUG 00483 fprintf(stderr, "parseRTSPRequestString() failed\n"); 00484 #endif 00485 // The request was not (valid) RTSP, but check for a special case: HTTP commands (for setting up RTSP-over-HTTP tunneling): 00486 char sessionCookie[RTSP_PARAM_STRING_MAX]; 00487 char acceptStr[RTSP_PARAM_STRING_MAX]; 00488 if (parseHTTPRequestString(cmdName, sizeof cmdName, 00489 urlSuffix, sizeof urlPreSuffix, 00490 sessionCookie, sizeof sessionCookie, 00491 acceptStr, sizeof acceptStr)) { 00492 #ifdef DEBUG 00493 fprintf(stderr, "parseHTTPRequestString() succeeded, returning cmdName \"%s\", urlSuffix \"%s\", sessionCookie \"%s\", acceptStr \"%s\"\n", cmdName, urlSuffix, sessionCookie, acceptStr); 00494 #endif 00495 // Check that the HTTP command is valid for RTSP-over-HTTP tunneling: There must be a 'session cookie'. 00496 Boolean isValidHTTPCmd = True; 00497 if (sessionCookie[0] == '\0') { 00498 // There was no "x-sessionCookie:" header. If there was an "Accept: application/x-rtsp-tunnelled" header, 00499 // then this is a bad tunneling request. Otherwise, assume that it's an attempt to access the stream via HTTP. 00500 if (strcmp(acceptStr, "application/x-rtsp-tunnelled") == 0) { 00501 isValidHTTPCmd = False; 00502 } else { 00503 handleHTTPCmd_StreamingGET(urlSuffix, (char const*)fRequestBuffer); 00504 } 00505 } else if (strcmp(cmdName, "GET") == 0) { 00506 handleHTTPCmd_TunnelingGET(sessionCookie); 00507 } else if (strcmp(cmdName, "POST") == 0) { 00508 // We might have received additional data following the HTTP "POST" command - i.e., the first Base64-encoded RTSP command. 00509 // Check for this, and handle it if it exists: 00510 unsigned char const* extraData = fLastCRLF+4; 00511 unsigned extraDataSize = &fRequestBuffer[fRequestBytesAlreadySeen] - extraData; 00512 if (handleHTTPCmd_TunnelingPOST(sessionCookie, extraData, extraDataSize)) { 00513 // We don't respond to the "POST" command, and we go away: 00514 fSessionIsActive = False; 00515 break; 00516 } 00517 } else { 00518 isValidHTTPCmd = False; 00519 } 00520 if (!isValidHTTPCmd) { 00521 handleHTTPCmd_notSupported(); 00522 } 00523 } else { 00524 #ifdef DEBUG 00525 fprintf(stderr, "parseHTTPRequestString() failed!\n"); 00526 #endif 00527 handleCmd_bad(cseq); 00528 } 00529 } 00530 00531 #ifdef DEBUG 00532 fprintf(stderr, "sending response: %s", fResponseBuffer); 00533 #endif 00534 send(fClientOutputSocket, (char const*)fResponseBuffer, strlen((char*)fResponseBuffer), 0); 00535 00536 if (strcmp(cmdName, "SETUP") == 0 && fStreamAfterSETUP) { 00537 // The client has asked for streaming to commence now, rather than after a 00538 // subsequent "PLAY" command. So, simulate the effect of a "PLAY" command: 00539 handleCmd_withinSession("PLAY", urlPreSuffix, urlSuffix, cseq, 00540 (char const*)fRequestBuffer); 00541 } 00542 00543 resetRequestBuffer(); // to prepare for any subsequent request 00544 } while (0); 00545 00546 --fRecursionCount; 00547 if (!fSessionIsActive) { 00548 if (fRecursionCount > 0) closeSockets(); else delete this; 00549 // Note: The "fRecursionCount" test is for a pathological situation where we got called recursively while handling a command. 00550 // In such a case we don't want to actually delete ourself until we leave the outermost call. 00551 } 00552 }
| void RTSPServer::RTSPClientSession::noteLiveness | ( | ) | [protected] |
Definition at line 1523 of file RTSPServer.cpp.
References envir(), fClientAddr, fLivenessCheckTask, fOurServer, RTSPServer::fReclamationTestSeconds, livenessTimeoutTask(), TaskScheduler::rescheduleDelayedTask(), and UsageEnvironment::taskScheduler().
Referenced by handleRequestBytes(), noteClientLiveness(), and RTSPClientSession().
01523 { 01524 #ifdef DEBUG 01525 fprintf(stderr, "Liveness indication from client at %s\n", AddressString(fClientAddr).val()); 01526 #endif 01527 if (fOurServer.fReclamationTestSeconds > 0) { 01528 envir().taskScheduler() 01529 .rescheduleDelayedTask(fLivenessCheckTask, 01530 fOurServer.fReclamationTestSeconds*1000000, 01531 (TaskFunc*)livenessTimeoutTask, this); 01532 } 01533 }
| void RTSPServer::RTSPClientSession::noteClientLiveness | ( | RTSPClientSession * | clientSession | ) | [static, protected] |
| void RTSPServer::RTSPClientSession::livenessTimeoutTask | ( | RTSPClientSession * | clientSession | ) | [static, protected] |
Definition at line 1541 of file RTSPServer.cpp.
References fClientAddr.
Referenced by noteLiveness().
01541 { 01542 // If this gets called, the client session is assumed to have timed out, 01543 // so delete it: 01544 #ifdef DEBUG 01545 fprintf(stderr, "RTSP client session from %s has timed out (due to inactivity)\n", AddressString(clientSession->fClientAddr).val()); 01546 #endif 01547 delete clientSession; 01548 }
| void RTSPServer::RTSPClientSession::changeClientInputSocket | ( | int | newSocketNum, | |
| unsigned char const * | extraData, | |||
| unsigned | extraDataSize | |||
| ) | [protected] |
Definition at line 1556 of file RTSPServer.cpp.
References Medium::envir(), UsageEnvironment::taskScheduler(), TaskScheduler::turnOffBackgroundReadHandling(), and TaskScheduler::turnOnBackgroundReadHandling().
Referenced by handleHTTPCmd_TunnelingPOST().
01556 { 01557 envir().taskScheduler().turnOffBackgroundReadHandling(fClientInputSocket); 01558 fClientInputSocket = newSocketNum; 01559 envir().taskScheduler().turnOnBackgroundReadHandling(fClientInputSocket, 01560 (TaskScheduler::BackgroundHandlerProc*)&incomingRequestHandler, this); 01561 01562 // Also write any extra data to our buffer, and handle it: 01563 if (extraDataSize > 0 && extraDataSize <= fRequestBufferBytesLeft/*sanity check; should always be true*/) { 01564 unsigned char* ptr = &fRequestBuffer[fRequestBytesAlreadySeen]; 01565 for (unsigned i = 0; i < extraDataSize; ++i) { 01566 ptr[i] = extraData[i]; 01567 } 01568 handleRequestBytes(extraDataSize); 01569 } 01570 }
RTSPServer& RTSPServer::RTSPClientSession::fOurServer [protected] |
Definition at line 184 of file RTSPServer.hh.
Referenced by envir(), handleHTTPCmd_TunnelingGET(), noteLiveness(), and ~RTSPClientSession().
unsigned RTSPServer::RTSPClientSession::fOurSessionId [protected] |
int RTSPServer::RTSPClientSession::fClientInputSocket [protected] |
Definition at line 187 of file RTSPServer.hh.
Referenced by closeSockets(), handleRequestBytes(), incomingRequestHandler1(), and RTSPClientSession().
int RTSPServer::RTSPClientSession::fClientOutputSocket [protected] |
Definition at line 187 of file RTSPServer.hh.
Referenced by closeSockets(), handleHTTPCmd_TunnelingGET(), and handleRequestBytes().
struct sockaddr_in RTSPServer::RTSPClientSession::fClientAddr [read, protected] |
Definition at line 188 of file RTSPServer.hh.
Referenced by livenessTimeoutTask(), and noteLiveness().
char* RTSPServer::RTSPClientSession::fSessionCookie [protected] |
unsigned char RTSPServer::RTSPClientSession::fRequestBuffer[RTSP_BUFFER_SIZE] [protected] |
Definition at line 191 of file RTSPServer.hh.
Referenced by handleAlternativeRequestByte1(), handleRequestBytes(), incomingRequestHandler1(), parseHTTPRequestString(), and resetRequestBuffer().
unsigned RTSPServer::RTSPClientSession::fRequestBytesAlreadySeen [protected] |
Definition at line 192 of file RTSPServer.hh.
Referenced by handleAlternativeRequestByte1(), handleRequestBytes(), incomingRequestHandler1(), parseHTTPRequestString(), and resetRequestBuffer().
unsigned RTSPServer::RTSPClientSession::fRequestBufferBytesLeft [protected] |
Definition at line 192 of file RTSPServer.hh.
Referenced by handleAlternativeRequestByte1(), handleRequestBytes(), incomingRequestHandler1(), and resetRequestBuffer().
unsigned char* RTSPServer::RTSPClientSession::fLastCRLF [protected] |
Definition at line 193 of file RTSPServer.hh.
Referenced by handleRequestBytes(), and resetRequestBuffer().
unsigned RTSPServer::RTSPClientSession::fBase64RemainderCount [protected] |
Definition at line 194 of file RTSPServer.hh.
Referenced by handleRequestBytes(), and resetRequestBuffer().
unsigned char RTSPServer::RTSPClientSession::fResponseBuffer[RTSP_BUFFER_SIZE] [protected] |
Definition at line 195 of file RTSPServer.hh.
Referenced by handleCmd_bad(), handleCmd_notFound(), handleCmd_notSupported(), handleCmd_OPTIONS(), handleCmd_unsupportedTransport(), handleHTTPCmd_notFound(), handleHTTPCmd_notSupported(), handleHTTPCmd_TunnelingGET(), and handleRequestBytes().
Boolean RTSPServer::RTSPClientSession::fIsMulticast [protected] |
Definition at line 196 of file RTSPServer.hh.
Referenced by handleCmd_notFound(), handleCmd_unsupportedTransport(), and handleRequestBytes().
Definition at line 197 of file RTSPServer.hh.
unsigned char RTSPServer::RTSPClientSession::fTCPStreamIdCount [protected] |
Definition at line 198 of file RTSPServer.hh.
unsigned RTSPServer::RTSPClientSession::fNumStreamStates [protected] |
struct RTSPServer::RTSPClientSession::streamState * RTSPServer::RTSPClientSession::fStreamStates [protected] |
Referenced by reclaimStreamStates().
unsigned RTSPServer::RTSPClientSession::fRecursionCount [protected] |
1.5.2