00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "RTSPClient.hh"
00022 #include "RTSPCommon.hh"
00023 #include "Base64.hh"
00024 #include "Locale.hh"
00025 #include <GroupsockHelper.hh>
00026 #include "our_md5.h"
00027
00029
00030 RTSPClient* RTSPClient::createNew(UsageEnvironment& env, char const* rtspURL,
00031 int verbosityLevel,
00032 char const* applicationName,
00033 portNumBits tunnelOverHTTPPortNum) {
00034 return new RTSPClient(env, rtspURL,
00035 verbosityLevel, applicationName, tunnelOverHTTPPortNum);
00036 }
00037
00038 unsigned RTSPClient::sendDescribeCommand(responseHandler* responseHandler, Authenticator* authenticator) {
00039 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00040 return sendRequest(new RequestRecord(++fCSeq, "DESCRIBE", responseHandler));
00041 }
00042
00043 unsigned RTSPClient::sendOptionsCommand(responseHandler* responseHandler, Authenticator* authenticator) {
00044 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00045 return sendRequest(new RequestRecord(++fCSeq, "OPTIONS", responseHandler));
00046 }
00047
00048 unsigned RTSPClient::sendAnnounceCommand(char const* sdpDescription, responseHandler* responseHandler, Authenticator* authenticator) {
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 }
00052
00053 unsigned RTSPClient::sendSetupCommand(MediaSubsession& subsession, responseHandler* responseHandler,
00054 Boolean streamOutgoing, Boolean streamUsingTCP, Boolean forceMulticastOnUnspecified,
00055 Authenticator* authenticator) {
00056 if (fTunnelOverHTTPPortNum != 0) streamUsingTCP = True;
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 }
00065
00066 unsigned RTSPClient::sendPlayCommand(MediaSession& session, responseHandler* responseHandler,
00067 double start, double end, float scale,
00068 Authenticator* authenticator) {
00069 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00070 return sendRequest(new RequestRecord(++fCSeq, "PLAY", responseHandler, &session, NULL, 0, start, end, scale));
00071 }
00072
00073 unsigned RTSPClient::sendPlayCommand(MediaSubsession& subsession, responseHandler* responseHandler,
00074 double start, double end, float scale,
00075 Authenticator* authenticator) {
00076 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00077 return sendRequest(new RequestRecord(++fCSeq, "PLAY", responseHandler, NULL, &subsession, 0, start, end, scale));
00078 }
00079
00080 unsigned RTSPClient::sendPauseCommand(MediaSession& session, responseHandler* responseHandler, Authenticator* authenticator) {
00081 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00082 return sendRequest(new RequestRecord(++fCSeq, "PAUSE", responseHandler, &session));
00083 }
00084
00085 unsigned RTSPClient::sendPauseCommand(MediaSubsession& subsession, responseHandler* responseHandler, Authenticator* authenticator) {
00086 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00087 return sendRequest(new RequestRecord(++fCSeq, "PAUSE", responseHandler, NULL, &subsession));
00088 }
00089
00090 unsigned RTSPClient::sendRecordCommand(MediaSession& session, responseHandler* responseHandler, Authenticator* authenticator) {
00091 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00092 return sendRequest(new RequestRecord(++fCSeq, "RECORD", responseHandler, &session));
00093 }
00094
00095 unsigned RTSPClient::sendRecordCommand(MediaSubsession& subsession, responseHandler* responseHandler, Authenticator* authenticator) {
00096 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00097 return sendRequest(new RequestRecord(++fCSeq, "RECORD", responseHandler, NULL, &subsession));
00098 }
00099
00100 unsigned RTSPClient::sendTeardownCommand(MediaSession& session, responseHandler* responseHandler, Authenticator* authenticator) {
00101 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00102 return sendRequest(new RequestRecord(++fCSeq, "TEARDOWN", responseHandler, &session));
00103 }
00104
00105 unsigned RTSPClient::sendTeardownCommand(MediaSubsession& subsession, responseHandler* responseHandler, Authenticator* authenticator) {
00106 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00107 return sendRequest(new RequestRecord(++fCSeq, "TEARDOWN", responseHandler, NULL, &subsession));
00108 }
00109
00110 unsigned RTSPClient::sendSetParameterCommand(MediaSession& session, responseHandler* responseHandler,
00111 char const* parameterName, char const* parameterValue,
00112 Authenticator* authenticator) {
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 }
00120
00121 unsigned RTSPClient::sendGetParameterCommand(MediaSession& session, responseHandler* responseHandler, char const* parameterName,
00122 Authenticator* authenticator) {
00123 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00124
00125
00126
00127
00128
00129 unsigned parameterNameLen = parameterName == NULL ? 0 : strlen(parameterName);
00130 char* paramString = new char[parameterNameLen + 3];
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 }
00140
00141 Boolean RTSPClient::changeResponseHandler(unsigned cseq, responseHandler* newResponseHandler) {
00142
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 }
00153
00154 Boolean RTSPClient::lookupByName(UsageEnvironment& env,
00155 char const* instanceName,
00156 RTSPClient*& resultClient) {
00157 resultClient = NULL;
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 }
00170
00171 Boolean RTSPClient::parseRTSPURL(UsageEnvironment& env, char const* url,
00172 NetAddress& address,
00173 portNumBits& portNum,
00174 char const** urlSuffix) {
00175 do {
00176
00177
00178
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
00191
00192
00193
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
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;
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;
00240 }
00241
00242
00243 if (urlSuffix != NULL) *urlSuffix = from;
00244
00245 return True;
00246 } while (0);
00247
00248 return False;
00249 }
00250
00251 Boolean RTSPClient::parseRTSPURLUsernamePassword(char const* url,
00252 char*& username,
00253 char*& password) {
00254 username = password = NULL;
00255 do {
00256
00257 char const* prefix = "rtsp://";
00258 unsigned const prefixLength = 7;
00259 if (_strncasecmp(url, prefix, prefixLength) != 0) break;
00260
00261
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;
00270 }
00271 }
00272 if (atIndex == 0) break;
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 }
00290
00291 void RTSPClient::setUserAgentString(char const* userAgentName) {
00292 if (userAgentName == NULL) return;
00293
00294
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 }
00302
00303 unsigned RTSPClient::responseBufferSize = 20000;
00304
00305 RTSPClient::RTSPClient(UsageEnvironment& env, char const* rtspURL,
00306 int verbosityLevel, char const* applicationName,
00307 portNumBits tunnelOverHTTPPortNum)
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
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 }
00335
00336 RTSPClient::~RTSPClient() {
00337 reset();
00338
00339 delete[] fResponseBuffer;
00340 delete[] fUserAgentHeaderStr;
00341 }
00342
00343 Boolean RTSPClient::isRTSPClient() const {
00344 return True;
00345 }
00346
00347 void RTSPClient::reset() {
00348 resetTCPSockets();
00349 resetResponseBuffer();
00350 fServerAddress = 0;
00351
00352 setBaseURL(NULL);
00353
00354 fCurrentAuthenticator.reset();
00355
00356 delete[] fLastSessionId; fLastSessionId = NULL;
00357 }
00358
00359 void RTSPClient::resetTCPSockets() {
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 }
00370
00371 void RTSPClient::resetResponseBuffer() {
00372 fResponseBytesAlreadySeen = 0;
00373 fResponseBufferBytesLeft = responseBufferSize;
00374 }
00375
00376 void RTSPClient::setBaseURL(char const* url) {
00377 delete[] fBaseURL; fBaseURL = strDup(url);
00378 }
00379
00380 int RTSPClient::openConnection() {
00381 do {
00382
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
00392 fInputSocketNum = fOutputSocketNum = setupStreamSocket(envir(), 0);
00393 if (fInputSocketNum < 0) break;
00394
00395
00396 fServerAddress = *(unsigned*)(destAddress.data());
00397 int connectResult = connectToServer(fInputSocketNum, destPortNum);
00398 if (connectResult < 0) break;
00399 else if (connectResult > 0) {
00400
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 }
00410
00411 int RTSPClient::connectToServer(int socketNum, portNumBits remotePortNum) {
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
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 }
00431
00432 char*
00433 RTSPClient::createAuthenticatorString(char const* cmd, char const* url) {
00434 Authenticator& auth = fCurrentAuthenticator;
00435 if (auth.realm() != NULL && auth.username() != NULL && auth.password() != NULL) {
00436
00437 char* authenticatorStr;
00438 if (auth.nonce() != NULL) {
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 {
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
00469 return strDup("");
00470 }
00471
00472 static char* createSessionString(char const* sessionId) {
00473 char* sessionStr;
00474 if (sessionId != NULL) {
00475 sessionStr = new char[20+strlen(sessionId)];
00476 sprintf(sessionStr, "Session: %s\r\n", sessionId);
00477 } else {
00478 sessionStr = strDup("");
00479 }
00480 return sessionStr;
00481 }
00482
00483 static char* createScaleString(float scale, float currentScale) {
00484 char buf[100];
00485 if (scale == 1.0f && currentScale == 1.0f) {
00486
00487 buf[0] = '\0';
00488 } else {
00489 Locale l("C", LC_NUMERIC);
00490 sprintf(buf, "Scale: %f\r\n", scale);
00491 }
00492
00493 return strDup(buf);
00494 }
00495
00496 static char* createRangeString(double start, double end) {
00497 char buf[100];
00498 if (start < 0) {
00499
00500 buf[0] = '\0';
00501 } else if (end < 0) {
00502
00503 Locale l("C", LC_NUMERIC);
00504 sprintf(buf, "Range: npt=%.3f-\r\n", start);
00505 } else {
00506
00507 Locale l("C", LC_NUMERIC);
00508 sprintf(buf, "Range: npt=%.3f-%.3f\r\n", start, end);
00509 }
00510
00511 return strDup(buf);
00512 }
00513
00514 unsigned RTSPClient::sendRequest(RequestRecord* request) {
00515 char* cmd = NULL;
00516 do {
00517 Boolean connectionIsPending = False;
00518 if (!fRequestsAwaitingConnection.isEmpty()) {
00519
00520 connectionIsPending = True;
00521 } else if (fInputSocketNum < 0) {
00522 int connectResult = openConnection();
00523 if (connectResult < 0) break;
00524 else if (connectResult == 0) {
00525
00526 connectionIsPending = True;
00527 }
00528 }
00529 if (connectionIsPending) {
00530 fRequestsAwaitingConnection.enqueue(request);
00531 return request->cseq();
00532 }
00533
00534
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
00542
00543
00544
00545 char* cmdURL = fBaseURL;
00546 Boolean cmdURLWasAllocated = False;
00547
00548 char const* protocolStr = "RTSP/1.0";
00549
00550 char* extraHeaders = (char*)"";
00551 Boolean extraHeadersWereAllocated = False;
00552
00553 char* contentLengthHeader = (char*)"";
00554 Boolean contentLengthHeaderWasAllocated = False;
00555
00556 char const* contentStr = request->contentStr();
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 ;
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
00596 char const* transportTypeStr;
00597 char const* modeStr = streamOutgoing ? ";mode=receive" : "";
00598
00599 char const* portTypeStr;
00600 portNumBits rtpNumber, rtcpNumber;
00601 if (streamUsingTCP) {
00602 transportTypeStr = "/TCP;unicast";
00603 portTypeStr = ";interleaved";
00604 rtpNumber = fTCPStreamIdCount++;
00605 rtcpNumber = fTCPStreamIdCount++;
00606 } else {
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 ;
00622 char* transportStr = new char[transportSize];
00623 sprintf(transportStr, transportFmt,
00624 transportTypeStr, modeStr, portTypeStr, rtpNumber, rtcpNumber);
00625
00626
00627 char* sessionStr = createSessionString(fLastSessionId);
00628
00629
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
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
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 {
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 {
00683
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
00693 cmdURL = (char*)sessionURL(*request->session());
00694
00695 sessionId = fLastSessionId;
00696 originalScale = request->session()->scale();
00697 } else {
00698
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
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
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
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
00762
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
00780 fRequestsAwaitingResponse.enqueue(request);
00781
00782 delete[] cmd;
00783 return request->cseq();
00784 } while (0);
00785
00786
00787 delete[] cmd;
00788 handleRequestError(request);
00789 delete request;
00790 return 0;
00791 }
00792
00793 void RTSPClient::handleRequestError(RequestRecord* request) {
00794 int resultCode = -envir().getErrno();
00795 if (resultCode == 0) {
00796
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 }
00805
00806 Boolean RTSPClient
00807 ::parseResponseCode(char const* line, unsigned& responseCode, char const*& responseString, Boolean& responseIsHTTP) {
00808 responseIsHTTP = False;
00809 if (sscanf(line, "RTSP/%*s%u", &responseCode) != 1) {
00810 if (sscanf(line, "HTTP/%*s%u", &responseCode) != 1) return False;
00811 responseIsHTTP = True;
00812
00813
00814 }
00815
00816
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;
00820
00821 return True;
00822 }
00823
00824 void RTSPClient::handleIncomingRequest() {
00825
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 }
00846
00847 Boolean RTSPClient::checkForHeader(char const* line, char const* headerName, unsigned headerNameLength, char const*& headerParams) {
00848 if (_strncasecmp(line, headerName, headerNameLength) != 0) return False;
00849
00850
00851 unsigned paramIndex = headerNameLength;
00852 while (line[paramIndex] != '\0' && (line[paramIndex] == ' ' || line[paramIndex] == '\t')) ++paramIndex;
00853 if (&line[paramIndex] == '\0') return False;
00854
00855 headerParams = &line[paramIndex];
00856 return True;
00857 }
00858
00859 Boolean RTSPClient::parseTransportParams(char const* paramsStr,
00860 char*& serverAddressStr, portNumBits& serverPortNum,
00861 unsigned char& rtpChannelId, unsigned char& rtcpChannelId) {
00862
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;
00874 char* foundDestinationStr = NULL;
00875 portNumBits multicastPortNumRTP, multicastPortNumRTCP;
00876 Boolean foundMulticastPortNum = False;
00877
00878
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;
00905 if (fields[0] == '\0') break;
00906 }
00907 delete[] field;
00908
00909
00910
00911
00912 if (isMulticast && foundDestinationStr != NULL && foundMulticastPortNum) {
00913 delete[] foundServerAddressStr;
00914 serverAddressStr = foundDestinationStr;
00915 serverPortNum = multicastPortNumRTP;
00916 return True;
00917 }
00918 delete[] foundDestinationStr;
00919
00920
00921
00922
00923
00924
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 }
00936
00937 Boolean RTSPClient::parseScaleParam(char const* paramStr, float& scale) {
00938 Locale l("C", LC_NUMERIC);
00939 return sscanf(paramStr, "%f", &scale) == 1;
00940 }
00941
00942 Boolean RTSPClient::parseRTPInfoParams(char const*& paramsStr, u_int16_t& seqNum, u_int32_t& timestamp) {
00943 while (paramsStr[0] == ',') ++paramsStr;
00944
00945
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
00956 ++paramsStr;
00957 }
00958
00959 delete[] field;
00960 return True;
00961 }
00962
00963 Boolean RTSPClient::handleSETUPResponse(MediaSubsession& subsession, char const* sessionParamsStr, char const* transportParamsStr,
00964 Boolean streamUsingTCP) {
00965 char* sessionId = new char[responseBufferSize];
00966 Boolean success = False;
00967 do {
00968
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
00977 char const* afterSessionId = sessionParamsStr + strlen(sessionId);
00978 int timeoutVal;
00979 if (sscanf(afterSessionId, "; timeout = %d", &timeoutVal) == 1) {
00980 fSessionTimeoutParameter = timeoutVal;
00981 }
00982
00983
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
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
01006
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 }
01018
01019 Boolean RTSPClient::handlePLAYResponse(MediaSession& session, MediaSubsession& subsession,
01020 char const* scaleParamsStr, char const* rangeParamsStr, char const* rtpInfoParamsStr) {
01021 Boolean scaleOK = False, rangeOK = False;
01022 do {
01023 if (&session != NULL) {
01024
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
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
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
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 }
01073
01074 Boolean RTSPClient::handleTEARDOWNResponse(MediaSession& session, MediaSubsession& subsession) {
01075 if (&session != NULL) {
01076
01077
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
01086 delete[] (char*)subsession.sessionId;
01087 subsession.sessionId = NULL;
01088 }
01089 return True;
01090 }
01091
01092 Boolean RTSPClient::handleGET_PARAMETERResponse(char const* parameterName, char*& resultValueString) {
01093 do {
01094
01095 if (parameterName != NULL && parameterName[0] != '\0') {
01096 if (parameterName[1] == '\0') break;
01097
01098 unsigned parameterNameLen = strlen(parameterName);
01099
01100 parameterNameLen -= 2;
01101 if (_strncasecmp(resultValueString, parameterName, parameterNameLen) != 0) break;
01102 resultValueString += parameterNameLen;
01103 if (resultValueString[0] == ':') ++resultValueString;
01104 while (resultValueString[0] == ' ' || resultValueString[0] == '\t') ++resultValueString;
01105 }
01106
01107
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
01116 envir().setResultMsg("Bad \"GET_PARAMETER\" response");
01117 return False;
01118 }
01119
01120 Boolean RTSPClient::handleAuthenticationFailure(char const* paramsStr) {
01121
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);
01130 } else {
01131 success = False;
01132 }
01133 delete[] realm; delete[] nonce;
01134
01135 if (alreadyHadRealm || fCurrentAuthenticator.username() == NULL || fCurrentAuthenticator.password() == NULL) {
01136
01137
01138 success = False;
01139 }
01140
01141 return success;
01142 }
01143
01144 Boolean RTSPClient::resendCommand(RequestRecord* request) {
01145 if (fVerbosityLevel >= 1) envir() << "Resending...\n";
01146 if (request != NULL) request->cseq() = ++fCSeq;
01147 return sendRequest(request) != 0;
01148 }
01149
01150 char const* RTSPClient::sessionURL(MediaSession const& session) const {
01151 char const* url = session.controlPath();
01152 if (url == NULL || strcmp(url, "*") == 0) url = fBaseURL;
01153
01154 return url;
01155 }
01156
01157 void RTSPClient::handleAlternativeRequestByte(void* rtspClient, u_int8_t requestByte) {
01158 ((RTSPClient*)rtspClient)->handleAlternativeRequestByte1(requestByte);
01159 }
01160
01161 void RTSPClient::handleAlternativeRequestByte1(u_int8_t requestByte) {
01162 fResponseBuffer[fResponseBytesAlreadySeen] = requestByte;
01163 handleResponseBytes(1);
01164 }
01165
01166 static Boolean isAbsoluteURL(char const* url) {
01167
01168
01169 while (*url != '\0' && *url != '/') {
01170 if (*url == ':') return True;
01171 ++url;
01172 }
01173
01174 return False;
01175 }
01176
01177 void RTSPClient::constructSubsessionURL(MediaSubsession const& subsession,
01178 char const*& prefix,
01179 char const*& separator,
01180 char const*& suffix) {
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
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 }
01205
01206 Boolean RTSPClient::setupHTTPTunneling1() {
01207
01208
01209 if (fVerbosityLevel >= 1) {
01210 envir() << "Requesting RTSP-over-HTTP tunneling (on port " << fTunnelOverHTTPPortNum << ")\n\n";
01211 }
01212
01213
01214 return sendRequest(new RequestRecord(1, "GET", responseHandlerForHTTP_GET)) != 0;
01215 }
01216
01217 void RTSPClient::responseHandlerForHTTP_GET(RTSPClient* rtspClient, int responseCode, char* responseString) {
01218 if (rtspClient != NULL) rtspClient->responseHandlerForHTTP_GET1(responseCode, responseString);
01219 }
01220
01221 void RTSPClient::responseHandlerForHTTP_GET1(int responseCode, char* responseString) {
01222 RequestRecord* request;
01223 do {
01224
01225
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;
01232 else if (connectResult == 0) {
01233
01234
01235 while ((request = fRequestsAwaitingHTTPTunneling.dequeue()) != NULL) {
01236 fRequestsAwaitingConnection.enqueue(request);
01237 }
01238 return;
01239 }
01240
01241
01242 if (!setupHTTPTunneling2()) break;
01243
01244
01245 while ((request = fRequestsAwaitingHTTPTunneling.dequeue()) != NULL) {
01246 sendRequest(request);
01247 }
01248 return;
01249 } while (0);
01250
01251
01252 fHTTPTunnelingConnectionIsPending = False;
01253 while ((request = fRequestsAwaitingHTTPTunneling.dequeue()) != NULL) {
01254 handleRequestError(request);
01255 delete request;
01256 }
01257 resetTCPSockets();
01258 }
01259
01260 Boolean RTSPClient::setupHTTPTunneling2() {
01261 fHTTPTunnelingConnectionIsPending = False;
01262
01263
01264 return sendRequest(new RequestRecord(1, "POST", NULL)) != 0;
01265 }
01266
01267 void RTSPClient::connectionHandler(void* instance, int ) {
01268 RTSPClient* client = (RTSPClient*)instance;
01269 client->connectionHandler1();
01270 }
01271
01272 void RTSPClient::connectionHandler1() {
01273
01274 envir().taskScheduler().disableBackgroundHandling(fOutputSocketNum);
01275 envir().taskScheduler().setBackgroundHandling(fInputSocketNum, SOCKET_READABLE,
01276 (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this);
01277
01278
01279
01280 RequestQueue tmpRequestQueue;
01281 RequestRecord* request;
01282 while ((request = fRequestsAwaitingConnection.dequeue()) != NULL) {
01283 tmpRequestQueue.enqueue(request);
01284 }
01285
01286
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
01297 if (fVerbosityLevel >= 1) envir() << "...remote connection opened\n";
01298 if (fHTTPTunnelingConnectionIsPending && !setupHTTPTunneling2()) break;
01299
01300
01301 while ((request = tmpRequestQueue.dequeue()) != NULL) {
01302 sendRequest(request);
01303 }
01304 return;
01305 } while (0);
01306
01307
01308 while ((request = tmpRequestQueue.dequeue()) != NULL) {
01309 handleRequestError(request);
01310 delete request;
01311 }
01312 resetTCPSockets();
01313 }
01314
01315 void RTSPClient::incomingDataHandler(void* instance, int ) {
01316 RTSPClient* client = (RTSPClient*)instance;
01317 client->incomingDataHandler1();
01318 }
01319
01320 void RTSPClient::incomingDataHandler1() {
01321 struct sockaddr_in dummy;
01322
01323 int bytesRead = readSocket(envir(), fInputSocketNum, (unsigned char*)&fResponseBuffer[fResponseBytesAlreadySeen], fResponseBufferBytesLeft, dummy);
01324 handleResponseBytes(bytesRead);
01325 }
01326
01327 static char* getLine(char* startOfLine) {
01328
01329 for (char* ptr = startOfLine; *ptr != '\0'; ++ptr) {
01330
01331 if (*ptr == '\r' || *ptr == '\n') {
01332
01333 if (*ptr == '\r') {
01334 *ptr++ = '\0';
01335 if (*ptr == '\n') ++ptr;
01336 } else {
01337 *ptr++ = '\0';
01338 }
01339 return ptr;
01340 }
01341 }
01342
01343 return NULL;
01344 }
01345
01346 void RTSPClient::handleResponseBytes(int newBytesRead) {
01347 do {
01348 if (newBytesRead > 0 && (unsigned)newBytesRead < fResponseBufferBytesLeft) break;
01349
01350 if ((unsigned)newBytesRead >= fResponseBufferBytesLeft) {
01351
01352 envir().setResultMsg("RTSP response was truncated. Increase \"RTSPClient::responseBufferSize\"");
01353 }
01354
01355
01356 RequestRecord* request;
01357 while ((request = fRequestsAwaitingResponse.dequeue()) != NULL) {
01358 handleRequestError(request);
01359 delete request;
01360
01361 if (newBytesRead > 0) break;
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
01375
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
01383 endOfHeaders = True;
01384 break;
01385 }
01386 }
01387 }
01388
01389 if (!endOfHeaders) return;
01390
01391
01392
01393
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;
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
01418 handleIncomingRequest();
01419 break;
01420 }
01421
01422
01423 Boolean reachedEndOfHeaders;
01424 unsigned cseq = 0;
01425 unsigned contentLength = 0;
01426
01427 while (1) {
01428 reachedEndOfHeaders = True;
01429 lineStart = nextLineStart;
01430 if (lineStart == NULL) break;
01431
01432 nextLineStart = getLine(lineStart);
01433 if (lineStart[0] == '\0') break;
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
01443 RequestRecord* request;
01444 while ((request = fRequestsAwaitingResponse.dequeue()) != NULL) {
01445 if (request->cseq() < cseq) {
01446
01447 delete request;
01448 } else if (request->cseq() == cseq) {
01449
01450 foundRequest = request;
01451 break;
01452 } else {
01453
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
01471
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
01478 } else if (checkForHeader(lineStart, "Location:", 9, headerParamsStr)) {
01479 setBaseURL(headerParamsStr);
01480 }
01481
01482 }
01483 if (!reachedEndOfHeaders) break;
01484
01485 if (foundRequest == NULL && responseIsHTTP) {
01486
01487 foundRequest = fRequestsAwaitingResponse.dequeue();
01488 }
01489
01490
01491 unsigned bodyOffset = nextLineStart - headerDataCopy;
01492 bodyStart = &fResponseBuffer[bodyOffset];
01493 numBodyBytes = fResponseBytesAlreadySeen - bodyOffset;
01494 if (contentLength > numBodyBytes) {
01495
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);
01513 return;
01514 }
01515
01516
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;
01525 if (responseCode == 200) {
01526
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) {
01539 resetTCPSockets();
01540 needToResendCommand = True;
01541 }
01542
01543 if (needToResendCommand) {
01544 resetResponseBuffer();
01545 if (!resendCommand(foundRequest)) break;
01546 delete[] headerDataCopy;
01547 return;
01548 }
01549 }
01550
01551 responseSuccess = True;
01552 } while (0);
01553
01554
01555 resetResponseBuffer();
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
01564 } else {
01565 resultCode = responseCode;
01566 resultString = strDup(responseStr);
01567 envir().setResultMsg(responseStr);
01568 }
01569 (*foundRequest->handler())(this, resultCode, resultString);
01570 } else {
01571
01572 handleRequestError(foundRequest);
01573 }
01574 }
01575 delete foundRequest;
01576 delete[] headerDataCopy;
01577 }
01578
01579
01581
01582 RTSPClient::RequestRecord::RequestRecord(unsigned cseq, char const* commandName, responseHandler* handler,
01583 MediaSession* session, MediaSubsession* subsession, u_int32_t booleanFlags,
01584 double start, double end, float scale, char const* contentStr)
01585 : fNext(NULL), fCSeq(cseq), fCommandName(commandName), fSession(session), fSubsession(subsession), fBooleanFlags(booleanFlags),
01586 fStart(start), fEnd(end), fScale(scale), fContentStr(strDup(contentStr)), fHandler(handler) {
01587 }
01588
01589 RTSPClient::RequestRecord::~RequestRecord() {
01590
01591 delete fNext;
01592
01593 delete[] fContentStr;
01594 }
01595
01596
01598
01599 RTSPClient::RequestQueue::RequestQueue()
01600 : fHead(NULL), fTail(NULL) {
01601 }
01602
01603 RTSPClient::RequestQueue::~RequestQueue() {
01604 delete fHead;
01605 }
01606
01607 void RTSPClient::RequestQueue::enqueue(RequestRecord* request) {
01608 if (fTail == NULL) {
01609 fHead = request;
01610 } else {
01611 fTail->next() = request;
01612 }
01613 fTail = request;
01614 }
01615
01616 RTSPClient::RequestRecord* RTSPClient::RequestQueue::dequeue() {
01617 RequestRecord* request = fHead;
01618 if (fHead == fTail) {
01619 fHead = NULL;
01620 fTail = NULL;
01621 } else {
01622 fHead = fHead->next();
01623 }
01624 if (request != NULL) request->next() = NULL;
01625 return request;
01626 }
01627
01628 void RTSPClient::RequestQueue::putAtHead(RequestRecord* request) {
01629 request->next() = fHead;
01630 fHead = request;
01631 if (fTail == NULL) {
01632 fTail = request;
01633 }
01634 }
01635
01636 RTSPClient::RequestRecord* RTSPClient::RequestQueue::findByCSeq(unsigned cseq) {
01637 RequestRecord* request;
01638 for (request = fHead; request != NULL; request = request->next()) {
01639 if (request->cseq() == cseq) return request;
01640 }
01641 return NULL;
01642 }
01643
01644
01645 #ifdef RTSPCLIENT_SYNCHRONOUS_INTERFACE
01646
01647 RTSPClient* RTSPClient::createNew(UsageEnvironment& env,
01648 int verbosityLevel,
01649 char const* applicationName,
01650 portNumBits tunnelOverHTTPPortNum) {
01651 return new RTSPClient(env, NULL,
01652 verbosityLevel, applicationName, tunnelOverHTTPPortNum);
01653 }
01654
01655 char* RTSPClient::describeURL(char const* url, Authenticator* authenticator,
01656 Boolean allowKasennaProtocol, int timeout) {
01657
01658
01659
01660
01661
01662 char* username; char* password;
01663 if (authenticator == NULL
01664 && parseRTSPURLUsernamePassword(url, username, password)) {
01665 char* result = describeWithPassword(url, username, password, allowKasennaProtocol, timeout);
01666 delete[] username; delete[] password;
01667 return result;
01668 }
01669
01670 setBaseURL(url);
01671 fWatchVariableForSyncInterface = 0;
01672 fTimeoutTask = NULL;
01673 if (timeout > 0) {
01674
01675
01676
01677 fTimeoutTask = envir().taskScheduler().scheduleDelayedTask(timeout*1000000, timeoutHandlerForSyncInterface, this);
01678 }
01679 (void)sendDescribeCommand(responseHandlerForSyncInterface, authenticator);
01680
01681
01682 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01683 if (fResultCode == 0) return fResultString;
01684 delete[] fResultString;
01685 return NULL;
01686 }
01687
01688 char* RTSPClient::describeWithPassword(char const* url,
01689 char const* username, char const* password,
01690 Boolean allowKasennaProtocol, int timeout) {
01691 Authenticator authenticator;
01692 authenticator.setUsernameAndPassword(username, password);
01693 return describeURL(url, &authenticator, allowKasennaProtocol, timeout);
01694 }
01695
01696 char* RTSPClient::sendOptionsCmd(char const* url,
01697 char* username, char* password,
01698 Authenticator* authenticator,
01699 int timeout) {
01700 char* result = NULL;
01701 Boolean haveAllocatedAuthenticator = False;
01702 if (authenticator == NULL) {
01703
01704
01705 if (username == NULL && password == NULL
01706 && parseRTSPURLUsernamePassword(url, username, password)) {
01707 Authenticator newAuthenticator;
01708 newAuthenticator.setUsernameAndPassword(username, password);
01709 result = sendOptionsCmd(url, username, password, &newAuthenticator, timeout);
01710 delete[] username; delete[] password;
01711 return result;
01712 } else if (username != NULL && password != NULL) {
01713
01714 authenticator = new Authenticator;
01715 haveAllocatedAuthenticator = True;
01716 authenticator->setUsernameAndPassword(username, password);
01717
01718 result = sendOptionsCmd(url, username, password, authenticator, timeout);
01719 if (result != NULL) return result;
01720
01721
01722 if (authenticator->realm() == NULL) {
01723
01724 return NULL;
01725 }
01726 }
01727 }
01728
01729 setBaseURL(url);
01730 fWatchVariableForSyncInterface = 0;
01731 fTimeoutTask = NULL;
01732 if (timeout > 0) {
01733
01734
01735
01736 fTimeoutTask = envir().taskScheduler().scheduleDelayedTask(timeout*1000000, timeoutHandlerForSyncInterface, this);
01737 }
01738 (void)sendOptionsCommand(responseHandlerForSyncInterface, authenticator);
01739
01740
01741 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01742 if (fResultCode == 0) return fResultString;
01743 delete[] fResultString;
01744 return NULL;
01745 }
01746
01747 Boolean RTSPClient::announceSDPDescription(char const* url,
01748 char const* sdpDescription,
01749 Authenticator* authenticator,
01750 int timeout) {
01751 setBaseURL(url);
01752 fWatchVariableForSyncInterface = 0;
01753 fTimeoutTask = NULL;
01754 if (timeout > 0) {
01755
01756
01757
01758 fTimeoutTask = envir().taskScheduler().scheduleDelayedTask(timeout*1000000, timeoutHandlerForSyncInterface, this);
01759 }
01760 (void)sendAnnounceCommand(sdpDescription, responseHandlerForSyncInterface, authenticator);
01761
01762
01763 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01764 delete[] fResultString;
01765 return fResultCode == 0;
01766 }
01767
01768 Boolean RTSPClient
01769 ::announceWithPassword(char const* url, char const* sdpDescription,
01770 char const* username, char const* password, int timeout) {
01771 Authenticator authenticator;
01772 authenticator.setUsernameAndPassword(username, password);
01773 return announceSDPDescription(url, sdpDescription, &authenticator, timeout);
01774 }
01775
01776 Boolean RTSPClient::setupMediaSubsession(MediaSubsession& subsession,
01777 Boolean streamOutgoing,
01778 Boolean streamUsingTCP,
01779 Boolean forceMulticastOnUnspecified) {
01780 fWatchVariableForSyncInterface = 0;
01781 fTimeoutTask = NULL;
01782 (void)sendSetupCommand(subsession, responseHandlerForSyncInterface, streamOutgoing, streamUsingTCP, forceMulticastOnUnspecified);
01783
01784
01785 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01786 delete[] fResultString;
01787 return fResultCode == 0;
01788 }
01789
01790 Boolean RTSPClient::playMediaSession(MediaSession& session,
01791 double start, double end, float scale) {
01792 fWatchVariableForSyncInterface = 0;
01793 fTimeoutTask = NULL;
01794 (void)sendPlayCommand(session, responseHandlerForSyncInterface, start, end, scale);
01795
01796
01797 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01798 delete[] fResultString;
01799 return fResultCode == 0;
01800 }
01801
01802 Boolean RTSPClient::playMediaSubsession(MediaSubsession& subsession,
01803 double start, double end, float scale,
01804 Boolean ) {
01805
01806
01807 fWatchVariableForSyncInterface = 0;
01808 fTimeoutTask = NULL;
01809 (void)sendPlayCommand(subsession, responseHandlerForSyncInterface, start, end, scale);
01810
01811
01812 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01813 delete[] fResultString;
01814 return fResultCode == 0;
01815 }
01816
01817 Boolean RTSPClient::pauseMediaSession(MediaSession& session) {
01818 fWatchVariableForSyncInterface = 0;
01819 fTimeoutTask = NULL;
01820 (void)sendPauseCommand(session, responseHandlerForSyncInterface);
01821
01822
01823 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01824 delete[] fResultString;
01825 return fResultCode == 0;
01826 }
01827
01828 Boolean RTSPClient::pauseMediaSubsession(MediaSubsession& subsession) {
01829 fWatchVariableForSyncInterface = 0;
01830 fTimeoutTask = NULL;
01831 (void)sendPauseCommand(subsession, responseHandlerForSyncInterface);
01832
01833
01834 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01835 delete[] fResultString;
01836 return fResultCode == 0;
01837 }
01838
01839 Boolean RTSPClient::recordMediaSubsession(MediaSubsession& subsession) {
01840 fWatchVariableForSyncInterface = 0;
01841 fTimeoutTask = NULL;
01842 (void)sendRecordCommand(subsession, responseHandlerForSyncInterface);
01843
01844
01845 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01846 delete[] fResultString;
01847 return fResultCode == 0;
01848 }
01849
01850 Boolean RTSPClient::setMediaSessionParameter(MediaSession& session,
01851 char const* parameterName,
01852 char const* parameterValue) {
01853 fWatchVariableForSyncInterface = 0;
01854 fTimeoutTask = NULL;
01855 (void)sendSetParameterCommand(session, responseHandlerForSyncInterface, parameterName, parameterValue);
01856
01857
01858 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01859 delete[] fResultString;
01860 return fResultCode == 0;
01861 }
01862
01863 Boolean RTSPClient::getMediaSessionParameter(MediaSession& session,
01864 char const* parameterName,
01865 char*& parameterValue) {
01866 fWatchVariableForSyncInterface = 0;
01867 fTimeoutTask = NULL;
01868 (void)sendGetParameterCommand(session, responseHandlerForSyncInterface, parameterName);
01869
01870
01871 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01872 parameterValue = fResultString;
01873 return fResultCode == 0;
01874 }
01875
01876 Boolean RTSPClient::teardownMediaSession(MediaSession& session) {
01877 fWatchVariableForSyncInterface = 0;
01878 fTimeoutTask = NULL;
01879 (void)sendTeardownCommand(session, responseHandlerForSyncInterface);
01880
01881
01882 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01883 delete[] fResultString;
01884 return fResultCode == 0;
01885 }
01886
01887 Boolean RTSPClient::teardownMediaSubsession(MediaSubsession& subsession) {
01888 fWatchVariableForSyncInterface = 0;
01889 fTimeoutTask = NULL;
01890 (void)sendTeardownCommand(subsession, responseHandlerForSyncInterface);
01891
01892
01893 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01894 delete[] fResultString;
01895 return fResultCode == 0;
01896 }
01897
01898 void RTSPClient::responseHandlerForSyncInterface(RTSPClient* rtspClient, int responseCode, char* responseString) {
01899 if (rtspClient != NULL) rtspClient->responseHandlerForSyncInterface1(responseCode, responseString);
01900 }
01901
01902 void RTSPClient::responseHandlerForSyncInterface1(int responseCode, char* responseString) {
01903
01904 if (fTimeoutTask != NULL) envir().taskScheduler().unscheduleDelayedTask(fTimeoutTask);
01905
01906
01907 fResultCode = responseCode;
01908 fResultString = responseString;
01909
01910
01911 fWatchVariableForSyncInterface = ~0;
01912 }
01913
01914 void RTSPClient::timeoutHandlerForSyncInterface(void* rtspClient) {
01915 if (rtspClient != NULL) ((RTSPClient*)rtspClient)->timeoutHandlerForSyncInterface1();
01916 }
01917
01918 void RTSPClient::timeoutHandlerForSyncInterface1() {
01919
01920
01921
01922 changeResponseHandler(fCSeq, NULL);
01923 fTimeoutTask = NULL;
01924
01925
01926 fResultCode = ~0;
01927 fResultString = NULL;
01928
01929
01930 fWatchVariableForSyncInterface = ~0;
01931 }
01932
01933 #endif