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 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
char * describeURL (char const *url, Authenticator *authenticator=NULL, Boolean allowKasennaProtocol=False, int timeout=-1)
char * describeWithPassword (char const *url, char const *username, char const *password, Boolean allowKasennaProtocol=False, int timeout=-1)
char * sendOptionsCmd (char const *url, char *username=NULL, char *password=NULL, Authenticator *authenticator=NULL, int timeout=-1)
Boolean announceSDPDescription (char const *url, char const *sdpDescription, Authenticator *authenticator=NULL, int timeout=-1)
Boolean announceWithPassword (char const *url, char const *sdpDescription, char const *username, char const *password, int timeout=-1)
Boolean setupMediaSubsession (MediaSubsession &subsession, Boolean streamOutgoing=False, Boolean streamUsingTCP=False, Boolean forceMulticastOnUnspecified=False)
Boolean playMediaSession (MediaSession &session, double start=0.0f, double end=-1.0f, float scale=1.0f)
Boolean playMediaSubsession (MediaSubsession &subsession, double start=0.0f, double end=-1.0f, float scale=1.0f, Boolean hackForDSS=False)
Boolean pauseMediaSession (MediaSession &session)
Boolean pauseMediaSubsession (MediaSubsession &subsession)
Boolean recordMediaSubsession (MediaSubsession &subsession)
Boolean setMediaSessionParameter (MediaSession &session, char const *parameterName, char const *parameterValue)
Boolean getMediaSessionParameter (MediaSession &session, char const *parameterName, char *&parameterValue)
Boolean teardownMediaSession (MediaSession &session)
Boolean teardownMediaSubsession (MediaSubsession &subsession)
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)
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 RTSPClientcreateNew (UsageEnvironment &env, int verbosityLevel=0, char const *applicationName=NULL, portNumBits tunnelOverHTTPPortNum=0)
static Boolean parseRTSPURLUsernamePassword (char const *url, char *&username, char *&password)
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)
virtual ~RTSPClient ()
void setBaseURL (char const *url)
TaskTokennextTask ()

Private Member Functions

virtual Boolean isRTSPClient () const
void reset ()
void resetTCPSockets ()
void resetResponseBuffer ()
int openConnection ()
int connectToServer (int socketNum, portNumBits remotePortNum)
char * createAuthenticatorString (char const *cmd, char const *url)
unsigned sendRequest (RequestRecord *request)
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)
void responseHandlerForSyncInterface1 (int responseCode, char *responseString)
void timeoutHandlerForSyncInterface1 ()

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)
static void responseHandlerForSyncInterface (RTSPClient *rtspClient, int responseCode, char *responseString)
static void timeoutHandlerForSyncInterface (void *rtspClient)

Private Attributes

int fVerbosityLevel
portNumBits fTunnelOverHTTPPortNum
char * fUserAgentHeaderStr
unsigned fUserAgentHeaderStrLen
int fInputSocketNum
int fOutputSocketNum
netAddressBits fServerAddress
unsigned fCSeq
char * fBaseURL
Authenticator fCurrentAuthenticator
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
TaskToken fTimeoutTask
char fWatchVariableForSyncInterface
char * fResultString
int fResultCode

Friends

class MediaLookupTable

Data Structures

class  RequestQueue
class  RequestRecord

Detailed Description

Definition at line 36 of file RTSPClient.hh.


Member Typedef Documentation

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

Definition at line 46 of file RTSPClient.hh.


Constructor & Destructor Documentation

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

Definition at line 282 of file RTSPClient.cpp.

References fResponseBuffer, libVersionStr, LIVEMEDIA_LIBRARY_VERSION_STRING, NULL, resetResponseBuffer(), responseBufferSize, setBaseURL(), and setUserAgentString().

Referenced by createNew().

00285   : Medium(env),
00286     fVerbosityLevel(verbosityLevel), fTunnelOverHTTPPortNum(tunnelOverHTTPPortNum),
00287     fUserAgentHeaderStr(NULL), fUserAgentHeaderStrLen(0), fInputSocketNum(-1), fOutputSocketNum(-1), fServerAddress(0), fCSeq(1),
00288     fBaseURL(NULL), fTCPStreamIdCount(0), fLastSessionId(NULL), fSessionTimeoutParameter(0),
00289     fSessionCookieCounter(0), fHTTPTunnelingConnectionIsPending(False) {
00290   setBaseURL(rtspURL);
00291 
00292   fResponseBuffer = new char[responseBufferSize+1];
00293   resetResponseBuffer();
00294 
00295   // Set the "User-Agent:" header to use in each request:
00296   char const* const libName = "LIVE555 Streaming Media v";
00297   char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING;
00298   char const* libPrefix; char const* libSuffix;
00299   if (applicationName == NULL || applicationName[0] == '\0') {
00300     applicationName = libPrefix = libSuffix = "";
00301   } else {
00302     libPrefix = " (";
00303     libSuffix = ")";
00304   }
00305   unsigned userAgentNameSize
00306     = strlen(applicationName) + strlen(libPrefix) + strlen(libName) + strlen(libVersionStr) + strlen(libSuffix) + 1;
00307   char* userAgentName = new char[userAgentNameSize];
00308   sprintf(userAgentName, "%s%s%s%s%s", applicationName, libPrefix, libName, libVersionStr, libSuffix);
00309   setUserAgentString(userAgentName);
00310   delete[] userAgentName;
00311 }

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

Definition at line 313 of file RTSPClient.cpp.

References fResponseBuffer, fUserAgentHeaderStr, and reset().

00313                         {
00314   reset();
00315 
00316   delete[] fResponseBuffer;
00317   delete[] fUserAgentHeaderStr;
00318 }


Member Function Documentation

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

Reimplemented in ourRTSPClient.

Definition at line 30 of file RTSPClient.cpp.

References env, and RTSPClient().

Referenced by createClient().

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

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

Definition at line 38 of file RTSPClient.cpp.

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

Referenced by getSDPDescription(), and openURL().

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

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

Definition at line 43 of file RTSPClient.cpp.

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

Referenced by getOptions().

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

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

Definition at line 48 of file RTSPClient.cpp.

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

Referenced by DarwinInjector::setDestination().

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

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

Definition at line 53 of file RTSPClient.cpp.

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

Referenced by DarwinInjector::setDestination(), setupNextSubsession(), and setupSubsession().

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

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 66 of file RTSPClient.cpp.

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

Referenced by DarwinInjector::setDestination(), setupNextSubsession(), and startPlayingSession().

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

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 73 of file RTSPClient.cpp.

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

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

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

Definition at line 80 of file RTSPClient.cpp.

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

00080                                                                                                                            {
00081   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00082   return sendRequest(new RequestRecord(++fCSeq, "PAUSE", responseHandler, &session));
00083 }

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

Definition at line 85 of file RTSPClient.cpp.

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

00085                                                                                                                                  {
00086   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00087   return sendRequest(new RequestRecord(++fCSeq, "PAUSE", responseHandler, NULL, &subsession));
00088 }

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

Definition at line 90 of file RTSPClient.cpp.

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

00090                                                                                                                             {
00091   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00092   return sendRequest(new RequestRecord(++fCSeq, "RECORD", responseHandler, &session));
00093 }

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

Definition at line 95 of file RTSPClient.cpp.

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

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

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

Definition at line 100 of file RTSPClient.cpp.

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

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

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

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

Definition at line 105 of file RTSPClient.cpp.

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

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

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

Definition at line 110 of file RTSPClient.cpp.

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

00112                                                                            {
00113   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00114   char* paramString = new char[strlen(parameterName) + strlen(parameterValue) + 10];
00115   sprintf(paramString, "%s: %s\r\n", parameterName, parameterValue);
00116   unsigned result = sendRequest(new RequestRecord(++fCSeq, "SET_PARAMETER", responseHandler, &session, NULL, False, 0.0, 0.0, 0.0, paramString));
00117   delete[] paramString;
00118   return result;
00119 }

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

Definition at line 121 of file RTSPClient.cpp.

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

00122                                                                            {
00123   if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00124 
00125   // We assume that:
00126   //    parameterName is NULL means: Send no body in the request.
00127   //    parameterName is "" means: Send only \r\n in the request body.  
00128   //    parameterName is non-empty means: Send "<parameterName>\r\n" as the request body.  
00129   unsigned parameterNameLen = parameterName == NULL ? 0 : strlen(parameterName);
00130   char* paramString = new char[parameterNameLen + 3]; // the 3 is for \r\n + the '\0' byte
00131   if (parameterName == NULL) {
00132     paramString[0] = '\0';
00133   } else {
00134     sprintf(paramString, "%s\r\n", parameterName);
00135   }
00136   unsigned result = sendRequest(new RequestRecord(++fCSeq, "GET_PARAMETER", responseHandler, &session, NULL, False, 0.0, 0.0, 0.0, paramString));
00137   delete[] paramString;
00138   return result;
00139 }

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

Definition at line 141 of file RTSPClient.cpp.

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

