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 * 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, NetAddress &address, portNumBits &portNum, char const **urlSuffix=NULL)
static Boolean parseRTSPURLUsernamePassword (char const *url, char *&username, char *&password)
static RTSPClientcreateNew (UsageEnvironment &env, int verbosityLevel=0, char const *applicationName=NULL, portNumBits tunnelOverHTTPPortNum=0)
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 ()
TaskTokennextTask ()

Private Member Functions

virtual Boolean isRTSPClient () const
void reset ()
void resetTCPSockets ()
void resetResponseBuffer ()
void setBaseURL (char const *url)
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, Boolean &responseIsHTTP)
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
unsigned 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

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

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

Referenced by createNew().

00308   : Medium(env),
00309     fVerbosityLevel(verbosityLevel), fTunnelOverHTTPPortNum(tunnelOverHTTPPortNum),
00310     fUserAgentHeaderStr(NULL), fUserAgentHeaderStrLen(0), fInputSocketNum(-1), fOutputSocketNum(-1), fServerAddress(0), fCSeq(1),
00311     fBaseURL(NULL), fTCPStreamIdCount(0), fLastSessionId(NULL), fSessionTimeoutParameter(0),
00312     fSessionCookieCounter(0), fHTTPTunnelingConnectionIsPending(False) {
00313   setBaseURL(rtspURL);
00314 
00315   fResponseBuffer = new char[responseBufferSize+1];
00316   resetResponseBuffer();
00317 
00318   // Set the "User-Agent:" header to use in each request:
00319   char const* const libName = "LIVE555 Streaming Media v";
00320   char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING;
00321   char const* libPrefix; char const* libSuffix;
00322   if (applicationName == NULL || applicationName[0] == '\0') {
00323     applicationName = libPrefix = libSuffix = "";
00324   } else {
00325     libPrefix = " (";
00326     libSuffix = ")";
00327   }
00328   unsigned userAgentNameSize
00329     = strlen(applicationName) + strlen(libPrefix) + strlen(libName) + strlen(libVersionStr) + strlen(libSuffix) + 1;
00330   char* userAgentName = new char[userAgentNameSize];
00331   sprintf(userAgentName, "%s%s%s%s%s", applicationName, libPrefix, libName, libVersionStr, libSuffix);
00332   setUserAgentString(userAgentName);
00333   delete[] userAgentName;
00334 }

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

Definition at line 336 of file RTSPClient.cpp.

References fResponseBuffer, fUserAgentHeaderStr, and reset().

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


Member Function Documentation

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

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

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(), 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(), 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 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 138 of file RTSPClient.hh.

References fInputSocketNum.

Referenced by DarwinInjector::setDestination().

