RTSPClient Class Reference

#include <RTSPClient.hh>

Inheritance diagram for RTSPClient:

Inheritance graph
[legend]
Collaboration diagram for RTSPClient:

Collaboration graph
[legend]

Public Member Functions

int socketNum () const
char * describeURL (char const *url, Authenticator *authenticator=NULL, Boolean allowKasennaProtocol=False)
char * describeWithPassword (char const *url, char const *username, char const *password, Boolean allowKasennaProtocol=False)
Boolean announceSDPDescription (char const *url, char const *sdpDescription, Authenticator *authenticator=NULL)
Boolean announceWithPassword (char const *url, char const *sdpDescription, char const *username, char const *password)
char * sendOptionsCmd (char const *url, char *username=NULL, char *password=NULL, Authenticator *authenticator=NULL)
Boolean setupMediaSubsession (MediaSubsession &subsession, Boolean streamOutgoing=False, Boolean streamUsingTCP=False, Boolean forceMulticastOnUnspecified=False)
Boolean playMediaSession (MediaSession &session, float start=0.0f, float end=-1.0f, float scale=1.0f)
Boolean playMediaSubsession (MediaSubsession &subsession, float start=0.0f, float 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)
unsigned describeStatus () const
void setUserAgentString (char const *userAgentStr)
unsigned sessionTimeoutParameter () const
UsageEnvironmentenvir () const
char const * name () const
virtual Boolean isSource () const
virtual Boolean isSink () const
virtual Boolean isRTCPInstance () const
virtual Boolean isRTSPServer () const
virtual Boolean isMediaSession () const
virtual Boolean isServerMediaSession () const
virtual Boolean isDarwinInjector () const

Static Public Member Functions