00141                                                                                             { 
00142   // Look for the matching request record in each of our 'pending requests' queues:
00143   RequestRecord* request;
00144   if ((request = fRequestsAwaitingConnection.findByCSeq(cseq)) != NULL
00145       || (request = fRequestsAwaitingHTTPTunneling.findByCSeq(cseq)) != NULL
00146       || (request = fRequestsAwaitingResponse.findByCSeq(cseq)) != NULL) {
00147     request->handler() = newResponseHandler;
00148     return True;
00149   }
00150 
00151   return False;
00152 }

int RTSPClient::socketNum (  )  const [inline]

Definition at line 140 of file RTSPClient.hh.

References fInputSocketNum.

Referenced by DarwinInjector::setDestination().

00140 { return fInputSocketNum; }

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

Definition at line 154 of file RTSPClient.cpp.

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

00156                                                             {
00157   resultClient = NULL; // unless we succeed
00158 
00159   Medium* medium;
00160   if (!Medium::lookupByName(env, instanceName, medium)) return False;
00161 
00162   if (!medium->isRTSPClient()) {
00163     env.setResultMsg(instanceName, " is not a RTSP client");
00164     return False;
00165   }
00166 
00167   resultClient = (RTSPClient*)medium;
00168   return True;
00169 }

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

Definition at line 171 of file RTSPClient.cpp.

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

Referenced by openConnection(), and sendRequest().

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

void RTSPClient::setUserAgentString ( char const *  userAgentName  ) 

Definition at line 268 of file RTSPClient.cpp.

References fUserAgentHeaderStr, fUserAgentHeaderStrLen, and NULL.

Referenced by RTSPClient().

00268                                                              {
00269   if (userAgentName == NULL) return;
00270 
00271   // Change the existing user agent header string:
00272   char const* const formatStr = "User-Agent: %s\r\n";
00273   unsigned const headerSize = strlen(formatStr) + strlen(userAgentName);
00274   delete[] fUserAgentHeaderStr;
00275   fUserAgentHeaderStr = new char[headerSize];
00276   sprintf(fUserAgentHeaderStr, formatStr, userAgentName);
00277   fUserAgentHeaderStrLen = strlen(fUserAgentHeaderStr);
00278 }

unsigned RTSPClient::sessionTimeoutParameter (  )  const [inline]

Definition at line 154 of file RTSPClient.hh.

References fSessionTimeoutParameter.

00154 { return fSessionTimeoutParameter; }

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

Definition at line 156 of file RTSPClient.hh.

References fBaseURL.

Referenced by operator<<(), and sessionURL().

00156 { return fBaseURL; }

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

Definition at line 353 of file RTSPClient.cpp.

References fBaseURL, and strDup().

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

00353                                            {
00354   delete[] fBaseURL; fBaseURL = strDup(url);
00355 }

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

Reimplemented from Medium.

Definition at line 320 of file RTSPClient.cpp.

References True.

00320                                        {
00321   return True;
00322 }

void RTSPClient::reset (  )  [private]

Definition at line 324 of file RTSPClient.cpp.

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

Referenced by ~RTSPClient().

00324                        {
00325   resetTCPSockets();
00326   resetResponseBuffer();
00327   fServerAddress = 0;
00328 
00329   setBaseURL(NULL);
00330 
00331   fCurrentAuthenticator.reset();
00332 
00333   delete[] fLastSessionId; fLastSessionId = NULL;
00334 }

void RTSPClient::resetTCPSockets (  )  [private]

Definition at line 336 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 348 of file RTSPClient.cpp.

References fResponseBufferBytesLeft, fResponseBytesAlreadySeen, and responseBufferSize.

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

int RTSPClient::openConnection (  )  [private]

Definition at line 357 of file RTSPClient.cpp.

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

Referenced by sendRequest().

