RTSPClient Class Reference

#include <RTSPClient.hh>

Inheritance diagram for RTSPClient:

Inheritance graph
[legend]
Collaboration diagram for RTSPClient:

Collaboration graph
[legend]

Public Types

typedef void( responseHandler )(RTSPClient *rtspClient, int resultCode, char *resultString)

Public Member Functions

unsigned sendDescribeCommand (responseHandler *responseHandler, Authenticator *authenticator=NULL)
unsigned sendOptionsCommand (responseHandler *responseHandler, Authenticator *authenticator=NULL)
unsigned sendAnnounceCommand (char const *sdpDescription, responseHandler *responseHandler, Authenticator *authenticator=NULL)
unsigned sendSetupCommand (MediaSubsession &subsession, responseHandler *responseHandler, Boolean streamOutgoing=False, Boolean streamUsingTCP=False, Boolean forceMulticastOnUnspecified=False, Authenticator *authenticator=NULL)
unsigned sendPlayCommand (MediaSession &session, responseHandler *responseHandler, double start=0.0f, double end=-1.0f, float scale=1.0f, Authenticator *authenticator=NULL)
unsigned sendPlayCommand (MediaSubsession &subsession, responseHandler *responseHandler, double start=0.0f, double end=-1.0f, float scale=1.0f, Authenticator *authenticator=NULL)
unsigned sendPlayCommand (MediaSession &session, responseHandler *responseHandler, char const *absStartTime, char const *absEndTime=NULL, float scale=1.0f, Authenticator *authenticator=NULL)
unsigned sendPlayCommand (MediaSubsession &subsession, responseHandler *responseHandler, char const *absStartTime, char const *absEndTime=NULL, float scale=1.0f, Authenticator *authenticator=NULL)
unsigned sendPauseCommand (MediaSession &session, responseHandler *responseHandler, Authenticator *authenticator=NULL)
unsigned sendPauseCommand (MediaSubsession &subsession, responseHandler *responseHandler, Authenticator *authenticator=NULL)
unsigned sendRecordCommand (MediaSession &session, responseHandler *responseHandler, Authenticator *authenticator=NULL)
unsigned sendRecordCommand (MediaSubsession &subsession, responseHandler *responseHandler, Authenticator *authenticator=NULL)
unsigned sendTeardownCommand (MediaSession &session, responseHandler *responseHandler, Authenticator *authenticator=NULL)
unsigned sendTeardownCommand (MediaSubsession &subsession, responseHandler *responseHandler, Authenticator *authenticator=NULL)
unsigned sendSetParameterCommand (MediaSession &session, responseHandler *responseHandler, char const *parameterName, char const *parameterValue, Authenticator *authenticator=NULL)
unsigned sendGetParameterCommand (MediaSession &session, responseHandler *responseHandler, char const *parameterName, Authenticator *authenticator=NULL)
Boolean changeResponseHandler (unsigned cseq, responseHandler *newResponseHandler)
int socketNum () const
void setUserAgentString (char const *userAgentName)
unsigned sessionTimeoutParameter () const
char const * url () const
UsageEnvironmentenvir () const
char const * name () const
virtual Boolean isSource () const
virtual Boolean isSink () const
virtual Boolean isRTCPInstance () const
virtual Boolean isRTSPServer () const
virtual Boolean isMediaSession () const
virtual Boolean isServerMediaSession () const
virtual Boolean isDarwinInjector () const

Static Public Member Functions

static RTSPClientcreateNew (UsageEnvironment &env, char const *rtspURL, int verbosityLevel=0, char const *applicationName=NULL, portNumBits tunnelOverHTTPPortNum=0, int socketNumToServer=-1)
static Boolean lookupByName (UsageEnvironment &env, char const *sourceName, RTSPClient *&resultClient)
static Boolean parseRTSPURL (UsageEnvironment &env, char const *url, char *&username, char *&password, NetAddress &address, portNumBits &portNum, char const **urlSuffix=NULL)
static Boolean lookupByName (UsageEnvironment &env, char const *mediumName, Medium *&resultMedium)
static void close (UsageEnvironment &env, char const *mediumName)
static void close (Medium *medium)

Static Public Attributes

static unsigned responseBufferSize = 20000

Protected Member Functions

 RTSPClient (UsageEnvironment &env, char const *rtspURL, int verbosityLevel, char const *applicationName, portNumBits tunnelOverHTTPPortNum, int socketNumToServer)
virtual ~RTSPClient ()
void reset ()
void setBaseURL (char const *url)
virtual unsigned sendRequest (RequestRecord *request)
TaskTokennextTask ()

Protected Attributes

int fVerbosityLevel
unsigned fCSeq
Authenticator fCurrentAuthenticator

Private Member Functions

virtual Boolean isRTSPClient () const
void resetTCPSockets ()
void resetResponseBuffer ()
int openConnection ()
int connectToServer (int socketNum, portNumBits remotePortNum)
char * createAuthenticatorString (char const *cmd, char const *url)
void handleRequestError (RequestRecord *request)
Boolean parseResponseCode (char const *line, unsigned &responseCode, char const *&responseString)
void handleIncomingRequest ()
Boolean parseTransportParams (char const *paramsStr, char *&serverAddressStr, portNumBits &serverPortNum, unsigned char &rtpChannelId, unsigned char &rtcpChannelId)
Boolean parseScaleParam (char const *paramStr, float &scale)
Boolean parseRTPInfoParams (char const *&paramStr, u_int16_t &seqNum, u_int32_t &timestamp)
Boolean handleSETUPResponse (MediaSubsession &subsession, char const *sessionParamsStr, char const *transportParamsStr, Boolean streamUsingTCP)
Boolean handlePLAYResponse (MediaSession &session, MediaSubsession &subsession, char const *scaleParamsStr, char const *rangeParamsStr, char const *rtpInfoParamsStr)
Boolean handleTEARDOWNResponse (MediaSession &session, MediaSubsession &subsession)
Boolean handleGET_PARAMETERResponse (char const *parameterName, char *&resultValueString)
Boolean handleAuthenticationFailure (char const *wwwAuthenticateParamsStr)
Boolean resendCommand (RequestRecord *request)
char const * sessionURL (MediaSession const &session) const
void handleAlternativeRequestByte1 (u_int8_t requestByte)
void constructSubsessionURL (MediaSubsession const &subsession, char const *&prefix, char const *&separator, char const *&suffix)
Boolean setupHTTPTunneling1 ()
void responseHandlerForHTTP_GET1 (int responseCode, char *responseString)
Boolean setupHTTPTunneling2 ()
void connectionHandler1 ()
void incomingDataHandler1 ()
void handleResponseBytes (int newBytesRead)

Static Private Member Functions

static Boolean checkForHeader (char const *line, char const *headerName, unsigned headerNameLength, char const *&headerParams)
static void handleAlternativeRequestByte (void *, u_int8_t requestByte)
static void responseHandlerForHTTP_GET (RTSPClient *rtspClient, int responseCode, char *responseString)
static void connectionHandler (void *, int)
static void incomingDataHandler (void *, int)

Private Attributes

portNumBits fTunnelOverHTTPPortNum
char * fUserAgentHeaderStr
unsigned fUserAgentHeaderStrLen
int fInputSocketNum
int fOutputSocketNum
netAddressBits fServerAddress
char * fBaseURL
unsigned char fTCPStreamIdCount
char * fLastSessionId
unsigned fSessionTimeoutParameter
char * fResponseBuffer
unsigned fResponseBytesAlreadySeen
unsigned fResponseBufferBytesLeft
RequestQueue fRequestsAwaitingConnection
RequestQueue fRequestsAwaitingHTTPTunneling
RequestQueue fRequestsAwaitingResponse
char fSessionCookie [33]
unsigned fSessionCookieCounter
Boolean fHTTPTunnelingConnectionIsPending

Friends

class MediaLookupTable

Data Structures

class  RequestQueue
class  RequestRecord

Detailed Description

Definition at line 37 of file RTSPClient.hh.


Member Typedef Documentation

typedef void( RTSPClient::responseHandler)(RTSPClient *rtspClient, int resultCode, char *resultString)

Definition at line 50 of file RTSPClient.hh.


Constructor & Destructor Documentation

RTSPClient::RTSPClient ( UsageEnvironment env,
char const *  rtspURL,
int  verbosityLevel,
char const *  applicationName,
portNumBits  tunnelOverHTTPPortNum,
int  socketNumToServer 
) [protected]

Definition at line 297 of file RTSPClient.cpp.

References Medium::envir(), fInputSocketNum, fOutputSocketNum, fResponseBuffer, incomingDataHandler(), libVersionStr, LIVEMEDIA_LIBRARY_VERSION_STRING, NULL, resetResponseBuffer(), responseBufferSize, TaskScheduler::setBackgroundHandling(), setBaseURL(), setUserAgentString(), SOCKET_EXCEPTION, SOCKET_READABLE, and UsageEnvironment::taskScheduler().

Referenced by createNew().