00138 { 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,
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().

00174                                                          {
00175   do {
00176     // Parse the URL as "rtsp://<address>:<port>/<etc>"
00177     // (with ":<port>" and "/<etc>" optional)
00178     // Also, skip over any "<username>[:<password>]@" preceding <address>
00179     char const* prefix = "rtsp://";
00180     unsigned const prefixLength = 7;
00181     if (_strncasecmp(url, prefix, prefixLength) != 0) {
00182       env.setResultMsg("URL is not of the form \"", prefix, "\"");
00183       break;
00184     }
00185 
00186     unsigned const parseBufferSize = 100;
00187     char parseBuffer[parseBufferSize];
00188     char const* from = &url[prefixLength];
00189 
00190     // Skip over any "<username>[:<password>]@"
00191     // (Note that this code fails if <password> contains '@' or '/', but
00192     // given that these characters can also appear in <etc>, there seems to
00193     // be no way of unambiguously parsing that situation.)
00194     char const* from1 = from;
00195     while (*from1 != '\0' && *from1 != '/') {
00196       if (*from1 == '@') {
00197         from = ++from1;
00198         break;
00199       }
00200       ++from1;
00201     }
00202 
00203     char* to = &parseBuffer[0];
00204     unsigned i;
00205     for (i = 0; i < parseBufferSize; ++i) {
00206       if (*from == '\0' || *from == ':' || *from == '/') {
00207         // We've completed parsing the address
00208         *to = '\0';
00209         break;
00210       }
00211       *to++ = *from++;
00212     }
00213     if (i == parseBufferSize) {
00214       env.setResultMsg("URL is too long");
00215       break;
00216     }
00217 
00218     NetAddressList addresses(parseBuffer);
00219     if (addresses.numAddresses() == 0) {
00220       env.setResultMsg("Failed to find network address for \"",
00221                        parseBuffer, "\"");
00222       break;
00223     }
00224     address = *(addresses.firstAddress());
00225 
00226     portNum = 554; // default value
00227     char nextChar = *from;
00228     if (nextChar == ':') {
00229       int portNumInt;
00230       if (sscanf(++from, "%d", &portNumInt) != 1) {
00231         env.setResultMsg("No port number follows ':'");
00232         break;
00233       }
00234       if (portNumInt < 1 || portNumInt > 65535) {
00235         env.setResultMsg("Bad port number");
00236         break;
00237       }
00238       portNum = (portNumBits)portNumInt;
00239       while (*from >= '0' && *from <= '9') ++from; // skip over port number
00240     }
00241 
00242     // The remainder of the URL is the suffix:
00243     if (urlSuffix != NULL) *urlSuffix = from;
00244 
00245     return True;
00246   } while (0);
00247 
00248   return False;
00249 }

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

Definition at line 251 of file RTSPClient.cpp.

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

00253                                                                   {
00254   username = password = NULL; // by default
00255   do {
00256     // Parse the URL as "rtsp://<username>[:<password>]@<whatever>"
00257     char const* prefix = "rtsp://";
00258     unsigned const prefixLength = 7;
00259     if (_strncasecmp(url, prefix, prefixLength) != 0) break;
00260 
00261     // Look for the ':' and '@':
00262     unsigned usernameIndex = prefixLength;
00263     unsigned colonIndex = 0, atIndex = 0;
00264     for (unsigned i = usernameIndex; url[i] != '\0' && url[i] != '/'; ++i) {
00265       if (url[i] == ':' && colonIndex == 0) {
00266         colonIndex = i;
00267       } else if (url[i] == '@') {
00268         atIndex = i;
00269         break; // we're done
00270       }
00271     }
00272     if (atIndex == 0) break; // no '@' found
00273 
00274     char* urlCopy = strDup(url);
00275     urlCopy[atIndex] = '\0';
00276     if (colonIndex > 0) {
00277       urlCopy[colonIndex] = '\0';
00278       password = strDup(&urlCopy[colonIndex+1]);
00279     } else {
00280       password = strDup("");
00281     }
00282     username = strDup(&urlCopy[usernameIndex]);
00283     delete[] urlCopy;
00284 
00285     return True;
00286   } while (0);
00287 
00288   return False;
00289 }

void RTSPClient::setUserAgentString ( char const *  userAgentName  ) 

Definition at line 291 of file RTSPClient.cpp.

References fUserAgentHeaderStr, fUserAgentHeaderStrLen, and NULL.

Referenced by RTSPClient().

00291                                                              {
00292   if (userAgentName == NULL) return;
00293 
00294   // Change the existing user agent header string:
00295   char const* const formatStr = "User-Agent: %s\r\n";
00296   unsigned const headerSize = strlen(formatStr) + strlen(userAgentName);
00297   delete[] fUserAgentHeaderStr;
00298   fUserAgentHeaderStr = new char[headerSize];
00299   sprintf(fUserAgentHeaderStr, formatStr, userAgentName);
00300   fUserAgentHeaderStrLen = strlen(fUserAgentHeaderStr);
00301 }

unsigned RTSPClient::sessionTimeoutParameter (  )  const [inline]

Definition at line 153 of file RTSPClient.hh.

References fSessionTimeoutParameter.

00153 { return fSessionTimeoutParameter; }

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

Reimplemented from Medium.

Definition at line 343 of file RTSPClient.cpp.

References True.

00343                                        {
00344   return True;
00345 }

void RTSPClient::reset (  )  [private]

Definition at line 347 of file RTSPClient.cpp.

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

Referenced by ~RTSPClient().

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

void RTSPClient::resetTCPSockets (  )  [private]

Definition at line 359 of file RTSPClient.cpp.

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

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

void RTSPClient::resetResponseBuffer (  )  [private]

Definition at line 371 of file RTSPClient.cpp.

References fResponseBufferBytesLeft, fResponseBytesAlreadySeen, and responseBufferSize.

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

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

Definition at line 376 of file RTSPClient.cpp.

References fBaseURL, and strDup().

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

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

int RTSPClient::openConnection (  )  [private]

Definition at line 380 of file RTSPClient.cpp.

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

Referenced by sendRequest().

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

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

Definition at line 411 of file RTSPClient.cpp.

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

Referenced by openConnection(), and responseHandlerForHTTP_GET1().

00411                                                                         {
00412   MAKE_SOCKADDR_IN(remoteName, fServerAddress, htons(remotePortNum));
00413   if (fVerbosityLevel >= 1) {
00414     envir() << "Opening connection to " << our_inet_ntoa(remoteName.sin_addr) << ", port " << remotePortNum << "...\n";
00415   }
00416   if (connect(socketNum, (struct sockaddr*) &remoteName, sizeof remoteName) != 0) {
00417     if (envir().getErrno() == EINPROGRESS) {
00418       // The connection is pending; we'll need to handle it later.  Wait for our socket to be 'writable', or have an exception.
00419       envir().taskScheduler().setBackgroundHandling(socketNum, SOCKET_WRITABLE|SOCKET_EXCEPTION,
00420                                                     (TaskScheduler::BackgroundHandlerProc*)&connectionHandler, this);
00421       return 0;
00422     }
00423     envir().setResultErrMsg("connect() failed: ");
00424     if (fVerbosityLevel >= 1) envir() << "..." << envir().getResultMsg() << "\n";
00425     return -1;
00426   }
00427   if (fVerbosityLevel >= 1) envir() << "...local connection opened\n";
00428 
00429   return 1;
00430 }

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

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

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

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

Definition at line 514 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(), 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, and True.

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

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

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

Definition at line 793 of file RTSPClient.cpp.

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

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

00793                                                           {
00794   int resultCode = -envir().getErrno();
00795   if (resultCode == 0) {
00796     // Choose some generic error code instead:
00797 #if defined(__WIN32__) || defined(_WIN32) || defined(_QNX4)
00798     resultCode = -WSAENOTCONN;
00799 #else
00800     resultCode = -ENOTCONN;
00801 #endif
00802   }
00803   if (request->handler() != NULL) (*request->handler())(this, resultCode, strDup(envir().getResultMsg()));
00804 }

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

Definition at line 807 of file RTSPClient.cpp.

References False, and True.

Referenced by handleResponseBytes().

00807                                                                                                                   {
00808   responseIsHTTP = False; // by default
00809   if (sscanf(line, "RTSP/%*s%u", &responseCode) != 1) {
00810     if (sscanf(line, "HTTP/%*s%u", &responseCode) != 1) return False;
00811     responseIsHTTP = True;
00812     // Note: We check for HTTP responses as well as RTSP responses, both in order to setup RTSP-over-HTTP tunneling,
00813     // and so that we get back a meaningful error if the client tried to mistakenly send a RTSP command to a HTTP-only server.
00814   }
00815 
00816   // Use everything after the RTSP/* as the response string:
00817   responseString = line;
00818   while (responseString[0] != '\0' && responseString[0] != ' '  && responseString[0] != '\t') ++responseString;
00819   while (responseString[0] != '\0' && (responseString[0] == ' '  || responseString[0] == '\t')) ++responseString; // skip whitespace
00820 
00821   return True;
00822 }

void RTSPClient::handleIncomingRequest (  )  [private]

Definition at line 824 of file RTSPClient.cpp.

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

Referenced by handleResponseBytes().

00824                                        {
00825   // Parse the request string into command name and 'CSeq', then 'handle' the command (by responding that we don't support it):
00826   char cmdName[RTSP_PARAM_STRING_MAX];
00827   char urlPreSuffix[RTSP_PARAM_STRING_MAX];
00828   char urlSuffix[RTSP_PARAM_STRING_MAX];
00829   char cseq[RTSP_PARAM_STRING_MAX];
00830   if (!parseRTSPRequestString(fResponseBuffer, fResponseBytesAlreadySeen,
00831                               cmdName, sizeof cmdName,
00832                               urlPreSuffix, sizeof urlPreSuffix,
00833                               urlSuffix, sizeof urlSuffix,
00834                               cseq, sizeof cseq)) {
00835     return;
00836   } else {
00837     if (fVerbosityLevel >= 1) {
00838       envir() << "Received incoming RTSP request: " << fResponseBuffer << "\n";
00839     }
00840     char tmpBuf[2*RTSP_PARAM_STRING_MAX];
00841     snprintf((char*)tmpBuf, sizeof tmpBuf,
00842              "RTSP/1.0 405 Method Not Allowed\r\nCSeq: %s\r\n\r\n", cseq);
00843     send(fOutputSocketNum, tmpBuf, strlen(tmpBuf), 0);
00844   }
00845 }

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

Definition at line 847 of file RTSPClient.cpp.

References _strncasecmp, False, and True.

Referenced by handleResponseBytes().

00847                                                                                                                                  {
00848   if (_strncasecmp(line, headerName, headerNameLength) != 0) return False;
00849 
00850   // The line begins with the desired header name.  Trim off any whitespace, and return the header parameters:
00851   unsigned paramIndex = headerNameLength;
00852   while (line[paramIndex] != '\0' && (line[paramIndex] == ' ' || line[paramIndex] == '\t')) ++paramIndex;
00853   if (&line[paramIndex] == '\0') return False; // the header is assumed to be bad if it has no parameters
00854 
00855   headerParams = &line[paramIndex];
00856   return True;
00857 }

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

Definition at line 859 of file RTSPClient.cpp.

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

Referenced by handleSETUPResponse().

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

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

Definition at line 937 of file RTSPClient.cpp.

Referenced by handlePLAYResponse().

00937                                                                       {
00938   Locale l("C", LC_NUMERIC);
00939   return sscanf(paramStr, "%f", &scale) == 1;
00940 }

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

Definition at line 942 of file RTSPClient.cpp.

References strDupSize(), and True.

Referenced by handlePLAYResponse().

00942                                                                                                       {
00943   while (paramsStr[0] == ',') ++paramsStr;
00944 
00945   // "paramsStr" now consists of a ';'-separated list of parameters, ending with ',' or '\0'.
00946   char* field = strDupSize(paramsStr);
00947 
00948   while (sscanf(paramsStr, "%[^;,]", field) == 1) {
00949     if (sscanf(field, "seq=%hu", &seqNum) == 1 ||
00950         sscanf(field, "rtptime=%u", &timestamp) == 1) {
00951     }
00952 
00953     paramsStr += strlen(field);
00954     if (paramsStr[0] == '\0' || paramsStr[0] == ',') break;
00955     // ASSERT: paramsStr[0] == ';'
00956     ++paramsStr; // skip over the ';'
00957   }
00958 
00959   delete[] field;
00960   return True;
00961 }

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

Definition at line 963 of file RTSPClient.cpp.

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

Referenced by handleResponseBytes().

00964                                                                 {
00965   char* sessionId = new char[responseBufferSize]; // ensures we have enough space
00966   Boolean success = False;
00967   do {
00968     // Check for a session id:
00969     if (sessionParamsStr == NULL || sscanf(sessionParamsStr, "%[^;]", sessionId) != 1) {
00970       envir().setResultMsg("Missing or bad \"Session:\" header");
00971       break;
00972     }
00973     subsession.sessionId = strDup(sessionId);
00974     delete[] fLastSessionId; fLastSessionId = strDup(sessionId);
00975 
00976     // Also look for an optional "; timeout = " parameter following this:
00977     char const* afterSessionId = sessionParamsStr + strlen(sessionId);
00978     int timeoutVal;
00979     if (sscanf(afterSessionId, "; timeout = %d", &timeoutVal) == 1) {
00980       fSessionTimeoutParameter = timeoutVal;
00981     }
00982 
00983     // Parse the "Transport:" header parameters:
00984     char* serverAddressStr;
00985     portNumBits serverPortNum;
00986     unsigned char rtpChannelId, rtcpChannelId;
00987     if (!parseTransportParams(transportParamsStr, serverAddressStr, serverPortNum, rtpChannelId, rtcpChannelId)) {
00988       envir().setResultMsg("Missing or bad \"Transport:\" header");
00989       break;
00990     }
00991     delete[] subsession.connectionEndpointName();
00992     subsession.connectionEndpointName() = serverAddressStr;
00993     subsession.serverPortNum = serverPortNum;
00994     subsession.rtpChannelId = rtpChannelId;
00995     subsession.rtcpChannelId = rtcpChannelId;
00996 
00997     if (streamUsingTCP) {
00998       // Tell the subsession to receive RTP (and send/receive RTCP) over the RTSP stream:
00999       if (subsession.rtpSource() != NULL) {
01000         subsession.rtpSource()->setStreamSocket(fInputSocketNum, subsession.rtpChannelId);
01001         subsession.rtpSource()->setServerRequestAlternativeByteHandler(fInputSocketNum, handleAlternativeRequestByte, this);
01002       }
01003       if (subsession.rtcpInstance() != NULL) subsession.rtcpInstance()->setStreamSocket(fInputSocketNum, subsession.rtcpChannelId);
01004     } else {
01005       // Normal case.
01006       // Set the RTP and RTCP sockets' destination address and port from the information in the SETUP response (if present):
01007       netAddressBits destAddress = subsession.connectionEndpointAddress();
01008       if (destAddress == 0) destAddress = fServerAddress;
01009       subsession.setDestinations(destAddress);
01010     }
01011 
01012     success = True;
01013   } while (0);
01014 
01015   delete[] sessionId;
01016   return success;
01017 }

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

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

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

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

Definition at line 1074 of file RTSPClient.cpp.

References iter, MediaSubsessionIterator::next(), NULL, session, MediaSubsession::sessionId, subsession, and True.

Referenced by handleResponseBytes().

01074                                                                                              {
01075   if (&session != NULL) {
01076     // The command was on the whole session
01077     // Run through each subsession, deleting its "sessionId":
01078     MediaSubsessionIterator iter(session);
01079     MediaSubsession* subsession;
01080     while ((subsession = iter.next()) != NULL) {
01081       delete[] (char*)subsession->sessionId;
01082       subsession->sessionId = NULL;
01083     }
01084   } else {
01085     // The command was on a subsession
01086     delete[] (char*)subsession.sessionId;
01087     subsession.sessionId = NULL;
01088   }
01089   return True;
01090 }

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

Definition at line 1092 of file RTSPClient.cpp.

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

Referenced by handleResponseBytes().

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

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

Definition at line 1120 of file RTSPClient.cpp.

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

Referenced by handleResponseBytes().

01120                                                                      {
01121   // Fill in "fCurrentAuthenticator" with the information from the "WWW-Authenticate:" header:
01122   Boolean alreadyHadRealm = fCurrentAuthenticator.realm() != NULL;
01123   char* realm = strDupSize(paramsStr);
01124   char* nonce = strDupSize(paramsStr);
01125   Boolean success = True;
01126   if (sscanf(paramsStr, "Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"", realm, nonce) == 2) {
01127     fCurrentAuthenticator.setRealmAndNonce(realm, nonce);
01128   } else if (sscanf(paramsStr, "Basic realm=\"%[^\"]\"", realm) == 1) {
01129     fCurrentAuthenticator.setRealmAndNonce(realm, NULL); // Basic authentication
01130   } else {
01131     success = False; // bad "WWW-Authenticate:" header
01132   }
01133   delete[] realm; delete[] nonce;
01134 
01135   if (alreadyHadRealm || fCurrentAuthenticator.username() == NULL || fCurrentAuthenticator.password() == NULL) {
01136     // We already had a 'realm', or don't have a username and/or password,
01137     // so the new "WWW-Authenticate:" header information won't help us.  We remain unauthenticated.
01138     success = False;
01139   }
01140 
01141   return success;
01142 }

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

Definition at line 1144 of file RTSPClient.cpp.

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

Referenced by handleResponseBytes().

01144                                                         {
01145   if (fVerbosityLevel >= 1) envir() << "Resending...\n";
01146   if (request != NULL) request->cseq() = ++fCSeq;
01147   return sendRequest(request) != 0;
01148 }

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

Definition at line 1150 of file RTSPClient.cpp.

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

Referenced by constructSubsessionURL(), and sendRequest().

01150                                                                     {
01151   char const* url = session.controlPath();
01152   if (url == NULL || strcmp(url, "*") == 0) url = fBaseURL;
01153 
01154   return url;
01155 }

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

Definition at line 1157 of file RTSPClient.cpp.

Referenced by handleSETUPResponse().

01157                                                                                     {
01158   ((RTSPClient*)rtspClient)->handleAlternativeRequestByte1(requestByte);
01159 }

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

Definition at line 1161 of file RTSPClient.cpp.

References fResponseBuffer, fResponseBytesAlreadySeen, and handleResponseBytes().

01161                                                                    {
01162   fResponseBuffer[fResponseBytesAlreadySeen] = requestByte;
01163   handleResponseBytes(1);
01164 }

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

Definition at line 1177 of file RTSPClient.cpp.

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

Referenced by sendRequest().

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

Boolean RTSPClient::setupHTTPTunneling1 (  )  [private]

Definition at line 1206 of file RTSPClient.cpp.

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

Referenced by sendRequest().

01206                                         {
01207   // Set up RTSP-over-HTTP tunneling, as described in
01208   //     http://developer.apple.com/documentation/QuickTime/QTSS/Concepts/chapter_2_section_14.html
01209   if (fVerbosityLevel >= 1) {
01210     envir() << "Requesting RTSP-over-HTTP tunneling (on port " << fTunnelOverHTTPPortNum << ")\n\n";
01211   }
01212 
01213   // Begin by sending a HTTP "GET", to set up the server->client link.  Continue when we handle the response:
01214   return sendRequest(new RequestRecord(1, "GET", responseHandlerForHTTP_GET)) != 0;
01215 }

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

Definition at line 1217 of file RTSPClient.cpp.

References NULL, and responseHandlerForHTTP_GET1().

Referenced by setupHTTPTunneling1().

01217                                                                                                           {
01218   if (rtspClient != NULL) rtspClient->responseHandlerForHTTP_GET1(responseCode, responseString);
01219 }

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

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

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

Boolean RTSPClient::setupHTTPTunneling2 (  )  [private]

Definition at line 1260 of file RTSPClient.cpp.

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

Referenced by connectionHandler1(), and responseHandlerForHTTP_GET1().

01260                                         {
01261   fHTTPTunnelingConnectionIsPending = False;
01262 
01263   // Send a HTTP "POST", to set up the client->server link.  (Note that we won't see a reply to the "POST".)
01264   return sendRequest(new RequestRecord(1, "POST", NULL)) != 0;
01265 }

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

Definition at line 1267 of file RTSPClient.cpp.

References connectionHandler1().

Referenced by connectToServer().

01267                                                                {
01268   RTSPClient* client = (RTSPClient*)instance;
01269   client->connectionHandler1();
01270 }

void RTSPClient::connectionHandler1 (  )  [private]

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

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

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

Definition at line 1315 of file RTSPClient.cpp.

References incomingDataHandler1().

Referenced by connectionHandler1(), and openConnection().

01315                                                                  {
01316   RTSPClient* client = (RTSPClient*)instance;
01317   client->incomingDataHandler1();
01318 }

void RTSPClient::incomingDataHandler1 (  )  [private]

Definition at line 1320 of file RTSPClient.cpp.

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

Referenced by incomingDataHandler().

01320                                       {
01321   struct sockaddr_in dummy; // 'from' address - not used
01322 
01323   int bytesRead = readSocket(envir(), fInputSocketNum, (unsigned char*)&fResponseBuffer[fResponseBytesAlreadySeen], fResponseBufferBytesLeft, dummy);
01324   handleResponseBytes(bytesRead);
01325 }

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

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

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

00066                                                          {
00067   resultMedium = MediaLookupTable::ourMedia(env)->lookup(mediumName);
00068   if (resultMedium == NULL) {
00069     env.setResultMsg("Medium ", mediumName, " does not exist");
00070     return False;
00071   }
00072 
00073   return True;
00074 }

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

Definition at line 76 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(), MediaSubsession::initiate(), MPEG1or2ProgramStreamFileDuration(), MPEG1or2Demux::noteElementaryStreamDeletion(), ByteStreamMultiFileSource::onSourceClosure1(), StreamState::reclaim(), RTSPServer::removeServerMediaSession(), OnDemandServerMediaSubsession::sdpLines(), H264VideoRTPSink::stopPlaying(), subsessionAfterPlaying(), ClientTrickPlayState::updateStateOnScaleChange(), AMRDeinterleaver::~AMRDeinterleaver(), ByteStreamMultiFileSource::~ByteStreamMultiFileSource(), DarwinInjector::~DarwinInjector(), FramedFilter::~FramedFilter(), H264VideoRTPSink::~H264VideoRTPSink(), InputESSourceRecord::~InputESSourceRecord(), MPEG1or2Demux::~MPEG1or2Demux(), MPEG1or2FileServerDemux::~MPEG1or2FileServerDemux(), MPEG2TransportFileServerMediaSubsession::~MPEG2TransportFileServerMediaSubsession(), MPEG2TransportStreamFromPESSource::~MPEG2TransportStreamFromPESSource(), ServerMediaSession::~ServerMediaSession(), and ServerMediaSubsession::~ServerMediaSubsession().

00076                                                           {
00077   MediaLookupTable::ourMedia(env)->remove(name);
00078 }

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

Definition at line 80 of file Media.cpp.

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

00080                                  {
00081   if (medium == NULL) return;
00082 
00083   close(medium->envir(), medium->name());
00084 }

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::afterGettingBytes(), MultiFramedRTPSink::afterGettingFrame1(), InputESSourceRecord::afterGettingFrame1(), MPEG2TransportStreamFramer::afterGettingFrame1(), MPEG2IFrameIndexFromTransportStream::afterGettingFrame1(), HTTPSink::afterGettingFrame1(), BasicUDPSink::afterGettingFrame1(), MPEG4VideoFileServerMediaSubsession::afterPlayingDummy1(), MPEG4VideoStreamParser::analyzeVOLHeader(), announceStream(), MPEG4VideoFileServerMediaSubsession::checkForAuxSDPLine1(), Medium::close(), MPEG2IFrameIndexFromTransportStream::compactParseBuffer(), connectionHandler1(), connectToServer(), QuickTimeFileSink::continuePlaying(), HTTPSink::continuePlaying(), H264VideoRTPSink::continuePlaying(), AVIFileSink::continuePlaying(), MPEG4VideoFileServerMediaSubsession::createNewRTPSink(), MPEG2TransportFileServerMediaSubsession::createNewRTPSink(), MPEG1or2VideoFileServerMediaSubsession::createNewRTPSink(), MPEG1or2DemuxedServerMediaSubsession::createNewRTPSink(), H263plusVideoFileServerMediaSubsession::createNewRTPSink(), DVVideoFileServerMediaSubsession::createNewRTPSink(), AMRAudioFileServerMediaSubsession::createNewRTPSink(), ADTSAudioFileServerMediaSubsession::createNewRTPSink(), MPEG4VideoFileServerMediaSubsession::createNewStreamSource(), MPEG2TransportFileServerMediaSubsession::createNewStreamSource(), MPEG1or2VideoFileServerMediaSubsession::createNewStreamSource(), MPEG1or2DemuxedServerMediaSubsession::createNewStreamSource(), H263plusVideoFileServerMediaSubsession::createNewStreamSource(), DVVideoFileServerMediaSubsession::createNewStreamSource(), AMRAudioFileServerMediaSubsession::createNewStreamSource(), ADTSAudioFileServerMediaSubsession::createNewStreamSource(), MPEG2IFrameIndexFromTransportStream::deliverIndexRecord(), SegmentQueue::dequeue(), WAVAudioFileSource::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(), ByteStreamFileSource::doStopGettingFrames(), BasicUDPSource::doStopGettingFrames(), SegmentQueue::enqueueNewSegment(), StreamParser::ensureValidBytes1(), MediaSubsession::env(), SubsessionIOState::envir(), RTSPServer::RTSPClientSession::envir(), RTSPOverHTTPServer::HTTPClientConnection::envir(), RTPInterface::envir(), AVISubsessionIOState::envir(), ServerMediaSession::generateSDPDescription(), RTPSource::getAttributes(), MP3FileSource::getAttributes(), MP3ADUTranscoder::getAttributes(), MediaSource::getAttributes(), MPEG4VideoFileServerMediaSubsession::getAuxSDPLine(), getMPEG1or2TimeCode(), FramedSource::getNextFrame(), getOptions(), DVVideoStreamFramer::getProfile(), SIPClient::getResponse(), SIPClient::getResponseCode(), getSDPDescription(), OnDemandServerMediaSubsession::getStreamParameters(), handleGET_PARAMETERResponse(), handleIncomingRequest(), handlePLAYResponse(), handleRequestError(), handleResponseBytes(), handleSETUPResponse(), RTSPServer::incomingConnectionHandler1(), RTSPOverHTTPServer::incomingConnectionHandler1(), incomingDataHandler1(), RTCPInstance::incomingReportHandler1(), MP3FileSource::initializeStream(), MediaSession::initializeWithSDP(), MediaSession::initiateByMediaType(), SIPClient::invite1(), DynamicRTSPServer::lookupServerMediaSession(), MPEG4GenericRTPSource::MPEG4GenericRTPSource(), 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(), MPEGProgramStreamParser::parseSystemHeader(), MPEG4VideoStreamParser::parseVideoObjectLayer(), MPEG4VideoStreamParser::parseVideoObjectPlane(), MPEG4VideoStreamParser::parseVisualObject(), AC3AudioRTPSource::processSpecialHeader(), 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(), QuickTimeFileSink::setWord(), AVIFileSink::setWord(), QuickTimeFileSink::setWord64(), SIPClient::SIPClient(), 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(), RTSPOverHTTPServer::HTTPClientConnection::~HTTPClientConnection(), and RTSPServer::~RTSPServer().

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 86 of file Media.cpp.

References False.

Referenced by MediaSource::lookupByName().

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

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

Reimplemented in MediaSink.

Definition at line 90 of file Media.cpp.

References False.

Referenced by MediaSink::lookupByName().

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

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

Reimplemented in RTCPInstance.

Definition at line 94 of file Media.cpp.

References False.

Referenced by RTCPInstance::lookupByName().

00094                                      {
00095   return False; // default implementation
00096 }

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

Reimplemented in RTSPServer.

Definition at line 102 of file Media.cpp.

References False.

Referenced by RTSPServer::lookupByName().

00102                                    {
00103   return False; // default implementation
00104 }

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

Reimplemented in MediaSession.

Definition at line 106 of file Media.cpp.

References False.

Referenced by MediaSession::lookupByName().

00106                                      {
00107   return False; // default implementation
00108 }

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

Reimplemented in ServerMediaSession.

Definition at line 110 of file Media.cpp.

References False.

Referenced by ServerMediaSession::lookupByName().

00110                                            {
00111   return False; // default implementation
00112 }

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

Reimplemented in DarwinInjector.

Definition at line 114 of file Media.cpp.

References False.

Referenced by DarwinInjector::lookupByName().

00114                                        {
00115   return False; // default implementation
00116 }

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

Definition at line 77 of file Media.hh.

References Medium::fNextTask.

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

00077                         {
00078         return fNextTask;
00079   }


Field Documentation

unsigned RTSPClient::responseBufferSize = 20000 [static]

Definition at line 155 of file RTSPClient.hh.

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

int RTSPClient::fVerbosityLevel [private]

Definition at line 265 of file RTSPClient.hh.

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

portNumBits RTSPClient::fTunnelOverHTTPPortNum [private]

Definition at line 266 of file RTSPClient.hh.

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

char* RTSPClient::fUserAgentHeaderStr [private]

Definition at line 267 of file RTSPClient.hh.

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

unsigned RTSPClient::fUserAgentHeaderStrLen [private]

Definition at line 268 of file RTSPClient.hh.

Referenced by sendRequest(), and setUserAgentString().

int RTSPClient::fInputSocketNum [private]

Definition at line 269 of file RTSPClient.hh.

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

int RTSPClient::fOutputSocketNum [private]

Definition at line 269 of file RTSPClient.hh.

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

unsigned RTSPClient::fServerAddress [private]

Definition at line 270 of file RTSPClient.hh.

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

unsigned RTSPClient::fCSeq [private]

Definition at line 271 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 272 of file RTSPClient.hh.

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

Authenticator RTSPClient::fCurrentAuthenticator [private]

Definition at line 273 of file RTSPClient.hh.

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

unsigned char RTSPClient::fTCPStreamIdCount [private]

Definition at line 274 of file RTSPClient.hh.

Referenced by sendRequest().

char* RTSPClient::fLastSessionId [private]

Definition at line 275 of file RTSPClient.hh.

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

unsigned RTSPClient::fSessionTimeoutParameter [private]

Definition at line 276 of file RTSPClient.hh.

Referenced by handleSETUPResponse(), and sessionTimeoutParameter().

char* RTSPClient::fResponseBuffer [private]

Definition at line 277 of file RTSPClient.hh.

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

unsigned RTSPClient::fResponseBytesAlreadySeen [private]

Definition at line 278 of file RTSPClient.hh.

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

unsigned RTSPClient::fResponseBufferBytesLeft [private]

Definition at line 278 of file RTSPClient.hh.

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

RequestQueue RTSPClient::fRequestsAwaitingConnection [private]

Definition at line 279 of file RTSPClient.hh.

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

RequestQueue RTSPClient::fRequestsAwaitingHTTPTunneling [private]

Definition at line 279 of file RTSPClient.hh.

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

RequestQueue RTSPClient::fRequestsAwaitingResponse [private]

Definition at line 279 of file RTSPClient.hh.

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

char RTSPClient::fSessionCookie[33] [private]

Definition at line 282 of file RTSPClient.hh.

Referenced by sendRequest().

unsigned RTSPClient::fSessionCookieCounter [private]

Definition at line 283 of file RTSPClient.hh.

Referenced by sendRequest().

Boolean RTSPClient::fHTTPTunnelingConnectionIsPending [private]

Definition at line 284 of file RTSPClient.hh.

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

TaskToken RTSPClient::fTimeoutTask [private]

Definition at line 338 of file RTSPClient.hh.

char RTSPClient::fWatchVariableForSyncInterface [private]

Definition at line 339 of file RTSPClient.hh.

char* RTSPClient::fResultString [private]

Definition at line 340 of file RTSPClient.hh.

int RTSPClient::fResultCode [private]

Definition at line 341 of file RTSPClient.hh.


The documentation for this class was generated from the following files:
Generated on Fri Sep 3 02:37:46 2010 for live by  doxygen 1.5.2