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