RTSPServer::RTSPClientSession Class Reference

#include <RTSPServer.hh>

Inheritance diagram for RTSPServer::RTSPClientSession:

Inheritance graph
[legend]
Collaboration diagram for RTSPServer::RTSPClientSession:

Collaboration graph
[legend]

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)
UsageEnvironmentenvir ()
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

RTSPServerfOurServer
unsigned fOurSessionId
ServerMediaSessionfOurServerMediaSession
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::streamStatefStreamStates
unsigned fRecursionCount

Data Structures

struct  streamState

Detailed Description

Definition at line 124 of file RTSPServer.hh.


Constructor & Destructor Documentation

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().

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 }


Member Function Documentation

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]

Definition at line 1536 of file RTSPServer.cpp.

References noteLiveness().

01536                                                      {
01537   clientSession->noteLiveness();
01538 }

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 }


Field Documentation

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]

Definition at line 185 of file RTSPServer.hh.

Referenced by reclaimStreamStates().

ServerMediaSession* RTSPServer::RTSPClientSession::fOurServerMediaSession [protected]

Definition at line 186 of file RTSPServer.hh.

Referenced by ~RTSPClientSession().

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]

Definition at line 189 of file RTSPServer.hh.

Referenced by ~RTSPClientSession().

TaskToken RTSPServer::RTSPClientSession::fLivenessCheckTask [protected]

Definition at line 190 of file RTSPServer.hh.

Referenced by closeSockets(), and noteLiveness().

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 isMulticast().

Boolean RTSPServer::RTSPClientSession::fSessionIsActive [protected]

Definition at line 196 of file RTSPServer.hh.

Referenced by handleCmd_notFound(), handleCmd_unsupportedTransport(), and handleRequestBytes().

Boolean RTSPServer::RTSPClientSession::fStreamAfterSETUP [protected]

Definition at line 196 of file RTSPServer.hh.

Referenced by handleRequestBytes().

Authenticator RTSPServer::RTSPClientSession::fCurrentAuthenticator [protected]

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]

Definition at line 199 of file RTSPServer.hh.

Referenced by reclaimStreamStates().

struct RTSPServer::RTSPClientSession::streamState * RTSPServer::RTSPClientSession::fStreamStates [protected]

Referenced by reclaimStreamStates().

unsigned RTSPServer::RTSPClientSession::fRecursionCount [protected]

Definition at line 204 of file RTSPServer.hh.

Referenced by handleRequestBytes().


The documentation for this class was generated from the following files:
Generated on Thu Feb 2 23:55:53 2012 for live by  doxygen 1.5.2