00300   : Medium(env),
00301     fVerbosityLevel(verbosityLevel), fCSeq(1),
00302     fTunnelOverHTTPPortNum(tunnelOverHTTPPortNum), fUserAgentHeaderStr(NULL), fUserAgentHeaderStrLen(0),
00303     fInputSocketNum(-1), fOutputSocketNum(-1), fServerAddress(0), fBaseURL(NULL), fTCPStreamIdCount(0),
00304     fLastSessionId(NULL), fSessionTimeoutParameter(0), fSessionCookieCounter(0), fHTTPTunnelingConnectionIsPending(False) {
00305   setBaseURL(rtspURL);
00306 
00307   fResponseBuffer = new char[responseBufferSize+1];
00308   resetResponseBuffer();
00309 
00310   if (socketNumToServer >= 0) {
00311     // This socket number is (assumed to be) already connected to the server.
00312     // Use it, and arrange to handle responses to requests sent on it:
00313     fInputSocketNum = fOutputSocketNum = socketNumToServer;
00314     envir().taskScheduler().setBackgroundHandling(fInputSocketNum, SOCKET_READABLE|SOCKET_EXCEPTION,
00315                                                   (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this);
00316   }
00317 
00318   // Set the "User-Agent:" header to use in each request:
00319   char const* const libName = "LIVE555 Streaming Media v";
00320   char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING;
00321   char const* libPrefix; char const* libSuffix;
00322   if (applicationName == NULL || applicationName[0] == '\0') {
00323     applicationName = libPrefix = libSuffix = "";
00324   } else {
00325     libPrefix = " (";
00326     libSuffix = ")";
00327   }
00328   unsigned userAgentNameSize
00329     = strlen(applicationName) + strlen(libPrefix) + strlen(libName) + strlen(libVersionStr) + strlen(libSuffix) + 1;
00330   char* userAgentName = new char[userAgentNameSize];
00331   sprintf(userAgentName, "%s%s%s%s%s", applicationName, libPrefix, libName, libVersionStr, libSuffix);
00332   setUserAgentString(userAgentName);
00333   delete[] userAgentName;
00334 }

RTSPClient::~RTSPClient (  )  [protected, virtual]

Definition at line 336 of file RTSPClient.cpp.

References fResponseBuffer, fUserAgentHeaderStr, and reset().

00336                         {
00337   reset();
00338 
00339   delete[] fResponseBuffer;
00340   delete[] fUserAgentHeaderStr;
00341 }


Member Function Documentation

RTSPClient * RTSPClient::createNew ( UsageEnvironment env,
char const *  rtspURL,
int  verbosityLevel = 0,
char const *  applicationName = NULL,
portNumBits  tunnelOverHTTPPortNum = 0,
int  socketNumToServer = -1 
) [static]

Definition at line 30 of file RTSPClient.cpp.

References env, and RTSPClient().

Referenced by createClient(), HandlerServerForREGISTERCommand::createNewRTSPClient(), and ProxyServerMediaSubsession::createNewStreamSource().

00034                                                          {
00035   return new RTSPClient(env, rtspURL,
00036                         verbosityLevel, applicationName, tunnelOverHTTPPortNum, socketNumToServer);
00037 }

unsigned RTSPClient::sendDescribeCommand ( responseHandler responseHandler,
Authenticator authenticator = NULL 
)

Definition at line 39 of file RTSPClient.cpp.

References fCSeq, fCurrentAuthenticator, NULL, and sendRequest().

Referenced by getSDPDescription(), openURL(), and ProxyRTSPClient::sendDESCRIBE().

00039                                                                                                        {
00040   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00041   return sendRequest(new RequestRecord(++fCSeq, "DESCRIBE", responseHandler));
00042 }

unsigned RTSPClient::sendOptionsCommand ( responseHandler responseHandler,
Authenticator authenticator = NULL 
)

Definition at line 44 of file RTSPClient.cpp.

References fCSeq, fCurrentAuthenticator, NULL, and sendRequest().

Referenced by getOptions(), and ProxyRTSPClient::sendLivenessCommand().

00044                                                                                                       {
00045   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00046   return sendRequest(new RequestRecord(++fCSeq, "OPTIONS", responseHandler));
00047 }

unsigned RTSPClient::sendAnnounceCommand ( char const *  sdpDescription,
responseHandler responseHandler,
Authenticator authenticator = NULL 
)

Definition at line 49 of file RTSPClient.cpp.

References False, fCSeq, fCurrentAuthenticator, NULL, and sendRequest().

Referenced by DarwinInjector::setDestination().

00049                                                                                                                                    {
00050   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00051   return sendRequest(new RequestRecord(++fCSeq, "ANNOUNCE", responseHandler, NULL, NULL, False, 0.0, 0.0, 0.0, sdpDescription));
00052 }

unsigned RTSPClient::sendSetupCommand ( MediaSubsession subsession,
responseHandler responseHandler,
Boolean  streamOutgoing = False,
Boolean  streamUsingTCP = False,
Boolean  forceMulticastOnUnspecified = False,
Authenticator authenticator = NULL 
)

Definition at line 54 of file RTSPClient.cpp.

References fCSeq, fCurrentAuthenticator, fTunnelOverHTTPPortNum, NULL, sendRequest(), subsession, and True.

Referenced by ProxyRTSPClient::continueAfterSETUP(), ProxyServerMediaSubsession::createNewStreamSource(), DarwinInjector::setDestination(), setupNextSubsession(), and setupSubsession().

00056                                                                     {
00057   if (fTunnelOverHTTPPortNum != 0) streamUsingTCP = True; // RTSP-over-HTTP tunneling uses TCP (by definition)
00058   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00059 
00060   u_int32_t booleanFlags = 0;
00061   if (streamUsingTCP) booleanFlags |= 0x1;
00062   if (streamOutgoing) booleanFlags |= 0x2;
00063   if (forceMulticastOnUnspecified) booleanFlags |= 0x4;
00064   return sendRequest(new RequestRecord(++fCSeq, "SETUP", responseHandler, NULL, &subsession, booleanFlags));
00065 }

unsigned RTSPClient::sendPlayCommand ( MediaSession session,
responseHandler responseHandler,
double  start = 0.0f,
double  end = -1.0f,
float  scale = 1.0f,
Authenticator authenticator = NULL 
)

Definition at line 67 of file RTSPClient.cpp.

References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and session.

Referenced by ProxyRTSPClient::continueAfterSETUP(), ProxyServerMediaSubsession::createNewStreamSource(), ProxyRTSPClient::handleSubsessionTimeout(), DarwinInjector::setDestination(), setupNextSubsession(), and startPlayingSession().

00069                                                                    {
00070   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00071   return sendRequest(new RequestRecord(++fCSeq, "PLAY", responseHandler, &session, NULL, 0, start, end, scale));
00072 }

unsigned RTSPClient::sendPlayCommand ( MediaSubsession subsession,
responseHandler responseHandler,
double  start = 0.0f,
double  end = -1.0f,
float  scale = 1.0f,
Authenticator authenticator = NULL 
)

Definition at line 74 of file RTSPClient.cpp.

References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and subsession.

00076                                                                    {
00077   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00078   return sendRequest(new RequestRecord(++fCSeq, "PLAY", responseHandler, NULL, &subsession, 0, start, end, scale));
00079 }

unsigned RTSPClient::sendPlayCommand ( MediaSession session,
responseHandler responseHandler,
char const *  absStartTime,
char const *  absEndTime = NULL,
float  scale = 1.0f,
Authenticator authenticator = NULL 
)

Definition at line 81 of file RTSPClient.cpp.

References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and session.

00083                                                                    {
00084   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00085   return sendRequest(new RequestRecord(++fCSeq, responseHandler, absStartTime, absEndTime, scale, &session, NULL));
00086 }

unsigned RTSPClient::sendPlayCommand ( MediaSubsession subsession,
responseHandler responseHandler,
char const *  absStartTime,
char const *  absEndTime = NULL,
float  scale = 1.0f,
Authenticator authenticator = NULL 
)

Definition at line 88 of file RTSPClient.cpp.

References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and subsession.

00090                                                                    {
00091   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00092   return sendRequest(new RequestRecord(++fCSeq, responseHandler, absStartTime, absEndTime, scale, NULL, &subsession));
00093 }

unsigned RTSPClient::sendPauseCommand ( MediaSession session,
responseHandler responseHandler,
Authenticator authenticator = NULL 
)

Definition at line 95 of file RTSPClient.cpp.

References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and session.

Referenced by ProxyServerMediaSubsession::closeStreamSource().

00095                                                                                                                            {
00096   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00097   return sendRequest(new RequestRecord(++fCSeq, "PAUSE", responseHandler, &session));
00098 }

unsigned RTSPClient::sendPauseCommand ( MediaSubsession subsession,
responseHandler responseHandler,
Authenticator authenticator = NULL 
)

Definition at line 100 of file RTSPClient.cpp.

References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and subsession.

00100                                                                                                                                  {
00101   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00102   return sendRequest(new RequestRecord(++fCSeq, "PAUSE", responseHandler, NULL, &subsession));
00103 }

unsigned RTSPClient::sendRecordCommand ( MediaSession session,
responseHandler responseHandler,
Authenticator authenticator = NULL 
)

Definition at line 105 of file RTSPClient.cpp.

References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and session.

00105                                                                                                                             {
00106   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00107   return sendRequest(new RequestRecord(++fCSeq, "RECORD", responseHandler, &session));
00108 }

unsigned RTSPClient::sendRecordCommand ( MediaSubsession subsession,
responseHandler responseHandler,
Authenticator authenticator = NULL 
)

Definition at line 110 of file RTSPClient.cpp.

References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and subsession.

00110                                                                                                                                   {
00111   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00112   return sendRequest(new RequestRecord(++fCSeq, "RECORD", responseHandler, NULL, &subsession));
00113 }

unsigned RTSPClient::sendTeardownCommand ( MediaSession session,
responseHandler responseHandler,
Authenticator authenticator = NULL 
)

Definition at line 115 of file RTSPClient.cpp.

References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and session.

Referenced by shutdownStream(), tearDownSession(), DarwinInjector::~DarwinInjector(), and ProxyServerMediaSession::~ProxyServerMediaSession().

00115                                                                                                                               {
00116   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00117   return sendRequest(new RequestRecord(++fCSeq, "TEARDOWN", responseHandler, &session));
00118 }

unsigned RTSPClient::sendTeardownCommand ( MediaSubsession subsession,
responseHandler responseHandler,
Authenticator authenticator = NULL 
)

Definition at line 120 of file RTSPClient.cpp.

References fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and subsession.

00120                                                                                                                                     {
00121   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00122   return sendRequest(new RequestRecord(++fCSeq, "TEARDOWN", responseHandler, NULL, &subsession));
00123 }

unsigned RTSPClient::sendSetParameterCommand ( MediaSession session,
responseHandler responseHandler,
char const *  parameterName,
char const *  parameterValue,
Authenticator authenticator = NULL 
)

Definition at line 125 of file RTSPClient.cpp.

References False, fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and session.

00127                                                                            {
00128   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00129   char* paramString = new char[strlen(parameterName) + strlen(parameterValue) + 10];
00130   sprintf(paramString, "%s: %s\r\n", parameterName, parameterValue);
00131   unsigned result = sendRequest(new RequestRecord(++fCSeq, "SET_PARAMETER", responseHandler, &session, NULL, False, 0.0, 0.0, 0.0, paramString));
00132   delete[] paramString;
00133   return result;
00134 }

unsigned RTSPClient::sendGetParameterCommand ( MediaSession session,
responseHandler responseHandler,
char const *  parameterName,
Authenticator authenticator = NULL 
)

Definition at line 136 of file RTSPClient.cpp.

References False, fCSeq, fCurrentAuthenticator, NULL, sendRequest(), and session.

Referenced by ProxyRTSPClient::sendLivenessCommand().

00137                                                                            {
00138   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00139 
00140   // We assume that:
00141   //    parameterName is NULL means: Send no body in the request.
00142   //    parameterName is "" means: Send only \r\n in the request body.  
00143   //    parameterName is non-empty means: Send "<parameterName>\r\n" as the request body.  
00144   unsigned parameterNameLen = parameterName == NULL ? 0 : strlen(parameterName);
00145   char* paramString = new char[parameterNameLen + 3]; // the 3 is for \r\n + the '\0' byte
00146   if (parameterName == NULL) {
00147     paramString[0] = '\0';
00148   } else {
00149     sprintf(paramString, "%s\r\n", parameterName);
00150   }
00151   unsigned result = sendRequest(new RequestRecord(++fCSeq, "GET_PARAMETER", responseHandler, &session, NULL, False, 0.0, 0.0, 0.0, paramString));
00152   delete[] paramString;
00153   return result;
00154 }

Boolean RTSPClient::changeResponseHandler ( unsigned  cseq,
responseHandler newResponseHandler 
)

Definition at line 156 of file RTSPClient.cpp.

References False, RTSPClient::RequestQueue::findByCSeq(), fRequestsAwaitingConnection, fRequestsAwaitingHTTPTunneling, fRequestsAwaitingResponse, RTSPClient::RequestRecord::handler(), NULL, and True.

00156                                                                                             { 
00157   // Look for the matching request record in each of our 'pending requests' queues:
00158   RequestRecord* request;
00159   if ((request = fRequestsAwaitingConnection.findByCSeq(cseq)) != NULL
00160       || (request = fRequestsAwaitingHTTPTunneling.findByCSeq(cseq)) != NULL
00161       || (request = fRequestsAwaitingResponse.findByCSeq(cseq)) != NULL) {
00162     request->handler() = newResponseHandler;
00163     return True;
00164   }
00165 
00166   return False;
00167 }

int RTSPClient::socketNum (  )  const [inline]

Definition at line 154 of file RTSPClient.hh.

References fInputSocketNum.

Referenced by DarwinInjector::setDestination().

00154 { return fInputSocketNum; }

Boolean RTSPClient::lookupByName ( UsageEnvironment env,
char const *  sourceName,
RTSPClient *&  resultClient 
) [static]

Definition at line 169 of file RTSPClient.cpp.

References env, False, Medium::isRTSPClient(), Medium::lookupByName(), NULL, and True.

00171                                                             {
00172   resultClient = NULL; // unless we succeed
00173 
00174   Medium* medium;
00175   if (!Medium::lookupByName(env, instanceName, medium)) return False;
00176 
00177   if (!medium->isRTSPClient()) {
00178     env.setResultMsg(instanceName, " is not a RTSP client");
00179     return False;
00180   }
00181 
00182   resultClient = (RTSPClient*)medium;
00183   return True;
00184 }

Boolean RTSPClient::parseRTSPURL ( UsageEnvironment env,
char const *  url,
char *&  username,
char *&  password,
NetAddress address,
portNumBits portNum,
char const **  urlSuffix = NULL 
) [static]

Definition at line 186 of file RTSPClient.cpp.

References _strncasecmp, env, False, NetAddressList::firstAddress(), NULL, NetAddressList::numAddresses(), UsageEnvironment::setResultMsg(), and True.

Referenced by openConnection(), and sendRequest().

00190                                                          {
00191   do {
00192     // Parse the URL as "rtsp://[<username>[:<password>]@]<server-address-or-name>[:<port>][/<stream-name>]"
00193     char const* prefix = "rtsp://";
00194     unsigned const prefixLength = 7;
00195     if (_strncasecmp(url, prefix, prefixLength) != 0) {
00196       env.setResultMsg("URL is not of the form \"", prefix, "\"");
00197       break;
00198     }
00199 
00200     unsigned const parseBufferSize = 100;
00201     char parseBuffer[parseBufferSize];
00202     char const* from = &url[prefixLength];
00203 
00204     // Check whether "<username>[:<password>]@" occurs next.
00205     // We do this by checking whether '@' appears before the end of the URL, or before the first '/'.
00206     username = password = NULL; // default return values
00207     char const* colonPasswordStart = NULL;
00208     char const* p;
00209     for (p = from; *p != '\0' && *p != '/'; ++p) {
00210       if (*p == ':' && colonPasswordStart == NULL) {
00211         colonPasswordStart = p;
00212       } else if (*p == '@') {
00213         // We found <username> (and perhaps <password>).  Copy them into newly-allocated result strings:
00214         if (colonPasswordStart == NULL) colonPasswordStart = p;
00215 
00216         char const* usernameStart = from;
00217         unsigned usernameLen = colonPasswordStart - usernameStart;
00218         username = new char[usernameLen + 1] ; // allow for the trailing '\0'
00219         for (unsigned i = 0; i < usernameLen; ++i) username[i] = usernameStart[i];
00220         username[usernameLen] = '\0';
00221 
00222         char const* passwordStart = colonPasswordStart;
00223         if (passwordStart < p) ++passwordStart; // skip over the ':'
00224         unsigned passwordLen = p - passwordStart;
00225         password = new char[passwordLen + 1]; // allow for the trailing '\0'
00226         for (unsigned j = 0; j < passwordLen; ++j) password[j] = passwordStart[j];
00227         password[passwordLen] = '\0';
00228 
00229         from = p + 1; // skip over the '@'
00230         break;
00231       }
00232     }
00233 
00234     // Next, parse <server-address-or-name>
00235     char* to = &parseBuffer[0];
00236     unsigned i;
00237     for (i = 0; i < parseBufferSize; ++i) {
00238       if (*from == '\0' || *from == ':' || *from == '/') {
00239         // We've completed parsing the address
00240         *to = '\0';
00241         break;
00242       }
00243       *to++ = *from++;
00244     }
00245     if (i == parseBufferSize) {
00246       env.setResultMsg("URL is too long");
00247       break;
00248     }
00249 
00250     NetAddressList addresses(parseBuffer);
00251     if (addresses.numAddresses() == 0) {
00252       env.setResultMsg("Failed to find network address for \"",
00253                        parseBuffer, "\"");
00254       break;
00255     }
00256     address = *(addresses.firstAddress());
00257 
00258     portNum = 554; // default value
00259     char nextChar = *from;
00260     if (nextChar == ':') {
00261       int portNumInt;
00262       if (sscanf(++from, "%d", &portNumInt) != 1) {
00263         env.setResultMsg("No port number follows ':'");
00264         break;
00265       }
00266       if (portNumInt < 1 || portNumInt > 65535) {
00267         env.setResultMsg("Bad port number");
00268         break;
00269       }
00270       portNum = (portNumBits)portNumInt;
00271       while (*from >= '0' && *from <= '9') ++from; // skip over port number
00272     }
00273 
00274     // The remainder of the URL is the suffix:
00275     if (urlSuffix != NULL) *urlSuffix = from;
00276 
00277     return True;
00278   } while (0);
00279 
00280   return False;
00281 }

void RTSPClient::setUserAgentString ( char const *  userAgentName  ) 

Definition at line 283 of file RTSPClient.cpp.

References fUserAgentHeaderStr, fUserAgentHeaderStrLen, and NULL.

Referenced by RTSPClient().

00283                                                              {
00284   if (userAgentName == NULL) return;
00285 
00286   // Change the existing user agent header string:
00287   char const* const formatStr = "User-Agent: %s\r\n";
00288   unsigned const headerSize = strlen(formatStr) + strlen(userAgentName);
00289   delete[] fUserAgentHeaderStr;
00290   fUserAgentHeaderStr = new char[headerSize];
00291   sprintf(fUserAgentHeaderStr, formatStr, userAgentName);
00292   fUserAgentHeaderStrLen = strlen(fUserAgentHeaderStr);
00293 }

unsigned RTSPClient::sessionTimeoutParameter (  )  const [inline]

Definition at line 168 of file RTSPClient.hh.

References fSessionTimeoutParameter.

Referenced by ProxyRTSPClient::scheduleLivenessCommand().

00168 { return fSessionTimeoutParameter; }

char const* RTSPClient::url (  )  const [inline]

Definition at line 170 of file RTSPClient.hh.

References fBaseURL.

Referenced by continueAfterClientCreation0(), operator<<(), sessionURL(), and ProxyServerMediaSession::url().

00170 { return fBaseURL; }

void RTSPClient::reset (  )  [protected]

Reimplemented in ProxyRTSPClient.

Definition at line 347 of file RTSPClient.cpp.

References fCurrentAuthenticator, fLastSessionId, fServerAddress, NULL, Authenticator::reset(), resetResponseBuffer(), resetTCPSockets(), and setBaseURL().

Referenced by ProxyRTSPClient::reset(), and ~RTSPClient().

00347                        {
00348   resetTCPSockets();
00349   resetResponseBuffer();
00350   fServerAddress = 0;
00351 
00352   setBaseURL(NULL);
00353 
00354   fCurrentAuthenticator.reset();
00355 
00356   delete[] fLastSessionId; fLastSessionId = NULL;
00357 }

void RTSPClient::setBaseURL ( char const *  url  )  [protected]

Definition at line 376 of file RTSPClient.cpp.

References fBaseURL, and strDup().

Referenced by ProxyRTSPClient::continueAfterLivenessCommand(), handleResponseBytes(), reset(), and RTSPClient().

00376                                            {
00377   delete[] fBaseURL; fBaseURL = strDup(url);
00378 }

unsigned RTSPClient::sendRequest ( RequestRecord request  )  [protected, virtual]

Definition at line 537 of file RTSPClient.cpp.

References RTSPClient::RequestRecord::absEndTime(), RTSPClient::RequestRecord::absStartTime(), base64Encode(), RTSPClient::RequestRecord::booleanFlags(), MediaSubsession::clientPortNum(), RTSPClient::RequestRecord::commandName(), MediaSubsession::connectionEndpointAddress(), constructSubsessionURL(), RTSPClient::RequestRecord::contentStr(), createAuthenticatorString(), createRangeString(), createScaleString(), createSessionString(), RTSPClient::RequestRecord::cseq(), RTSPClient::RequestRecord::end(), RTSPClient::RequestQueue::enqueue(), Medium::envir(), False, fBaseURL, fInputSocketNum, fLastSessionId, fOutputSocketNum, fRequestsAwaitingConnection, fRequestsAwaitingHTTPTunneling, fRequestsAwaitingResponse, fSessionCookie, fSessionCookieCounter, fTCPStreamIdCount, fTunnelOverHTTPPortNum, fUserAgentHeaderStr, fUserAgentHeaderStrLen, fVerbosityLevel, handleRequestError(), RTSPClient::RequestQueue::isEmpty(), IsMulticastAddress(), NULL, openConnection(), our_MD5Data(), parseRTSPURL(), password, MediaSubsession::protocolName(), RTSPClient::RequestRecord::scale(), MediaSubsession::scale(), MediaSession::scale(), RTSPClient::RequestRecord::session(), MediaSubsession::sessionId(), sessionURL(), UsageEnvironment::setResultErrMsg(), UsageEnvironment::setResultMsg(), setupHTTPTunneling1(), RTSPClient::RequestRecord::start(), streamUsingTCP, RTSPClient::RequestRecord::subsession(), subsession, True, and username.

Referenced by connectionHandler1(), resendCommand(), responseHandlerForHTTP_GET1(), sendAnnounceCommand(), sendDescribeCommand(), sendGetParameterCommand(), sendOptionsCommand(), sendPauseCommand(), sendPlayCommand(), sendRecordCommand(), sendSetParameterCommand(), sendSetupCommand(), sendTeardownCommand(), setupHTTPTunneling1(), and setupHTTPTunneling2().

00537                                                        {
00538   char* cmd = NULL;
00539   do {
00540     Boolean connectionIsPending = False;
00541     if (!fRequestsAwaitingConnection.isEmpty()) {
00542       // A connection is currently pending (with at least one enqueued request).  Enqueue this request also:
00543       connectionIsPending = True;
00544     } else if (fInputSocketNum < 0) { // we need to open a connection
00545       int connectResult = openConnection();
00546       if (connectResult < 0) break; // an error occurred
00547       else if (connectResult == 0) {
00548         // A connection is pending
00549         connectionIsPending = True;
00550       } // else the connection succeeded.  Continue sending the command.
00551     }
00552     if (connectionIsPending) {
00553       fRequestsAwaitingConnection.enqueue(request);
00554       return request->cseq();
00555     }
00556 
00557     // If requested (and we're not already doing it, or have done it), set up the special protocol for tunneling RTSP-over-HTTP:
00558     if (fTunnelOverHTTPPortNum != 0 && strcmp(request->commandName(), "GET") != 0 && fOutputSocketNum == fInputSocketNum) {
00559       if (!setupHTTPTunneling1()) break;
00560       fRequestsAwaitingHTTPTunneling.enqueue(request);
00561       return request->cseq();
00562     }
00563 
00564     // Construct and send the command:
00565 
00566     // First, construct command-specific headers that we need:
00567 
00568     char* cmdURL = fBaseURL; // by default
00569     Boolean cmdURLWasAllocated = False;
00570 
00571     char const* protocolStr = "RTSP/1.0"; // by default
00572 
00573     char* extraHeaders = (char*)""; // by default
00574     Boolean extraHeadersWereAllocated = False; 
00575 
00576     char* contentLengthHeader = (char*)""; // by default
00577     Boolean contentLengthHeaderWasAllocated = False;
00578 
00579     char const* contentStr = request->contentStr(); // by default
00580     if (contentStr == NULL) contentStr = "";
00581     unsigned contentStrLen = strlen(contentStr);
00582     if (contentStrLen > 0) {
00583       char const* contentLengthHeaderFmt =
00584         "Content-Length: %d\r\n";
00585       unsigned contentLengthHeaderSize = strlen(contentLengthHeaderFmt)
00586         + 20 /* max int len */;
00587       contentLengthHeader = new char[contentLengthHeaderSize];
00588       sprintf(contentLengthHeader, contentLengthHeaderFmt, contentStrLen);
00589       contentLengthHeaderWasAllocated = True;
00590     }
00591 
00592     if (strcmp(request->commandName(), "DESCRIBE") == 0) {
00593       extraHeaders = (char*)"Accept: application/sdp\r\n";
00594     } else if (strcmp(request->commandName(), "OPTIONS") == 0) {
00595     } else if (strcmp(request->commandName(), "ANNOUNCE") == 0) {
00596       extraHeaders = (char*)"Content-Type: application/sdp\r\n";
00597     } else if (strcmp(request->commandName(), "SETUP") == 0) {
00598       MediaSubsession& subsession = *request->subsession();
00599       Boolean streamUsingTCP = (request->booleanFlags()&0x1) != 0;
00600       Boolean streamOutgoing = (request->booleanFlags()&0x2) != 0;
00601       Boolean forceMulticastOnUnspecified = (request->booleanFlags()&0x4) != 0;
00602 
00603       char const *prefix, *separator, *suffix;
00604       constructSubsessionURL(subsession, prefix, separator, suffix);
00605 
00606       char const* transportFmt;
00607       if (strcmp(subsession.protocolName(), "UDP") == 0) {
00608         suffix = "";
00609         transportFmt = "Transport: RAW/RAW/UDP%s%s%s=%d-%d\r\n";
00610       } else {
00611         transportFmt = "Transport: RTP/AVP%s%s%s=%d-%d\r\n";
00612       }
00613 
00614       cmdURL = new char[strlen(prefix) + strlen(separator) + strlen(suffix) + 1];
00615       cmdURLWasAllocated = True;
00616       sprintf(cmdURL, "%s%s%s", prefix, separator, suffix);
00617 
00618       // Construct a "Transport:" header.
00619       char const* transportTypeStr;
00620       char const* modeStr = streamOutgoing ? ";mode=receive" : "";
00621           // Note: I think the above is nonstandard, but DSS wants it this way
00622       char const* portTypeStr;
00623       portNumBits rtpNumber, rtcpNumber;
00624       if (streamUsingTCP) { // streaming over the RTSP connection
00625         transportTypeStr = "/TCP;unicast";
00626         portTypeStr = ";interleaved";
00627         rtpNumber = fTCPStreamIdCount++;
00628         rtcpNumber = fTCPStreamIdCount++;
00629       } else { // normal RTP streaming
00630         unsigned connectionAddress = subsession.connectionEndpointAddress();
00631         Boolean requestMulticastStreaming
00632           = IsMulticastAddress(connectionAddress) || (connectionAddress == 0 && forceMulticastOnUnspecified);
00633         transportTypeStr = requestMulticastStreaming ? ";multicast" : ";unicast";
00634         portTypeStr = ";client_port";
00635         rtpNumber = subsession.clientPortNum();
00636         if (rtpNumber == 0) {
00637           envir().setResultMsg("Client port number unknown\n");
00638           delete[] cmdURL;
00639           break;
00640         }
00641         rtcpNumber = rtpNumber + 1;
00642       }
00643       unsigned transportSize = strlen(transportFmt)
00644         + strlen(transportTypeStr) + strlen(modeStr) + strlen(portTypeStr) + 2*5 /* max port len */;
00645       char* transportStr = new char[transportSize];
00646       sprintf(transportStr, transportFmt,
00647               transportTypeStr, modeStr, portTypeStr, rtpNumber, rtcpNumber);
00648 
00649       // When sending more than one "SETUP" request, include a "Session:" header in the 2nd and later commands:
00650       char* sessionStr = createSessionString(fLastSessionId);
00651 
00652       // The "Transport:" and "Session:" (if present) headers make up the 'extra headers':
00653       extraHeaders = new char[transportSize + strlen(sessionStr)];
00654       extraHeadersWereAllocated = True;
00655       sprintf(extraHeaders, "%s%s", transportStr, sessionStr);
00656       delete[] transportStr; delete[] sessionStr;
00657     } else if (strcmp(request->commandName(), "GET") == 0 || strcmp(request->commandName(), "POST") == 0) {
00658       // We will be sending a HTTP (not a RTSP) request.
00659       // Begin by re-parsing our RTSP URL, just to get the stream name, which we'll use as our 'cmdURL' in the subsequent request:
00660       char* username;
00661       char* password;
00662       NetAddress destAddress;
00663       portNumBits urlPortNum;
00664       if (!parseRTSPURL(envir(), fBaseURL, username, password, destAddress, urlPortNum, (char const**)&cmdURL)) break;
00665       if (cmdURL[0] == '\0') cmdURL = (char*)"/";
00666       delete[] username;
00667       delete[] password;
00668 
00669       protocolStr = "HTTP/1.0";
00670 
00671       if (strcmp(request->commandName(), "GET") == 0) {
00672         // Create a 'session cookie' string, using MD5:
00673         struct {
00674           struct timeval timestamp;
00675           unsigned counter;
00676         } seedData;
00677         gettimeofday(&seedData.timestamp, NULL);
00678         seedData.counter = ++fSessionCookieCounter;
00679         our_MD5Data((unsigned char*)(&seedData), sizeof seedData, fSessionCookie);
00680         // DSS seems to require that the 'session cookie' string be 22 bytes long:
00681         fSessionCookie[23] = '\0';
00682         
00683         char const* const extraHeadersFmt =
00684           "x-sessioncookie: %s\r\n"
00685           "Accept: application/x-rtsp-tunnelled\r\n"
00686           "Pragma: no-cache\r\n"
00687           "Cache-Control: no-cache\r\n";
00688         unsigned extraHeadersSize = strlen(extraHeadersFmt)
00689           + strlen(fSessionCookie);
00690         extraHeaders = new char[extraHeadersSize];
00691         extraHeadersWereAllocated = True;
00692         sprintf(extraHeaders, extraHeadersFmt,
00693         fSessionCookie);
00694       } else { // "POST"
00695         char const* const extraHeadersFmt =
00696           "x-sessioncookie: %s\r\n"
00697           "Content-Type: application/x-rtsp-tunnelled\r\n"
00698           "Pragma: no-cache\r\n"
00699           "Cache-Control: no-cache\r\n"
00700           "Content-Length: 32767\r\n"
00701           "Expires: Sun, 9 Jan 1972 00:00:00 GMT\r\n";
00702         unsigned extraHeadersSize = strlen(extraHeadersFmt)
00703           + strlen(fSessionCookie);
00704         extraHeaders = new char[extraHeadersSize];
00705         extraHeadersWereAllocated = True;
00706         sprintf(extraHeaders, extraHeadersFmt,
00707                 fSessionCookie);
00708       }
00709     } else { // "PLAY", "PAUSE", "TEARDOWN", "RECORD", "SET_PARAMETER", "GET_PARAMETER"
00710       // First, make sure that we have a RTSP session in progress
00711       if (fLastSessionId == NULL) {
00712         envir().setResultMsg("No RTSP session is currently in progress\n");
00713         break;
00714       }
00715 
00716       char const* sessionId;
00717       float originalScale;
00718       if (request->session() != NULL) {
00719         // Session-level operation
00720         cmdURL = (char*)sessionURL(*request->session());
00721 
00722         sessionId = fLastSessionId;
00723         originalScale = request->session()->scale();
00724       } else {
00725         // Media-level operation
00726         char const *prefix, *separator, *suffix;
00727         constructSubsessionURL(*request->subsession(), prefix, separator, suffix);
00728         cmdURL = new char[strlen(prefix) + strlen(separator) + strlen(suffix) + 1];
00729         cmdURLWasAllocated = True;
00730         sprintf(cmdURL, "%s%s%s", prefix, separator, suffix);
00731         
00732         sessionId = request->subsession()->sessionId();
00733         originalScale = request->subsession()->scale();
00734       }
00735 
00736       if (strcmp(request->commandName(), "PLAY") == 0) {
00737         // Create "Session:", "Scale:", and "Range:" headers; these make up the 'extra headers':
00738         char* sessionStr = createSessionString(sessionId);
00739         char* scaleStr = createScaleString(request->scale(), originalScale);
00740         char* rangeStr = createRangeString(request->start(), request->end(), request->absStartTime(), request->absEndTime());
00741         extraHeaders = new char[strlen(sessionStr) + strlen(scaleStr) + strlen(rangeStr) + 1];
00742         extraHeadersWereAllocated = True;
00743         sprintf(extraHeaders, "%s%s%s", sessionStr, scaleStr, rangeStr);
00744         delete[] sessionStr; delete[] scaleStr; delete[] rangeStr;
00745       } else {
00746         // Create a "Session:" header; this makes up our 'extra headers':
00747         extraHeaders = createSessionString(sessionId);
00748         extraHeadersWereAllocated = True;
00749       }
00750     }
00751 
00752     char* authenticatorStr = createAuthenticatorString(request->commandName(), fBaseURL);
00753 
00754     char const* const cmdFmt =
00755       "%s %s %s\r\n"
00756       "CSeq: %d\r\n"
00757       "%s"
00758       "%s"
00759       "%s"
00760       "%s"
00761       "\r\n"
00762       "%s";
00763     unsigned cmdSize = strlen(cmdFmt)
00764       + strlen(request->commandName()) + strlen(cmdURL) + strlen(protocolStr)
00765       + 20 /* max int len */
00766       + strlen(authenticatorStr)
00767       + fUserAgentHeaderStrLen
00768       + strlen(extraHeaders)
00769       + strlen(contentLengthHeader)
00770       + contentStrLen;
00771     cmd = new char[cmdSize];
00772     sprintf(cmd, cmdFmt,
00773             request->commandName(), cmdURL, protocolStr,
00774             request->cseq(),
00775             authenticatorStr,
00776             fUserAgentHeaderStr,
00777             extraHeaders,
00778             contentLengthHeader,
00779             contentStr);
00780     delete[] authenticatorStr;
00781     if (cmdURLWasAllocated) delete[] cmdURL;
00782     if (extraHeadersWereAllocated) delete[] extraHeaders;
00783     if (contentLengthHeaderWasAllocated) delete[] contentLengthHeader;
00784 
00785     if (fVerbosityLevel >= 1) envir() << "Sending request: " << cmd << "\n";
00786 
00787     if (fTunnelOverHTTPPortNum != 0 && strcmp(request->commandName(), "GET") != 0 && strcmp(request->commandName(), "POST") != 0) {
00788       // When we're tunneling RTSP-over-HTTP, we Base-64-encode the request before we send it.
00789       // (However, we don't do this for the HTTP "GET" and "POST" commands that we use to set up the tunnel.)
00790       char* origCmd = cmd;
00791       cmd = base64Encode(origCmd, strlen(cmd));
00792       if (fVerbosityLevel >= 1) envir() << "\tThe request was base-64 encoded to: " << cmd << "\n\n";
00793       delete[] origCmd;
00794     }
00795 
00796     if (send(fOutputSocketNum, cmd, strlen(cmd), 0) < 0) {
00797       char const* errFmt = "%s send() failed: ";
00798       unsigned const errLength = strlen(errFmt) + strlen(request->commandName());
00799       char* err = new char[errLength];
00800       sprintf(err, errFmt, request->commandName());
00801       envir().setResultErrMsg(err);
00802       delete[] err;
00803       break;
00804     }
00805 
00806     // The command send succeeded, so enqueue the request record, so that its response (when it comes) can be handled.
00807     // However, note that we do not expect a response to a POST command with RTSP-over-HTTP, so don't enqueue that.
00808     int cseq = request->cseq();
00809 
00810     if (fTunnelOverHTTPPortNum == 0 || strcmp(request->commandName(), "POST") != 0) {
00811       fRequestsAwaitingResponse.enqueue(request);
00812     } else {
00813       delete request;
00814     }
00815 
00816     delete[] cmd;
00817     return cseq;
00818   } while (0);
00819 
00820   // An error occurred, so call the response handler immediately (indicating the error):
00821   delete[] cmd;
00822   handleRequestError(request);
00823   delete request;
00824   return 0;
00825 }

Boolean RTSPClient::isRTSPClient (  )  const [private, virtual]

Reimplemented from Medium.

Definition at line 343 of file RTSPClient.cpp.

References True.

00343                                        {
00344   return True;
00345 }

void RTSPClient::resetTCPSockets (  )  [private]

Definition at line 359 of file RTSPClient.cpp.

References closeSocket, TaskScheduler::disableBackgroundHandling(), Medium::envir(), fInputSocketNum, fOutputSocketNum, and UsageEnvironment::taskScheduler().

Referenced by connectionHandler1(), handleResponseBytes(), openConnection(), reset(), and responseHandlerForHTTP_GET1().

void RTSPClient::resetResponseBuffer (  )  [private]

Definition at line 371 of file RTSPClient.cpp.

References fResponseBufferBytesLeft, fResponseBytesAlreadySeen, and responseBufferSize.

Referenced by handleResponseBytes(), reset(), and RTSPClient().

int RTSPClient::openConnection (  )  [private]

Definition at line 380 of file RTSPClient.cpp.

References connectToServer(), NetAddress::data(), Medium::envir(), fBaseURL, fCurrentAuthenticator, fInputSocketNum, fOutputSocketNum, fServerAddress, fTunnelOverHTTPPortNum, ignoreSigPipeOnSocket(), incomingDataHandler(), NULL, parseRTSPURL(), password, resetTCPSockets(), TaskScheduler::setBackgroundHandling(), setupStreamSocket(), Authenticator::setUsernameAndPassword(), SOCKET_EXCEPTION, SOCKET_READABLE, UsageEnvironment::taskScheduler(), and username.

Referenced by sendRequest().

00380                                {
00381   do {
00382     // Set up a connection to the server.  Begin by parsing the URL:
00383 
00384     char* username;
00385     char* password;
00386     NetAddress destAddress;
00387     portNumBits urlPortNum;
00388     char const* urlSuffix;
00389     if (!parseRTSPURL(envir(), fBaseURL, username, password, destAddress, urlPortNum, &urlSuffix)) break;
00390     portNumBits destPortNum = fTunnelOverHTTPPortNum == 0 ? urlPortNum : fTunnelOverHTTPPortNum;
00391     if (username != NULL || password != NULL) {
00392       fCurrentAuthenticator.setUsernameAndPassword(username, password);
00393       delete[] username;
00394       delete[] password;
00395     }
00396 
00397     // We don't yet have a TCP socket (or we used to have one, but it got closed).  Set it up now.
00398     fInputSocketNum = fOutputSocketNum = setupStreamSocket(envir(), 0);
00399     if (fInputSocketNum < 0) break;
00400     ignoreSigPipeOnSocket(fInputSocketNum); // so that servers on the same host that get killed don't also kill us
00401       
00402     // Connect to the remote endpoint:
00403     fServerAddress = *(netAddressBits*)(destAddress.data());
00404     int connectResult = connectToServer(fInputSocketNum, destPortNum);
00405     if (connectResult < 0) break;
00406     else if (connectResult > 0) {
00407       // The connection succeeded.  Arrange to handle responses to requests sent on it:
00408       envir().taskScheduler().setBackgroundHandling(fInputSocketNum, SOCKET_READABLE|SOCKET_EXCEPTION,
00409                                                     (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this);
00410     }
00411     return connectResult;
00412   } while (0);
00413   
00414   resetTCPSockets();
00415   return -1;
00416 }

int RTSPClient::connectToServer ( int  socketNum,
portNumBits  remotePortNum 
) [private]

Definition at line 418 of file RTSPClient.cpp.

References connectionHandler(), Medium::envir(), fServerAddress, fVerbosityLevel, UsageEnvironment::getErrno(), UsageEnvironment::getResultMsg(), MAKE_SOCKADDR_IN, TaskScheduler::setBackgroundHandling(), UsageEnvironment::setResultErrMsg(), SOCKET_EXCEPTION, SOCKET_WRITABLE, and UsageEnvironment::taskScheduler().

Referenced by openConnection(), and responseHandlerForHTTP_GET1().

00418                                                                         {
00419   MAKE_SOCKADDR_IN(remoteName, fServerAddress, htons(remotePortNum));
00420   if (fVerbosityLevel >= 1) {
00421     envir() << "Opening connection to " << AddressString(remoteName).val() << ", port " << remotePortNum << "...\n";
00422   }
00423   if (connect(socketNum, (struct sockaddr*) &remoteName, sizeof remoteName) != 0) {
00424     int const err = envir().getErrno();
00425     if (err == EINPROGRESS || err == EWOULDBLOCK) {
00426       // The connection is pending; we'll need to handle it later.  Wait for our socket to be 'writable', or have an exception.
00427       envir().taskScheduler().setBackgroundHandling(socketNum, SOCKET_WRITABLE|SOCKET_EXCEPTION,
00428                                                     (TaskScheduler::BackgroundHandlerProc*)&connectionHandler, this);
00429       return 0;
00430     }
00431     envir().setResultErrMsg("connect() failed: ");
00432     if (fVerbosityLevel >= 1) envir() << "..." << envir().getResultMsg() << "\n";
00433     return -1;
00434   }
00435   if (fVerbosityLevel >= 1) envir() << "...local connection opened\n";
00436 
00437   return 1;
00438 }

char * RTSPClient::createAuthenticatorString ( char const *  cmd,
char const *  url 
) [private]

Definition at line 441 of file RTSPClient.cpp.

References base64Encode(), Authenticator::computeDigestResponse(), fCurrentAuthenticator, Authenticator::nonce(), NULL, Authenticator::password(), Authenticator::realm(), Authenticator::reclaimDigestResponse(), strDup(), and Authenticator::username().

Referenced by sendRequest().

00441                                                                       {
00442   Authenticator& auth = fCurrentAuthenticator; // alias, for brevity
00443   if (auth.realm() != NULL && auth.username() != NULL && auth.password() != NULL) {
00444     // We have a filled-in authenticator, so use it:
00445     char* authenticatorStr;
00446     if (auth.nonce() != NULL) { // Digest authentication
00447       char const* const authFmt =
00448         "Authorization: Digest username=\"%s\", realm=\"%s\", "
00449         "nonce=\"%s\", uri=\"%s\", response=\"%s\"\r\n";
00450       char const* response = auth.computeDigestResponse(cmd, url);
00451       unsigned authBufSize = strlen(authFmt)
00452         + strlen(auth.username()) + strlen(auth.realm())
00453         + strlen(auth.nonce()) + strlen(url) + strlen(response);
00454       authenticatorStr = new char[authBufSize];
00455       sprintf(authenticatorStr, authFmt,
00456               auth.username(), auth.realm(),
00457               auth.nonce(), url, response);
00458       auth.reclaimDigestResponse(response);
00459     } else { // Basic authentication
00460       char const* const authFmt = "Authorization: Basic %s\r\n";
00461 
00462       unsigned usernamePasswordLength = strlen(auth.username()) + 1 + strlen(auth.password());
00463       char* usernamePassword = new char[usernamePasswordLength+1];
00464       sprintf(usernamePassword, "%s:%s", auth.username(), auth.password());
00465 
00466       char* response = base64Encode(usernamePassword, usernamePasswordLength);
00467       unsigned const authBufSize = strlen(authFmt) + strlen(response) + 1;
00468       authenticatorStr = new char[authBufSize];
00469       sprintf(authenticatorStr, authFmt, response);
00470       delete[] response; delete[] usernamePassword;
00471     }
00472 
00473     return authenticatorStr;
00474   }
00475 
00476   // We don't have a (filled-in) authenticator.
00477   return strDup("");
00478 }

void RTSPClient::handleRequestError ( RequestRecord request  )  [private]

Definition at line 827 of file RTSPClient.cpp.

References Medium::envir(), UsageEnvironment::getErrno(), RTSPClient::RequestRecord::handler(), NULL, and strDup().

Referenced by connectionHandler1(), handleResponseBytes(), responseHandlerForHTTP_GET1(), and sendRequest().

00827                                                           {
00828   int resultCode = -envir().getErrno();
00829   if (resultCode == 0) {
00830     // Choose some generic error code instead:
00831 #if defined(__WIN32__) || defined(_WIN32) || defined(_QNX4)
00832     resultCode = -WSAENOTCONN;
00833 #else
00834     resultCode = -ENOTCONN;
00835 #endif
00836   }
00837   if (request->handler() != NULL) (*request->handler())(this, resultCode, strDup(envir().getResultMsg()));
00838 }

Boolean RTSPClient::parseResponseCode ( char const *  line,
unsigned &  responseCode,
char const *&  responseString 
) [private]

Definition at line 841 of file RTSPClient.cpp.

References False, and True.

Referenced by handleResponseBytes().

00841                                                                                          {
00842   if (sscanf(line, "RTSP/%*s%u", &responseCode) != 1 &&
00843       sscanf(line, "HTTP/%*s%u", &responseCode) != 1) return False;
00844   // Note: We check for HTTP responses as well as RTSP responses, both in order to setup RTSP-over-HTTP tunneling,
00845   // and so that we get back a meaningful error if the client tried to mistakenly send a RTSP command to a HTTP-only server.
00846 
00847   // Use everything after the RTSP/* (or HTTP/*) as the response string:
00848   responseString = line;
00849   while (responseString[0] != '\0' && responseString[0] != ' '  && responseString[0] != '\t') ++responseString;
00850   while (responseString[0] != '\0' && (responseString[0] == ' '  || responseString[0] == '\t')) ++responseString; // skip whitespace
00851 
00852   return True;
00853 }

void RTSPClient::handleIncomingRequest (  )  [private]

Definition at line 855 of file RTSPClient.cpp.

References Medium::envir(), fOutputSocketNum, fResponseBuffer, fResponseBytesAlreadySeen, fVerbosityLevel, parseRTSPRequestString(), and RTSP_PARAM_STRING_MAX.

Referenced by handleResponseBytes().

00855                                        {
00856   // Parse the request string into command name and 'CSeq', then 'handle' the command (by responding that we don't support it):
00857   char cmdName[RTSP_PARAM_STRING_MAX];
00858   char urlPreSuffix[RTSP_PARAM_STRING_MAX];
00859   char urlSuffix[RTSP_PARAM_STRING_MAX];
00860   char cseq[RTSP_PARAM_STRING_MAX];
00861   char sessionId[RTSP_PARAM_STRING_MAX];
00862   unsigned contentLength;
00863   if (!parseRTSPRequestString(fResponseBuffer, fResponseBytesAlreadySeen,
00864                               cmdName, sizeof cmdName,
00865                               urlPreSuffix, sizeof urlPreSuffix,
00866                               urlSuffix, sizeof urlSuffix,
00867                               cseq, sizeof cseq,
00868                               sessionId, sizeof sessionId,
00869                               contentLength)) {
00870     return;
00871   } else {
00872     if (fVerbosityLevel >= 1) {
00873       envir() << "Received incoming RTSP request: " << fResponseBuffer << "\n";
00874     }
00875     char tmpBuf[2*RTSP_PARAM_STRING_MAX];
00876     snprintf((char*)tmpBuf, sizeof tmpBuf,
00877              "RTSP/1.0 405 Method Not Allowed\r\nCSeq: %s\r\n\r\n", cseq);
00878     send(fOutputSocketNum, tmpBuf, strlen(tmpBuf), 0);
00879   }
00880 }

Boolean RTSPClient::checkForHeader ( char const *  line,
char const *  headerName,
unsigned  headerNameLength,
char const *&  headerParams 
) [static, private]

Definition at line 882 of file RTSPClient.cpp.

References _strncasecmp, False, and True.

Referenced by handleResponseBytes().

00882                                                                                                                                  {
00883   if (_strncasecmp(line, headerName, headerNameLength) != 0) return False;
00884 
00885   // The line begins with the desired header name.  Trim off any whitespace, and return the header parameters:
00886   unsigned paramIndex = headerNameLength;
00887   while (line[paramIndex] != '\0' && (line[paramIndex] == ' ' || line[paramIndex] == '\t')) ++paramIndex;
00888   if (&line[paramIndex] == '\0') return False; // the header is assumed to be bad if it has no parameters
00889 
00890   headerParams = &line[paramIndex];
00891   return True;
00892 }

Boolean RTSPClient::parseTransportParams ( char const *  paramsStr,
char *&  serverAddressStr,
portNumBits serverPortNum,
unsigned char &  rtpChannelId,
unsigned char &  rtcpChannelId 
) [private]

Definition at line 894 of file RTSPClient.cpp.

References _strncasecmp, False, NULL, strDup(), strDupSize(), and True.

Referenced by handleSETUPResponse().

00896                                                                                                     {
00897   // Initialize the return parameters to 'not found' values:
00898   serverAddressStr = NULL;
00899   serverPortNum = 0;
00900   rtpChannelId = rtcpChannelId = 0xFF;
00901   if (paramsStr == NULL) return False;  
00902 
00903   char* foundServerAddressStr = NULL;
00904   Boolean foundServerPortNum = False;
00905   portNumBits clientPortNum = 0;
00906   Boolean foundClientPortNum = False;
00907   Boolean foundChannelIds = False;
00908   unsigned rtpCid, rtcpCid;
00909   Boolean isMulticast = True; // by default
00910   char* foundDestinationStr = NULL;
00911   portNumBits multicastPortNumRTP, multicastPortNumRTCP;
00912   Boolean foundMulticastPortNum = False;
00913 
00914   // Run through each of the parameters, looking for ones that we handle:
00915   char const* fields = paramsStr;
00916   char* field = strDupSize(fields);
00917   while (sscanf(fields, "%[^;]", field) == 1) {
00918     if (sscanf(field, "server_port=%hu", &serverPortNum) == 1) {
00919       foundServerPortNum = True;
00920     } else if (sscanf(field, "client_port=%hu", &clientPortNum) == 1) {
00921       foundClientPortNum = True;
00922     } else if (_strncasecmp(field, "source=", 7) == 0) {
00923       delete[] foundServerAddressStr;
00924       foundServerAddressStr = strDup(field+7);
00925     } else if (sscanf(field, "interleaved=%u-%u", &rtpCid, &rtcpCid) == 2) {
00926       rtpChannelId = (unsigned char)rtpCid;
00927       rtcpChannelId = (unsigned char)rtcpCid;
00928       foundChannelIds = True;
00929     } else if (strcmp(field, "unicast") == 0) {
00930       isMulticast = False;
00931     } else if (_strncasecmp(field, "destination=", 12) == 0) {
00932       delete[] foundDestinationStr;
00933       foundDestinationStr = strDup(field+12);
00934     } else if (sscanf(field, "port=%hu-%hu", &multicastPortNumRTP, &multicastPortNumRTCP) == 2 ||
00935                sscanf(field, "port=%hu", &multicastPortNumRTP) == 1) {
00936       foundMulticastPortNum = True;
00937     }
00938 
00939     fields += strlen(field);
00940     while (fields[0] == ';') ++fields; // skip over all leading ';' chars
00941     if (fields[0] == '\0') break;
00942   }
00943   delete[] field;
00944 
00945   // If we're multicast, and have a "destination=" (multicast) address, then use this
00946   // as the 'server' address (because some weird servers don't specify the multicast
00947   // address earlier, in the "DESCRIBE" response's SDP:
00948   if (isMulticast && foundDestinationStr != NULL && foundMulticastPortNum) {
00949     delete[] foundServerAddressStr;
00950     serverAddressStr = foundDestinationStr;
00951     serverPortNum = multicastPortNumRTP;
00952     return True;
00953   }
00954   delete[] foundDestinationStr;
00955 
00956   // We have a valid "Transport:" header if any of the following are true:
00957   //   - We saw a "interleaved=" field, indicating RTP/RTCP-over-TCP streaming, or
00958   //   - We saw a "server_port=" field, or
00959   //   - We saw a "client_port=" field.
00960   //     If we didn't also see a "server_port=" field, then the server port is assumed to be the same as the client port.
00961   if (foundChannelIds || foundServerPortNum || foundClientPortNum) {
00962     if (foundClientPortNum && !foundServerPortNum) {
00963       serverPortNum = clientPortNum;
00964     }
00965     serverAddressStr = foundServerAddressStr;
00966     return True;
00967   }
00968 
00969   delete[] foundServerAddressStr;
00970   return False;
00971 }

Boolean RTSPClient::parseScaleParam ( char const *  paramStr,
float &  scale 
) [private]

Definition at line 973 of file RTSPClient.cpp.

References Numeric.

Referenced by handlePLAYResponse().

00973                                                                       {
00974   Locale l("C", Numeric);
00975   return sscanf(paramStr, "%f", &scale) == 1;
00976 }

Boolean RTSPClient::parseRTPInfoParams ( char const *&  paramStr,
u_int16_t &  seqNum,
u_int32_t &  timestamp 
) [private]

Definition at line 978 of file RTSPClient.cpp.

References False, NULL, strDupSize(), and True.

Referenced by handlePLAYResponse().

00978                                                                                                       {
00979   if (paramsStr == NULL || paramsStr[0] == '\0') return False;
00980   while (paramsStr[0] == ',') ++paramsStr;
00981 
00982   // "paramsStr" now consists of a ';'-separated list of parameters, ending with ',' or '\0'.
00983   char* field = strDupSize(paramsStr);
00984 
00985   Boolean sawSeq = False, sawRtptime = False;
00986   while (sscanf(paramsStr, "%[^;,]", field) == 1) {
00987     if (sscanf(field, "seq=%hu", &seqNum) == 1) {
00988       sawSeq = True;
00989     } else if (sscanf(field, "rtptime=%u", &timestamp) == 1) {
00990       sawRtptime = True;
00991     }
00992 
00993     paramsStr += strlen(field);
00994     if (paramsStr[0] == '\0' || paramsStr[0] == ',') break;
00995     // ASSERT: paramsStr[0] == ';'
00996     ++paramsStr; // skip over the ';'
00997   }
00998 
00999   delete[] field;
01000   // For the "RTP-Info:" parameters to be useful to us, we need to have seen both the "seq=" and "rtptime=" parameters:
01001   return sawSeq && sawRtptime;
01002 }

Boolean RTSPClient::handleSETUPResponse ( MediaSubsession subsession,
char const *  sessionParamsStr,
char const *  transportParamsStr,
Boolean  streamUsingTCP 
) [private]

Definition at line 1004 of file RTSPClient.cpp.

References MediaSubsession::connectionEndpointAddress(), MediaSubsession::connectionEndpointName(), RTPSource::enableRTCPReports(), Medium::envir(), False, fInputSocketNum, fLastSessionId, fServerAddress, fSessionTimeoutParameter, handleAlternativeRequestByte(), NULL, Groupsock::output(), parseTransportParams(), responseBufferSize, MediaSubsession::rtcpChannelId, RTCPInstance::RTCPgs(), MediaSubsession::rtcpInstance(), MediaSubsession::rtpChannelId, RTPSource::RTPgs(), MediaSubsession::rtpSource(), MediaSubsession::serverPortNum, MediaSubsession::setDestinations(), UsageEnvironment::setResultMsg(), RTPSource::setServerRequestAlternativeByteHandler(), MediaSubsession::setSessionId(), RTCPInstance::setStreamSocket(), RTPSource::setStreamSocket(), strDup(), subsession, and True.

Referenced by handleResponseBytes().

01005                                                                 {
01006   char* sessionId = new char[responseBufferSize]; // ensures we have enough space
01007   Boolean success = False;
01008   do {
01009     // Check for a session id:
01010     if (sessionParamsStr == NULL || sscanf(sessionParamsStr, "%[^;]", sessionId) != 1) {
01011       envir().setResultMsg("Missing or bad \"Session:\" header");
01012       break;
01013     }
01014     subsession.setSessionId(sessionId);
01015     delete[] fLastSessionId; fLastSessionId = strDup(sessionId);
01016 
01017     // Also look for an optional "; timeout = " parameter following this:
01018     char const* afterSessionId = sessionParamsStr + strlen(sessionId);
01019     int timeoutVal;
01020     if (sscanf(afterSessionId, "; timeout = %d", &timeoutVal) == 1) {
01021       fSessionTimeoutParameter = timeoutVal;
01022     }
01023 
01024     // Parse the "Transport:" header parameters:
01025     char* serverAddressStr;
01026     portNumBits serverPortNum;
01027     unsigned char rtpChannelId, rtcpChannelId;
01028     if (!parseTransportParams(transportParamsStr, serverAddressStr, serverPortNum, rtpChannelId, rtcpChannelId)) {
01029       envir().setResultMsg("Missing or bad \"Transport:\" header");
01030       break;
01031     }
01032     delete[] subsession.connectionEndpointName();
01033     subsession.connectionEndpointName() = serverAddressStr;
01034     subsession.serverPortNum = serverPortNum;
01035     subsession.rtpChannelId = rtpChannelId;
01036     subsession.rtcpChannelId = rtcpChannelId;
01037 
01038     if (streamUsingTCP) {
01039       // Tell the subsession to receive RTP (and send/receive RTCP) over the RTSP stream:
01040       if (subsession.rtpSource() != NULL) {
01041         subsession.rtpSource()->setStreamSocket(fInputSocketNum, subsession.rtpChannelId);
01042         subsession.rtpSource()->setServerRequestAlternativeByteHandler(fInputSocketNum, handleAlternativeRequestByte, this);
01043         subsession.rtpSource()->enableRTCPReports() = False;
01044           // To avoid confusing the server (which won't start handling RTP/RTCP-over-TCP until "PLAY"), don't send RTCP "RR"s yet
01045       }
01046       if (subsession.rtcpInstance() != NULL) subsession.rtcpInstance()->setStreamSocket(fInputSocketNum, subsession.rtcpChannelId);
01047     } else {
01048       // Normal case.
01049       // Set the RTP and RTCP sockets' destination address and port from the information in the SETUP response (if present):
01050       netAddressBits destAddress = subsession.connectionEndpointAddress();
01051       if (destAddress == 0) destAddress = fServerAddress;
01052       subsession.setDestinations(destAddress);
01053 
01054       // Hack: To increase the likelihood of UDP packets from the server reaching us, if we're behind a NAT, send a few 'dummy'
01055       // UDP packets to the server now.  (We do this on both our RTP port and our RTCP port.)
01056       Groupsock* gs1 = NULL; Groupsock* gs2 = NULL;
01057       if (subsession.rtpSource() != NULL) gs1 = subsession.rtpSource()->RTPgs();
01058       if (subsession.rtcpInstance() != NULL) gs2 = subsession.rtcpInstance()->RTCPgs();
01059       u_int32_t const dummy = 0xFEEDFACE;
01060       unsigned const numDummyPackets = 2;
01061       for (unsigned i = 0; i < numDummyPackets; ++i) {
01062         if (gs1 != NULL) gs1->output(envir(), 255, (unsigned char*)&dummy, sizeof dummy);
01063         if (gs2 != NULL) gs2->output(envir(), 255, (unsigned char*)&dummy, sizeof dummy);
01064       }
01065     }
01066 
01067     success = True;
01068   } while (0);
01069 
01070   delete[] sessionId;
01071   return success;
01072 }

Boolean RTSPClient::handlePLAYResponse ( MediaSession session,
MediaSubsession subsession,
char const *  scaleParamsStr,
char const *  rangeParamsStr,
char const *  rtpInfoParamsStr 
) [private]

Definition at line 1074 of file RTSPClient.cpp.

References MediaSubsession::_absEndTime(), MediaSession::_absEndTime(), MediaSubsession::_absStartTime(), MediaSession::_absStartTime(), MediaSubsession::_playEndTime(), MediaSubsession::_playStartTime(), RTPSource::enableRTCPReports(), Medium::envir(), False, MediaSubsession::infoIsNew, iter, MediaSubsessionIterator::next(), NULL, parseRangeParam(), parseRTPInfoParams(), parseScaleParam(), MediaSession::playEndTime(), MediaSession::playStartTime(), MediaSubsession::rtpInfo, MediaSubsession::rtpSource(), MediaSubsession::scale(), MediaSession::scale(), MediaSubsession::seqNum, session, UsageEnvironment::setResultMsg(), subsession, MediaSubsession::timestamp, and True.

Referenced by handleResponseBytes().

01075                                                                                                                              {
01076   Boolean scaleOK = False, rangeOK = False;
01077   do {
01078     if (&session != NULL) {
01079       // The command was on the whole session
01080       if (scaleParamsStr != NULL && !parseScaleParam(scaleParamsStr, session.scale())) break;
01081       scaleOK = True;
01082       if (rangeParamsStr != NULL && !parseRangeParam(rangeParamsStr, session.playStartTime(), session.playEndTime(),
01083                                                      session._absStartTime(), session._absEndTime())) break;
01084       rangeOK = True;
01085 
01086       MediaSubsessionIterator iter(session);
01087       MediaSubsession* subsession;
01088       while ((subsession = iter.next()) != NULL) {
01089         u_int16_t seqNum; u_int32_t timestamp;
01090         subsession->rtpInfo.infoIsNew = False;
01091         if (parseRTPInfoParams(rtpInfoParamsStr, seqNum, timestamp)) {
01092           subsession->rtpInfo.seqNum = seqNum;
01093           subsession->rtpInfo.timestamp = timestamp;
01094           subsession->rtpInfo.infoIsNew = True;
01095         }
01096 
01097         if (subsession->rtpSource() != NULL) subsession->rtpSource()->enableRTCPReports() = True; // start sending RTCP "RR"s now
01098       }
01099     } else {
01100       // The command was on a subsession
01101       if (scaleParamsStr != NULL && !parseScaleParam(scaleParamsStr, subsession.scale())) break;
01102       scaleOK = True;
01103       if (rangeParamsStr != NULL && !parseRangeParam(rangeParamsStr, subsession._playStartTime(), subsession._playEndTime(),
01104                                                      subsession._absStartTime(), subsession._absEndTime())) break;
01105       rangeOK = True;
01106 
01107       u_int16_t seqNum; u_int32_t timestamp;
01108       subsession.rtpInfo.infoIsNew = False;
01109       if (parseRTPInfoParams(rtpInfoParamsStr, seqNum, timestamp)) {
01110         subsession.rtpInfo.seqNum = seqNum;
01111         subsession.rtpInfo.timestamp = timestamp;
01112         subsession.rtpInfo.infoIsNew = True;
01113       }
01114 
01115       if (subsession.rtpSource() != NULL) subsession.rtpSource()->enableRTCPReports() = True; // start sending RTCP "RR"s now
01116     }
01117 
01118     return True;
01119   } while (0);
01120 
01121   // An error occurred:
01122   if (!scaleOK) {
01123     envir().setResultMsg("Bad \"Scale:\" header");
01124   } else if (!rangeOK) {
01125     envir().setResultMsg("Bad \"Range:\" header");
01126   } else {
01127     envir().setResultMsg("Bad \"RTP-Info:\" header");
01128   }
01129   return False;
01130 }

Boolean RTSPClient::handleTEARDOWNResponse ( MediaSession session,
MediaSubsession subsession 
) [private]

Definition at line 1132 of file RTSPClient.cpp.

References True.

Referenced by handleResponseBytes().

01132                                                                                                      {
01133   // Because we don't expect to always get a response to "TEARDOWN", we don't need to do anything if we do get one:
01134   return True;
01135 }

Boolean RTSPClient::handleGET_PARAMETERResponse ( char const *  parameterName,
char *&  resultValueString 
) [private]

Definition at line 1137 of file RTSPClient.cpp.

References _strncasecmp, Medium::envir(), False, NULL, UsageEnvironment::setResultMsg(), and True.

Referenced by handleResponseBytes().

01137                                                                                                    {
01138   do {
01139     // If "parameterName" is non-empty, it may be (possibly followed by ':' and whitespace) at the start of the result string:
01140     if (parameterName != NULL && parameterName[0] != '\0') {
01141       if (parameterName[1] == '\0') break; // sanity check; there should have been \r\n at the end of "parameterName"
01142 
01143       unsigned parameterNameLen = strlen(parameterName);
01144       // ASSERT: parameterNameLen >= 2;
01145       parameterNameLen -= 2; // because of the trailing \r\n
01146       if (_strncasecmp(resultValueString, parameterName, parameterNameLen) == 0) {
01147         resultValueString += parameterNameLen;
01148         if (resultValueString[0] == ':') ++resultValueString;
01149         while (resultValueString[0] == ' ' || resultValueString[0] == '\t') ++resultValueString;
01150       }
01151     }
01152 
01153     // The rest of "resultValueStr" should be our desired result, but first trim off any \r and/or \n characters at the end:
01154     unsigned resultLen = strlen(resultValueString);
01155     while (resultLen > 0 && (resultValueString[resultLen-1] == '\r' || resultValueString[resultLen-1] == '\n')) --resultLen;
01156     resultValueString[resultLen] = '\0';
01157 
01158     return True;
01159   } while (0);
01160 
01161   // An error occurred:
01162   envir().setResultMsg("Bad \"GET_PARAMETER\" response");
01163   return False;
01164 }

Boolean RTSPClient::handleAuthenticationFailure ( char const *  wwwAuthenticateParamsStr  )  [private]

Definition at line 1166 of file RTSPClient.cpp.

References False, fCurrentAuthenticator, NULL, Authenticator::password(), Authenticator::realm(), Authenticator::setRealmAndNonce(), strDupSize(), True, and Authenticator::username().

Referenced by handleResponseBytes().

01166                                                                      {
01167   if (paramsStr == NULL) return False; // There was no "WWW-Authenticate:" header; we can't proceed.
01168 
01169   // Fill in "fCurrentAuthenticator" with the information from the "WWW-Authenticate:" header:
01170   Boolean alreadyHadRealm = fCurrentAuthenticator.realm() != NULL;
01171   char* realm = strDupSize(paramsStr);
01172   char* nonce = strDupSize(paramsStr);
01173   Boolean success = True;
01174   if (sscanf(paramsStr, "Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"", realm, nonce) == 2) {
01175     fCurrentAuthenticator.setRealmAndNonce(realm, nonce);
01176   } else if (sscanf(paramsStr, "Basic realm=\"%[^\"]\"", realm) == 1) {
01177     fCurrentAuthenticator.setRealmAndNonce(realm, NULL); // Basic authentication
01178   } else {
01179     success = False; // bad "WWW-Authenticate:" header
01180   }
01181   delete[] realm; delete[] nonce;
01182 
01183   if (alreadyHadRealm || fCurrentAuthenticator.username() == NULL || fCurrentAuthenticator.password() == NULL) {
01184     // We already had a 'realm', or don't have a username and/or password,
01185     // so the new "WWW-Authenticate:" header information won't help us.  We remain unauthenticated.
01186     success = False;
01187   }
01188 
01189   return success;
01190 }

Boolean RTSPClient::resendCommand ( RequestRecord request  )  [private]

Definition at line 1192 of file RTSPClient.cpp.

References RTSPClient::RequestRecord::commandName(), RTSPClient::RequestRecord::cseq(), Medium::envir(), fCSeq, fVerbosityLevel, NULL, and sendRequest().

Referenced by handleResponseBytes().

01192                                                         {
01193   if (fVerbosityLevel >= 1) envir() << "Resending...\n";
01194   if (request != NULL && strcmp(request->commandName(), "GET") != 0) request->cseq() = ++fCSeq;
01195   return sendRequest(request) != 0;
01196 }

char const * RTSPClient::sessionURL ( MediaSession const &  session  )  const [private]

Definition at line 1198 of file RTSPClient.cpp.

References MediaSession::controlPath(), fBaseURL, NULL, session, and url().

Referenced by constructSubsessionURL(), and sendRequest().

01198                                                                     {
01199   char const* url = session.controlPath();
01200   if (url == NULL || strcmp(url, "*") == 0) url = fBaseURL;
01201 
01202   return url;
01203 }

void RTSPClient::handleAlternativeRequestByte ( void *  ,
u_int8_t  requestByte 
) [static, private]

Definition at line 1205 of file RTSPClient.cpp.

Referenced by handleSETUPResponse().

01205                                                                                     {
01206   ((RTSPClient*)rtspClient)->handleAlternativeRequestByte1(requestByte);
01207 }

void RTSPClient::handleAlternativeRequestByte1 ( u_int8_t  requestByte  )  [private]

Definition at line 1209 of file RTSPClient.cpp.

References Medium::envir(), fInputSocketNum, fResponseBuffer, fResponseBytesAlreadySeen, handleResponseBytes(), incomingDataHandler(), TaskScheduler::setBackgroundHandling(), SOCKET_EXCEPTION, SOCKET_READABLE, and UsageEnvironment::taskScheduler().

01209                                                                    {
01210   if (requestByte == 0xFF) {
01211     // Hack: The new handler of the input TCP socket encountered an error reading it.  Indicate this:
01212     handleResponseBytes(-1);
01213   } else if (requestByte == 0xFE) {
01214     // Another hack: The new handler of the input TCP socket no longer needs it, so take back control:
01215     envir().taskScheduler().setBackgroundHandling(fInputSocketNum, SOCKET_READABLE|SOCKET_EXCEPTION,
01216                                                   (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this);
01217   } else {
01218     // Normal case:
01219     fResponseBuffer[fResponseBytesAlreadySeen] = requestByte;
01220     handleResponseBytes(1);
01221   }
01222 }

void RTSPClient::constructSubsessionURL ( MediaSubsession const &  subsession,
char const *&  prefix,
char const *&  separator,
char const *&  suffix 
) [private]

Definition at line 1235 of file RTSPClient.cpp.

References MediaSubsession::controlPath(), isAbsoluteURL(), NULL, MediaSubsession::parentSession(), sessionURL(), and subsession.

Referenced by sendRequest().

01238                                                              {
01239   // Figure out what the URL describing "subsession" will look like.
01240   // The URL is returned in three parts: prefix; separator; suffix
01241   //##### NOTE: This code doesn't really do the right thing if "sessionURL()"
01242   // doesn't end with a "/", and "subsession.controlPath()" is relative.
01243   // The right thing would have been to truncate "sessionURL()" back to the
01244   // rightmost "/", and then add "subsession.controlPath()".
01245   // In practice, though, each "DESCRIBE" response typically contains
01246   // a "Content-Base:" header that consists of "sessionURL()" followed by
01247   // a "/", in which case this code ends up giving the correct result.
01248   // However, we should really fix this code to do the right thing, and
01249   // also check for and use the "Content-Base:" header appropriately. #####
01250   prefix = sessionURL(subsession.parentSession());
01251   if (prefix == NULL) prefix = "";
01252 
01253   suffix = subsession.controlPath();
01254   if (suffix == NULL) suffix = "";
01255 
01256   if (isAbsoluteURL(suffix)) {
01257     prefix = separator = "";
01258   } else {
01259     unsigned prefixLen = strlen(prefix);
01260     separator = (prefixLen == 0 || prefix[prefixLen-1] == '/' || suffix[0] == '/') ? "" : "/";
01261   }
01262 }

Boolean RTSPClient::setupHTTPTunneling1 (  )  [private]

Definition at line 1264 of file RTSPClient.cpp.

References Medium::envir(), fTunnelOverHTTPPortNum, fVerbosityLevel, responseHandlerForHTTP_GET(), and sendRequest().

Referenced by sendRequest().

01264                                         {
01265   // Set up RTSP-over-HTTP tunneling, as described in
01266   //     http://developer.apple.com/quicktime/icefloe/dispatch028.html and http://images.apple.com/br/quicktime/pdf/QTSS_Modules.pdf
01267   if (fVerbosityLevel >= 1) {
01268     envir() << "Requesting RTSP-over-HTTP tunneling (on port " << fTunnelOverHTTPPortNum << ")\n\n";
01269   }
01270 
01271   // Begin by sending a HTTP "GET", to set up the server->client link.  Continue when we handle the response:
01272   return sendRequest(new RequestRecord(1, "GET", responseHandlerForHTTP_GET)) != 0;
01273 }

void RTSPClient::responseHandlerForHTTP_GET ( RTSPClient rtspClient,
int  responseCode,
char *  responseString 
) [static, private]

Definition at line 1275 of file RTSPClient.cpp.

References NULL, and responseHandlerForHTTP_GET1().

Referenced by setupHTTPTunneling1().

01275                                                                                                           {
01276   if (rtspClient != NULL) rtspClient->responseHandlerForHTTP_GET1(responseCode, responseString);
01277 }

void RTSPClient::responseHandlerForHTTP_GET1 ( int  responseCode,
char *  responseString 
) [private]

Definition at line 1279 of file RTSPClient.cpp.

References connectToServer(), RTSPClient::RequestQueue::dequeue(), RTSPClient::RequestQueue::enqueue(), Medium::envir(), False, fHTTPTunnelingConnectionIsPending, fOutputSocketNum, fRequestsAwaitingConnection, fRequestsAwaitingHTTPTunneling, fTunnelOverHTTPPortNum, handleRequestError(), ignoreSigPipeOnSocket(), NULL, resetTCPSockets(), sendRequest(), setupHTTPTunneling2(), setupStreamSocket(), and True.

Referenced by responseHandlerForHTTP_GET().

01279                                                                                    {
01280   RequestRecord* request;
01281   do {
01282     if (responseCode != 0) break; // The HTTP "GET" failed.
01283 
01284     // Having successfully set up (using the HTTP "GET" command) the server->client link, set up a second TCP connection
01285     // (to the same server & port as before) for the client->server link.  All future output will be to this new socket.
01286     fOutputSocketNum = setupStreamSocket(envir(), 0);
01287     if (fOutputSocketNum < 0) break;
01288     ignoreSigPipeOnSocket(fOutputSocketNum); // so that servers on the same host that killed don't also kill us
01289 
01290     fHTTPTunnelingConnectionIsPending = True;
01291     int connectResult = connectToServer(fOutputSocketNum, fTunnelOverHTTPPortNum);
01292     if (connectResult < 0) break; // an error occurred
01293     else if (connectResult == 0) {
01294       // A connection is pending.  Continue setting up RTSP-over-HTTP when the connection completes.
01295       // First, move the pending requests to the 'awaiting connection' queue:
01296       while ((request = fRequestsAwaitingHTTPTunneling.dequeue()) != NULL) {
01297         fRequestsAwaitingConnection.enqueue(request);
01298       }
01299       return;
01300     }
01301 
01302     // The connection succeeded.  Continue setting up RTSP-over-HTTP:
01303     if (!setupHTTPTunneling2()) break;
01304 
01305     // RTSP-over-HTTP tunneling succeeded.  Resume the pending request(s):
01306     while ((request = fRequestsAwaitingHTTPTunneling.dequeue()) != NULL) {
01307       sendRequest(request);
01308     }
01309     return;
01310   } while (0);
01311 
01312   // An error occurred.  Dequeue the pending request(s), and tell them about the error:
01313   fHTTPTunnelingConnectionIsPending = False;
01314   resetTCPSockets(); // do this now, in case an error handler deletes "this"
01315   RequestQueue requestQueue(fRequestsAwaitingHTTPTunneling);
01316   while ((request = requestQueue.dequeue()) != NULL) {
01317     handleRequestError(request);
01318     delete request;
01319   }
01320 }

Boolean RTSPClient::setupHTTPTunneling2 (  )  [private]

Definition at line 1322 of file RTSPClient.cpp.

References False, fHTTPTunnelingConnectionIsPending, NULL, and sendRequest().

Referenced by connectionHandler1(), and responseHandlerForHTTP_GET1().

01322                                         {
01323   fHTTPTunnelingConnectionIsPending = False;
01324 
01325   // Send a HTTP "POST", to set up the client->server link.  (Note that we won't see a reply to the "POST".)
01326   return sendRequest(new RequestRecord(1, "POST", NULL)) != 0;
01327 }

void RTSPClient::connectionHandler ( void *  ,
int   
) [static, private]

Definition at line 1329 of file RTSPClient.cpp.

References connectionHandler1().

Referenced by connectToServer().

01329                                                                {
01330   RTSPClient* client = (RTSPClient*)instance;
01331   client->connectionHandler1();
01332 }

void RTSPClient::connectionHandler1 (  )  [private]

Definition at line 1334 of file RTSPClient.cpp.

References RTSPClient::RequestQueue::dequeue(), TaskScheduler::disableBackgroundHandling(), Medium::envir(), fHTTPTunnelingConnectionIsPending, fInputSocketNum, fOutputSocketNum, fRequestsAwaitingConnection, fVerbosityLevel, UsageEnvironment::getResultMsg(), handleRequestError(), incomingDataHandler(), NULL, resetTCPSockets(), sendRequest(), TaskScheduler::setBackgroundHandling(), UsageEnvironment::setResultErrMsg(), setupHTTPTunneling2(), SOCKET_EXCEPTION, SOCKET_READABLE, SOCKLEN_T, and UsageEnvironment::taskScheduler().

Referenced by connectionHandler().

01334                                     {
01335   // Restore normal handling on our sockets:
01336   envir().taskScheduler().disableBackgroundHandling(fOutputSocketNum);
01337   envir().taskScheduler().setBackgroundHandling(fInputSocketNum, SOCKET_READABLE|SOCKET_EXCEPTION,
01338                                                 (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this);
01339 
01340   // Move all requests awaiting connection into a new, temporary queue, to clear "fRequestsAwaitingConnection"
01341   // (so that "sendRequest()" doesn't get confused by "fRequestsAwaitingConnection" being nonempty, and enqueue them all over again).
01342   RequestQueue tmpRequestQueue(fRequestsAwaitingConnection);
01343   RequestRecord* request;
01344 
01345   // Find out whether the connection succeeded or failed:
01346   do {
01347     int err = 0;
01348     SOCKLEN_T len = sizeof err;
01349     if (getsockopt(fInputSocketNum, SOL_SOCKET, SO_ERROR, (char*)&err, &len) < 0 || err != 0) {
01350       envir().setResultErrMsg("Connection to server failed: ", err);
01351       if (fVerbosityLevel >= 1) envir() << "..." << envir().getResultMsg() << "\n";
01352       break;
01353     }
01354 
01355     // The connection succeeded.  If the connection came about from an attempt to set up RTSP-over-HTTP, finish this now:
01356     if (fVerbosityLevel >= 1) envir() << "...remote connection opened\n";
01357     if (fHTTPTunnelingConnectionIsPending && !setupHTTPTunneling2()) break;
01358 
01359     // Resume sending all pending requests:
01360     while ((request = tmpRequestQueue.dequeue()) != NULL) {
01361       sendRequest(request);
01362     }
01363     return;
01364   } while (0);
01365 
01366   // An error occurred.  Tell all pending requests about the error:
01367   resetTCPSockets(); // do this now, in case an error handler deletes "this"
01368   while ((request = tmpRequestQueue.dequeue()) != NULL) {
01369     handleRequestError(request);
01370     delete request;
01371   }
01372 }

void RTSPClient::incomingDataHandler ( void *  ,
int   
) [static, private]

Definition at line 1374 of file RTSPClient.cpp.

References incomingDataHandler1().

Referenced by connectionHandler1(), handleAlternativeRequestByte1(), openConnection(), and RTSPClient().

01374                                                                  {
01375   RTSPClient* client = (RTSPClient*)instance;
01376   client->incomingDataHandler1();
01377 }

void RTSPClient::incomingDataHandler1 (  )  [private]

Definition at line 1379 of file RTSPClient.cpp.

References Medium::envir(), fInputSocketNum, fResponseBuffer, fResponseBufferBytesLeft, fResponseBytesAlreadySeen, handleResponseBytes(), and readSocket().

Referenced by incomingDataHandler().

01379                                       {
01380   struct sockaddr_in dummy; // 'from' address - not used
01381 
01382   int bytesRead = readSocket(envir(), fInputSocketNum, (unsigned char*)&fResponseBuffer[fResponseBytesAlreadySeen], fResponseBufferBytesLeft, dummy);
01383   handleResponseBytes(bytesRead);
01384 }

void RTSPClient::handleResponseBytes ( int  newBytesRead  )  [private]

Definition at line 1405 of file RTSPClient.cpp.

References _strncasecmp, RTSPClient::RequestRecord::booleanFlags(), checkForHeader(), RTSPClient::RequestRecord::commandName(), RTSPClient::RequestRecord::contentStr(), RTSPClient::RequestRecord::cseq(), RTSPClient::RequestQueue::dequeue(), Medium::envir(), False, fRequestsAwaitingResponse, fResponseBuffer, fResponseBufferBytesLeft, fResponseBytesAlreadySeen, fVerbosityLevel, getLine(), handleAuthenticationFailure(), handleGET_PARAMETERResponse(), handleIncomingRequest(), handlePLAYResponse(), RTSPClient::RequestRecord::handler(), handleRequestError(), handleSETUPResponse(), handleTEARDOWNResponse(), NULL, parseResponseCode(), RTSPClient::RequestQueue::putAtHead(), resendCommand(), resetResponseBuffer(), resetTCPSockets(), responseBufferSize, RTSPClient::RequestRecord::session(), setBaseURL(), UsageEnvironment::setResultMsg(), strDup(), RTSPClient::RequestRecord::subsession(), and True.

Referenced by handleAlternativeRequestByte1(), and incomingDataHandler1().

01405                                                      {
01406   do {
01407     if (newBytesRead >= 0 && (unsigned)newBytesRead < fResponseBufferBytesLeft) break; // data was read OK; process it below
01408 
01409     if (newBytesRead >= (int)fResponseBufferBytesLeft) {
01410       // We filled up our response buffer.  Treat this as an error (for the first response handler):
01411       envir().setResultMsg("RTSP response was truncated. Increase \"RTSPClient::responseBufferSize\"");
01412     }
01413 
01414     // An error occurred while reading our TCP socket.  Call all pending response handlers, indicating this error.
01415     // (However, the "RTSP response was truncated" error is applied to the first response handler only.)
01416     resetResponseBuffer();
01417     RequestRecord* request;
01418     if (newBytesRead > 0) { // The "RTSP response was truncated" error
01419       if ((request = fRequestsAwaitingResponse.dequeue()) != NULL) {
01420         handleRequestError(request);
01421         delete request;
01422       }
01423     } else {
01424       RequestQueue requestQueue(fRequestsAwaitingResponse);
01425       resetTCPSockets(); // do this now, in case an error handler deletes "this"
01426 
01427       while ((request = requestQueue.dequeue()) != NULL) {
01428         handleRequestError(request);
01429         delete request;
01430       }
01431     }
01432     return;
01433   } while (0);
01434 
01435   fResponseBufferBytesLeft -= newBytesRead;
01436   fResponseBytesAlreadySeen += newBytesRead;
01437   fResponseBuffer[fResponseBytesAlreadySeen] = '\0';
01438   if (fVerbosityLevel >= 1 && newBytesRead > 1) envir() << "Received " << newBytesRead << " new bytes of response data.\n";
01439   
01440   unsigned numExtraBytesAfterResponse = 0;
01441   Boolean responseSuccess = False; // by default
01442   do {
01443     // Data was read OK.  Look through the data that we've read so far, to see if it contains <CR><LF><CR><LF>.
01444     // (If not, wait for more data to arrive.)
01445     Boolean endOfHeaders = False;
01446     char const* ptr = fResponseBuffer;
01447     if (fResponseBytesAlreadySeen > 3) {
01448       char const* const ptrEnd = &fResponseBuffer[fResponseBytesAlreadySeen-3];
01449       while (ptr < ptrEnd) {
01450         if (*ptr++ == '\r' && *ptr++ == '\n' && *ptr++ == '\r' && *ptr++ == '\n') {
01451           // This is it
01452           endOfHeaders = True;
01453           break;
01454         }
01455       }
01456     }
01457     
01458     if (!endOfHeaders) return; // subsequent reads will be needed to get the complete response
01459     
01460     // Now that we have the complete response headers (ending with <CR><LF><CR><LF>), parse them to get the response code, CSeq,
01461     // and various other header parameters.  To do this, we first make a copy of the received header data, because we'll be
01462     // modifying it by adding '\0' bytes.
01463     char* headerDataCopy;
01464     unsigned responseCode = 200;
01465     char const* responseStr = NULL;
01466     RequestRecord* foundRequest = NULL;
01467     char const* sessionParamsStr = NULL;
01468     char const* transportParamsStr = NULL;
01469     char const* scaleParamsStr = NULL;
01470     char const* rangeParamsStr = NULL;
01471     char const* rtpInfoParamsStr = NULL;
01472     char const* wwwAuthenticateParamsStr = NULL;
01473     char const* publicParamsStr = NULL;
01474     char* bodyStart = NULL;
01475     unsigned numBodyBytes = 0;
01476     responseSuccess = False;
01477     do {
01478       headerDataCopy = new char[responseBufferSize];
01479       strncpy(headerDataCopy, fResponseBuffer, fResponseBytesAlreadySeen);
01480       headerDataCopy[fResponseBytesAlreadySeen] = '\0';
01481       
01482       char* lineStart = headerDataCopy;
01483       char* nextLineStart = getLine(lineStart);
01484       if (!parseResponseCode(lineStart, responseCode, responseStr)) {
01485         // This does not appear to be a RTSP response; perhaps it's a RTSP request instead?
01486         handleIncomingRequest();
01487         break; // we're done with this data
01488       }
01489       
01490       // Scan through the headers, handling the ones that we're interested in:
01491       Boolean reachedEndOfHeaders;
01492       unsigned cseq = 0;
01493       unsigned contentLength = 0;
01494       
01495       while (1) {
01496         reachedEndOfHeaders = True; // by default; may get changed below
01497         lineStart = nextLineStart;
01498         if (lineStart == NULL) break;
01499         
01500         nextLineStart = getLine(lineStart);
01501         if (lineStart[0] == '\0') break; // this is a blank line
01502         reachedEndOfHeaders = False;
01503         
01504         char const* headerParamsStr; 
01505         if (checkForHeader(lineStart, "CSeq:", 5, headerParamsStr)) {
01506           if (sscanf(headerParamsStr, "%u", &cseq) != 1 || cseq <= 0) {
01507             envir().setResultMsg("Bad \"CSeq:\" header: \"", lineStart, "\"");
01508             break;
01509           }
01510           // Find the handler function for "cseq":
01511           RequestRecord* request;
01512           while ((request = fRequestsAwaitingResponse.dequeue()) != NULL) {
01513             if (request->cseq() < cseq) { // assumes that the CSeq counter will never wrap around
01514               // We never received (and will never receive) a response for this handler, so delete it:
01515               if (fVerbosityLevel >= 1 && strcmp(request->commandName(), "POST") != 0) {
01516                 envir() << "WARNING: The server did not respond to our \"" << request->commandName() << "\" request (CSeq: "
01517                         << request->cseq() << ").  The server appears to be buggy (perhaps not handling pipelined requests properly).\n";
01518               }
01519               delete request;
01520             } else if (request->cseq() == cseq) {
01521               // This is the handler that we want. Remove its record, but remember it, so that we can later call its handler:
01522               foundRequest = request;
01523               break;
01524             } else { // request->cseq() > cseq
01525               // No handler was registered for this response, so ignore it.
01526               break;
01527             }
01528           }
01529         } else if (checkForHeader(lineStart, "Content-Length:", 15, headerParamsStr)) {
01530           if (sscanf(headerParamsStr, "%u", &contentLength) != 1) {
01531             envir().setResultMsg("Bad \"Content-Length:\" header: \"", lineStart, "\"");
01532             break;
01533           }
01534         } else if (checkForHeader(lineStart, "Content-Base:", 13, headerParamsStr)) {
01535           setBaseURL(headerParamsStr);
01536         } else if (checkForHeader(lineStart, "Session:", 8, sessionParamsStr)) {
01537         } else if (checkForHeader(lineStart, "Transport:", 10, transportParamsStr)) {
01538         } else if (checkForHeader(lineStart, "Scale:", 6, scaleParamsStr)) {
01539         } else if (checkForHeader(lineStart, "Range:", 6, rangeParamsStr)) {
01540         } else if (checkForHeader(lineStart, "RTP-Info:", 9, rtpInfoParamsStr)) {
01541         } else if (checkForHeader(lineStart, "WWW-Authenticate:", 17, headerParamsStr)) {
01542           // If we've already seen a "WWW-Authenticate:" header, then we replace it with this new one only if
01543           // the new one specifies "Digest" authentication:
01544           if (wwwAuthenticateParamsStr == NULL || _strncasecmp(headerParamsStr, "Digest", 6) == 0) {
01545             wwwAuthenticateParamsStr = headerParamsStr;
01546           }
01547         } else if (checkForHeader(lineStart, "Public:", 7, publicParamsStr)) {
01548         } else if (checkForHeader(lineStart, "Allow:", 6, publicParamsStr)) {
01549           // Note: we accept "Allow:" instead of "Public:", so that "OPTIONS" requests made to HTTP servers will work.
01550         } else if (checkForHeader(lineStart, "Location:", 9, headerParamsStr)) {
01551           setBaseURL(headerParamsStr);
01552         }
01553       }
01554       if (!reachedEndOfHeaders) break; // an error occurred
01555       
01556       if (foundRequest == NULL) {
01557         // Hack: The response didn't have a "CSeq:" header; assume it's for our most recent request:
01558         foundRequest = fRequestsAwaitingResponse.dequeue();
01559       }
01560       
01561       // If we saw a "Content-Length:" header, then make sure that we have the amount of data that it specified:
01562       unsigned bodyOffset = nextLineStart == NULL ? fResponseBytesAlreadySeen : nextLineStart - headerDataCopy;
01563       bodyStart = &fResponseBuffer[bodyOffset];
01564       numBodyBytes = fResponseBytesAlreadySeen - bodyOffset;
01565       if (contentLength > numBodyBytes) {
01566         // We need to read more data.  First, make sure we have enough space for it:
01567         unsigned numExtraBytesNeeded = contentLength - numBodyBytes;
01568         unsigned remainingBufferSize = responseBufferSize - fResponseBytesAlreadySeen;
01569         if (numExtraBytesNeeded > remainingBufferSize) {
01570           char tmpBuf[200];
01571           sprintf(tmpBuf, "Response buffer size (%d) is too small for \"Content-Length:\" %d (need a buffer size of >= %d bytes\n",
01572                   responseBufferSize, contentLength, fResponseBytesAlreadySeen + numExtraBytesNeeded);
01573           envir().setResultMsg(tmpBuf);
01574           break;
01575         }
01576         
01577         if (fVerbosityLevel >= 1) {
01578           envir() << "Have received " << fResponseBytesAlreadySeen << " total bytes of a "
01579                   << (foundRequest != NULL ? foundRequest->commandName() : "(unknown)")
01580                   << " RTSP response; awaiting " << numExtraBytesNeeded << " bytes more.\n";
01581         }
01582         delete[] headerDataCopy;
01583         if (foundRequest != NULL) fRequestsAwaitingResponse.putAtHead(foundRequest);// put our request record back; we need it again
01584         return; // We need to read more data
01585       }
01586       
01587       // We now have a complete response (including all bytes specified by the "Content-Length:" header, if any).
01588       char* responseEnd = bodyStart + contentLength;
01589       numExtraBytesAfterResponse = &fResponseBuffer[fResponseBytesAlreadySeen] - responseEnd;
01590 
01591       if (fVerbosityLevel >= 1) {
01592         char saved = *responseEnd;
01593         *responseEnd = '\0';
01594         envir() << "Received a complete "
01595                 << (foundRequest != NULL ? foundRequest->commandName() : "(unknown)")
01596                 << " response:\n" << fResponseBuffer << "\n";
01597         if (numExtraBytesAfterResponse > 0) envir() << "\t(plus " << numExtraBytesAfterResponse << " additional bytes)\n";
01598         *responseEnd = saved;
01599       }
01600       
01601       if (foundRequest != NULL) {
01602         Boolean needToResendCommand = False; // by default...
01603         if (responseCode == 200) {
01604           // Do special-case response handling for some commands:
01605           if (strcmp(foundRequest->commandName(), "SETUP") == 0) {
01606             if (!handleSETUPResponse(*foundRequest->subsession(), sessionParamsStr, transportParamsStr, foundRequest->booleanFlags()&0x1)) break;
01607           } else if (strcmp(foundRequest->commandName(), "PLAY") == 0) {
01608             if (!handlePLAYResponse(*foundRequest->session(), *foundRequest->subsession(), scaleParamsStr, rangeParamsStr, rtpInfoParamsStr)) break;
01609           } else if (strcmp(foundRequest->commandName(), "TEARDOWN") == 0) {
01610             if (!handleTEARDOWNResponse(*foundRequest->session(), *foundRequest->subsession())) break;
01611           } else if (strcmp(foundRequest->commandName(), "GET_PARAMETER") == 0) {
01612             if (!handleGET_PARAMETERResponse(foundRequest->contentStr(), bodyStart)) break;
01613           }
01614         } else if (responseCode == 401 && handleAuthenticationFailure(wwwAuthenticateParamsStr)) {
01615           // We need to resend the command, with an "Authorization:" header:
01616           needToResendCommand = True;
01617           
01618           if (strcmp(foundRequest->commandName(), "GET") == 0) {
01619             // Note: If a HTTP "GET" command (for RTSP-over-HTTP tunneling) returns "401 Unauthorized", then we resend it
01620             // (with an "Authorization:" header), just as we would for a RTSP command.  However, we do so using a new TCP connection,
01621             // because some servers close the original connection after returning the "401 Unauthorized".
01622             resetTCPSockets(); // forces the opening of a new connection for the resent command
01623           }
01624         } else if (responseCode == 301 || responseCode == 302) { // redirection
01625           resetTCPSockets(); // because we need to connect somewhere else next
01626           needToResendCommand = True;
01627         }
01628         
01629         if (needToResendCommand) {
01630           resetResponseBuffer();
01631           if (!resendCommand(foundRequest)) break;
01632           delete[] headerDataCopy;
01633           return; // without calling our response handler; the response to the resent command will do that
01634         }
01635       }
01636       
01637       responseSuccess = True;
01638     } while (0);
01639     
01640     // If we have a handler function for this response, call it.
01641     // But first, reset our response buffer, in case the handler goes to the event loop, and we end up getting called recursively:
01642     if (numExtraBytesAfterResponse > 0) {
01643       // An unusual case; usually due to having received pipelined responses.  Move the extra bytes to the front of the buffer:
01644       char* responseEnd = &fResponseBuffer[fResponseBytesAlreadySeen - numExtraBytesAfterResponse];
01645       
01646       // But first: A hack to save a copy of the response 'body', in case it's needed below for "resultString":
01647       numBodyBytes -= numExtraBytesAfterResponse;
01648       if (numBodyBytes > 0) {
01649         char saved = *responseEnd;
01650         *responseEnd = '\0';
01651         bodyStart = strDup(bodyStart);
01652         *responseEnd = saved;
01653       }
01654       
01655       memmove(fResponseBuffer, responseEnd, numExtraBytesAfterResponse);
01656       fResponseBytesAlreadySeen = numExtraBytesAfterResponse;
01657       fResponseBufferBytesLeft = responseBufferSize - numExtraBytesAfterResponse;
01658       fResponseBuffer[numExtraBytesAfterResponse] = '\0';
01659     } else {
01660       resetResponseBuffer();
01661     }
01662     if (foundRequest != NULL && foundRequest->handler() != NULL) {
01663       int resultCode;
01664       char* resultString;
01665       if (responseSuccess) {
01666         if (responseCode == 200) {
01667           resultCode = 0;
01668           resultString = numBodyBytes > 0 ? strDup(bodyStart) : strDup(publicParamsStr);
01669           // Note: The "strDup(bodyStart)" call assumes that the body is encoded without interior '\0' bytes
01670         } else {
01671           resultCode = responseCode;
01672           resultString = strDup(responseStr);
01673           envir().setResultMsg(responseStr);
01674         }
01675         (*foundRequest->handler())(this, resultCode, resultString);
01676       } else {
01677         // An error occurred parsing the response, so call the handler, indicating an error:
01678         handleRequestError(foundRequest);
01679       }
01680     }
01681     delete foundRequest;
01682     delete[] headerDataCopy;
01683     if (numExtraBytesAfterResponse > 0 && numBodyBytes > 0) delete[] bodyStart;
01684   } while (numExtraBytesAfterResponse > 0 && responseSuccess);
01685 }

Boolean Medium::lookupByName ( UsageEnvironment env,
char const *  mediumName,
Medium *&  resultMedium 
) [static, inherited]

Definition at line 41 of file Media.cpp.

References env, False, MediaLookupTable::lookup(), NULL, MediaLookupTable::ourMedia(), UsageEnvironment::setResultMsg(), and True.

Referenced by ServerMediaSession::lookupByName(), RTSPServer::lookupByName(), lookupByName(), RTCPInstance::lookupByName(), MediaSource::lookupByName(), MediaSink::lookupByName(), MediaSession::lookupByName(), and DarwinInjector::lookupByName().

00042                                                          {
00043   resultMedium = MediaLookupTable::ourMedia(env)->lookup(mediumName);
00044   if (resultMedium == NULL) {
00045     env.setResultMsg("Medium ", mediumName, " does not exist");
00046     return False;
00047   }
00048 
00049   return True;
00050 }

void Medium::close ( UsageEnvironment env,
char const *  mediumName 
) [static, inherited]

Definition at line 52 of file Media.cpp.

References env, MediaLookupTable::ourMedia(), and MediaLookupTable::remove().

Referenced by afterPlaying(), Medium::close(), closeMediaSinks(), OnDemandServerMediaSubsession::closeStreamSource(), continueAfterClientCreation0(), continueAfterTEARDOWN(), WAVAudioFileSource::createNew(), QuickTimeFileSink::createNew(), QCELPAudioRTPSource::createNew(), MP3FileSource::createNew(), AVIFileSink::createNew(), AMRAudioRTPSource::createNew(), WAVAudioFileServerMediaSubsession::createNewStreamSource(), MPEG1or2DemuxedServerMediaSubsession::createNewStreamSource(), MediaSubsession::deInitiate(), ServerMediaSession::deleteAllSubsessions(), RTSPServerSupportingHTTPStreaming::RTSPClientConnectionSupportingHTTPStreaming::handleHTTPCmd_StreamingGET(), MediaSubsession::initiate(), MPEG1or2ProgramStreamFileDuration(), MPEG1or2Demux::noteElementaryStreamDeletion(), ByteStreamMultiFileSource::onSourceClosure1(), StreamState::reclaim(), RTSPServer::removeServerMediaSession(), ProxyServerMediaSession::resetDESCRIBEState(), OnDemandServerMediaSubsession::sdpLines(), shutdownStream(), subsessionAfterPlaying(), ClientTrickPlayState::updateStateOnScaleChange(), AMRDeinterleaver::~AMRDeinterleaver(), ByteStreamMultiFileSource::~ByteStreamMultiFileSource(), DarwinInjector::~DarwinInjector(), FramedFilter::~FramedFilter(), H264VideoRTPSink::~H264VideoRTPSink(), InputESSourceRecord::~InputESSourceRecord(), MatroskaFileParser::~MatroskaFileParser(), MatroskaFileServerDemux::~MatroskaFileServerDemux(), MPEG1or2Demux::~MPEG1or2Demux(), MPEG1or2FileServerDemux::~MPEG1or2FileServerDemux(), MPEG2TransportFileServerMediaSubsession::~MPEG2TransportFileServerMediaSubsession(), MPEG2TransportStreamFromPESSource::~MPEG2TransportStreamFromPESSource(), ProxyServerMediaSession::~ProxyServerMediaSession(), RTSPServerSupportingHTTPStreaming::RTSPClientConnectionSupportingHTTPStreaming::~RTSPClientConnectionSupportingHTTPStreaming(), ServerMediaSubsession::~ServerMediaSubsession(), StreamClientState::~StreamClientState(), StreamReplicator::~StreamReplicator(), and T140TextRTPSink::~T140TextRTPSink().

00052                                                           {
00053   MediaLookupTable::ourMedia(env)->remove(name);
00054 }

void Medium::close ( Medium medium  )  [static, inherited]

Definition at line 56 of file Media.cpp.

References Medium::close(), Medium::envir(), Medium::name(), and NULL.

00056                                  {
00057   if (medium == NULL) return;
00058 
00059   close(medium->envir(), medium->name());
00060 }

UsageEnvironment& Medium::envir (  )  const [inline, inherited]

Definition at line 59 of file Media.hh.

References Medium::fEnviron.

Referenced by QuickTimeFileSink::addArbitraryString(), FileSink::addData(), RTCPInstance::addStreamSocket(), MPEG2IFrameIndexFromTransportStream::addToTail(), StreamParser::afterGettingBytes1(), DummySink::afterGettingFrame(), TCPStreamSink::afterGettingFrame(), T140IdleFilter::afterGettingFrame(), FileSink::afterGettingFrame(), MultiFramedRTPSink::afterGettingFrame1(), InputESSourceRecord::afterGettingFrame1(), MPEG2TransportStreamFramer::afterGettingFrame1(), MPEG2IFrameIndexFromTransportStream::afterGettingFrame1(), H264VideoStreamDiscreteFramer::afterGettingFrame1(), BasicUDPSink::afterGettingFrame1(), MPEG4VideoFileServerMediaSubsession::afterPlayingDummy1(), H264VideoFileServerMediaSubsession::afterPlayingDummy1(), MPEG4VideoStreamParser::analyzeVOLHeader(), announceStream(), RTSPServer::RTSPClientConnection::changeClientInputSocket(), MPEG4VideoFileServerMediaSubsession::checkForAuxSDPLine1(), H264VideoFileServerMediaSubsession::checkForAuxSDPLine1(), Medium::close(), ProxyServerMediaSubsession::closeStreamSource(), MPEG2IFrameIndexFromTransportStream::compactParseBuffer(), connectionHandler1(), connectToServer(), ProxyServerMediaSession::continueAfterDESCRIBE(), ProxyRTSPClient::continueAfterLivenessCommand(), ProxyRTSPClient::continueAfterSETUP(), T140TextRTPSink::continuePlaying(), QuickTimeFileSink::continuePlaying(), H264VideoRTPSink::continuePlaying(), AVIFileSink::continuePlaying(), RTSPServer::continueRegisterStream(), VP8VideoMatroskaFileServerMediaSubsession::createNewRTPSink(), VorbisAudioMatroskaFileServerMediaSubsession::createNewRTPSink(), T140TextMatroskaFileServerMediaSubsession::createNewRTPSink(), ProxyServerMediaSubsession::createNewRTPSink(), MPEG4VideoFileServerMediaSubsession::createNewRTPSink(), MPEG2TransportUDPServerMediaSubsession::createNewRTPSink(), MPEG2TransportFileServerMediaSubsession::createNewRTPSink(), MPEG1or2VideoFileServerMediaSubsession::createNewRTPSink(), MPEG1or2DemuxedServerMediaSubsession::createNewRTPSink(), MP3AudioFileServerMediaSubsession::createNewRTPSink(), H264VideoFileServerMediaSubsession::createNewRTPSink(), H263plusVideoFileServerMediaSubsession::createNewRTPSink(), DVVideoFileServerMediaSubsession::createNewRTPSink(), AMRAudioFileServerMediaSubsession::createNewRTPSink(), ADTSAudioFileServerMediaSubsession::createNewRTPSink(), AC3AudioMatroskaFileServerMediaSubsession::createNewRTPSink(), AC3AudioFileServerMediaSubsession::createNewRTPSink(), AACAudioMatroskaFileServerMediaSubsession::createNewRTPSink(), HandlerServerForREGISTERCommand::createNewRTSPClient(), ProxyServerMediaSubsession::createNewStreamSource(), MPEG4VideoFileServerMediaSubsession::createNewStreamSource(), MPEG2TransportUDPServerMediaSubsession::createNewStreamSource(), MPEG2TransportFileServerMediaSubsession::createNewStreamSource(), MPEG1or2VideoFileServerMediaSubsession::createNewStreamSource(), MPEG1or2DemuxedServerMediaSubsession::createNewStreamSource(), MP3AudioFileServerMediaSubsession::createNewStreamSource(), H264VideoMatroskaFileServerMediaSubsession::createNewStreamSource(), H264VideoFileServerMediaSubsession::createNewStreamSource(), H263plusVideoFileServerMediaSubsession::createNewStreamSource(), DVVideoFileServerMediaSubsession::createNewStreamSource(), AMRAudioFileServerMediaSubsession::createNewStreamSource(), ADTSAudioFileServerMediaSubsession::createNewStreamSource(), AC3AudioFileServerMediaSubsession::createNewStreamSource(), AMRDeinterleavingBuffer::deliverIncomingFrame(), MPEG2IFrameIndexFromTransportStream::deliverIndexRecord(), SegmentQueue::dequeue(), DeviceSource::DeviceSource(), WAVAudioFileSource::doGetNextFrame(), T140IdleFilter::doGetNextFrame(), MPEG2TransportStreamMultiplexor::doGetNextFrame(), MPEG2IFrameIndexFromTransportStream::doGetNextFrame(), MP3FileSource::doGetNextFrame(), H264FUAFragmenter::doGetNextFrame(), ByteStreamMultiFileSource::doGetNextFrame(), ByteStreamFileSource::doGetNextFrame(), BasicUDPSource::doGetNextFrame(), AMRAudioFileSource::doGetNextFrame(), ADTSAudioFileSource::doGetNextFrame(), MultiFramedRTPSource::doGetNextFrame1(), MP3FileSource::doGetNextFrame1(), ADUFromMP3Source::doGetNextFrame1(), SIPClient::doInviteStateMachine(), WAVAudioFileSource::doReadFromFile(), ByteStreamFileSource::doReadFromFile(), MPEG1or2VideoRTPSink::doSpecialFrameHandling(), MP3ADURTPSink::doSpecialFrameHandling(), H263plusVideoRTPSink::doSpecialFrameHandling(), WAVAudioFileSource::doStopGettingFrames(), T140IdleFilter::doStopGettingFrames(), MultiFramedRTPSource::doStopGettingFrames(), FramedSource::doStopGettingFrames(), ByteStreamFileSource::doStopGettingFrames(), BasicUDPSource::doStopGettingFrames(), SegmentQueue::enqueueNewSegment(), StreamParser::ensureValidBytes1(), MediaSubsession::env(), SubsessionIOState::envir(), RTSPServer::RegisterRequestRecord::envir(), RTSPServer::RTSPClientSession::envir(), RTSPServer::RTSPClientConnection::envir(), RTPInterface::envir(), AVISubsessionIOState::envir(), ServerMediaSession::generateSDPDescription(), RTPSource::getAttributes(), MP3FileSource::getAttributes(), MP3ADUTranscoder::getAttributes(), MediaSource::getAttributes(), MPEG4VideoFileServerMediaSubsession::getAuxSDPLine(), H264VideoFileServerMediaSubsession::getAuxSDPLine(), getMPEG1or2TimeCode(), FramedSource::getNextFrame(), getOptions(), DVVideoStreamFramer::getProfile(), SIPClient::getResponse(), SIPClient::getResponseCode(), getSDPDescription(), OnDemandServerMediaSubsession::getStreamParameters(), handleAlternativeRequestByte1(), handleGET_PARAMETERResponse(), RTSPServerSupportingHTTPStreaming::RTSPClientConnectionSupportingHTTPStreaming::handleHTTPCmd_StreamingGET(), handleIncomingRequest(), handlePLAYResponse(), handleRequestError(), handleResponseBytes(), handleSETUPResponse(), RTSPServerWithREGISTERProxying::implementCmd_REGISTER(), RTSPServer::incomingConnectionHandler(), incomingDataHandler1(), RTCPInstance::incomingReportHandler1(), MP3FileSource::initializeStream(), MediaSession::initializeWithSDP(), MediaSession::initiateByMediaType(), SIPClient::invite1(), DynamicRTSPServer::lookupServerMediaSession(), MatroskaDemux::MatroskaDemux(), MatroskaFile::MatroskaFile(), MPEG4GenericRTPSource::MPEG4GenericRTPSource(), MultiFramedRTPSource::networkReadHandler1(), MatroskaDemux::newDemuxedTrack(), MPEG1or2FileServerDemux::newElementaryStream(), MPEG1or2Demux::newElementaryStream(), MPEG4GenericBufferedPacket::nextEnclosedFrameSize(), AMRBufferedPacket::nextEnclosedFrameSize(), T140IdleFilter::onSourceClosure(), openConnection(), MPEG2TransportStreamIndexFile::openFid(), MPEG2IFrameIndexFromTransportStream::parseFrame(), AC3AudioStreamParser::parseFrame(), MPEGProgramStreamParser::parsePackHeader(), MPEGProgramStreamParser::parsePESPacket(), SIPClient::parseResponseCode(), MediaSession::parseSDPLine(), MPEG1or2VideoStreamParser::parseSlice(), MatroskaFileParser::parseStartOfFile(), MPEGProgramStreamParser::parseSystemHeader(), MPEG4VideoStreamParser::parseVideoObjectLayer(), MPEG4VideoStreamParser::parseVideoObjectPlane(), MPEG4VideoStreamParser::parseVisualObject(), TCPStreamSink::processBuffer(), SIPClient::processURL(), AC3AudioStreamParser::readAndSaveAFrame(), MPEG1or2Demux::registerReadInterest(), RTSPServer::registerStream(), RTCPInstance::reschedule(), resendCommand(), ProxyRTSPClient::reset(), resetTCPSockets(), responseHandlerForHTTP_GET1(), RTSPClient(), RTSPServer::rtspURLPrefix(), RTCPInstance::schedule(), ProxyRTSPClient::scheduleDESCRIBECommand(), ProxyRTSPClient::scheduleLivenessCommand(), OnDemandServerMediaSubsession::sdpLines(), SIPClient::sendACK(), SIPClient::sendBYE(), SIPClient::sendINVITE(), MultiFramedRTPSink::sendPacketIfNecessary(), SIPClient::sendRequest(), sendRequest(), DarwinInjector::setDestination(), setupHTTPTunneling1(), setupNextSubsession(), RTSPServer::setUpTunnelingOverHTTP(), QuickTimeFileSink::setWord(), AVIFileSink::setWord(), QuickTimeFileSink::setWord64(), shutdownStream(), SIPClient::SIPClient(), TCPStreamSink::socketWritableHandler1(), AMRAudioRTPSink::sourceIsCompatibleWithUs(), QuickTimeFileSink::startPlaying(), StreamState::startPlaying(), MediaSink::startPlaying(), AVIFileSink::startPlaying(), startPlayingSession(), PassiveServerMediaSubsession::startStream(), MediaSink::stopPlaying(), ProxyServerMediaSubsession::subsessionByeHandler(), tearDownSession(), SIPClient::timerAHandler(), SIPClient::timerBHandler(), SIPClient::timerDHandler(), ClientTrickPlayState::updateStateOnScaleChange(), MPEG2TransportStreamFramer::updateTSPacketDurationEstimate(), BasicUDPSource::~BasicUDPSource(), ByteStreamFileSource::~ByteStreamFileSource(), DeviceSource::~DeviceSource(), ProxyServerMediaSession::~ProxyServerMediaSession(), ProxyServerMediaSubsession::~ProxyServerMediaSubsession(), RTSPServer::~RTSPServer(), StreamClientState::~StreamClientState(), T140IdleFilter::~T140IdleFilter(), and WAVAudioFileSource::~WAVAudioFileSource().

00059 {return fEnviron;}

char const* Medium::name (  )  const [inline, inherited]

Definition at line 61 of file Media.hh.

References Medium::fMediumName.

Referenced by QuickTimeFileSink::addAtom_hdlr2(), Medium::close(), MP3ADUTranscoder::createNew(), MP3FromADUSource::createNew(), ADUFromMP3Source::createNew(), and MP3FileSource::initializeStream().

00061 {return fMediumName;}

Boolean Medium::isSource (  )  const [virtual, inherited]

Reimplemented in MediaSource.

Definition at line 62 of file Media.cpp.

References False.

Referenced by MediaSource::lookupByName().

00062                                {
00063   return False; // default implementation
00064 }

Boolean Medium::isSink (  )  const [virtual, inherited]

Reimplemented in MediaSink.

Definition at line 66 of file Media.cpp.

References False.

Referenced by MediaSink::lookupByName().

00066                              {
00067   return False; // default implementation
00068 }

Boolean Medium::isRTCPInstance (  )  const [virtual, inherited]

Reimplemented in RTCPInstance.

Definition at line 70 of file Media.cpp.

References False.

Referenced by RTCPInstance::lookupByName().

00070                                      {
00071   return False; // default implementation
00072 }

Boolean Medium::isRTSPServer (  )  const [virtual, inherited]

Reimplemented in RTSPServer.

Definition at line 78 of file Media.cpp.

References False.

Referenced by RTSPServer::lookupByName().

00078                                    {
00079   return False; // default implementation
00080 }

Boolean Medium::isMediaSession (  )  const [virtual, inherited]

Reimplemented in MediaSession.

Definition at line 82 of file Media.cpp.

References False.

Referenced by MediaSession::lookupByName().

00082                                      {
00083   return False; // default implementation
00084 }

Boolean Medium::isServerMediaSession (  )  const [virtual, inherited]

Reimplemented in ServerMediaSession.

Definition at line 86 of file Media.cpp.

References False.

Referenced by ServerMediaSession::lookupByName().

00086                                            {
00087   return False; // default implementation
00088 }

Boolean Medium::isDarwinInjector (  )  const [virtual, inherited]

Reimplemented in DarwinInjector.

Definition at line 90 of file Media.cpp.

References False.

Referenced by DarwinInjector::lookupByName().

00090                                        {
00091   return False; // default implementation
00092 }

TaskToken& Medium::nextTask (  )  [inline, protected, inherited]

Definition at line 78 of file Media.hh.

References Medium::fNextTask.

Referenced by BasicUDPSink::afterGettingFrame1(), MPEG4VideoFileServerMediaSubsession::afterPlayingDummy1(), H264VideoFileServerMediaSubsession::afterPlayingDummy1(), MPEG4VideoFileServerMediaSubsession::checkForAuxSDPLine1(), H264VideoFileServerMediaSubsession::checkForAuxSDPLine1(), MP3FileSource::doGetNextFrame(), AMRAudioFileSource::doGetNextFrame(), ADTSAudioFileSource::doGetNextFrame(), MultiFramedRTPSource::doGetNextFrame1(), WAVAudioFileSource::doReadFromFile(), ByteStreamFileSource::doReadFromFile(), MultiFramedRTPSource::doStopGettingFrames(), FramedSource::doStopGettingFrames(), ByteStreamFileSource::doStopGettingFrames(), RTCPInstance::reschedule(), RTCPInstance::schedule(), MultiFramedRTPSink::sendPacketIfNecessary(), and MediaSink::stopPlaying().

00078                         {
00079         return fNextTask;
00080   }


Friends And Related Function Documentation

friend class MediaLookupTable [friend, inherited]

Definition at line 74 of file Media.hh.


Field Documentation

unsigned RTSPClient::responseBufferSize = 20000 [static]

Definition at line 172 of file RTSPClient.hh.

Referenced by handleResponseBytes(), handleSETUPResponse(), resetResponseBuffer(), and RTSPClient().

int RTSPClient::fVerbosityLevel [protected]

Definition at line 292 of file RTSPClient.hh.

Referenced by connectionHandler1(), connectToServer(), ProxyRTSPClient::continueAfterLivenessCommand(), ProxyRTSPClient::continueAfterSETUP(), handleIncomingRequest(), handleResponseBytes(), resendCommand(), ProxyRTSPClient::scheduleDESCRIBECommand(), sendRequest(), and setupHTTPTunneling1().

unsigned RTSPClient::fCSeq [protected]

Definition at line 293 of file RTSPClient.hh.

Referenced by resendCommand(), sendAnnounceCommand(), sendDescribeCommand(), sendGetParameterCommand(), sendOptionsCommand(), sendPauseCommand(), sendPlayCommand(), sendRecordCommand(), sendSetParameterCommand(), sendSetupCommand(), and sendTeardownCommand().

Authenticator RTSPClient::fCurrentAuthenticator [protected]

Definition at line 294 of file RTSPClient.hh.

Referenced by createAuthenticatorString(), handleAuthenticationFailure(), openConnection(), reset(), sendAnnounceCommand(), sendDescribeCommand(), sendGetParameterCommand(), sendOptionsCommand(), sendPauseCommand(), sendPlayCommand(), sendRecordCommand(), sendSetParameterCommand(), sendSetupCommand(), and sendTeardownCommand().

portNumBits RTSPClient::fTunnelOverHTTPPortNum [private]

Definition at line 297 of file RTSPClient.hh.

Referenced by openConnection(), responseHandlerForHTTP_GET1(), sendRequest(), sendSetupCommand(), and setupHTTPTunneling1().

char* RTSPClient::fUserAgentHeaderStr [private]

Definition at line 298 of file RTSPClient.hh.

Referenced by sendRequest(), setUserAgentString(), and ~RTSPClient().

unsigned RTSPClient::fUserAgentHeaderStrLen [private]

Definition at line 299 of file RTSPClient.hh.

Referenced by sendRequest(), and setUserAgentString().

int RTSPClient::fInputSocketNum [private]

Definition at line 300 of file RTSPClient.hh.

Referenced by connectionHandler1(), handleAlternativeRequestByte1(), handleSETUPResponse(), incomingDataHandler1(), openConnection(), resetTCPSockets(), RTSPClient(), sendRequest(), and socketNum().

int RTSPClient::fOutputSocketNum [private]

Definition at line 300 of file RTSPClient.hh.

Referenced by connectionHandler1(), handleIncomingRequest(), openConnection(), resetTCPSockets(), responseHandlerForHTTP_GET1(), RTSPClient(), and sendRequest().

netAddressBits RTSPClient::fServerAddress [private]

Definition at line 301 of file RTSPClient.hh.

Referenced by connectToServer(), handleSETUPResponse(), openConnection(), and reset().

char* RTSPClient::fBaseURL [private]

Definition at line 302 of file RTSPClient.hh.

Referenced by openConnection(), sendRequest(), sessionURL(), setBaseURL(), and url().

unsigned char RTSPClient::fTCPStreamIdCount [private]

Definition at line 303 of file RTSPClient.hh.

Referenced by sendRequest().

char* RTSPClient::fLastSessionId [private]

Definition at line 304 of file RTSPClient.hh.

Referenced by handleSETUPResponse(), reset(), and sendRequest().

unsigned RTSPClient::fSessionTimeoutParameter [private]

Definition at line 305 of file RTSPClient.hh.

Referenced by handleSETUPResponse(), and sessionTimeoutParameter().

char* RTSPClient::fResponseBuffer [private]

Definition at line 306 of file RTSPClient.hh.

Referenced by handleAlternativeRequestByte1(), handleIncomingRequest(), handleResponseBytes(), incomingDataHandler1(), RTSPClient(), and ~RTSPClient().

unsigned RTSPClient::fResponseBytesAlreadySeen [private]

Definition at line 307 of file RTSPClient.hh.

Referenced by handleAlternativeRequestByte1(), handleIncomingRequest(), handleResponseBytes(), incomingDataHandler1(), and resetResponseBuffer().

unsigned RTSPClient::fResponseBufferBytesLeft [private]

Definition at line 307 of file RTSPClient.hh.

Referenced by handleResponseBytes(), incomingDataHandler1(), and resetResponseBuffer().

RequestQueue RTSPClient::fRequestsAwaitingConnection [private]

Definition at line 308 of file RTSPClient.hh.

Referenced by changeResponseHandler(), connectionHandler1(), responseHandlerForHTTP_GET1(), and sendRequest().

RequestQueue RTSPClient::fRequestsAwaitingHTTPTunneling [private]

Definition at line 308 of file RTSPClient.hh.

Referenced by changeResponseHandler(), responseHandlerForHTTP_GET1(), and sendRequest().

RequestQueue RTSPClient::fRequestsAwaitingResponse [private]

Definition at line 308 of file RTSPClient.hh.

Referenced by changeResponseHandler(), handleResponseBytes(), and sendRequest().

char RTSPClient::fSessionCookie[33] [private]

Definition at line 311 of file RTSPClient.hh.

Referenced by sendRequest().

unsigned RTSPClient::fSessionCookieCounter [private]

Definition at line 312 of file RTSPClient.hh.

Referenced by sendRequest().

Boolean RTSPClient::fHTTPTunnelingConnectionIsPending [private]

Definition at line 313 of file RTSPClient.hh.

Referenced by connectionHandler1(), responseHandlerForHTTP_GET1(), and setupHTTPTunneling2().


The documentation for this class was generated from the following files:
Generated on Tue Jun 18 13:21:26 2013 for live by  doxygen 1.5.2