#include <RTSPClient.hh>
Inheritance diagram for RTSPClient:


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 *¶meterValue) |
| Boolean | teardownMediaSession (MediaSession &session) |
| Boolean | teardownMediaSubsession (MediaSubsession &subsession) |
| UsageEnvironment & | envir () 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 RTSPClient * | createNew (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 RTSPClient * | createNew (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 () |
| TaskToken & | nextTask () |
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 *¶mStr, u_int16_t &seqNum, u_int32_t ×tamp) |
| 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 |
Definition at line 36 of file RTSPClient.hh.
| typedef void( RTSPClient::responseHandler)(RTSPClient *rtspClient, int resultCode, char *resultString) |
Definition at line 46 of file RTSPClient.hh.
| 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 }
| 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().
00359 { 00360 if (fInputSocketNum >= 0) { 00361 envir().taskScheduler().disableBackgroundHandling(fInputSocketNum); 00362 ::closeSocket(fInputSocketNum); 00363 if (fOutputSocketNum != fInputSocketNum) { 00364 envir().taskScheduler().disableBackgroundHandling(fOutputSocketNum); 00365 ::closeSocket(fOutputSocketNum); 00366 } 00367 } 00368 fInputSocketNum = fOutputSocketNum = -1; 00369 }
| void RTSPClient::resetResponseBuffer | ( | ) | [private] |
Definition at line 371 of file RTSPClient.cpp.
References fResponseBufferBytesLeft, fResponseBytesAlreadySeen, and responseBufferSize.
Referenced by handleResponseBytes(), reset(), and RTSPClient().
00371 { 00372 fResponseBytesAlreadySeen = 0; 00373 fResponseBufferBytesLeft = responseBufferSize; 00374 }
| 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().
| 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.
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] |
| 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", ×tamp) == 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] |
| 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 }
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().
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().
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] |
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().
Definition at line 279 of file RTSPClient.hh.
Referenced by changeResponseHandler(), connectionHandler1(), responseHandlerForHTTP_GET1(), and sendRequest().
Definition at line 279 of file RTSPClient.hh.
Referenced by changeResponseHandler(), responseHandlerForHTTP_GET1(), and sendRequest().
Definition at line 279 of file RTSPClient.hh.
Referenced by changeResponseHandler(), handleResponseBytes(), and sendRequest().
char RTSPClient::fSessionCookie[33] [private] |
unsigned RTSPClient::fSessionCookieCounter [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.
1.5.2