00357                                {
00358   do {
00359     // Set up a connection to the server.  Begin by parsing the URL:
00360 
00361     char* username;
00362     char* password;
00363     NetAddress destAddress;
00364     portNumBits urlPortNum;
00365     char const* urlSuffix;
00366     if (!parseRTSPURL(envir(), fBaseURL, username, password, destAddress, urlPortNum, &urlSuffix)) break;
00367     portNumBits destPortNum = fTunnelOverHTTPPortNum == 0 ? urlPortNum : fTunnelOverHTTPPortNum;
00368     if (username != NULL || password != NULL) {
00369       fCurrentAuthenticator.setUsernameAndPassword(username, password);
00370       delete[] username;
00371       delete[] password;
00372     }
00373 
00374     // We don't yet have a TCP socket (or we used to have one, but it got closed).  Set it up now.
00375     fInputSocketNum = fOutputSocketNum = setupStreamSocket(envir(), 0);
00376     if (fInputSocketNum < 0) break;
00377       
00378     // Connect to the remote endpoint:
00379     fServerAddress = *(netAddressBits*)(destAddress.data());
00380     int connectResult = connectToServer(fInputSocketNum, destPortNum);
00381     if (connectResult < 0) break;
00382     else if (connectResult > 0) {
00383       // The connection succeeded.  Arrange to handle responses to requests sent on it:
00384       envir().taskScheduler().setBackgroundHandling(fInputSocketNum, SOCKET_READABLE,
00385                                                     (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this);
00386     }
00387     return connectResult;
00388   } while (0);
00389   
00390   resetTCPSockets();
00391   return -1;
00392 }

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

Definition at line 394 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().

00394                                                                         {
00395   MAKE_SOCKADDR_IN(remoteName, fServerAddress, htons(remotePortNum));
00396   if (fVerbosityLevel >= 1) {
00397     envir() << "Opening connection to " << AddressString(remoteName).val() << ", port " << remotePortNum << "...\n";
00398   }
00399   if (connect(socketNum, (struct sockaddr*) &remoteName, sizeof remoteName) != 0) {
00400     int const err = envir().getErrno();
00401     if (err == EINPROGRESS || err == EWOULDBLOCK) {
00402       // The connection is pending; we'll need to handle it later.  Wait for our socket to be 'writable', or have an exception.
00403       envir().taskScheduler().setBackgroundHandling(socketNum, SOCKET_WRITABLE|SOCKET_EXCEPTION,
00404                                                     (TaskScheduler::BackgroundHandlerProc*)&connectionHandler, this);
00405       return 0;
00406     }
00407     envir().setResultErrMsg("connect() failed: ");
00408     if (fVerbosityLevel >= 1) envir() << "..." << envir().getResultMsg() << "\n";
00409     return -1;
00410   }
00411   if (fVerbosityLevel >= 1) envir() << "...local connection opened\n";
00412 
00413   return 1;
00414 }

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

Definition at line 417 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().

00417                                                                       {
00418   Authenticator& auth = fCurrentAuthenticator; // alias, for brevity
00419   if (auth.realm() != NULL && auth.username() != NULL && auth.password() != NULL) {
00420     // We have a filled-in authenticator, so use it:
00421     char* authenticatorStr;
00422     if (auth.nonce() != NULL) { // Digest authentication
00423       char const* const authFmt =
00424         "Authorization: Digest username=\"%s\", realm=\"%s\", "
00425         "nonce=\"%s\", uri=\"%s\", response=\"%s\"\r\n";
00426       char const* response = auth.computeDigestResponse(cmd, url);
00427       unsigned authBufSize = strlen(authFmt)
00428         + strlen(auth.username()) + strlen(auth.realm())
00429         + strlen(auth.nonce()) + strlen(url) + strlen(response);
00430       authenticatorStr = new char[authBufSize];
00431       sprintf(authenticatorStr, authFmt,
00432               auth.username(), auth.realm(),
00433               auth.nonce(), url, response);
00434       auth.reclaimDigestResponse(response);
00435     } else { // Basic authentication
00436       char const* const authFmt = "Authorization: Basic %s\r\n";
00437 
00438       unsigned usernamePasswordLength = strlen(auth.username()) + 1 + strlen(auth.password());
00439       char* usernamePassword = new char[usernamePasswordLength+1];
00440       sprintf(usernamePassword, "%s:%s", auth.username(), auth.password());
00441 
00442       char* response = base64Encode(usernamePassword, usernamePasswordLength);
00443       unsigned const authBufSize = strlen(authFmt) + strlen(response) + 1;
00444       authenticatorStr = new char[authBufSize];
00445       sprintf(authenticatorStr, authFmt, response);
00446       delete[] response; delete[] usernamePassword;
00447     }
00448 
00449     return authenticatorStr;
00450   }
00451 
00452   // We don't have a (filled-in) authenticator.
00453   return strDup("");
00454 }

unsigned RTSPClient::sendRequest ( RequestRecord request  )  [private]

Definition at line 498 of file RTSPClient.cpp.

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

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

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

Definition at line 781 of file RTSPClient.cpp.

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

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

00781                                                           {
00782   int resultCode = -envir().getErrno();
00783   if (resultCode == 0) {
00784     // Choose some generic error code instead:
00785 #if defined(__WIN32__) || defined(_WIN32) || defined(_QNX4)
00786     resultCode = -WSAENOTCONN;
00787 #else
00788     resultCode = -ENOTCONN;
00789 #endif
00790   }
00791   if (request->handler() != NULL) (*request->handler())(this, resultCode, strDup(envir().getResultMsg()));
00792 }

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

Definition at line 795 of file RTSPClient.cpp.

References False, and True.

Referenced by handleResponseBytes().

00795                                                                                          {
00796   if (sscanf(line, "RTSP/%*s%u", &responseCode) != 1 &&
00797       sscanf(line, "HTTP/%*s%u", &responseCode) != 1) return False;
00798   // Note: We check for HTTP responses as well as RTSP responses, both in order to setup RTSP-over-HTTP tunneling,
00799   // and so that we get back a meaningful error if the client tried to mistakenly send a RTSP command to a HTTP-only server.
00800 
00801   // Use everything after the RTSP/* (or HTTP/*) as the response string:
00802   responseString = line;
00803   while (responseString[0] != '\0' && responseString[0] != ' '  && responseString[0] != '\t') ++responseString;
00804   while (responseString[0] != '\0' && (responseString[0] == ' '  || responseString[0] == '\t')) ++responseString; // skip whitespace
00805 
00806   return True;
00807 }

void RTSPClient::handleIncomingRequest (  )  [private]

Definition at line 809 of file RTSPClient.cpp.

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

Referenced by handleResponseBytes().

00809                                        {
00810   // Parse the request string into command name and 'CSeq', then 'handle' the command (by responding that we don't support it):
00811   char cmdName[RTSP_PARAM_STRING_MAX];
00812   char urlPreSuffix[RTSP_PARAM_STRING_MAX];
00813   char urlSuffix[RTSP_PARAM_STRING_MAX];
00814   char cseq[RTSP_PARAM_STRING_MAX];
00815   unsigned contentLength;
00816   if (!parseRTSPRequestString(fResponseBuffer, fResponseBytesAlreadySeen,
00817                               cmdName, sizeof cmdName,
00818                               urlPreSuffix, sizeof urlPreSuffix,
00819                               urlSuffix, sizeof urlSuffix,
00820                               cseq, sizeof cseq,
00821                               contentLength)) {
00822     return;
00823   } else {
00824     if (fVerbosityLevel >= 1) {
00825       envir() << "Received incoming RTSP request: " << fResponseBuffer << "\n";
00826     }
00827     char tmpBuf[2*RTSP_PARAM_STRING_MAX];
00828     snprintf((char*)tmpBuf, sizeof tmpBuf,
00829              "RTSP/1.0 405 Method Not Allowed\r\nCSeq: %s\r\n\r\n", cseq);
00830     send(fOutputSocketNum, tmpBuf, strlen(tmpBuf), 0);
00831   }
00832 }

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

Definition at line 834 of file RTSPClient.cpp.

References _strncasecmp, False, and True.

Referenced by handleResponseBytes().

00834                                                                                                                                  {
00835   if (_strncasecmp(line, headerName, headerNameLength) != 0) return False;
00836 
00837   // The line begins with the desired header name.  Trim off any whitespace, and return the header parameters:
00838   unsigned paramIndex = headerNameLength;
00839   while (line[paramIndex] != '\0' && (line[paramIndex] == ' ' || line[paramIndex] == '\t')) ++paramIndex;
00840   if (&line[paramIndex] == '\0') return False; // the header is assumed to be bad if it has no parameters
00841 
00842   headerParams = &line[paramIndex];
00843   return True;
00844 }

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

Definition at line 846 of file RTSPClient.cpp.

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

Referenced by handleSETUPResponse().

00848                                                                                                     {
00849   // Initialize the return parameters to 'not found' values:
00850   serverAddressStr = NULL;
00851   serverPortNum = 0;
00852   rtpChannelId = rtcpChannelId = 0xFF;
00853 
00854   char* foundServerAddressStr = NULL;
00855   Boolean foundServerPortNum = False;
00856   portNumBits clientPortNum = 0;
00857   Boolean foundClientPortNum = False;
00858   Boolean foundChannelIds = False;
00859   unsigned rtpCid, rtcpCid;
00860   Boolean isMulticast = True; // by default
00861   char* foundDestinationStr = NULL;
00862   portNumBits multicastPortNumRTP, multicastPortNumRTCP;
00863   Boolean foundMulticastPortNum = False;
00864 
00865   // Run through each of the parameters, looking for ones that we handle:
00866   char const* fields = paramsStr;
00867   char* field = strDupSize(fields);
00868   while (sscanf(fields, "%[^;]", field) == 1) {
00869     if (sscanf(field, "server_port=%hu", &serverPortNum) == 1) {
00870       foundServerPortNum = True;
00871     } else if (sscanf(field, "client_port=%hu", &clientPortNum) == 1) {
00872       foundClientPortNum = True;
00873     } else if (_strncasecmp(field, "source=", 7) == 0) {
00874       delete[] foundServerAddressStr;
00875       foundServerAddressStr = strDup(field+7);
00876     } else if (sscanf(field, "interleaved=%u-%u", &rtpCid, &rtcpCid) == 2) {
00877       rtpChannelId = (unsigned char)rtpCid;
00878       rtcpChannelId = (unsigned char)rtcpCid;
00879       foundChannelIds = True;
00880     } else if (strcmp(field, "unicast") == 0) {
00881       isMulticast = False;
00882     } else if (_strncasecmp(field, "destination=", 12) == 0) {
00883       delete[] foundDestinationStr;
00884       foundDestinationStr = strDup(field+12);
00885     } else if (sscanf(field, "port=%hu-%hu", &multicastPortNumRTP, &multicastPortNumRTCP) == 2 ||
00886                sscanf(field, "port=%hu", &multicastPortNumRTP) == 1) {
00887       foundMulticastPortNum = True;
00888     }
00889 
00890     fields += strlen(field);
00891     while (fields[0] == ';') ++fields; // skip over all leading ';' chars
00892     if (fields[0] == '\0') break;
00893   }
00894   delete[] field;
00895 
00896   // If we're multicast, and have a "destination=" (multicast) address, then use this
00897   // as the 'server' address (because some weird servers don't specify the multicast
00898   // address earlier, in the "DESCRIBE" response's SDP:
00899   if (isMulticast && foundDestinationStr != NULL && foundMulticastPortNum) {
00900     delete[] foundServerAddressStr;
00901     serverAddressStr = foundDestinationStr;
00902     serverPortNum = multicastPortNumRTP;
00903     return True;
00904   }
00905   delete[] foundDestinationStr;
00906 
00907   // We have a valid "Transport:" header if any of the following are true:
00908   //   - We saw a "interleaved=" field, indicating RTP/RTCP-over-TCP streaming, or
00909   //   - We saw a "server_port=" field, or
00910   //   - We saw a "client_port=" field.
00911   //     If we didn't also see a "server_port=" field, then the server port is assumed to be the same as the client port.
00912   if (foundChannelIds || foundServerPortNum || foundClientPortNum) {
00913     if (foundClientPortNum && !foundServerPortNum) {
00914       serverPortNum = clientPortNum;
00915     }
00916     serverAddressStr = foundServerAddressStr;
00917     return True;
00918   }
00919 
00920   delete[] foundServerAddressStr;
00921   return False;
00922 }

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

Definition at line 924 of file RTSPClient.cpp.

References Numeric.

Referenced by handlePLAYResponse().

00924                                                                       {
00925   Locale l("C", Numeric);
00926   return sscanf(paramStr, "%f", &scale) == 1;
00927 }

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

Definition at line 929 of file RTSPClient.cpp.

References strDupSize(), and True.

Referenced by handlePLAYResponse().

00929                                                                                                       {
00930   while (paramsStr[0] == ',') ++paramsStr;
00931 
00932   // "paramsStr" now consists of a ';'-separated list of parameters, ending with ',' or '\0'.
00933   char* field = strDupSize(paramsStr);
00934 
00935   while (sscanf(paramsStr, "%[^;,]", field) == 1) {
00936     if (sscanf(field, "seq=%hu", &seqNum) == 1 ||
00937         sscanf(field, "rtptime=%u", &timestamp) == 1) {
00938     }
00939 
00940     paramsStr += strlen(field);
00941     if (paramsStr[0] == '\0' || paramsStr[0] == ',') break;
00942     // ASSERT: paramsStr[0] == ';'
00943     ++paramsStr; // skip over the ';'
00944   }
00945 
00946   delete[] field;
00947   return True;
00948 }

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

Definition at line 950 of file RTSPClient.cpp.

References MediaSubsession::connectionEndpointAddress(), MediaSubsession::connectionEndpointName(), Medium::envir(), False, fInputSocketNum, fLastSessionId, fServerAddress, fSessionTimeoutParameter, handleAlternativeRequestByte(), NULL, Groupsock::output(), parseTransportParams(), responseBufferSize, MediaSubsession::rtcpChannelId, 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().

00951                                                                 {
00952   char* sessionId = new char[responseBufferSize]; // ensures we have enough space
00953   Boolean success = False;
00954   do {
00955     // Check for a session id:
00956     if (sessionParamsStr == NULL || sscanf(sessionParamsStr, "%[^;]", sessionId) != 1) {
00957       envir().setResultMsg("Missing or bad \"Session:\" header");
00958       break;
00959     }
00960     subsession.setSessionId(sessionId);
00961     delete[] fLastSessionId; fLastSessionId = strDup(sessionId);
00962 
00963     // Also look for an optional "; timeout = " parameter following this:
00964     char const* afterSessionId = sessionParamsStr + strlen(sessionId);
00965     int timeoutVal;
00966     if (sscanf(afterSessionId, "; timeout = %d", &timeoutVal) == 1) {
00967       fSessionTimeoutParameter = timeoutVal;
00968     }
00969 
00970     // Parse the "Transport:" header parameters:
00971     char* serverAddressStr;
00972     portNumBits serverPortNum;
00973     unsigned char rtpChannelId, rtcpChannelId;
00974     if (!parseTransportParams(transportParamsStr, serverAddressStr, serverPortNum, rtpChannelId, rtcpChannelId)) {
00975       envir().setResultMsg("Missing or bad \"Transport:\" header");
00976       break;
00977     }
00978     delete[] subsession.connectionEndpointName();
00979     subsession.connectionEndpointName() = serverAddressStr;
00980     subsession.serverPortNum = serverPortNum;
00981     subsession.rtpChannelId = rtpChannelId;
00982     subsession.rtcpChannelId = rtcpChannelId;
00983 
00984     if (streamUsingTCP) {
00985       // Tell the subsession to receive RTP (and send/receive RTCP) over the RTSP stream:
00986       if (subsession.rtpSource() != NULL) {
00987         subsession.rtpSource()->setStreamSocket(fInputSocketNum, subsession.rtpChannelId);
00988         subsession.rtpSource()->setServerRequestAlternativeByteHandler(fInputSocketNum, handleAlternativeRequestByte, this);
00989       }
00990       if (subsession.rtcpInstance() != NULL) subsession.rtcpInstance()->setStreamSocket(fInputSocketNum, subsession.rtcpChannelId);
00991     } else {
00992       // Normal case.
00993       // Set the RTP and RTCP sockets' destination address and port from the information in the SETUP response (if present):
00994       netAddressBits destAddress = subsession.connectionEndpointAddress();
00995       if (destAddress == 0) destAddress = fServerAddress;
00996       subsession.setDestinations(destAddress);
00997 
00998       // Hack: To increase the likelihood of UDP packets from the server reaching us, if we're behind a NAT, send a few 'dummy'
00999       // UDP packets to the server now.  (We do this only for RTP, not RTCP, because for RTCP our regular RTCP "RR" packets will
01000       // have the same effect.)                                                                                                     
01001       if (subsession.rtpSource() != NULL) {
01002         Groupsock* gs = subsession.rtpSource()->RTPgs();
01003         if (gs != NULL) {
01004           u_int32_t dummy = 0xFEEDFACE;
01005           unsigned const numDummyPackets = 2;
01006           for (unsigned i = 0; i < numDummyPackets; ++i) gs->output(envir(), 255, (unsigned char*)&dummy, sizeof dummy);
01007         }
01008       }
01009     }
01010 
01011     success = True;
01012   } while (0);
01013 
01014   delete[] sessionId;
01015   return success;
01016 }

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

Definition at line 1018 of file RTSPClient.cpp.

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

Referenced by handleResponseBytes().

01019                                                                                                                              {
01020   Boolean scaleOK = False, rangeOK = False;
01021   do {
01022     if (&session != NULL) {
01023       // The command was on the whole session
01024       if (scaleParamsStr != NULL && !parseScaleParam(scaleParamsStr, session.scale())) break;
01025       scaleOK = True;
01026       if (rangeParamsStr != NULL && !parseRangeParam(rangeParamsStr, session.playStartTime(), session.playEndTime())) break;
01027       rangeOK = True;
01028 
01029       u_int16_t seqNum; u_int32_t timestamp;
01030       if (rtpInfoParamsStr != NULL) {
01031         if (!parseRTPInfoParams(rtpInfoParamsStr, seqNum, timestamp)) break;
01032         // This is data for our first subsession.  Fill it in, and do the same for our other subsessions:
01033         MediaSubsessionIterator iter(session);
01034         MediaSubsession* subsession;
01035         while ((subsession = iter.next()) != NULL) {
01036           subsession->rtpInfo.seqNum = seqNum;
01037           subsession->rtpInfo.timestamp = timestamp;
01038           subsession->rtpInfo.infoIsNew = True;
01039 
01040           if (!parseRTPInfoParams(rtpInfoParamsStr, seqNum, timestamp)) break;
01041         }
01042       }
01043     } else {
01044       // The command was on a subsession
01045       if (scaleParamsStr != NULL && !parseScaleParam(scaleParamsStr, subsession.scale())) break;
01046       scaleOK = True;
01047       if (rangeParamsStr != NULL && !parseRangeParam(rangeParamsStr, subsession._playStartTime(), subsession._playEndTime())) break;
01048       rangeOK = True;
01049 
01050       u_int16_t seqNum; u_int32_t timestamp;
01051       if (rtpInfoParamsStr != NULL) {
01052         if (!parseRTPInfoParams(rtpInfoParamsStr, seqNum, timestamp)) break;
01053         subsession.rtpInfo.seqNum = seqNum;
01054         subsession.rtpInfo.timestamp = timestamp;
01055         subsession.rtpInfo.infoIsNew = True;
01056       }
01057     }
01058 
01059     return True;
01060   } while (0);
01061 
01062   // An error occurred:
01063   if (!scaleOK) {
01064     envir().setResultMsg("Bad \"Scale:\" header");
01065   } else if (!rangeOK) {
01066     envir().setResultMsg("Bad \"Range:\" header");
01067   } else {
01068     envir().setResultMsg("Bad \"RTP-Info:\" header");
01069   }
01070   return False;
01071 }

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

Definition at line 1073 of file RTSPClient.cpp.

References True.

Referenced by handleResponseBytes().

01073                                                                                                      {
01074   // Because we don't expect to always get a response to "TEARDOWN", we don't need to do anything if we do get one:
01075   return True;
01076 }

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

Definition at line 1078 of file RTSPClient.cpp.

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

Referenced by handleResponseBytes().

01078                                                                                                    {
01079   do {
01080     // If "parameterName" is non-empty, it should be (possibly followed by ':' and whitespace) at the start of the result string:
01081     if (parameterName != NULL && parameterName[0] != '\0') {
01082       if (parameterName[1] == '\0') break; // sanity check; there should have been \r\n at the end of "parameterName"
01083 
01084       unsigned parameterNameLen = strlen(parameterName);
01085       // ASSERT: parameterNameLen >= 2;
01086       parameterNameLen -= 2; // because of the trailing \r\n
01087       if (_strncasecmp(resultValueString, parameterName, parameterNameLen) != 0) {
01088         // The parameter name wasn't in the output, so just return an empty string:
01089         resultValueString[0] = '\0';
01090         return True;
01091       }
01092       resultValueString += parameterNameLen;
01093       if (resultValueString[0] == ':') ++resultValueString;
01094       while (resultValueString[0] == ' ' || resultValueString[0] == '\t') ++resultValueString;
01095     }
01096 
01097     // The rest of "resultValueStr" should be our desired result, but first trim off any \r and/or \n characters at the end:
01098     unsigned resultLen = strlen(resultValueString);
01099     while (resultLen > 0 && (resultValueString[resultLen-1] == '\r' || resultValueString[resultLen-1] == '\n')) --resultLen;
01100     resultValueString[resultLen] = '\0';
01101 
01102     return True;
01103   } while (0);
01104 
01105   // An error occurred:
01106   envir().setResultMsg("Bad \"GET_PARAMETER\" response");
01107   return False;
01108 }

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

Definition at line 1110 of file RTSPClient.cpp.

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

Referenced by handleResponseBytes().

01110                                                                      {
01111   if (paramsStr == NULL) return False; // There was no "WWW-Authenticate:" header; we can't proceed.
01112 
01113   // Fill in "fCurrentAuthenticator" with the information from the "WWW-Authenticate:" header:
01114   Boolean alreadyHadRealm = fCurrentAuthenticator.realm() != NULL;
01115   char* realm = strDupSize(paramsStr);
01116   char* nonce = strDupSize(paramsStr);
01117   Boolean success = True;
01118   if (sscanf(paramsStr, "Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"", realm, nonce) == 2) {
01119     fCurrentAuthenticator.setRealmAndNonce(realm, nonce);
01120   } else if (sscanf(paramsStr, "Basic realm=\"%[^\"]\"", realm) == 1) {
01121     fCurrentAuthenticator.setRealmAndNonce(realm, NULL); // Basic authentication
01122   } else {
01123     success = False; // bad "WWW-Authenticate:" header
01124   }
01125   delete[] realm; delete[] nonce;
01126 
01127   if (alreadyHadRealm || fCurrentAuthenticator.username() == NULL || fCurrentAuthenticator.password() == NULL) {
01128     // We already had a 'realm', or don't have a username and/or password,
01129     // so the new "WWW-Authenticate:" header information won't help us.  We remain unauthenticated.
01130     success = False;
01131   }
01132 
01133   return success;
01134 }

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

Definition at line 1136 of file RTSPClient.cpp.

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

Referenced by handleResponseBytes().

01136                                                         {
01137   if (fVerbosityLevel >= 1) envir() << "Resending...\n";
01138   if (request != NULL && strcmp(request->commandName(), "GET") != 0) request->cseq() = ++fCSeq;
01139   return sendRequest(request) != 0;
01140 }

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

Definition at line 1142 of file RTSPClient.cpp.

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

Referenced by constructSubsessionURL(), and sendRequest().

01142                                                                     {
01143   char const* url = session.controlPath();
01144   if (url == NULL || strcmp(url, "*") == 0) url = fBaseURL;
01145 
01146   return url;
01147 }

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

Definition at line 1149 of file RTSPClient.cpp.

Referenced by handleSETUPResponse().

01149                                                                                     {
01150   ((RTSPClient*)rtspClient)->handleAlternativeRequestByte1(requestByte);
01151 }

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

Definition at line 1153 of file RTSPClient.cpp.

References fResponseBuffer, fResponseBytesAlreadySeen, and handleResponseBytes().

01153                                                                    {
01154   fResponseBuffer[fResponseBytesAlreadySeen] = requestByte;
01155   handleResponseBytes(1);
01156 }

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

Definition at line 1169 of file RTSPClient.cpp.

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

Referenced by sendRequest().

01172                                                              {
01173   // Figure out what the URL describing "subsession" will look like.
01174   // The URL is returned in three parts: prefix; separator; suffix
01175   //##### NOTE: This code doesn't really do the right thing if "sessionURL()"
01176   // doesn't end with a "/", and "subsession.controlPath()" is relative.
01177   // The right thing would have been to truncate "sessionURL()" back to the
01178   // rightmost "/", and then add "subsession.controlPath()".
01179   // In practice, though, each "DESCRIBE" response typically contains
01180   // a "Content-Base:" header that consists of "sessionURL()" followed by
01181   // a "/", in which case this code ends up giving the correct result.
01182   // However, we should really fix this code to do the right thing, and
01183   // also check for and use the "Content-Base:" header appropriately. #####
01184   prefix = sessionURL(subsession.parentSession());
01185   if (prefix == NULL) prefix = "";
01186 
01187   suffix = subsession.controlPath();
01188   if (suffix == NULL) suffix = "";
01189 
01190   if (isAbsoluteURL(suffix)) {
01191     prefix = separator = "";
01192   } else {
01193     unsigned prefixLen = strlen(prefix);
01194     separator = (prefixLen == 0 || prefix[prefixLen-1] == '/' || suffix[0] == '/') ? "" : "/";
01195   }
01196 }

Boolean RTSPClient::setupHTTPTunneling1 (  )  [private]

Definition at line 1198 of file RTSPClient.cpp.

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

Referenced by sendRequest().

01198                                         {
01199   // Set up RTSP-over-HTTP tunneling, as described in
01200   //     http://developer.apple.com/quicktime/icefloe/dispatch028.html and http://images.apple.com/br/quicktime/pdf/QTSS_Modules.pdf
01201   if (fVerbosityLevel >= 1) {
01202     envir() << "Requesting RTSP-over-HTTP tunneling (on port " << fTunnelOverHTTPPortNum << ")\n\n";
01203   }
01204 
01205   // Begin by sending a HTTP "GET", to set up the server->client link.  Continue when we handle the response:
01206   return sendRequest(new RequestRecord(1, "GET", responseHandlerForHTTP_GET)) != 0;
01207 }

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

Definition at line 1209 of file RTSPClient.cpp.

References NULL, and responseHandlerForHTTP_GET1().

Referenced by setupHTTPTunneling1().

01209                                                                                                           {
01210   if (rtspClient != NULL) rtspClient->responseHandlerForHTTP_GET1(responseCode, responseString);
01211 }

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

Definition at line 1213 of file RTSPClient.cpp.

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

Referenced by responseHandlerForHTTP_GET().

01213                                                                                    {
01214   RequestRecord* request;
01215   do {
01216     if (responseCode != 0) break; // The HTTP "GET" failed.
01217 
01218     // Having successfully set up (using the HTTP "GET" command) the server->client link, set up a second TCP connection
01219     // (to the same server & port as before) for the client->server link.  All future output will be to this new socket.
01220     fOutputSocketNum = setupStreamSocket(envir(), 0);
01221     if (fOutputSocketNum < 0) break;
01222 
01223     fHTTPTunnelingConnectionIsPending = True;
01224     int connectResult = connectToServer(fOutputSocketNum, fTunnelOverHTTPPortNum);
01225     if (connectResult < 0) break; // an error occurred
01226     else if (connectResult == 0) {
01227       // A connection is pending.  Continue setting up RTSP-over-HTTP when the connection completes.
01228       // First, move the pending requests to the 'awaiting connection' queue:
01229       while ((request = fRequestsAwaitingHTTPTunneling.dequeue()) != NULL) {
01230         fRequestsAwaitingConnection.enqueue(request);
01231       }
01232       return;
01233     }
01234 
01235     // The connection succeeded.  Continue setting up RTSP-over-HTTP:
01236     if (!setupHTTPTunneling2()) break;
01237 
01238     // RTSP-over-HTTP tunneling succeeded.  Resume the pending request(s):
01239     while ((request = fRequestsAwaitingHTTPTunneling.dequeue()) != NULL) {
01240       sendRequest(request);
01241     }
01242     return;
01243   } while (0);
01244 
01245   // An error occurred.  Dequeue the pending request(s), and tell them about the error:
01246   fHTTPTunnelingConnectionIsPending = False;
01247   while ((request = fRequestsAwaitingHTTPTunneling.dequeue()) != NULL) {
01248     handleRequestError(request);
01249     delete request;
01250   }
01251   resetTCPSockets();
01252 }

Boolean RTSPClient::setupHTTPTunneling2 (  )  [private]

Definition at line 1254 of file RTSPClient.cpp.

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

Referenced by connectionHandler1(), and responseHandlerForHTTP_GET1().

01254                                         {
01255   fHTTPTunnelingConnectionIsPending = False;
01256 
01257   // Send a HTTP "POST", to set up the client->server link.  (Note that we won't see a reply to the "POST".)
01258   return sendRequest(new RequestRecord(1, "POST", NULL)) != 0;
01259 }

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

Definition at line 1261 of file RTSPClient.cpp.

References connectionHandler1().

Referenced by connectToServer().

01261                                                                {
01262   RTSPClient* client = (RTSPClient*)instance;
01263   client->connectionHandler1();
01264 }

void RTSPClient::connectionHandler1 (  )  [private]

Definition at line 1266 of file RTSPClient.cpp.

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

Referenced by connectionHandler().

01266                                     {
01267   // Restore normal handling on our sockets:
01268   envir().taskScheduler().disableBackgroundHandling(fOutputSocketNum);
01269   envir().taskScheduler().setBackgroundHandling(fInputSocketNum, SOCKET_READABLE,
01270                                                 (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this);
01271 
01272   // Move all requests awaiting connection into a new, temporary queue, to clear "fRequestsAwaitingConnection"
01273   // (so that "sendRequest()" doesn't get confused by "fRequestsAwaitingConnection" being nonempty, and enqueue them all over again).
01274   RequestQueue tmpRequestQueue;
01275   RequestRecord* request;
01276   while ((request = fRequestsAwaitingConnection.dequeue()) != NULL) {
01277     tmpRequestQueue.enqueue(request);
01278   }
01279 
01280   // Find out whether the connection succeeded or failed:
01281   do {
01282     int err = 0;
01283     SOCKLEN_T len = sizeof err;
01284     if (getsockopt(fInputSocketNum, SOL_SOCKET, SO_ERROR, (char*)&err, &len) < 0 || err != 0) {
01285       envir().setResultErrMsg("Connection to server failed: ", err);
01286       if (fVerbosityLevel >= 1) envir() << "..." << envir().getResultMsg() << "\n";
01287       break;
01288     }
01289 
01290     // The connection succeeded.  If the connection came about from an attempt to set up RTSP-over-HTTP, finish this now:
01291     if (fVerbosityLevel >= 1) envir() << "...remote connection opened\n";
01292     if (fHTTPTunnelingConnectionIsPending && !setupHTTPTunneling2()) break;
01293 
01294     // Resume sending all pending requests:
01295     while ((request = tmpRequestQueue.dequeue()) != NULL) {
01296       sendRequest(request);
01297     }
01298     return;
01299   } while (0);
01300 
01301   // An error occurred.  Tell all pending requests about the error:
01302   while ((request = tmpRequestQueue.dequeue()) != NULL) {
01303     handleRequestError(request);
01304     delete request;
01305   }
01306   resetTCPSockets();
01307 }

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

Definition at line 1309 of file RTSPClient.cpp.

References incomingDataHandler1().

Referenced by connectionHandler1(), and openConnection().

01309                                                                  {
01310   RTSPClient* client = (RTSPClient*)instance;
01311   client->incomingDataHandler1();
01312 }

void RTSPClient::incomingDataHandler1 (  )  [private]

Definition at line 1314 of file RTSPClient.cpp.

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

Referenced by incomingDataHandler().

01314                                       {
01315   struct sockaddr_in dummy; // 'from' address - not used
01316 
01317   int bytesRead = readSocket(envir(), fInputSocketNum, (unsigned char*)&fResponseBuffer[fResponseBytesAlreadySeen], fResponseBufferBytesLeft, dummy);
01318   handleResponseBytes(bytesRead);
01319 }

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

Definition at line 1340 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().

01340                                                      {
01341   do {
01342     if (newBytesRead > 0 && (unsigned)newBytesRead < fResponseBufferBytesLeft) break; // data was read OK; process it below
01343 
01344     if ((unsigned)newBytesRead >= fResponseBufferBytesLeft) {
01345       // We filled up our response buffer.  Treat this as an error (for the first response handler):
01346       envir().setResultMsg("RTSP response was truncated. Increase \"RTSPClient::responseBufferSize\"");
01347     }
01348 
01349     // An error occurred while reading our TCP socket.  Call all pending response handlers, indicating this error:
01350     RequestRecord* request;
01351     while ((request = fRequestsAwaitingResponse.dequeue()) != NULL) {
01352       handleRequestError(request);
01353       delete request;
01354 
01355       if (newBytesRead > 0) break; // The "RTSP response was truncated" error is applied to the first response handler only
01356     }
01357 
01358     if (newBytesRead <= 0) resetTCPSockets();
01359     resetResponseBuffer();
01360     return;    
01361   } while (0);
01362 
01363   fResponseBufferBytesLeft -= newBytesRead;
01364   fResponseBytesAlreadySeen += newBytesRead;
01365   fResponseBuffer[fResponseBytesAlreadySeen] = '\0';
01366   if (fVerbosityLevel >= 1 && newBytesRead > 1) envir() << "Received " << newBytesRead << " new bytes of response data.\n";
01367   
01368   // Data was read OK.  Look through the data that we've read so far, to see if it contains <CR><LF><CR><LF>.
01369   // (If not, wait for more data to arrive.)
01370   Boolean endOfHeaders = False;
01371   if (fResponseBytesAlreadySeen > 3) {
01372     char const* const ptrEnd = &fResponseBuffer[fResponseBytesAlreadySeen-3];
01373     char const* ptr = fResponseBuffer;
01374     while (ptr < ptrEnd) {
01375       if (*ptr++ == '\r' && *ptr++ == '\n' && *ptr++ == '\r' && *ptr++ == '\n') {
01376         // This is it
01377         endOfHeaders = True;
01378         break;
01379       }
01380     }
01381   }
01382 
01383   if (!endOfHeaders) return; // subsequent reads will be needed to get the complete response
01384 
01385   // Now that we have the complete response headers (ending with <CR><LF><CR><LF>), parse them to get the response code, CSeq,
01386   // and various other header parameters.  To do this, we first make a copy of the received header data, because we'll be modifying
01387   // it by adding '\0' bytes.
01388   char* headerDataCopy;
01389   unsigned responseCode = 200;
01390   char const* responseStr = NULL;
01391   RequestRecord* foundRequest = NULL;
01392   char const* sessionParamsStr = NULL;
01393   char const* transportParamsStr = NULL;
01394   char const* scaleParamsStr = NULL;
01395   char const* rangeParamsStr = NULL;
01396   char const* rtpInfoParamsStr = NULL;
01397   char const* wwwAuthenticateParamsStr = NULL;
01398   char const* publicParamsStr = NULL;
01399   char* bodyStart = NULL;
01400   unsigned numBodyBytes = 0;
01401   Boolean responseSuccess = False; // by default
01402   do {
01403     headerDataCopy = new char[responseBufferSize];
01404     strncpy(headerDataCopy, fResponseBuffer, fResponseBytesAlreadySeen);
01405     headerDataCopy[fResponseBytesAlreadySeen] = '\0';
01406 
01407     char* lineStart = headerDataCopy;
01408     char* nextLineStart = getLine(lineStart);
01409     if (!parseResponseCode(lineStart, responseCode, responseStr)) {
01410       // This does not appear to be a RTSP response; perhaps it's a RTSP request instead?
01411       handleIncomingRequest();
01412       break; // we're done with this data
01413     }
01414 
01415     // Scan through the headers, handling the ones that we're interested in:
01416     Boolean reachedEndOfHeaders;
01417     unsigned cseq = 0;
01418     unsigned contentLength = 0;
01419 
01420     while (1) {
01421       reachedEndOfHeaders = True; // by default; may get changed below
01422       lineStart = nextLineStart;
01423       if (lineStart == NULL) break;
01424 
01425       nextLineStart = getLine(lineStart);
01426       if (lineStart[0] == '\0') break; // this is a blank line
01427       reachedEndOfHeaders = False;
01428 
01429       char const* headerParamsStr; 
01430       if (checkForHeader(lineStart, "CSeq:", 5, headerParamsStr)) {
01431         if (sscanf(headerParamsStr, "%u", &cseq) != 1 || cseq <= 0) {
01432           envir().setResultMsg("Bad \"CSeq:\" header: \"", lineStart, "\"");
01433           break;
01434         }
01435         // Find the handler function for "cseq":
01436         RequestRecord* request;
01437         while ((request = fRequestsAwaitingResponse.dequeue()) != NULL) {
01438           if (request->cseq() < cseq) { // assumes that the CSeq counter will never wrap around
01439             // We never received (and will never receive) a response for this handler, so delete it:
01440             delete request;
01441           } else if (request->cseq() == cseq) {
01442             // This is the handler that we want. Remove its record, but remember it, so that we can later call its handler:
01443             foundRequest = request;
01444             break;
01445           } else { // request->cseq() > cseq
01446             // No handler was registered for this response, so ignore it.
01447             break;
01448           }
01449         }
01450       } else if (checkForHeader(lineStart, "Content-Length:", 15, headerParamsStr)) {
01451         if (sscanf(headerParamsStr, "%u", &contentLength) != 1) {
01452           envir().setResultMsg("Bad \"Content-Length:\" header: \"", lineStart, "\"");
01453           break;
01454         }
01455       } else if (checkForHeader(lineStart, "Content-Base:", 13, headerParamsStr)) {
01456         setBaseURL(headerParamsStr);
01457       } else if (checkForHeader(lineStart, "Session:", 8, sessionParamsStr)) {
01458       } else if (checkForHeader(lineStart, "Transport:", 10, transportParamsStr)) {
01459       } else if (checkForHeader(lineStart, "Scale:", 6, scaleParamsStr)) {
01460       } else if (checkForHeader(lineStart, "Range:", 6, rangeParamsStr)) {
01461       } else if (checkForHeader(lineStart, "RTP-Info:", 9, rtpInfoParamsStr)) {
01462       } else if (checkForHeader(lineStart, "WWW-Authenticate:", 17, headerParamsStr)) {
01463         // If we've already seen a "WWW-Authenticate:" header, then we replace it with this new one only if
01464         // the new one specifies "Digest" authentication:
01465         if (wwwAuthenticateParamsStr == NULL || _strncasecmp(headerParamsStr, "Digest", 6) == 0) {
01466           wwwAuthenticateParamsStr = headerParamsStr;
01467         }
01468       } else if (checkForHeader(lineStart, "Public:", 7, publicParamsStr)) {
01469       } else if (checkForHeader(lineStart, "Allow:", 6, publicParamsStr)) {
01470         // Note: we accept "Allow:" instead of "Public:", so that "OPTIONS" requests made to HTTP servers will work.
01471       } else if (checkForHeader(lineStart, "Location:", 9, headerParamsStr)) {
01472         setBaseURL(headerParamsStr);
01473       }
01474     }
01475     if (!reachedEndOfHeaders) break; // an error occurred
01476 
01477     if (foundRequest == NULL) {
01478       // Hack: The response didn't have a "CSeq:" header; assume it's for our most recent request:
01479       foundRequest = fRequestsAwaitingResponse.dequeue();
01480     }
01481 
01482     // If we saw a "Content-Length:" header, then make sure that we have the amount of data that it specified:
01483     unsigned bodyOffset = nextLineStart - headerDataCopy;
01484     bodyStart = &fResponseBuffer[bodyOffset];
01485     numBodyBytes = fResponseBytesAlreadySeen - bodyOffset;
01486     if (contentLength > numBodyBytes) {
01487       // We need to read more data.  First, make sure we have enough space for it:
01488       unsigned numExtraBytesNeeded = contentLength - numBodyBytes;
01489       unsigned remainingBufferSize = responseBufferSize - fResponseBytesAlreadySeen;
01490       if (numExtraBytesNeeded > remainingBufferSize) {
01491         char tmpBuf[200];
01492         sprintf(tmpBuf, "Response buffer size (%d) is too small for \"Content-Length:\" %d (need a buffer size of >= %d bytes\n",
01493                 responseBufferSize, contentLength, fResponseBytesAlreadySeen + numExtraBytesNeeded);
01494         envir().setResultMsg(tmpBuf);
01495         break;
01496       }
01497 
01498       if (fVerbosityLevel >= 1) {
01499         envir() << "Have received " << fResponseBytesAlreadySeen << " total bytes of a "
01500                 << (foundRequest != NULL ? foundRequest->commandName() : "(unknown)")
01501                 << " RTSP response; awaiting " << numExtraBytesNeeded << " bytes more.\n";
01502       }
01503       delete[] headerDataCopy;
01504       if (foundRequest != NULL) fRequestsAwaitingResponse.putAtHead(foundRequest); // put back our request record; we need it again
01505       return; // We need to read more data
01506     }
01507 
01508     // We now have a complete response (including all bytes specified by the "Content-Length:" header, if any).
01509     if (fVerbosityLevel >= 1) {
01510       envir() << "Received a complete "
01511               << (foundRequest != NULL ? foundRequest->commandName() : "(unknown)")
01512               << " response:\n" << fResponseBuffer << "\n";
01513     }
01514 
01515     if (foundRequest != NULL) {
01516       Boolean needToResendCommand = False; // by default...
01517       if (responseCode == 200) {
01518         // Do special-case response handling for some commands:
01519         if (strcmp(foundRequest->commandName(), "SETUP") == 0) {
01520           if (!handleSETUPResponse(*foundRequest->subsession(), sessionParamsStr, transportParamsStr, foundRequest->booleanFlags()&0x1)) break;
01521         } else if (strcmp(foundRequest->commandName(), "PLAY") == 0) {
01522           if (!handlePLAYResponse(*foundRequest->session(), *foundRequest->subsession(), scaleParamsStr, rangeParamsStr, rtpInfoParamsStr)) break;
01523         } else if (strcmp(foundRequest->commandName(), "TEARDOWN") == 0) {
01524           if (!handleTEARDOWNResponse(*foundRequest->session(), *foundRequest->subsession())) break;
01525         } else if (strcmp(foundRequest->commandName(), "GET_PARAMETER") == 0) {
01526           if (!handleGET_PARAMETERResponse(foundRequest->contentStr(), bodyStart)) break;
01527         }
01528       } else if (responseCode == 401 && handleAuthenticationFailure(wwwAuthenticateParamsStr)) {
01529         // We need to resend the command, with an "Authorization:" header:
01530         needToResendCommand = True;
01531 
01532         if (strcmp(foundRequest->commandName(), "GET") == 0) {
01533           // Note: If a HTTP "GET" command (for RTSP-over-HTTP tunneling) returns "401 Unauthorized", then we resend it
01534           // (with an "Authorization:" header), just as we would for a RTSP command.  However, we do so using a new TCP connection,
01535           // because some servers close the original connection after returning the "401 Unauthorized".
01536           resetTCPSockets(); // forces the opening of a new connection for the resent command
01537         }
01538       } else if (responseCode == 301 || responseCode == 302) { // redirection
01539         resetTCPSockets(); // because we need to connect somewhere else next
01540         needToResendCommand = True;
01541       }
01542 
01543       if (needToResendCommand) {
01544         resetResponseBuffer();
01545         if (!resendCommand(foundRequest)) break;
01546         delete[] headerDataCopy;
01547         return; // without calling our response handler; the response to the resent command will do that
01548       }
01549     }
01550 
01551     responseSuccess = True;
01552   } while (0);
01553 
01554   // If we have a handler function for this response, call it:
01555   resetResponseBuffer(); // in preparation for our next response.  Do this now, in case the handler function goes to the event loop.
01556   if (foundRequest != NULL && foundRequest->handler() != NULL) {
01557     int resultCode;
01558     char* resultString;
01559     if (responseSuccess) {
01560       if (responseCode == 200) {
01561         resultCode = 0;
01562         resultString = numBodyBytes != 0 ? strDup(bodyStart) : strDup(publicParamsStr);
01563           // Note: The "strDup(bodyStart)" call assumes that the body is encoded without interior '\0' bytes
01564       } else {
01565         resultCode = responseCode;
01566         resultString = strDup(responseStr);
01567         envir().setResultMsg(responseStr);
01568       }
01569       (*foundRequest->handler())(this, resultCode, resultString);
01570     } else {
01571       // An error occurred parsing the response, so call the handler, indicating an error:
01572       handleRequestError(foundRequest);
01573     }
01574   }
01575   delete foundRequest;
01576   delete[] headerDataCopy;
01577 }

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

char* RTSPClient::describeURL ( char const *  url,
Authenticator authenticator = NULL,
Boolean  allowKasennaProtocol = False,
int  timeout = -1 
)

char* RTSPClient::describeWithPassword ( char const *  url,
char const *  username,
char const *  password,
Boolean  allowKasennaProtocol = False,
int  timeout = -1 
)

char* RTSPClient::sendOptionsCmd ( char const *  url,
char *  username = NULL,
char *  password = NULL,
Authenticator authenticator = NULL,
int  timeout = -1 
)

Boolean RTSPClient::announceSDPDescription ( char const *  url,
char const *  sdpDescription,
Authenticator authenticator = NULL,
int  timeout = -1 
)

Boolean RTSPClient::announceWithPassword ( char const *  url,
char const *  sdpDescription,
char const *  username,
char const *  password,
int  timeout = -1 
)

Boolean RTSPClient::setupMediaSubsession ( MediaSubsession subsession,
Boolean  streamOutgoing = False,
Boolean  streamUsingTCP = False,
Boolean  forceMulticastOnUnspecified = False 
)

Boolean RTSPClient::playMediaSession ( MediaSession session,
double  start = 0.0f,
double  end = -1.0f,
float  scale = 1.0f 
)

Boolean RTSPClient::playMediaSubsession ( MediaSubsession subsession,
double  start = 0.0f,
double  end = -1.0f,
float  scale = 1.0f,
Boolean  hackForDSS = False 
)

Boolean RTSPClient::pauseMediaSession ( MediaSession session  ) 

Boolean RTSPClient::pauseMediaSubsession ( MediaSubsession subsession  ) 

Boolean RTSPClient::recordMediaSubsession ( MediaSubsession subsession  ) 

Boolean RTSPClient::setMediaSessionParameter ( MediaSession session,
char const *  parameterName,
char const *  parameterValue 
)

Boolean RTSPClient::getMediaSessionParameter ( MediaSession session,
char const *  parameterName,
char *&  parameterValue 
)

Boolean RTSPClient::teardownMediaSession ( MediaSession session  ) 

Boolean RTSPClient::teardownMediaSubsession ( MediaSubsession subsession  ) 

static Boolean RTSPClient::parseRTSPURLUsernamePassword ( char const *  url,
char *&  username,
char *&  password 
) [static]

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

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

static void RTSPClient::timeoutHandlerForSyncInterface ( void *  rtspClient  )  [static, private]

void RTSPClient::timeoutHandlerForSyncInterface1 (  )  [private]

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(), continueAfterTEARDOWN(), WAVAudioFileSource::createNew(), QuickTimeFileSink::createNew(), QCELPAudioRTPSource::createNew(), MP3HTTPSource::createNew(), MP3FileSource::createNew(), AVIFileSink::createNew(), AMRAudioRTPSource::createNew(), WAVAudioFileServerMediaSubsession::createNewStreamSource(), MPEG1or2DemuxedServerMediaSubsession::createNewStreamSource(), MediaSubsession::deInitiate(), RTSPServerSupportingHTTPStreaming::RTSPClientSessionSupportingHTTPStreaming::handleHTTPCmd_StreamingGET(), MediaSubsession::initiate(), MPEG1or2ProgramStreamFileDuration(), MPEG1or2Demux::noteElementaryStreamDeletion(), ByteStreamMultiFileSource::onSourceClosure1(), StreamState::reclaim(), RTSPServer::removeServerMediaSession(), OnDemandServerMediaSubsession::sdpLines(), shutdownStream(), T140TextRTPSink::stopPlaying(), H264VideoRTPSink::stopPlaying(), subsessionAfterPlaying(), ClientTrickPlayState::updateStateOnScaleChange(), AMRDeinterleaver::~AMRDeinterleaver(), ByteStreamMultiFileSource::~ByteStreamMultiFileSource(), DarwinInjector::~DarwinInjector(), FramedFilter::~FramedFilter(), InputESSourceRecord::~InputESSourceRecord(), MatroskaFileParser::~MatroskaFileParser(), MatroskaFileServerDemux::~MatroskaFileServerDemux(), MPEG1or2Demux::~MPEG1or2Demux(), MPEG1or2FileServerDemux::~MPEG1or2FileServerDemux(), MPEG2TransportFileServerMediaSubsession::~MPEG2TransportFileServerMediaSubsession(), MPEG2TransportStreamFromPESSource::~MPEG2TransportStreamFromPESSource(), RTSPServerSupportingHTTPStreaming::RTSPClientSessionSupportingHTTPStreaming::~RTSPClientSessionSupportingHTTPStreaming(), ServerMediaSession::~ServerMediaSession(), ServerMediaSubsession::~ServerMediaSubsession(), StreamClientState::~StreamClientState(), and StreamReplicator::~StreamReplicator().

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(), T140IdleFilter::afterGettingFrame(), MultiFramedRTPSink::afterGettingFrame1(), InputESSourceRecord::afterGettingFrame1(), MPEG2TransportStreamFramer::afterGettingFrame1(), MPEG2IFrameIndexFromTransportStream::afterGettingFrame1(), H264VideoStreamDiscreteFramer::afterGettingFrame1(), BasicUDPSink::afterGettingFrame1(), MPEG4VideoFileServerMediaSubsession::afterPlayingDummy1(), H264VideoFileServerMediaSubsession::afterPlayingDummy1(), MPEG4VideoStreamParser::analyzeVOLHeader(), announceStream(), RTSPServer::RTSPClientSession::changeClientInputSocket(), MPEG4VideoFileServerMediaSubsession::checkForAuxSDPLine1(), H264VideoFileServerMediaSubsession::checkForAuxSDPLine1(), Medium::close(), MPEG2IFrameIndexFromTransportStream::compactParseBuffer(), connectionHandler1(), connectToServer(), T140TextRTPSink::continuePlaying(), QuickTimeFileSink::continuePlaying(), H264VideoRTPSink::continuePlaying(), AVIFileSink::continuePlaying(), VP8VideoMatroskaFileServerMediaSubsession::createNewRTPSink(), VorbisAudioMatroskaFileServerMediaSubsession::createNewRTPSink(), T140TextMatroskaFileServerMediaSubsession::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(), 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(), MPEG2IFrameIndexFromTransportStream::doGetNextFrame(), MP3FileSource::doGetNextFrame(), H264FUAFragmenter::doGetNextFrame(), ByteStreamMultiFileSource::doGetNextFrame(), ByteStreamFileSource::doGetNextFrame(), BasicUDPSource::doGetNextFrame(), AMRAudioFileSource::doGetNextFrame(), ADTSAudioFileSource::doGetNextFrame(), MultiFramedRTPSource::doGetNextFrame1(), MP3FileSource::doGetNextFrame1(), ADUFromMP3Source::doGetNextFrame1(), SIPClient::doInviteStateMachine(), ByteStreamFileSource::doReadFromFile(), MPEG1or2VideoRTPSink::doSpecialFrameHandling(), MP3ADURTPSink::doSpecialFrameHandling(), H263plusVideoRTPSink::doSpecialFrameHandling(), T140IdleFilter::doStopGettingFrames(), ByteStreamFileSource::doStopGettingFrames(), BasicUDPSource::doStopGettingFrames(), SegmentQueue::enqueueNewSegment(), StreamParser::ensureValidBytes1(), MediaSubsession::env(), SubsessionIOState::envir(), RTSPServer::RTSPClientSession::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(), handleGET_PARAMETERResponse(), RTSPServerSupportingHTTPStreaming::RTSPClientSessionSupportingHTTPStreaming::handleHTTPCmd_StreamingGET(), handleIncomingRequest(), handlePLAYResponse(), handleRequestError(), handleResponseBytes(), handleSETUPResponse(), RTSPServer::incomingConnectionHandler(), incomingDataHandler1(), RTCPInstance::incomingReportHandler1(), MP3FileSource::initializeStream(), MediaSession::initializeWithSDP(), MediaSession::initiateByMediaType(), SIPClient::invite1(), DynamicRTSPServer::lookupServerMediaSession(), MatroskaDemux::MatroskaDemux(), MatroskaFile::MatroskaFile(), MPEG4GenericRTPSource::MPEG4GenericRTPSource(), MatroskaDemux::newDemuxedTrack(), MPEG1or2FileServerDemux::newElementaryStream(), MPEG1or2Demux::newElementaryStream(), MPEG4GenericBufferedPacket::nextEnclosedFrameSize(), AMRBufferedPacket::nextEnclosedFrameSize(), 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(), RTCPInstance::reschedule(), resendCommand(), resetTCPSockets(), responseHandlerForHTTP_GET1(), RTSPServer::rtspURLPrefix(), RTCPInstance::schedule(), 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(), tearDownSession(), SIPClient::timerAHandler(), SIPClient::timerBHandler(), SIPClient::timerDHandler(), ClientTrickPlayState::updateStateOnScaleChange(), MPEG2TransportStreamFramer::updateTSPacketDurationEstimate(), BasicUDPSource::~BasicUDPSource(), ByteStreamFileSource::~ByteStreamFileSource(), DeviceSource::~DeviceSource(), RTSPServer::~RTSPServer(), StreamClientState::~StreamClientState(), and T140IdleFilter::~T140IdleFilter().

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(), WAVAudioFileSource::doGetNextFrame(), MP3FileSource::doGetNextFrame(), AMRAudioFileSource::doGetNextFrame(), ADTSAudioFileSource::doGetNextFrame(), MultiFramedRTPSource::doGetNextFrame1(), ByteStreamFileSource::doReadFromFile(), 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 158 of file RTSPClient.hh.

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

int RTSPClient::fVerbosityLevel [private]

Definition at line 269 of file RTSPClient.hh.

Referenced by connectionHandler1(), connectToServer(), handleIncomingRequest(), handleResponseBytes(), resendCommand(), sendRequest(), and setupHTTPTunneling1().

portNumBits RTSPClient::fTunnelOverHTTPPortNum [private]

Definition at line 270 of file RTSPClient.hh.

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

char* RTSPClient::fUserAgentHeaderStr [private]

Definition at line 271 of file RTSPClient.hh.

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

unsigned RTSPClient::fUserAgentHeaderStrLen [private]

Definition at line 272 of file RTSPClient.hh.

Referenced by sendRequest(), and setUserAgentString().

int RTSPClient::fInputSocketNum [private]

Definition at line 273 of file RTSPClient.hh.

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

int RTSPClient::fOutputSocketNum [private]

Definition at line 273 of file RTSPClient.hh.

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

netAddressBits RTSPClient::fServerAddress [private]

Definition at line 274 of file RTSPClient.hh.

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

unsigned RTSPClient::fCSeq [private]

Definition at line 275 of file RTSPClient.hh.

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

char* RTSPClient::fBaseURL [private]

Definition at line 276 of file RTSPClient.hh.

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

Authenticator RTSPClient::fCurrentAuthenticator [private]

Definition at line 277 of file RTSPClient.hh.

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

unsigned char RTSPClient::fTCPStreamIdCount [private]

Definition at line 278 of file RTSPClient.hh.

Referenced by sendRequest().

char* RTSPClient::fLastSessionId [private]

Definition at line 279 of file RTSPClient.hh.

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

unsigned RTSPClient::fSessionTimeoutParameter [private]

Definition at line 280 of file RTSPClient.hh.

Referenced by handleSETUPResponse(), and sessionTimeoutParameter().

char* RTSPClient::fResponseBuffer [private]

Definition at line 281 of file RTSPClient.hh.

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

unsigned RTSPClient::fResponseBytesAlreadySeen [private]

Definition at line 282 of file RTSPClient.hh.

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

unsigned RTSPClient::fResponseBufferBytesLeft [private]

Definition at line 282 of file RTSPClient.hh.

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

RequestQueue RTSPClient::fRequestsAwaitingConnection [private]

Definition at line 283 of file RTSPClient.hh.

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

RequestQueue RTSPClient::fRequestsAwaitingHTTPTunneling [private]

Definition at line 283 of file RTSPClient.hh.

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

RequestQueue RTSPClient::fRequestsAwaitingResponse [private]

Definition at line 283 of file RTSPClient.hh.

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

char RTSPClient::fSessionCookie[33] [private]

Definition at line 286 of file RTSPClient.hh.

Referenced by sendRequest().

unsigned RTSPClient::fSessionCookieCounter [private]

Definition at line 287 of file RTSPClient.hh.

Referenced by sendRequest().

Boolean RTSPClient::fHTTPTunnelingConnectionIsPending [private]

Definition at line 288 of file RTSPClient.hh.

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

TaskToken RTSPClient::fTimeoutTask [private]

Definition at line 345 of file RTSPClient.hh.

char RTSPClient::fWatchVariableForSyncInterface [private]

Definition at line 346 of file RTSPClient.hh.

char* RTSPClient::fResultString [private]

Definition at line 347 of file RTSPClient.hh.

int RTSPClient::fResultCode [private]

Definition at line 348 of file RTSPClient.hh.


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