static RTSPClientcreateNew (UsageEnvironment &env, 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 Boolean lookupByName (UsageEnvironment &env, char const *mediumName, Medium *&resultMedium)
static void close (UsageEnvironment &env, char const *mediumName)
static void close (Medium *medium)

Protected Member Functions

 RTSPClient (UsageEnvironment &env, int verbosityLevel, char const *applicationName, portNumBits tunnelOverHTTPPortNum)
virtual ~RTSPClient ()
TaskTokennextTask ()

Private Member Functions

virtual Boolean isRTSPClient () const
void reset ()
void resetTCPSockets ()
Boolean openConnectionFromURL (char const *url, Authenticator *authenticator)
char * createAuthenticatorString (Authenticator const *authenticator, char const *cmd, char const *url)
Boolean sendRequest (char const *requestString, char const *tag, Boolean base64EncodeIfOverHTTP=True)
Boolean getResponse (char const *tag, unsigned &bytesRead, unsigned &responseCode, char *&firstLine, char *&nextLineStart, Boolean checkFor200Response=True)
unsigned getResponse1 (char *&responseBuffer, unsigned responseBufferSize)
Boolean parseResponseCode (char const *line, unsigned &responseCode)
Boolean parseTransportResponse (char const *line, char *&serverAddressStr, portNumBits &serverPortNum, unsigned char &rtpChannelId, unsigned char &rtcpChannelId)
Boolean parseRTPInfoHeader (char *&line, u_int16_t &seqNum, u_int32_t &timestamp)
Boolean parseScaleHeader (char const *line, float &scale)
Boolean parseGetParameterHeader (char const *line, const char *param, char *&value)
char const * sessionURL (MediaSession const &session) const
void constructSubsessionURL (MediaSubsession const &subsession, char const *&prefix, char const *&separator, char const *&suffix)
Boolean setupHTTPTunneling (char const *urlSuffix, Authenticator *authenticator)
void incomingRequestHandler1 ()
void handleCmd_notSupported (char const *cseq)

Static Private Member Functions

static void checkForAuthenticationFailure (unsigned responseCode, char *&nextLineStart, Authenticator *authenticator)
static void incomingRequestHandler (void *, int)

Private Attributes

int fVerbosityLevel
portNumBits fTunnelOverHTTPPortNum
char * fUserAgentHeaderStr
unsigned fUserAgentHeaderStrSize
int fInputSocketNum
int fOutputSocketNum
unsigned fServerAddress
char * fBaseURL
Authenticator fCurrentAuthenticator
unsigned char fTCPStreamIdCount
char * fLastSessionId
unsigned fSessionTimeoutParameter
unsigned fDescribeStatusCode
char * fResponseBuffer
unsigned fResponseBufferSize
Boolean fServerIsKasenna
char * fKasennaContentType
Boolean fServerIsMicrosoft

Static Private Attributes

static unsigned fCSeq = 0

Detailed Description

Definition at line 34 of file RTSPClient.hh.


Constructor & Destructor Documentation

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

Definition at line 60 of file RTSPClient.cpp.

References fResponseBuffer, fResponseBufferSize, fUserAgentHeaderStr, fUserAgentHeaderStrSize, libVersionStr, LIVEMEDIA_LIBRARY_VERSION_STRING, and NULL.

Referenced by createNew().

00063   : Medium(env),
00064     fVerbosityLevel(verbosityLevel),
00065     fTunnelOverHTTPPortNum(tunnelOverHTTPPortNum),
00066     fInputSocketNum(-1), fOutputSocketNum(-1), fServerAddress(0),
00067     fBaseURL(NULL), fTCPStreamIdCount(0), fLastSessionId(NULL),
00068     fSessionTimeoutParameter(0),
00069 #ifdef SUPPORT_REAL_RTSP
00070     fRealChallengeStr(NULL), fRealETagStr(NULL),
00071 #endif
00072     fServerIsKasenna(False), fKasennaContentType(NULL),
00073     fServerIsMicrosoft(False)
00074 {
00075   fResponseBufferSize = 20000;
00076   fResponseBuffer = new char[fResponseBufferSize+1];
00077 
00078   // Set the "User-Agent:" header to use in each request:
00079   char const* const libName = "LIVE555 Streaming Media v";
00080   char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING;
00081   char const* libPrefix; char const* libSuffix;
00082   if (applicationName == NULL || applicationName[0] == '\0') {
00083     applicationName = libPrefix = libSuffix = "";
00084   } else {
00085     libPrefix = " (";
00086     libSuffix = ")";
00087   }
00088   char const* const formatStr = "User-Agent: %s%s%s%s%s\r\n";
00089   unsigned headerSize
00090     = strlen(formatStr) + strlen(applicationName) + strlen(libPrefix)
00091     + strlen(libName) + strlen(libVersionStr) + strlen(libSuffix);
00092   fUserAgentHeaderStr = new char[headerSize];
00093   sprintf(fUserAgentHeaderStr, formatStr,
00094           applicationName, libPrefix, libName, libVersionStr, libSuffix);
00095   fUserAgentHeaderStrSize = strlen(fUserAgentHeaderStr);
00096 }

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

Definition at line 110 of file RTSPClient.cpp.

References Medium::envir(), fInputSocketNum, fResponseBuffer, fUserAgentHeaderStr, reset(), UsageEnvironment::taskScheduler(), and TaskScheduler::turnOffBackgroundReadHandling().

00110                         {
00111   envir().taskScheduler().turnOffBackgroundReadHandling(fInputSocketNum); // must be called before:
00112   reset();
00113 
00114   delete[] fResponseBuffer;
00115   delete[] fUserAgentHeaderStr;
00116 }


Member Function Documentation

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

Definition at line 33 of file RTSPClient.cpp.

References env, and RTSPClient().

Referenced by createClient(), and DarwinInjector::setDestination().

00036                                                                      {
00037   return new RTSPClient(env, verbosityLevel,
00038                         applicationName, tunnelOverHTTPPortNum);
00039 }

int RTSPClient::socketNum (  )  const [inline]

Definition at line 44 of file RTSPClient.hh.

References fInputSocketNum.

Referenced by DarwinInjector::setDestination().

00044 { return fInputSocketNum; }

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

Definition at line 41 of file RTSPClient.cpp.

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

00043                                                             {
00044   resultClient = NULL; // unless we succeed
00045 
00046   Medium* medium;
00047   if (!Medium::lookupByName(env, instanceName, medium)) return False;
00048 
00049   if (!medium->isRTSPClient()) {
00050     env.setResultMsg(instanceName, " is not a RTSP client");
00051     return False;
00052   }
00053 
00054   resultClient = (RTSPClient*)medium;
00055   return True;
00056 }

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

Definition at line 165 of file RTSPClient.cpp.

References checkForAuthenticationFailure(), createAuthenticatorString(), describeWithPassword(), Medium::envir(), False, fBaseURL, fCSeq, fCurrentAuthenticator, fDescribeStatusCode, fInputSocketNum, fKasennaContentType, fResponseBuffer, fResponseBufferSize, fServerAddress, fServerIsKasenna, fServerIsMicrosoft, fUserAgentHeaderStr, fUserAgentHeaderStrSize, fVerbosityLevel, getLine(), getResponse(), NULL, openConnectionFromURL(), parseRTSPURLUsernamePassword(), password, readSocket(), reset(), Authenticator::reset(), sendRequest(), UsageEnvironment::setResultMsg(), strDup(), True, and username.

Referenced by describeWithPassword(), and getSDPDescriptionFromURL().

00166                                                             {
00167   char* cmd = NULL;
00168   fDescribeStatusCode = 0;
00169   do {  
00170     // First, check whether "url" contains a username:password to be used:
00171     char* username; char* password;
00172     if (authenticator == NULL
00173         && parseRTSPURLUsernamePassword(url, username, password)) {
00174       char* result = describeWithPassword(url, username, password, allowKasennaProtocol);
00175       delete[] username; delete[] password; // they were dynamically allocated
00176       return result;
00177     }
00178 
00179     if (!openConnectionFromURL(url, authenticator)) break;
00180 
00181     // Send the DESCRIBE command:
00182 
00183     // First, construct an authenticator string:
00184     fCurrentAuthenticator.reset();
00185     char* authenticatorStr
00186       = createAuthenticatorString(authenticator, "DESCRIBE", url);
00187 
00188     char const* acceptStr = allowKasennaProtocol
00189       ? "Accept: application/x-rtsp-mh, application/sdp\r\n"
00190       : "Accept: application/sdp\r\n";
00191 
00192     // (Later implement more, as specified in the RTSP spec, sec D.1 #####)
00193     char* const cmdFmt =
00194       "DESCRIBE %s RTSP/1.0\r\n"
00195       "CSeq: %d\r\n"
00196       "%s"
00197       "%s"
00198       "%s"
00199 #ifdef SUPPORT_REAL_RTSP
00200       REAL_DESCRIBE_HEADERS
00201 #endif
00202       "\r\n";
00203     unsigned cmdSize = strlen(cmdFmt)
00204       + strlen(url)
00205       + 20 /* max int len */
00206       + strlen(acceptStr)
00207       + strlen(authenticatorStr)
00208       + fUserAgentHeaderStrSize;
00209     cmd = new char[cmdSize];
00210     sprintf(cmd, cmdFmt,
00211             url,
00212             ++fCSeq,
00213             acceptStr,
00214             authenticatorStr,
00215             fUserAgentHeaderStr);
00216     delete[] authenticatorStr;
00217 
00218     if (!sendRequest(cmd, "DESCRIBE")) break;
00219 
00220     // Get the response from the server:
00221     unsigned bytesRead; unsigned responseCode;
00222     char* firstLine; char* nextLineStart;
00223     if (!getResponse("DESCRIBE", bytesRead, responseCode, firstLine, nextLineStart,
00224                      False /*don't check for response code 200*/)) break;
00225 
00226     // Inspect the first line to check whether it's a result code that
00227     // we can handle.
00228     Boolean wantRedirection = False;
00229     char* redirectionURL = NULL;
00230 #ifdef SUPPORT_REAL_RTSP
00231     delete[] fRealETagStr; fRealETagStr = new char[fResponseBufferSize];
00232 #endif
00233     if (responseCode == 301 || responseCode == 302) {
00234       wantRedirection = True;
00235       redirectionURL = new char[fResponseBufferSize]; // ensures enough space
00236     } else if (responseCode != 200) {
00237       checkForAuthenticationFailure(responseCode, nextLineStart, authenticator);
00238       envir().setResultMsg("cannot handle DESCRIBE response: ", firstLine);
00239       break;
00240     }
00241 
00242     // Skip over subsequent header lines, until we see a blank line.
00243     // The remaining data is assumed to be the SDP descriptor that we want.
00244     // While skipping over the header lines, we also check for certain headers
00245     // that we recognize.
00246     // (We should also check for "Content-type: application/sdp",
00247     // "Content-location", "CSeq", etc.) #####
00248     char* serverType = new char[fResponseBufferSize]; // ensures enough space
00249     int contentLength = -1;
00250     char* lineStart;
00251     while (1) {
00252       lineStart = nextLineStart;
00253       if (lineStart == NULL) break;
00254 
00255       nextLineStart = getLine(lineStart);
00256       if (lineStart[0] == '\0') break; // this is a blank line
00257 
00258       if (sscanf(lineStart, "Content-Length: %d", &contentLength) == 1
00259           || sscanf(lineStart, "Content-length: %d", &contentLength) == 1) {
00260         if (contentLength < 0) {
00261           envir().setResultMsg("Bad \"Content-length:\" header: \"",
00262                                lineStart, "\"");
00263           break;
00264         }
00265       } else if (strncmp(lineStart, "Content-Base:", 13) == 0) {
00266         int cbIndex = 13;
00267 
00268         while (lineStart[cbIndex] == ' ' || lineStart[cbIndex] == '\t') ++cbIndex; 
00269         if (lineStart[cbIndex] != '\0'/*sanity check*/) {
00270           delete[] fBaseURL; fBaseURL = strDup(&lineStart[cbIndex]);
00271         }
00272       } else if (sscanf(lineStart, "Server: %s", serverType) == 1) {
00273         if (strncmp(serverType, "Kasenna", 7) == 0) fServerIsKasenna = True;
00274         if (strncmp(serverType, "WMServer", 8) == 0) fServerIsMicrosoft = True;
00275 #ifdef SUPPORT_REAL_RTSP
00276       } else if (sscanf(lineStart, "ETag: %s", fRealETagStr) == 1) {
00277 #endif
00278       } else if (wantRedirection) { 
00279         if (sscanf(lineStart, "Location: %s", redirectionURL) == 1) {
00280           // Try again with this URL
00281           if (fVerbosityLevel >= 1) {
00282             envir() << "Redirecting to the new URL \""
00283                     << redirectionURL << "\"\n";
00284           }
00285           reset();
00286           char* result = describeURL(redirectionURL, authenticator, allowKasennaProtocol);
00287           delete[] redirectionURL;
00288           delete[] serverType;
00289           delete[] cmd;
00290           return result;
00291         }
00292       }
00293     } 
00294     delete[] serverType;
00295 
00296     // We're now at the end of the response header lines
00297     if (wantRedirection) {
00298       envir().setResultMsg("Saw redirection response code, but not a \"Location:\" header");
00299       delete[] redirectionURL;
00300       break;
00301     }
00302     if (lineStart == NULL) {
00303       envir().setResultMsg("no content following header lines: ", fResponseBuffer);
00304       break;
00305     }
00306 
00307     // Use the remaining data as the SDP descr, but first, check
00308     // the "Content-length:" header (if any) that we saw.  We may need to
00309     // read more data, or we may have extraneous data in the buffer.
00310     char* bodyStart = nextLineStart;
00311     if (contentLength >= 0) {
00312       // We saw a "Content-length:" header
00313       unsigned numBodyBytes = &firstLine[bytesRead] - bodyStart;
00314       if (contentLength > (int)numBodyBytes) {
00315         // We need to read more data.  First, make sure we have enough
00316         // space for it:
00317         unsigned numExtraBytesNeeded = contentLength - numBodyBytes;
00318         unsigned remainingBufferSize
00319           = fResponseBufferSize - (bytesRead + (firstLine - fResponseBuffer));
00320         if (numExtraBytesNeeded > remainingBufferSize) {
00321           char tmpBuf[200];
00322           sprintf(tmpBuf, "Read buffer size (%d) is too small for \"Content-length:\" %d (need a buffer size of >= %d bytes\n",
00323                   fResponseBufferSize, contentLength,
00324                   fResponseBufferSize + numExtraBytesNeeded - remainingBufferSize);
00325           envir().setResultMsg(tmpBuf);
00326           break;
00327         }
00328 
00329         // Keep reading more data until we have enough:
00330         if (fVerbosityLevel >= 1) {
00331           envir() << "Need to read " << numExtraBytesNeeded
00332                   << " extra bytes\n";
00333         }
00334         while (numExtraBytesNeeded > 0) {
00335           struct sockaddr_in fromAddress;
00336           char* ptr = &firstLine[bytesRead];
00337           int bytesRead2 = readSocket(envir(), fInputSocketNum, (unsigned char*)ptr,
00338                                       numExtraBytesNeeded, fromAddress);
00339           if (bytesRead2 < 0) break;
00340           ptr[bytesRead2] = '\0';
00341           if (fVerbosityLevel >= 1) {
00342             envir() << "Read " << bytesRead2 << " extra bytes: "
00343                     << ptr << "\n";
00344           }
00345 
00346           bytesRead += bytesRead2;
00347           numExtraBytesNeeded -= bytesRead2;
00348         }
00349         if (numExtraBytesNeeded > 0) break; // one of the reads failed
00350       }
00351 
00352       // Remove any '\0' characters from inside the SDP description.
00353       // Any such characters would violate the SDP specification, but
00354       // some RTSP servers have been known to include them:
00355       int from, to = 0;
00356       for (from = 0; from < contentLength; ++from) {
00357         if (bodyStart[from] != '\0') {
00358           if (to != from) bodyStart[to] = bodyStart[from];
00359           ++to;
00360         }
00361       }
00362       if (from != to && fVerbosityLevel >= 1) {
00363         envir() << "Warning: " << from-to << " invalid 'NULL' bytes were found in (and removed from) the SDP description.\n";
00364       }
00365       bodyStart[to] = '\0'; // trims any extra data
00366     }
00367 
00369     // If necessary, handle Kasenna's non-standard BS response:
00370     if (fServerIsKasenna && strncmp(bodyStart, "<MediaDescription>", 18) == 0) {
00371       // Translate from x-rtsp-mh to sdp
00372       int videoPid, audioPid;
00373       u_int64_t mh_duration;
00374       char* currentWord = new char[fResponseBufferSize]; // ensures enough space
00375       delete[] fKasennaContentType;
00376       fKasennaContentType = new char[fResponseBufferSize]; // ensures enough space
00377       char* currentPos = bodyStart;
00378       
00379       while (strcmp(currentWord, "</MediaDescription>") != 0) {
00380           sscanf(currentPos, "%s", currentWord);
00381           
00382           if (strcmp(currentWord, "VideoPid") == 0) {
00383             currentPos += strlen(currentWord) + 1;
00384             sscanf(currentPos, "%s", currentWord);
00385             currentPos += strlen(currentWord) + 1;
00386             sscanf(currentPos, "%d", &videoPid);
00387             currentPos += 3;
00388           }
00389           
00390           if (strcmp(currentWord, "AudioPid") == 0) {
00391             currentPos += strlen(currentWord) + 1;
00392             sscanf(currentPos, "%s", currentWord);
00393             currentPos += strlen(currentWord) + 1;
00394             sscanf(currentPos, "%d", &audioPid);
00395             currentPos += 3;
00396           }
00397           
00398           if (strcmp(currentWord, "Duration") == 0) {
00399             currentPos += strlen(currentWord) + 1;
00400             sscanf(currentPos, "%s", currentWord);
00401             currentPos += strlen(currentWord) + 1;
00402             sscanf(currentPos, "%llu", &mh_duration);
00403             currentPos += 3;
00404           }
00405           
00406           if (strcmp(currentWord, "TypeSpecificData") == 0) {
00407             currentPos += strlen(currentWord) + 1;
00408             sscanf(currentPos, "%s", currentWord);
00409             currentPos += strlen(currentWord) + 1;
00410             sscanf(currentPos, "%s", fKasennaContentType);
00411             currentPos += 3;
00412             printf("Kasenna Content Type: %s\n", fKasennaContentType);
00413           }
00414           
00415           currentPos += strlen(currentWord) + 1;
00416         }
00417       
00418       if (fKasennaContentType != NULL
00419           && strcmp(fKasennaContentType, "PARTNER_41_MPEG-4") == 0) {
00420           char* describeSDP = describeURL(url, authenticator, True);
00421           
00422           delete[] currentWord;
00423           delete[] cmd;
00424           return describeSDP;
00425       }
00426       
00427       unsigned char byte1 = fServerAddress & 0x000000ff;
00428       unsigned char byte2 = (fServerAddress & 0x0000ff00) >>  8;
00429       unsigned char byte3 = (fServerAddress & 0x00ff0000) >> 16;
00430       unsigned char byte4 = (fServerAddress & 0xff000000) >> 24;
00431       
00432       char const* sdpFmt =
00433         "v=0\r\n"
00434         "o=NoSpacesAllowed 1 1 IN IP4 %u.%u.%u.%u\r\n"
00435         "s=%s\r\n"
00436         "c=IN IP4 %u.%u.%u.%u\r\n"
00437         "t=0 0\r\n"
00438         "a=control:*\r\n"
00439         "a=range:npt=0-%llu\r\n"
00440         "m=video 1554 RAW/RAW/UDP 33\r\n"
00441         "a=control:trackID=%d\r\n";
00442       unsigned sdpBufSize = strlen(sdpFmt)
00443         + 4*3 // IP address
00444         + strlen(url)
00445         + 20 // max int length
00446         + 20; // max int length
00447       char* sdpBuf = new char[sdpBufSize];
00448       sprintf(sdpBuf, sdpFmt,
00449               byte1, byte2, byte3, byte4,
00450               url,
00451               byte1, byte2, byte3, byte4,
00452               mh_duration/1000000,
00453               videoPid);
00454       
00455       char* result = strDup(sdpBuf);
00456       delete[] sdpBuf; delete[] currentWord;
00457       delete[] cmd;
00458       return result;
00459     }
00461     
00462     delete[] cmd;
00463     return strDup(bodyStart);
00464   } while (0);
00465   
00466   delete[] cmd;
00467   if (fDescribeStatusCode == 0) fDescribeStatusCode = 2;
00468   return NULL;
00469 }

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

Definition at line 472 of file RTSPClient.cpp.

References describeURL(), fCurrentAuthenticator, NULL, Authenticator::realm(), and Authenticator::setUsernameAndPassword().

Referenced by describeURL(), and getSDPDescriptionFromURL().

00474                                                      {
00475   Authenticator authenticator;
00476   authenticator.setUsernameAndPassword(username, password);
00477   char* describeResult = describeURL(url, &authenticator, allowKasennaProtocol);
00478   if (describeResult != NULL) {
00479     // We are already authorized
00480     return describeResult;
00481   }
00482 
00483   // The "realm" field should have been filled in:
00484   if (authenticator.realm() == NULL) {
00485     // We haven't been given enough information to try again, so fail:
00486     return NULL;
00487   }
00488 
00489   // Try again:
00490   describeResult = describeURL(url, &authenticator, allowKasennaProtocol);
00491   if (describeResult != NULL) {
00492     // The authenticator worked, so use it in future requests:
00493     fCurrentAuthenticator = authenticator;
00494   }
00495 
00496   return describeResult;
00497 }

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

Definition at line 647 of file RTSPClient.cpp.

References checkForAuthenticationFailure(), createAuthenticatorString(), Medium::envir(), False, fCSeq, fCurrentAuthenticator, getResponse(), NULL, openConnectionFromURL(), Authenticator::reset(), sendRequest(), UsageEnvironment::setResultMsg(), and True.

Referenced by announceWithPassword(), and DarwinInjector::setDestination().

00649                                                                          {
00650   char* cmd = NULL;
00651   do {
00652     if (!openConnectionFromURL(url, authenticator)) break;
00653 
00654     // Send the ANNOUNCE command:
00655 
00656     // First, construct an authenticator string:
00657     fCurrentAuthenticator.reset();
00658     char* authenticatorStr
00659       = createAuthenticatorString(authenticator, "ANNOUNCE", url);
00660 
00661     char* const cmdFmt =
00662       "ANNOUNCE %s RTSP/1.0\r\n"
00663       "CSeq: %d\r\n"
00664       "Content-Type: application/sdp\r\n"
00665       "%s"
00666       "Content-length: %d\r\n\r\n"
00667       "%s";
00668             // Note: QTSS hangs if an "ANNOUNCE" contains a "User-Agent:" field (go figure), so don't include one here
00669     unsigned sdpSize = strlen(sdpDescription);
00670     unsigned cmdSize = strlen(cmdFmt)
00671       + strlen(url)
00672       + 20 /* max int len */
00673       + strlen(authenticatorStr)
00674       + 20 /* max int len */
00675       + sdpSize;
00676     cmd = new char[cmdSize];
00677     sprintf(cmd, cmdFmt,
00678             url,
00679             ++fCSeq,
00680             authenticatorStr,
00681             sdpSize,
00682             sdpDescription);
00683     delete[] authenticatorStr;
00684 
00685     if (!sendRequest(cmd, "ANNOUNCE")) break;
00686 
00687     // Get the response from the server:
00688     unsigned bytesRead; unsigned responseCode;
00689     char* firstLine; char* nextLineStart;
00690     if (!getResponse("ANNOUNCE", bytesRead, responseCode, firstLine, nextLineStart,
00691                      False /*don't check for response code 200*/)) break;
00692 
00693     // Inspect the first line to check whether it's a result code 200
00694     if (responseCode != 200) {
00695       checkForAuthenticationFailure(responseCode, nextLineStart, authenticator);
00696       envir().setResultMsg("cannot handle ANNOUNCE response: ", firstLine);
00697       break;
00698     }
00699 
00700     delete[] cmd;
00701     return True;
00702   } while (0);
00703 
00704   delete[] cmd;
00705   return False;
00706 }

Boolean RTSPClient::announceWithPassword ( char const *  url,
char const *  sdpDescription,
char const *  username,
char const *  password 
)

Definition at line 709 of file RTSPClient.cpp.

References announceSDPDescription(), False, fCurrentAuthenticator, NULL, Authenticator::realm(), Authenticator::setUsernameAndPassword(), and True.

Referenced by DarwinInjector::setDestination().

00710                                                                    {
00711   Authenticator authenticator;
00712   authenticator.setUsernameAndPassword(username, password);
00713   if (announceSDPDescription(url, sdpDescription, &authenticator)) {
00714     // We are already authorized
00715     return True;
00716   }
00717 
00718   // The "realm" field should have been filled in:
00719   if (authenticator.realm() == NULL) {
00720     // We haven't been given enough information to try again, so fail:
00721     return False;
00722   }
00723 
00724   // Try again:
00725   Boolean secondTrySuccess
00726     = announceSDPDescription(url, sdpDescription, &authenticator);
00727 
00728   if (secondTrySuccess) {
00729     // The authenticator worked, so use it in future requests:
00730     fCurrentAuthenticator = authenticator;
00731   }
00732 
00733   return secondTrySuccess;
00734 }

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

Definition at line 499 of file RTSPClient.cpp.

References _strncasecmp, checkForAuthenticationFailure(), createAuthenticatorString(), Medium::envir(), False, fCSeq, fUserAgentHeaderStr, fUserAgentHeaderStrSize, getLine(), getResponse(), NULL, openConnectionFromURL(), parseRTSPURLUsernamePassword(), Authenticator::realm(), sendRequest(), UsageEnvironment::setResultMsg(), Authenticator::setUsernameAndPassword(), strDup(), and True.

Referenced by getOptionsResponse().

00501                                                                {
00502   char* result = NULL;
00503   char* cmd = NULL;
00504   Boolean haveAllocatedAuthenticator = False;
00505   do {
00506     if (authenticator == NULL) {
00507       // First, check whether "url" contains a username:password to be used
00508       // (and no username,password pair was supplied separately):
00509       if (username == NULL && password == NULL
00510           && parseRTSPURLUsernamePassword(url, username, password)) {
00511         Authenticator newAuthenticator;
00512         newAuthenticator.setUsernameAndPassword(username, password);
00513         result = sendOptionsCmd(url, username, password, &newAuthenticator);
00514         delete[] username; delete[] password; // they were dynamically allocated
00515         break;
00516       } else if (username != NULL && password != NULL) {
00517         // Use the separately supplied username and password:
00518         authenticator = new Authenticator;
00519         haveAllocatedAuthenticator = True;
00520         authenticator->setUsernameAndPassword(username, password);
00521 
00522         result = sendOptionsCmd(url, username, password, authenticator);
00523         if (result != NULL) break; // We are already authorized
00524 
00525         // The "realm" field should have been filled in:
00526         if (authenticator->realm() == NULL) {
00527           // We haven't been given enough information to try again, so fail:
00528           break;
00529         }
00530         // Try again:
00531       }
00532     }
00533 
00534     if (!openConnectionFromURL(url, authenticator)) break;
00535 
00536     // Send the OPTIONS command:
00537 
00538     // First, construct an authenticator string:
00539     char* authenticatorStr
00540       = createAuthenticatorString(authenticator, "OPTIONS", url);
00541 
00542     char* const cmdFmt =
00543       "OPTIONS %s RTSP/1.0\r\n"
00544       "CSeq: %d\r\n"
00545       "%s"
00546       "%s"
00547 #ifdef SUPPORT_REAL_RTSP
00548       REAL_OPTIONS_HEADERS
00549 #endif
00550       "\r\n";
00551     unsigned cmdSize = strlen(cmdFmt)
00552       + strlen(url)
00553       + 20 /* max int len */
00554       + strlen(authenticatorStr)
00555       + fUserAgentHeaderStrSize;
00556     cmd = new char[cmdSize];
00557     sprintf(cmd, cmdFmt,
00558             url,
00559             ++fCSeq,
00560             authenticatorStr,
00561             fUserAgentHeaderStr);
00562     delete[] authenticatorStr;
00563 
00564     if (!sendRequest(cmd, "OPTIONS")) break;
00565 
00566     // Get the response from the server:
00567     unsigned bytesRead; unsigned responseCode;
00568     char* firstLine; char* nextLineStart;
00569     if (!getResponse("OPTIONS", bytesRead, responseCode, firstLine, nextLineStart,
00570                      False /*don't check for response code 200*/)) break;
00571     if (responseCode != 200) {
00572       checkForAuthenticationFailure(responseCode, nextLineStart, authenticator);
00573       envir().setResultMsg("cannot handle OPTIONS response: ", firstLine);
00574       break;
00575     }
00576 
00577     // Look for a "Public:" header (which will contain our result str):
00578     char* lineStart;
00579     while (1) {
00580       lineStart = nextLineStart;
00581       if (lineStart == NULL) break;
00582 
00583       nextLineStart = getLine(lineStart);
00584 
00585       if (_strncasecmp(lineStart, "Public: ", 8) == 0) {
00586         delete[] result; result = strDup(&lineStart[8]);
00587 #ifdef SUPPORT_REAL_RTSP
00588       } else if (_strncasecmp(lineStart, "RealChallenge1: ", 16) == 0) {
00589         delete[] fRealChallengeStr; fRealChallengeStr = strDup(&lineStart[16]);
00590 #endif
00591       }
00592     }
00593   } while (0);
00594 
00595   delete[] cmd;
00596   if (haveAllocatedAuthenticator) delete authenticator;
00597   return result;
00598 }

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

Definition at line 736 of file RTSPClient.cpp.

References MediaSubsession::clientPortNum(), MediaSubsession::connectionEndpointAddress(), MediaSubsession::connectionEndpointName(), constructSubsessionURL(), createAuthenticatorString(), Medium::envir(), False, fBaseURL, fCSeq, fCurrentAuthenticator, fInputSocketNum, fLastSessionId, fResponseBufferSize, fServerAddress, fServerIsMicrosoft, fSessionTimeoutParameter, fTCPStreamIdCount, fUserAgentHeaderStr, fUserAgentHeaderStrSize, getLine(), getResponse(), getResponse1(), IsMulticastAddress(), MediaSession::mediaSessionType(), NULL, MediaSubsession::parentSession(), parseTransportResponse(), MediaSession::playEndTime(), MediaSubsession::pro