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::sendPlayCommand(MediaSession& session, responseHandler* responseHandler,
00081 char const* absStartTime, char const* absEndTime, float scale,
00082 Authenticator* authenticator) {
00083 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00084 return sendRequest(new RequestRecord(++fCSeq, responseHandler, absStartTime, absEndTime, scale, &session, NULL));
00085 }
00086
00087 unsigned RTSPClient::sendPlayCommand(MediaSubsession& subsession, responseHandler* responseHandler,
00088 char const* absStartTime, char const* absEndTime, float scale,
00089 Authenticator* authenticator) {
00090 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00091 return sendRequest(new RequestRecord(++fCSeq, responseHandler, absStartTime, absEndTime, scale, NULL, &subsession));
00092 }
00093
00094 unsigned RTSPClient::sendPauseCommand(MediaSession& session, responseHandler* responseHandler, Authenticator* authenticator) {
00095 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00096 return sendRequest(new RequestRecord(++fCSeq, "PAUSE", responseHandler, &session));
00097 }
00098
00099 unsigned RTSPClient::sendPauseCommand(MediaSubsession& subsession, responseHandler* responseHandler, Authenticator* authenticator) {
00100 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00101 return sendRequest(new RequestRecord(++fCSeq, "PAUSE", responseHandler, NULL, &subsession));
00102 }
00103
00104 unsigned RTSPClient::sendRecordCommand(MediaSession& session, responseHandler* responseHandler, Authenticator* authenticator) {
00105 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00106 return sendRequest(new RequestRecord(++fCSeq, "RECORD", responseHandler, &session));
00107 }
00108
00109 unsigned RTSPClient::sendRecordCommand(MediaSubsession& subsession, responseHandler* responseHandler, Authenticator* authenticator) {
00110 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00111 return sendRequest(new RequestRecord(++fCSeq, "RECORD", responseHandler, NULL, &subsession));
00112 }
00113
00114 unsigned RTSPClient::sendTeardownCommand(MediaSession& session, responseHandler* responseHandler, Authenticator* authenticator) {
00115 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00116 return sendRequest(new RequestRecord(++fCSeq, "TEARDOWN", responseHandler, &session));
00117 }
00118
00119 unsigned RTSPClient::sendTeardownCommand(MediaSubsession& subsession, responseHandler* responseHandler, Authenticator* authenticator) {
00120 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00121 return sendRequest(new RequestRecord(++fCSeq, "TEARDOWN", responseHandler, NULL, &subsession));
00122 }
00123
00124 unsigned RTSPClient::sendSetParameterCommand(MediaSession& session, responseHandler* responseHandler,
00125 char const* parameterName, char const* parameterValue,
00126 Authenticator* authenticator) {
00127 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00128 char* paramString = new char[strlen(parameterName) + strlen(parameterValue) + 10];
00129 sprintf(paramString, "%s: %s\r\n", parameterName, parameterValue);
00130 unsigned result = sendRequest(new RequestRecord(++fCSeq, "SET_PARAMETER", responseHandler, &session, NULL, False, 0.0, 0.0, 0.0, paramString));
00131 delete[] paramString;
00132 return result;
00133 }
00134
00135 unsigned RTSPClient::sendGetParameterCommand(MediaSession& session, responseHandler* responseHandler, char const* parameterName,
00136 Authenticator* authenticator) {
00137 if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
00138
00139
00140
00141
00142
00143 unsigned parameterNameLen = parameterName == NULL ? 0 : strlen(parameterName);
00144 char* paramString = new char[parameterNameLen + 3];
00145 if (parameterName == NULL) {
00146 paramString[0] = '\0';
00147 } else {
00148 sprintf(paramString, "%s\r\n", parameterName);
00149 }
00150 unsigned result = sendRequest(new RequestRecord(++fCSeq, "GET_PARAMETER", responseHandler, &session, NULL, False, 0.0, 0.0, 0.0, paramString));
00151 delete[] paramString;
00152 return result;
00153 }
00154
00155 Boolean RTSPClient::changeResponseHandler(unsigned cseq, responseHandler* newResponseHandler) {
00156
00157 RequestRecord* request;
00158 if ((request = fRequestsAwaitingConnection.findByCSeq(cseq)) != NULL
00159 || (request = fRequestsAwaitingHTTPTunneling.findByCSeq(cseq)) != NULL
00160 || (request = fRequestsAwaitingResponse.findByCSeq(cseq)) != NULL) {
00161 request->handler() = newResponseHandler;
00162 return True;
00163 }
00164
00165 return False;
00166 }
00167
00168 Boolean RTSPClient::lookupByName(UsageEnvironment& env,
00169 char const* instanceName,
00170 RTSPClient*& resultClient) {
00171 resultClient = NULL;
00172
00173 Medium* medium;
00174 if (!Medium::lookupByName(env, instanceName, medium)) return False;
00175
00176 if (!medium->isRTSPClient()) {
00177 env.setResultMsg(instanceName, " is not a RTSP client");
00178 return False;
00179 }
00180
00181 resultClient = (RTSPClient*)medium;
00182 return True;
00183 }
00184
00185 Boolean RTSPClient::parseRTSPURL(UsageEnvironment& env, char const* url,
00186 char*& username, char*& password,
00187 NetAddress& address,
00188 portNumBits& portNum,
00189 char const** urlSuffix) {
00190 do {
00191
00192 char const* prefix = "rtsp://";
00193 unsigned const prefixLength = 7;
00194 if (_strncasecmp(url, prefix, prefixLength) != 0) {
00195 env.setResultMsg("URL is not of the form \"", prefix, "\"");
00196 break;
00197 }
00198
00199 unsigned const parseBufferSize = 100;
00200 char parseBuffer[parseBufferSize];
00201 char const* from = &url[prefixLength];
00202
00203
00204
00205 username = password = NULL;
00206 char const* colonPasswordStart = NULL;
00207 char const* p;
00208 for (p = from; *p != '\0' && *p != '/'; ++p) {
00209 if (*p == ':' && colonPasswordStart == NULL) {
00210 colonPasswordStart = p;
00211 } else if (*p == '@') {
00212
00213 if (colonPasswordStart == NULL) colonPasswordStart = p;
00214
00215 char const* usernameStart = from;
00216 unsigned usernameLen = colonPasswordStart - usernameStart;
00217 username = new char[usernameLen + 1] ;
00218 for (unsigned i = 0; i < usernameLen; ++i) username[i] = usernameStart[i];
00219 username[usernameLen] = '\0';
00220
00221 char const* passwordStart = colonPasswordStart;
00222 if (passwordStart < p) ++passwordStart;
00223 unsigned passwordLen = p - passwordStart;
00224 password = new char[passwordLen + 1];
00225 for (unsigned j = 0; j < passwordLen; ++j) password[j] = passwordStart[j];
00226 password[passwordLen] = '\0';
00227
00228 from = p + 1;
00229 break;
00230 }
00231 }
00232
00233
00234 char* to = &parseBuffer[0];
00235 unsigned i;
00236 for (i = 0; i < parseBufferSize; ++i) {
00237 if (*from == '\0' || *from == ':' || *from == '/') {
00238
00239 *to = '\0';
00240 break;
00241 }
00242 *to++ = *from++;
00243 }
00244 if (i == parseBufferSize) {
00245 env.setResultMsg("URL is too long");
00246 break;
00247 }
00248
00249 NetAddressList addresses(parseBuffer);
00250 if (addresses.numAddresses() == 0) {
00251 env.setResultMsg("Failed to find network address for \"",
00252 parseBuffer, "\"");
00253 break;
00254 }
00255 address = *(addresses.firstAddress());
00256
00257 portNum = 554;
00258 char nextChar = *from;
00259 if (nextChar == ':') {
00260 int portNumInt;
00261 if (sscanf(++from, "%d", &portNumInt) != 1) {
00262 env.setResultMsg("No port number follows ':'");
00263 break;
00264 }
00265 if (portNumInt < 1 || portNumInt > 65535) {
00266 env.setResultMsg("Bad port number");
00267 break;
00268 }
00269 portNum = (portNumBits)portNumInt;
00270 while (*from >= '0' && *from <= '9') ++from;
00271 }
00272
00273
00274 if (urlSuffix != NULL) *urlSuffix = from;
00275
00276 return True;
00277 } while (0);
00278
00279 return False;
00280 }
00281
00282 void RTSPClient::setUserAgentString(char const* userAgentName) {
00283 if (userAgentName == NULL) return;
00284
00285
00286 char const* const formatStr = "User-Agent: %s\r\n";
00287 unsigned const headerSize = strlen(formatStr) + strlen(userAgentName);
00288 delete[] fUserAgentHeaderStr;
00289 fUserAgentHeaderStr = new char[headerSize];
00290 sprintf(fUserAgentHeaderStr, formatStr, userAgentName);
00291 fUserAgentHeaderStrLen = strlen(fUserAgentHeaderStr);
00292 }
00293
00294 unsigned RTSPClient::responseBufferSize = 20000;
00295
00296 RTSPClient::RTSPClient(UsageEnvironment& env, char const* rtspURL,
00297 int verbosityLevel, char const* applicationName,
00298 portNumBits tunnelOverHTTPPortNum)
00299 : Medium(env),
00300 fVerbosityLevel(verbosityLevel), fCSeq(1),
00301 fTunnelOverHTTPPortNum(tunnelOverHTTPPortNum), fUserAgentHeaderStr(NULL), fUserAgentHeaderStrLen(0),
00302 fInputSocketNum(-1), fOutputSocketNum(-1), fServerAddress(0), fBaseURL(NULL), fTCPStreamIdCount(0),
00303 fLastSessionId(NULL), fSessionTimeoutParameter(0), fSessionCookieCounter(0), fHTTPTunnelingConnectionIsPending(False) {
00304 setBaseURL(rtspURL);
00305
00306 fResponseBuffer = new char[responseBufferSize+1];
00307 resetResponseBuffer();
00308
00309
00310 char const* const libName = "LIVE555 Streaming Media v";
00311 char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING;
00312 char const* libPrefix; char const* libSuffix;
00313 if (applicationName == NULL || applicationName[0] == '\0') {
00314 applicationName = libPrefix = libSuffix = "";
00315 } else {
00316 libPrefix = " (";
00317 libSuffix = ")";
00318 }
00319 unsigned userAgentNameSize
00320 = strlen(applicationName) + strlen(libPrefix) + strlen(libName) + strlen(libVersionStr) + strlen(libSuffix) + 1;
00321 char* userAgentName = new char[userAgentNameSize];
00322 sprintf(userAgentName, "%s%s%s%s%s", applicationName, libPrefix, libName, libVersionStr, libSuffix);
00323 setUserAgentString(userAgentName);
00324 delete[] userAgentName;
00325 }
00326
00327 RTSPClient::~RTSPClient() {
00328 reset();
00329
00330 delete[] fResponseBuffer;
00331 delete[] fUserAgentHeaderStr;
00332 }
00333
00334 Boolean RTSPClient::isRTSPClient() const {
00335 return True;
00336 }
00337
00338 void RTSPClient::reset() {
00339 resetTCPSockets();
00340 resetResponseBuffer();
00341 fServerAddress = 0;
00342
00343 setBaseURL(NULL);
00344
00345 fCurrentAuthenticator.reset();
00346
00347 delete[] fLastSessionId; fLastSessionId = NULL;
00348 }
00349
00350 void RTSPClient::resetTCPSockets() {
00351 if (fInputSocketNum >= 0) {
00352 envir().taskScheduler().disableBackgroundHandling(fInputSocketNum);
00353 ::closeSocket(fInputSocketNum);
00354 if (fOutputSocketNum != fInputSocketNum) {
00355 envir().taskScheduler().disableBackgroundHandling(fOutputSocketNum);
00356 ::closeSocket(fOutputSocketNum);
00357 }
00358 }
00359 fInputSocketNum = fOutputSocketNum = -1;
00360 }
00361
00362 void RTSPClient::resetResponseBuffer() {
00363 fResponseBytesAlreadySeen = 0;
00364 fResponseBufferBytesLeft = responseBufferSize;
00365 }
00366
00367 void RTSPClient::setBaseURL(char const* url) {
00368 delete[] fBaseURL; fBaseURL = strDup(url);
00369 }
00370
00371 int RTSPClient::openConnection() {
00372 do {
00373
00374
00375 char* username;
00376 char* password;
00377 NetAddress destAddress;
00378 portNumBits urlPortNum;
00379 char const* urlSuffix;
00380 if (!parseRTSPURL(envir(), fBaseURL, username, password, destAddress, urlPortNum, &urlSuffix)) break;
00381 portNumBits destPortNum = fTunnelOverHTTPPortNum == 0 ? urlPortNum : fTunnelOverHTTPPortNum;
00382 if (username != NULL || password != NULL) {
00383 fCurrentAuthenticator.setUsernameAndPassword(username, password);
00384 delete[] username;
00385 delete[] password;
00386 }
00387
00388
00389 fInputSocketNum = fOutputSocketNum = setupStreamSocket(envir(), 0);
00390 if (fInputSocketNum < 0) break;
00391 ignoreSigPipeOnSocket(fInputSocketNum);
00392
00393
00394 fServerAddress = *(netAddressBits*)(destAddress.data());
00395 int connectResult = connectToServer(fInputSocketNum, destPortNum);
00396 if (connectResult < 0) break;
00397 else if (connectResult > 0) {
00398
00399 envir().taskScheduler().setBackgroundHandling(fInputSocketNum, SOCKET_READABLE|SOCKET_EXCEPTION,
00400 (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this);
00401 }
00402 return connectResult;
00403 } while (0);
00404
00405 resetTCPSockets();
00406 return -1;
00407 }
00408
00409 int RTSPClient::connectToServer(int socketNum, portNumBits remotePortNum) {
00410 MAKE_SOCKADDR_IN(remoteName, fServerAddress, htons(remotePortNum));
00411 if (fVerbosityLevel >= 1) {
00412 envir() << "Opening connection to " << AddressString(remoteName).val() << ", port " << remotePortNum << "...\n";
00413 }
00414 if (connect(socketNum, (struct sockaddr*) &remoteName, sizeof remoteName) != 0) {
00415 int const err = envir().getErrno();
00416 if (err == EINPROGRESS || err == EWOULDBLOCK) {
00417
00418 envir().taskScheduler().setBackgroundHandling(socketNum, SOCKET_WRITABLE|SOCKET_EXCEPTION,
00419 (TaskScheduler::BackgroundHandlerProc*)&connectionHandler, this);
00420 return 0;
00421 }
00422 envir().setResultErrMsg("connect() failed: ");
00423 if (fVerbosityLevel >= 1) envir() << "..." << envir().getResultMsg() << "\n";
00424 return -1;
00425 }
00426 if (fVerbosityLevel >= 1) envir() << "...local connection opened\n";
00427
00428 return 1;
00429 }
00430
00431 char*
00432 RTSPClient::createAuthenticatorString(char const* cmd, char const* url) {
00433 Authenticator& auth = fCurrentAuthenticator;
00434 if (auth.realm() != NULL && auth.username() != NULL && auth.password() != NULL) {
00435
00436 char* authenticatorStr;
00437 if (auth.nonce() != NULL) {
00438 char const* const authFmt =
00439 "Authorization: Digest username=\"%s\", realm=\"%s\", "
00440 "nonce=\"%s\", uri=\"%s\", response=\"%s\"\r\n";
00441 char const* response = auth.computeDigestResponse(cmd, url);
00442 unsigned authBufSize = strlen(authFmt)
00443 + strlen(auth.username()) + strlen(auth.realm())
00444 + strlen(auth.nonce()) + strlen(url) + strlen(response);
00445 authenticatorStr = new char[authBufSize];
00446 sprintf(authenticatorStr, authFmt,
00447 auth.username(), auth.realm(),
00448 auth.nonce(), url, response);
00449 auth.reclaimDigestResponse(response);
00450 } else {
00451 char const* const authFmt = "Authorization: Basic %s\r\n";
00452
00453 unsigned usernamePasswordLength = strlen(auth.username()) + 1 + strlen(auth.password());
00454 char* usernamePassword = new char[usernamePasswordLength+1];
00455 sprintf(usernamePassword, "%s:%s", auth.username(), auth.password());
00456
00457 char* response = base64Encode(usernamePassword, usernamePasswordLength);
00458 unsigned const authBufSize = strlen(authFmt) + strlen(response) + 1;
00459 authenticatorStr = new char[authBufSize];
00460 sprintf(authenticatorStr, authFmt, response);
00461 delete[] response; delete[] usernamePassword;
00462 }
00463
00464 return authenticatorStr;
00465 }
00466
00467
00468 return strDup("");
00469 }
00470
00471 static char* createSessionString(char const* sessionId) {
00472 char* sessionStr;
00473 if (sessionId != NULL) {
00474 sessionStr = new char[20+strlen(sessionId)];
00475 sprintf(sessionStr, "Session: %s\r\n", sessionId);
00476 } else {
00477 sessionStr = strDup("");
00478 }
00479 return sessionStr;
00480 }
00481
00482 static char* createScaleString(float scale, float currentScale) {
00483 char buf[100];
00484 if (scale == 1.0f && currentScale == 1.0f) {
00485
00486 buf[0] = '\0';
00487 } else {
00488 Locale l("C", Numeric);
00489 sprintf(buf, "Scale: %f\r\n", scale);
00490 }
00491
00492 return strDup(buf);
00493 }
00494
00495 static char* createRangeString(double start, double end, char const* absStartTime, char const* absEndTime) {
00496 char buf[100];
00497
00498 if (absStartTime != NULL) {
00499
00500
00501 if (absEndTime == NULL) {
00502
00503 snprintf(buf, sizeof buf, "Range: clock=%s-\r\n", absStartTime);
00504 } else {
00505
00506 snprintf(buf, sizeof buf, "Range: clock=%s-%s\r\n", absStartTime, absEndTime);
00507 }
00508 } else {
00509
00510
00511 if (start < 0) {
00512
00513 buf[0] = '\0';
00514 } else if (end < 0) {
00515
00516 Locale l("C", Numeric);
00517 sprintf(buf, "Range: npt=%.3f-\r\n", start);
00518 } else {
00519
00520 Locale l("C", Numeric);
00521 sprintf(buf, "Range: npt=%.3f-%.3f\r\n", start, end);
00522 }
00523 }
00524
00525 return strDup(buf);
00526 }
00527
00528 unsigned RTSPClient::sendRequest(RequestRecord* request) {
00529 char* cmd = NULL;
00530 do {
00531 Boolean connectionIsPending = False;
00532 if (!fRequestsAwaitingConnection.isEmpty()) {
00533
00534 connectionIsPending = True;
00535 } else if (fInputSocketNum < 0) {
00536 int connectResult = openConnection();
00537 if (connectResult < 0) break;
00538 else if (connectResult == 0) {
00539
00540 connectionIsPending = True;
00541 }
00542 }
00543 if (connectionIsPending) {
00544 fRequestsAwaitingConnection.enqueue(request);
00545 return request->cseq();
00546 }
00547
00548
00549 if (fTunnelOverHTTPPortNum != 0 && strcmp(request->commandName(), "GET") != 0 && fOutputSocketNum == fInputSocketNum) {
00550 if (!setupHTTPTunneling1()) break;
00551 fRequestsAwaitingHTTPTunneling.enqueue(request);
00552 return request->cseq();
00553 }
00554
00555
00556
00557
00558
00559 char* cmdURL = fBaseURL;
00560 Boolean cmdURLWasAllocated = False;
00561
00562 char const* protocolStr = "RTSP/1.0";
00563
00564 char* extraHeaders = (char*)"";
00565 Boolean extraHeadersWereAllocated = False;
00566
00567 char* contentLengthHeader = (char*)"";
00568 Boolean contentLengthHeaderWasAllocated = False;
00569
00570 char const* contentStr = request->contentStr();
00571 if (contentStr == NULL) contentStr = "";
00572 unsigned contentStrLen = strlen(contentStr);
00573 if (contentStrLen > 0) {
00574 char const* contentLengthHeaderFmt =
00575 "Content-Length: %d\r\n";
00576 unsigned contentLengthHeaderSize = strlen(contentLengthHeaderFmt)
00577 + 20 ;
00578 contentLengthHeader = new char[contentLengthHeaderSize];
00579 sprintf(contentLengthHeader, contentLengthHeaderFmt, contentStrLen);
00580 contentLengthHeaderWasAllocated = True;
00581 }
00582
00583 if (strcmp(request->commandName(), "DESCRIBE") == 0) {
00584 extraHeaders = (char*)"Accept: application/sdp\r\n";
00585 } else if (strcmp(request->commandName(), "OPTIONS") == 0) {
00586 } else if (strcmp(request->commandName(), "ANNOUNCE") == 0) {
00587 extraHeaders = (char*)"Content-Type: application/sdp\r\n";
00588 } else if (strcmp(request->commandName(), "SETUP") == 0) {
00589 MediaSubsession& subsession = *request->subsession();
00590 Boolean streamUsingTCP = (request->booleanFlags()&0x1) != 0;
00591 Boolean streamOutgoing = (request->booleanFlags()&0x2) != 0;
00592 Boolean forceMulticastOnUnspecified = (request->booleanFlags()&0x4) != 0;
00593
00594 char const *prefix, *separator, *suffix;
00595 constructSubsessionURL(subsession, prefix, separator, suffix);
00596
00597 char const* transportFmt;
00598 if (strcmp(subsession.protocolName(), "UDP") == 0) {
00599 suffix = "";
00600 transportFmt = "Transport: RAW/RAW/UDP%s%s%s=%d-%d\r\n";
00601 } else {
00602 transportFmt = "Transport: RTP/AVP%s%s%s=%d-%d\r\n";
00603 }
00604
00605 cmdURL = new char[strlen(prefix) + strlen(separator) + strlen(suffix) + 1];
00606 cmdURLWasAllocated = True;
00607 sprintf(cmdURL, "%s%s%s", prefix, separator, suffix);
00608
00609
00610 char const* transportTypeStr;
00611 char const* modeStr = streamOutgoing ? ";mode=receive" : "";
00612
00613 char const* portTypeStr;
00614 portNumBits rtpNumber, rtcpNumber;
00615 if (streamUsingTCP) {
00616 transportTypeStr = "/TCP;unicast";
00617 portTypeStr = ";interleaved";
00618 rtpNumber = fTCPStreamIdCount++;
00619 rtcpNumber = fTCPStreamIdCount++;
00620 } else {
00621 unsigned connectionAddress = subsession.connectionEndpointAddress();
00622 Boolean requestMulticastStreaming
00623 = IsMulticastAddress(connectionAddress) || (connectionAddress == 0 && forceMulticastOnUnspecified);
00624 transportTypeStr = requestMulticastStreaming ? ";multicast" : ";unicast";
00625 portTypeStr = ";client_port";
00626 rtpNumber = subsession.clientPortNum();
00627 if (rtpNumber == 0) {
00628 envir().setResultMsg("Client port number unknown\n");
00629 delete[] cmdURL;
00630 break;
00631 }
00632 rtcpNumber = rtpNumber + 1;
00633 }
00634 unsigned transportSize = strlen(transportFmt)
00635 + strlen(transportTypeStr) + strlen(modeStr) + strlen(portTypeStr) + 2*5 ;
00636 char* transportStr = new char[transportSize];
00637 sprintf(transportStr, transportFmt,
00638 transportTypeStr, modeStr, portTypeStr, rtpNumber, rtcpNumber);
00639
00640
00641 char* sessionStr = createSessionString(fLastSessionId);
00642
00643
00644 extraHeaders = new char[transportSize + strlen(sessionStr)];
00645 extraHeadersWereAllocated = True;
00646 sprintf(extraHeaders, "%s%s", transportStr, sessionStr);
00647 delete[] transportStr; delete[] sessionStr;
00648 } else if (strcmp(request->commandName(), "GET") == 0 || strcmp(request->commandName(), "POST") == 0) {
00649
00650
00651 char* username;
00652 char* password;
00653 NetAddress destAddress;
00654 portNumBits urlPortNum;
00655 if (!parseRTSPURL(envir(), fBaseURL, username, password, destAddress, urlPortNum, (char const**)&cmdURL)) break;
00656 if (cmdURL[0] == '\0') cmdURL = (char*)"/";
00657 delete[] username;
00658 delete[] password;
00659
00660 protocolStr = "HTTP/1.0";
00661
00662 if (strcmp(request->commandName(), "GET") == 0) {
00663
00664 struct {
00665 struct timeval timestamp;
00666 unsigned counter;
00667 } seedData;
00668 gettimeofday(&seedData.timestamp, NULL);
00669 seedData.counter = ++fSessionCookieCounter;
00670 our_MD5Data((unsigned char*)(&seedData), sizeof seedData, fSessionCookie);
00671
00672 fSessionCookie[23] = '\0';
00673
00674 char const* const extraHeadersFmt =
00675 "x-sessioncookie: %s\r\n"
00676 "Accept: application/x-rtsp-tunnelled\r\n"
00677 "Pragma: no-cache\r\n"
00678 "Cache-Control: no-cache\r\n";
00679 unsigned extraHeadersSize = strlen(extraHeadersFmt)
00680 + strlen(fSessionCookie);
00681 extraHeaders = new char[extraHeadersSize];
00682 extraHeadersWereAllocated = True;
00683 sprintf(extraHeaders, extraHeadersFmt,
00684 fSessionCookie);
00685 } else {
00686 char const* const extraHeadersFmt =
00687 "x-sessioncookie: %s\r\n"
00688 "Content-Type: application/x-rtsp-tunnelled\r\n"
00689 "Pragma: no-cache\r\n"
00690 "Cache-Control: no-cache\r\n"
00691 "Content-Length: 32767\r\n"
00692 "Expires: Sun, 9 Jan 1972 00:00:00 GMT\r\n";
00693 unsigned extraHeadersSize = strlen(extraHeadersFmt)
00694 + strlen(fSessionCookie);
00695 extraHeaders = new char[extraHeadersSize];
00696 extraHeadersWereAllocated = True;
00697 sprintf(extraHeaders, extraHeadersFmt,
00698 fSessionCookie);
00699 }
00700 } else {
00701
00702 if (fLastSessionId == NULL) {
00703 envir().setResultMsg("No RTSP session is currently in progress\n");
00704 break;
00705 }
00706
00707 char const* sessionId;
00708 float originalScale;
00709 if (request->session() != NULL) {
00710
00711 cmdURL = (char*)sessionURL(*request->session());
00712
00713 sessionId = fLastSessionId;
00714 originalScale = request->session()->scale();
00715 } else {
00716
00717 char const *prefix, *separator, *suffix;
00718 constructSubsessionURL(*request->subsession(), prefix, separator, suffix);
00719 cmdURL = new char[strlen(prefix) + strlen(separator) + strlen(suffix) + 1];
00720 cmdURLWasAllocated = True;
00721 sprintf(cmdURL, "%s%s%s", prefix, separator, suffix);
00722
00723 sessionId = request->subsession()->sessionId();
00724 originalScale = request->subsession()->scale();
00725 }
00726
00727 if (strcmp(request->commandName(), "PLAY") == 0) {
00728
00729 char* sessionStr = createSessionString(sessionId);
00730 char* scaleStr = createScaleString(request->scale(), originalScale);
00731 char* rangeStr = createRangeString(request->start(), request->end(), request->absStartTime(), request->absEndTime());
00732 extraHeaders = new char[strlen(sessionStr) + strlen(scaleStr) + strlen(rangeStr) + 1];
00733 extraHeadersWereAllocated = True;
00734 sprintf(extraHeaders, "%s%s%s", sessionStr, scaleStr, rangeStr);
00735 delete[] sessionStr; delete[] scaleStr; delete[] rangeStr;
00736 } else {
00737
00738 extraHeaders = createSessionString(sessionId);
00739 extraHeadersWereAllocated = True;
00740 }
00741 }
00742
00743 char* authenticatorStr = createAuthenticatorString(request->commandName(), fBaseURL);
00744
00745 char const* const cmdFmt =
00746 "%s %s %s\r\n"
00747 "CSeq: %d\r\n"
00748 "%s"
00749 "%s"
00750 "%s"
00751 "%s"
00752 "\r\n"
00753 "%s";
00754 unsigned cmdSize = strlen(cmdFmt)
00755 + strlen(request->commandName()) + strlen(cmdURL) + strlen(protocolStr)
00756 + 20
00757 + strlen(authenticatorStr)
00758 + fUserAgentHeaderStrLen
00759 + strlen(extraHeaders)
00760 + strlen(contentLengthHeader)
00761 + contentStrLen;
00762 cmd = new char[cmdSize];
00763 sprintf(cmd, cmdFmt,
00764 request->commandName(), cmdURL, protocolStr,
00765 request->cseq(),
00766 authenticatorStr,
00767 fUserAgentHeaderStr,
00768 extraHeaders,
00769 contentLengthHeader,
00770 contentStr);
00771 delete[] authenticatorStr;
00772 if (cmdURLWasAllocated) delete[] cmdURL;
00773 if (extraHeadersWereAllocated) delete[] extraHeaders;
00774 if (contentLengthHeaderWasAllocated) delete[] contentLengthHeader;
00775
00776 if (fVerbosityLevel >= 1) envir() << "Sending request: " << cmd << "\n";
00777
00778 if (fTunnelOverHTTPPortNum != 0 && strcmp(request->commandName(), "GET") != 0 && strcmp(request->commandName(), "POST") != 0) {
00779
00780
00781 char* origCmd = cmd;
00782 cmd = base64Encode(origCmd, strlen(cmd));
00783 if (fVerbosityLevel >= 1) envir() << "\tThe request was base-64 encoded to: " << cmd << "\n\n";
00784 delete[] origCmd;
00785 }
00786
00787 if (send(fOutputSocketNum, cmd, strlen(cmd), 0) < 0) {
00788 char const* errFmt = "%s send() failed: ";
00789 unsigned const errLength = strlen(errFmt) + strlen(request->commandName());
00790 char* err = new char[errLength];
00791 sprintf(err, errFmt, request->commandName());
00792 envir().setResultErrMsg(err);
00793 delete[] err;
00794 break;
00795 }
00796
00797
00798
00799 int cseq = request->cseq();
00800
00801 if (fTunnelOverHTTPPortNum == 0 || strcmp(request->commandName(), "POST") != 0) {
00802 fRequestsAwaitingResponse.enqueue(request);
00803 } else {
00804 delete request;
00805 }
00806
00807 delete[] cmd;
00808 return cseq;
00809 } while (0);
00810
00811
00812 delete[] cmd;
00813 handleRequestError(request);
00814 delete request;
00815 return 0;
00816 }
00817
00818 void RTSPClient::handleRequestError(RequestRecord* request) {
00819 int resultCode = -envir().getErrno();
00820 if (resultCode == 0) {
00821
00822 #if defined(__WIN32__) || defined(_WIN32) || defined(_QNX4)
00823 resultCode = -WSAENOTCONN;
00824 #else
00825 resultCode = -ENOTCONN;
00826 #endif
00827 }
00828 if (request->handler() != NULL) (*request->handler())(this, resultCode, strDup(envir().getResultMsg()));
00829 }
00830
00831 Boolean RTSPClient
00832 ::parseResponseCode(char const* line, unsigned& responseCode, char const*& responseString) {
00833 if (sscanf(line, "RTSP/%*s%u", &responseCode) != 1 &&
00834 sscanf(line, "HTTP/%*s%u", &responseCode) != 1) return False;
00835
00836
00837
00838
00839 responseString = line;
00840 while (responseString[0] != '\0' && responseString[0] != ' ' && responseString[0] != '\t') ++responseString;
00841 while (responseString[0] != '\0' && (responseString[0] == ' ' || responseString[0] == '\t')) ++responseString;
00842
00843 return True;
00844 }
00845
00846 void RTSPClient::handleIncomingRequest() {
00847
00848 char cmdName[RTSP_PARAM_STRING_MAX];
00849 char urlPreSuffix[RTSP_PARAM_STRING_MAX];
00850 char urlSuffix[RTSP_PARAM_STRING_MAX];
00851 char cseq[RTSP_PARAM_STRING_MAX];
00852 char sessionId[RTSP_PARAM_STRING_MAX];
00853 unsigned contentLength;
00854 if (!parseRTSPRequestString(fResponseBuffer, fResponseBytesAlreadySeen,
00855 cmdName, sizeof cmdName,
00856 urlPreSuffix, sizeof urlPreSuffix,
00857 urlSuffix, sizeof urlSuffix,
00858 cseq, sizeof cseq,
00859 sessionId, sizeof sessionId,
00860 contentLength)) {
00861 return;
00862 } else {
00863 if (fVerbosityLevel >= 1) {
00864 envir() << "Received incoming RTSP request: " << fResponseBuffer << "\n";
00865 }
00866 char tmpBuf[2*RTSP_PARAM_STRING_MAX];
00867 snprintf((char*)tmpBuf, sizeof tmpBuf,
00868 "RTSP/1.0 405 Method Not Allowed\r\nCSeq: %s\r\n\r\n", cseq);
00869 send(fOutputSocketNum, tmpBuf, strlen(tmpBuf), 0);
00870 }
00871 }
00872
00873 Boolean RTSPClient::checkForHeader(char const* line, char const* headerName, unsigned headerNameLength, char const*& headerParams) {
00874 if (_strncasecmp(line, headerName, headerNameLength) != 0) return False;
00875
00876
00877 unsigned paramIndex = headerNameLength;
00878 while (line[paramIndex] != '\0' && (line[paramIndex] == ' ' || line[paramIndex] == '\t')) ++paramIndex;
00879 if (&line[paramIndex] == '\0') return False;
00880
00881 headerParams = &line[paramIndex];
00882 return True;
00883 }
00884
00885 Boolean RTSPClient::parseTransportParams(char const* paramsStr,
00886 char*& serverAddressStr, portNumBits& serverPortNum,
00887 unsigned char& rtpChannelId, unsigned char& rtcpChannelId) {
00888
00889 serverAddressStr = NULL;
00890 serverPortNum = 0;
00891 rtpChannelId = rtcpChannelId = 0xFF;
00892 if (paramsStr == NULL) return False;
00893
00894 char* foundServerAddressStr = NULL;
00895 Boolean foundServerPortNum = False;
00896 portNumBits clientPortNum = 0;
00897 Boolean foundClientPortNum = False;
00898 Boolean foundChannelIds = False;
00899 unsigned rtpCid, rtcpCid;
00900 Boolean isMulticast = True;
00901 char* foundDestinationStr = NULL;
00902 portNumBits multicastPortNumRTP, multicastPortNumRTCP;
00903 Boolean foundMulticastPortNum = False;
00904
00905
00906 char const* fields = paramsStr;
00907 char* field = strDupSize(fields);
00908 while (sscanf(fields, "%[^;]", field) == 1) {
00909 if (sscanf(field, "server_port=%hu", &serverPortNum) == 1) {
00910 foundServerPortNum = True;
00911 } else if (sscanf(field, "client_port=%hu", &clientPortNum) == 1) {
00912 foundClientPortNum = True;
00913 } else if (_strncasecmp(field, "source=", 7) == 0) {
00914 delete[] foundServerAddressStr;
00915 foundServerAddressStr = strDup(field+7);
00916 } else if (sscanf(field, "interleaved=%u-%u", &rtpCid, &rtcpCid) == 2) {
00917 rtpChannelId = (unsigned char)rtpCid;
00918 rtcpChannelId = (unsigned char)rtcpCid;
00919 foundChannelIds = True;
00920 } else if (strcmp(field, "unicast") == 0) {
00921 isMulticast = False;
00922 } else if (_strncasecmp(field, "destination=", 12) == 0) {
00923 delete[] foundDestinationStr;
00924 foundDestinationStr = strDup(field+12);
00925 } else if (sscanf(field, "port=%hu-%hu", &multicastPortNumRTP, &multicastPortNumRTCP) == 2 ||
00926 sscanf(field, "port=%hu", &multicastPortNumRTP) == 1) {
00927 foundMulticastPortNum = True;
00928 }
00929
00930 fields += strlen(field);
00931 while (fields[0] == ';') ++fields;
00932 if (fields[0] == '\0') break;
00933 }
00934 delete[] field;
00935
00936
00937
00938
00939 if (isMulticast && foundDestinationStr != NULL && foundMulticastPortNum) {
00940 delete[] foundServerAddressStr;
00941 serverAddressStr = foundDestinationStr;
00942 serverPortNum = multicastPortNumRTP;
00943 return True;
00944 }
00945 delete[] foundDestinationStr;
00946
00947
00948
00949
00950
00951
00952 if (foundChannelIds || foundServerPortNum || foundClientPortNum) {
00953 if (foundClientPortNum && !foundServerPortNum) {
00954 serverPortNum = clientPortNum;
00955 }
00956 serverAddressStr = foundServerAddressStr;
00957 return True;
00958 }
00959
00960 delete[] foundServerAddressStr;
00961 return False;
00962 }
00963
00964 Boolean RTSPClient::parseScaleParam(char const* paramStr, float& scale) {
00965 Locale l("C", Numeric);
00966 return sscanf(paramStr, "%f", &scale) == 1;
00967 }
00968
00969 Boolean RTSPClient::parseRTPInfoParams(char const*& paramsStr, u_int16_t& seqNum, u_int32_t& timestamp) {
00970 if (paramsStr == NULL || paramsStr[0] == '\0') return False;
00971 while (paramsStr[0] == ',') ++paramsStr;
00972
00973
00974 char* field = strDupSize(paramsStr);
00975
00976 Boolean sawSeq = False, sawRtptime = False;
00977 while (sscanf(paramsStr, "%[^;,]", field) == 1) {
00978 if (sscanf(field, "seq=%hu", &seqNum) == 1) {
00979 sawSeq = True;
00980 } else if (sscanf(field, "rtptime=%u", ×tamp) == 1) {
00981 sawRtptime = True;
00982 }
00983
00984 paramsStr += strlen(field);
00985 if (paramsStr[0] == '\0' || paramsStr[0] == ',') break;
00986
00987 ++paramsStr;
00988 }
00989
00990 delete[] field;
00991
00992 return sawSeq && sawRtptime;
00993 }
00994
00995 Boolean RTSPClient::handleSETUPResponse(MediaSubsession& subsession, char const* sessionParamsStr, char const* transportParamsStr,
00996 Boolean streamUsingTCP) {
00997 char* sessionId = new char[responseBufferSize];
00998 Boolean success = False;
00999 do {
01000
01001 if (sessionParamsStr == NULL || sscanf(sessionParamsStr, "%[^;]", sessionId) != 1) {
01002 envir().setResultMsg("Missing or bad \"Session:\" header");
01003 break;
01004 }
01005 subsession.setSessionId(sessionId);
01006 delete[] fLastSessionId; fLastSessionId = strDup(sessionId);
01007
01008
01009 char const* afterSessionId = sessionParamsStr + strlen(sessionId);
01010 int timeoutVal;
01011 if (sscanf(afterSessionId, "; timeout = %d", &timeoutVal) == 1) {
01012 fSessionTimeoutParameter = timeoutVal;
01013 }
01014
01015
01016 char* serverAddressStr;
01017 portNumBits serverPortNum;
01018 unsigned char rtpChannelId, rtcpChannelId;
01019 if (!parseTransportParams(transportParamsStr, serverAddressStr, serverPortNum, rtpChannelId, rtcpChannelId)) {
01020 envir().setResultMsg("Missing or bad \"Transport:\" header");
01021 break;
01022 }
01023 delete[] subsession.connectionEndpointName();
01024 subsession.connectionEndpointName() = serverAddressStr;
01025 subsession.serverPortNum = serverPortNum;
01026 subsession.rtpChannelId = rtpChannelId;
01027 subsession.rtcpChannelId = rtcpChannelId;
01028
01029 if (streamUsingTCP) {
01030
01031 if (subsession.rtpSource() != NULL) {
01032 subsession.rtpSource()->setStreamSocket(fInputSocketNum, subsession.rtpChannelId);
01033 subsession.rtpSource()->setServerRequestAlternativeByteHandler(fInputSocketNum, handleAlternativeRequestByte, this);
01034 subsession.rtpSource()->enableRTCPReports() = False;
01035
01036 }
01037 if (subsession.rtcpInstance() != NULL) subsession.rtcpInstance()->setStreamSocket(fInputSocketNum, subsession.rtcpChannelId);
01038 } else {
01039
01040
01041 netAddressBits destAddress = subsession.connectionEndpointAddress();
01042 if (destAddress == 0) destAddress = fServerAddress;
01043 subsession.setDestinations(destAddress);
01044
01045
01046
01047 Groupsock* gs1 = NULL; Groupsock* gs2 = NULL;
01048 if (subsession.rtpSource() != NULL) gs1 = subsession.rtpSource()->RTPgs();
01049 if (subsession.rtcpInstance() != NULL) gs2 = subsession.rtcpInstance()->RTCPgs();
01050 u_int32_t const dummy = 0xFEEDFACE;
01051 unsigned const numDummyPackets = 2;
01052 for (unsigned i = 0; i < numDummyPackets; ++i) {
01053 if (gs1 != NULL) gs1->output(envir(), 255, (unsigned char*)&dummy, sizeof dummy);
01054 if (gs2 != NULL) gs2->output(envir(), 255, (unsigned char*)&dummy, sizeof dummy);
01055 }
01056 }
01057
01058 success = True;
01059 } while (0);
01060
01061 delete[] sessionId;
01062 return success;
01063 }
01064
01065 Boolean RTSPClient::handlePLAYResponse(MediaSession& session, MediaSubsession& subsession,
01066 char const* scaleParamsStr, char const* rangeParamsStr, char const* rtpInfoParamsStr) {
01067 Boolean scaleOK = False, rangeOK = False;
01068 do {
01069 if (&session != NULL) {
01070
01071 if (scaleParamsStr != NULL && !parseScaleParam(scaleParamsStr, session.scale())) break;
01072 scaleOK = True;
01073 if (rangeParamsStr != NULL && !parseRangeParam(rangeParamsStr, session.playStartTime(), session.playEndTime(),
01074 session._absStartTime(), session._absEndTime())) break;
01075 rangeOK = True;
01076
01077 MediaSubsessionIterator iter(session);
01078 MediaSubsession* subsession;
01079 while ((subsession = iter.next()) != NULL) {
01080 u_int16_t seqNum; u_int32_t timestamp;
01081 subsession->rtpInfo.infoIsNew = False;
01082 if (parseRTPInfoParams(rtpInfoParamsStr, seqNum, timestamp)) {
01083 subsession->rtpInfo.seqNum = seqNum;
01084 subsession->rtpInfo.timestamp = timestamp;
01085 subsession->rtpInfo.infoIsNew = True;
01086 }
01087
01088 if (subsession->rtpSource() != NULL) subsession->rtpSource()->enableRTCPReports() = True;
01089 }
01090 } else {
01091
01092 if (scaleParamsStr != NULL && !parseScaleParam(scaleParamsStr, subsession.scale())) break;
01093 scaleOK = True;
01094 if (rangeParamsStr != NULL && !parseRangeParam(rangeParamsStr, subsession._playStartTime(), subsession._playEndTime(),
01095 subsession._absStartTime(), subsession._absEndTime())) break;
01096 rangeOK = True;
01097
01098 u_int16_t seqNum; u_int32_t timestamp;
01099 subsession.rtpInfo.infoIsNew = False;
01100 if (parseRTPInfoParams(rtpInfoParamsStr, seqNum, timestamp)) {
01101 subsession.rtpInfo.seqNum = seqNum;
01102 subsession.rtpInfo.timestamp = timestamp;
01103 subsession.rtpInfo.infoIsNew = True;
01104 }
01105
01106 if (subsession.rtpSource() != NULL) subsession.rtpSource()->enableRTCPReports() = True;
01107 }
01108
01109 return True;
01110 } while (0);
01111
01112
01113 if (!scaleOK) {
01114 envir().setResultMsg("Bad \"Scale:\" header");
01115 } else if (!rangeOK) {
01116 envir().setResultMsg("Bad \"Range:\" header");
01117 } else {
01118 envir().setResultMsg("Bad \"RTP-Info:\" header");
01119 }
01120 return False;
01121 }
01122
01123 Boolean RTSPClient::handleTEARDOWNResponse(MediaSession& , MediaSubsession& ) {
01124
01125 return True;
01126 }
01127
01128 Boolean RTSPClient::handleGET_PARAMETERResponse(char const* parameterName, char*& resultValueString) {
01129 do {
01130
01131 if (parameterName != NULL && parameterName[0] != '\0') {
01132 if (parameterName[1] == '\0') break;
01133
01134 unsigned parameterNameLen = strlen(parameterName);
01135
01136 parameterNameLen -= 2;
01137 if (_strncasecmp(resultValueString, parameterName, parameterNameLen) == 0) {
01138 resultValueString += parameterNameLen;
01139 if (resultValueString[0] == ':') ++resultValueString;
01140 while (resultValueString[0] == ' ' || resultValueString[0] == '\t') ++resultValueString;
01141 }
01142 }
01143
01144
01145 unsigned resultLen = strlen(resultValueString);
01146 while (resultLen > 0 && (resultValueString[resultLen-1] == '\r' || resultValueString[resultLen-1] == '\n')) --resultLen;
01147 resultValueString[resultLen] = '\0';
01148
01149 return True;
01150 } while (0);
01151
01152
01153 envir().setResultMsg("Bad \"GET_PARAMETER\" response");
01154 return False;
01155 }
01156
01157 Boolean RTSPClient::handleAuthenticationFailure(char const* paramsStr) {
01158 if (paramsStr == NULL) return False;
01159
01160
01161 Boolean alreadyHadRealm = fCurrentAuthenticator.realm() != NULL;
01162 char* realm = strDupSize(paramsStr);
01163 char* nonce = strDupSize(paramsStr);
01164 Boolean success = True;
01165 if (sscanf(paramsStr, "Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"", realm, nonce) == 2) {
01166 fCurrentAuthenticator.setRealmAndNonce(realm, nonce);
01167 } else if (sscanf(paramsStr, "Basic realm=\"%[^\"]\"", realm) == 1) {
01168 fCurrentAuthenticator.setRealmAndNonce(realm, NULL);
01169 } else {
01170 success = False;
01171 }
01172 delete[] realm; delete[] nonce;
01173
01174 if (alreadyHadRealm || fCurrentAuthenticator.username() == NULL || fCurrentAuthenticator.password() == NULL) {
01175
01176
01177 success = False;
01178 }
01179
01180 return success;
01181 }
01182
01183 Boolean RTSPClient::resendCommand(RequestRecord* request) {
01184 if (fVerbosityLevel >= 1) envir() << "Resending...\n";
01185 if (request != NULL && strcmp(request->commandName(), "GET") != 0) request->cseq() = ++fCSeq;
01186 return sendRequest(request) != 0;
01187 }
01188
01189 char const* RTSPClient::sessionURL(MediaSession const& session) const {
01190 char const* url = session.controlPath();
01191 if (url == NULL || strcmp(url, "*") == 0) url = fBaseURL;
01192
01193 return url;
01194 }
01195
01196 void RTSPClient::handleAlternativeRequestByte(void* rtspClient, u_int8_t requestByte) {
01197 ((RTSPClient*)rtspClient)->handleAlternativeRequestByte1(requestByte);
01198 }
01199
01200 void RTSPClient::handleAlternativeRequestByte1(u_int8_t requestByte) {
01201 if (requestByte == 0xFF) {
01202
01203 handleResponseBytes(-1);
01204 } else if (requestByte == 0xFE) {
01205
01206 envir().taskScheduler().setBackgroundHandling(fInputSocketNum, SOCKET_READABLE|SOCKET_EXCEPTION,
01207 (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this);
01208 } else {
01209
01210 fResponseBuffer[fResponseBytesAlreadySeen] = requestByte;
01211 handleResponseBytes(1);
01212 }
01213 }
01214
01215 static Boolean isAbsoluteURL(char const* url) {
01216
01217
01218 while (*url != '\0' && *url != '/') {
01219 if (*url == ':') return True;
01220 ++url;
01221 }
01222
01223 return False;
01224 }
01225
01226 void RTSPClient::constructSubsessionURL(MediaSubsession const& subsession,
01227 char const*& prefix,
01228 char const*& separator,
01229 char const*& suffix) {
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241 prefix = sessionURL(subsession.parentSession());
01242 if (prefix == NULL) prefix = "";
01243
01244 suffix = subsession.controlPath();
01245 if (suffix == NULL) suffix = "";
01246
01247 if (isAbsoluteURL(suffix)) {
01248 prefix = separator = "";
01249 } else {
01250 unsigned prefixLen = strlen(prefix);
01251 separator = (prefixLen == 0 || prefix[prefixLen-1] == '/' || suffix[0] == '/') ? "" : "/";
01252 }
01253 }
01254
01255 Boolean RTSPClient::setupHTTPTunneling1() {
01256
01257
01258 if (fVerbosityLevel >= 1) {
01259 envir() << "Requesting RTSP-over-HTTP tunneling (on port " << fTunnelOverHTTPPortNum << ")\n\n";
01260 }
01261
01262
01263 return sendRequest(new RequestRecord(1, "GET", responseHandlerForHTTP_GET)) != 0;
01264 }
01265
01266 void RTSPClient::responseHandlerForHTTP_GET(RTSPClient* rtspClient, int responseCode, char* responseString) {
01267 if (rtspClient != NULL) rtspClient->responseHandlerForHTTP_GET1(responseCode, responseString);
01268 }
01269
01270 void RTSPClient::responseHandlerForHTTP_GET1(int responseCode, char* responseString) {
01271 RequestRecord* request;
01272 do {
01273 if (responseCode != 0) break;
01274
01275
01276
01277 fOutputSocketNum = setupStreamSocket(envir(), 0);
01278 if (fOutputSocketNum < 0) break;
01279 ignoreSigPipeOnSocket(fOutputSocketNum);
01280
01281 fHTTPTunnelingConnectionIsPending = True;
01282 int connectResult = connectToServer(fOutputSocketNum, fTunnelOverHTTPPortNum);
01283 if (connectResult < 0) break;
01284 else if (connectResult == 0) {
01285
01286
01287 while ((request = fRequestsAwaitingHTTPTunneling.dequeue()) != NULL) {
01288 fRequestsAwaitingConnection.enqueue(request);
01289 }
01290 return;
01291 }
01292
01293
01294 if (!setupHTTPTunneling2()) break;
01295
01296
01297 while ((request = fRequestsAwaitingHTTPTunneling.dequeue()) != NULL) {
01298 sendRequest(request);
01299 }
01300 return;
01301 } while (0);
01302
01303
01304 fHTTPTunnelingConnectionIsPending = False;
01305 resetTCPSockets();
01306 RequestQueue requestQueue(fRequestsAwaitingHTTPTunneling);
01307 while ((request = requestQueue.dequeue()) != NULL) {
01308 handleRequestError(request);
01309 delete request;
01310 }
01311 }
01312
01313 Boolean RTSPClient::setupHTTPTunneling2() {
01314 fHTTPTunnelingConnectionIsPending = False;
01315
01316
01317 return sendRequest(new RequestRecord(1, "POST", NULL)) != 0;
01318 }
01319
01320 void RTSPClient::connectionHandler(void* instance, int ) {
01321 RTSPClient* client = (RTSPClient*)instance;
01322 client->connectionHandler1();
01323 }
01324
01325 void RTSPClient::connectionHandler1() {
01326
01327 envir().taskScheduler().disableBackgroundHandling(fOutputSocketNum);
01328 envir().taskScheduler().setBackgroundHandling(fInputSocketNum, SOCKET_READABLE|SOCKET_EXCEPTION,
01329 (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this);
01330
01331
01332
01333 RequestQueue tmpRequestQueue(fRequestsAwaitingConnection);
01334 RequestRecord* request;
01335
01336
01337 do {
01338 int err = 0;
01339 SOCKLEN_T len = sizeof err;
01340 if (getsockopt(fInputSocketNum, SOL_SOCKET, SO_ERROR, (char*)&err, &len) < 0 || err != 0) {
01341 envir().setResultErrMsg("Connection to server failed: ", err);
01342 if (fVerbosityLevel >= 1) envir() << "..." << envir().getResultMsg() << "\n";
01343 break;
01344 }
01345
01346
01347 if (fVerbosityLevel >= 1) envir() << "...remote connection opened\n";
01348 if (fHTTPTunnelingConnectionIsPending && !setupHTTPTunneling2()) break;
01349
01350
01351 while ((request = tmpRequestQueue.dequeue()) != NULL) {
01352 sendRequest(request);
01353 }
01354 return;
01355 } while (0);
01356
01357
01358 resetTCPSockets();
01359 while ((request = tmpRequestQueue.dequeue()) != NULL) {
01360 handleRequestError(request);
01361 delete request;
01362 }
01363 }
01364
01365 void RTSPClient::incomingDataHandler(void* instance, int ) {
01366 RTSPClient* client = (RTSPClient*)instance;
01367 client->incomingDataHandler1();
01368 }
01369
01370 void RTSPClient::incomingDataHandler1() {
01371 struct sockaddr_in dummy;
01372
01373 int bytesRead = readSocket(envir(), fInputSocketNum, (unsigned char*)&fResponseBuffer[fResponseBytesAlreadySeen], fResponseBufferBytesLeft, dummy);
01374 handleResponseBytes(bytesRead);
01375 }
01376
01377 static char* getLine(char* startOfLine) {
01378
01379 for (char* ptr = startOfLine; *ptr != '\0'; ++ptr) {
01380
01381 if (*ptr == '\r' || *ptr == '\n') {
01382
01383 if (*ptr == '\r') {
01384 *ptr++ = '\0';
01385 if (*ptr == '\n') ++ptr;
01386 } else {
01387 *ptr++ = '\0';
01388 }
01389 return ptr;
01390 }
01391 }
01392
01393 return NULL;
01394 }
01395
01396 void RTSPClient::handleResponseBytes(int newBytesRead) {
01397 do {
01398 if (newBytesRead >= 0 && (unsigned)newBytesRead < fResponseBufferBytesLeft) break;
01399
01400 if (newBytesRead >= (int)fResponseBufferBytesLeft) {
01401
01402 envir().setResultMsg("RTSP response was truncated. Increase \"RTSPClient::responseBufferSize\"");
01403 }
01404
01405
01406
01407 resetResponseBuffer();
01408 RequestRecord* request;
01409 if (newBytesRead > 0) {
01410 if ((request = fRequestsAwaitingResponse.dequeue()) != NULL) {
01411 handleRequestError(request);
01412 delete request;
01413 }
01414 } else {
01415 RequestQueue requestQueue(fRequestsAwaitingResponse);
01416 resetTCPSockets();
01417
01418 while ((request = requestQueue.dequeue()) != NULL) {
01419 handleRequestError(request);
01420 delete request;
01421 }
01422 }
01423 return;
01424 } while (0);
01425
01426 fResponseBufferBytesLeft -= newBytesRead;
01427 fResponseBytesAlreadySeen += newBytesRead;
01428 fResponseBuffer[fResponseBytesAlreadySeen] = '\0';
01429 if (fVerbosityLevel >= 1 && newBytesRead > 1) envir() << "Received " << newBytesRead << " new bytes of response data.\n";
01430
01431 unsigned numExtraBytesAfterResponse = 0;
01432 Boolean responseSuccess = False;
01433 do {
01434
01435
01436 Boolean endOfHeaders = False;
01437 char const* ptr = fResponseBuffer;
01438 if (fResponseBytesAlreadySeen > 3) {
01439 char const* const ptrEnd = &fResponseBuffer[fResponseBytesAlreadySeen-3];
01440 while (ptr < ptrEnd) {
01441 if (*ptr++ == '\r' && *ptr++ == '\n' && *ptr++ == '\r' && *ptr++ == '\n') {
01442
01443 endOfHeaders = True;
01444 break;
01445 }
01446 }
01447 }
01448
01449 if (!endOfHeaders) return;
01450
01451
01452
01453
01454 char* headerDataCopy;
01455 unsigned responseCode = 200;
01456 char const* responseStr = NULL;
01457 RequestRecord* foundRequest = NULL;
01458 char const* sessionParamsStr = NULL;
01459 char const* transportParamsStr = NULL;
01460 char const* scaleParamsStr = NULL;
01461 char const* rangeParamsStr = NULL;
01462 char const* rtpInfoParamsStr = NULL;
01463 char const* wwwAuthenticateParamsStr = NULL;
01464 char const* publicParamsStr = NULL;
01465 char* bodyStart = NULL;
01466 unsigned numBodyBytes = 0;
01467 responseSuccess = False;
01468 do {
01469 headerDataCopy = new char[responseBufferSize];
01470 strncpy(headerDataCopy, fResponseBuffer, fResponseBytesAlreadySeen);
01471 headerDataCopy[fResponseBytesAlreadySeen] = '\0';
01472
01473 char* lineStart = headerDataCopy;
01474 char* nextLineStart = getLine(lineStart);
01475 if (!parseResponseCode(lineStart, responseCode, responseStr)) {
01476
01477 handleIncomingRequest();
01478 break;
01479 }
01480
01481
01482 Boolean reachedEndOfHeaders;
01483 unsigned cseq = 0;
01484 unsigned contentLength = 0;
01485
01486 while (1) {
01487 reachedEndOfHeaders = True;
01488 lineStart = nextLineStart;
01489 if (lineStart == NULL) break;
01490
01491 nextLineStart = getLine(lineStart);
01492 if (lineStart[0] == '\0') break;
01493 reachedEndOfHeaders = False;
01494
01495 char const* headerParamsStr;
01496 if (checkForHeader(lineStart, "CSeq:", 5, headerParamsStr)) {
01497 if (sscanf(headerParamsStr, "%u", &cseq) != 1 || cseq <= 0) {
01498 envir().setResultMsg("Bad \"CSeq:\" header: \"", lineStart, "\"");
01499 break;
01500 }
01501
01502 RequestRecord* request;
01503 while ((request = fRequestsAwaitingResponse.dequeue()) != NULL) {
01504 if (request->cseq() < cseq) {
01505
01506 if (fVerbosityLevel >= 1 && strcmp(request->commandName(), "POST") != 0) {
01507 envir() << "WARNING: The server did not respond to our \"" << request->commandName() << "\" request (CSeq: "
01508 << request->cseq() << "). The server appears to be buggy (perhaps not handling pipelined requests properly).\n";
01509 }
01510 delete request;
01511 } else if (request->cseq() == cseq) {
01512
01513 foundRequest = request;
01514 break;
01515 } else {
01516
01517 break;
01518 }
01519 }
01520 } else if (checkForHeader(lineStart, "Content-Length:", 15, headerParamsStr)) {
01521 if (sscanf(headerParamsStr, "%u", &contentLength) != 1) {
01522 envir().setResultMsg("Bad \"Content-Length:\" header: \"", lineStart, "\"");
01523 break;
01524 }
01525 } else if (checkForHeader(lineStart, "Content-Base:", 13, headerParamsStr)) {
01526 setBaseURL(headerParamsStr);
01527 } else if (checkForHeader(lineStart, "Session:", 8, sessionParamsStr)) {
01528 } else if (checkForHeader(lineStart, "Transport:", 10, transportParamsStr)) {
01529 } else if (checkForHeader(lineStart, "Scale:", 6, scaleParamsStr)) {
01530 } else if (checkForHeader(lineStart, "Range:", 6, rangeParamsStr)) {
01531 } else if (checkForHeader(lineStart, "RTP-Info:", 9, rtpInfoParamsStr)) {
01532 } else if (checkForHeader(lineStart, "WWW-Authenticate:", 17, headerParamsStr)) {
01533
01534
01535 if (wwwAuthenticateParamsStr == NULL || _strncasecmp(headerParamsStr, "Digest", 6) == 0) {
01536 wwwAuthenticateParamsStr = headerParamsStr;
01537 }
01538 } else if (checkForHeader(lineStart, "Public:", 7, publicParamsStr)) {
01539 } else if (checkForHeader(lineStart, "Allow:", 6, publicParamsStr)) {
01540
01541 } else if (checkForHeader(lineStart, "Location:", 9, headerParamsStr)) {
01542 setBaseURL(headerParamsStr);
01543 }
01544 }
01545 if (!reachedEndOfHeaders) break;
01546
01547 if (foundRequest == NULL) {
01548
01549 foundRequest = fRequestsAwaitingResponse.dequeue();
01550 }
01551
01552
01553 unsigned bodyOffset = nextLineStart == NULL ? fResponseBytesAlreadySeen : nextLineStart - headerDataCopy;
01554 bodyStart = &fResponseBuffer[bodyOffset];
01555 numBodyBytes = fResponseBytesAlreadySeen - bodyOffset;
01556 if (contentLength > numBodyBytes) {
01557
01558 unsigned numExtraBytesNeeded = contentLength - numBodyBytes;
01559 unsigned remainingBufferSize = responseBufferSize - fResponseBytesAlreadySeen;
01560 if (numExtraBytesNeeded > remainingBufferSize) {
01561 char tmpBuf[200];
01562 sprintf(tmpBuf, "Response buffer size (%d) is too small for \"Content-Length:\" %d (need a buffer size of >= %d bytes\n",
01563 responseBufferSize, contentLength, fResponseBytesAlreadySeen + numExtraBytesNeeded);
01564 envir().setResultMsg(tmpBuf);
01565 break;
01566 }
01567
01568 if (fVerbosityLevel >= 1) {
01569 envir() << "Have received " << fResponseBytesAlreadySeen << " total bytes of a "
01570 << (foundRequest != NULL ? foundRequest->commandName() : "(unknown)")
01571 << " RTSP response; awaiting " << numExtraBytesNeeded << " bytes more.\n";
01572 }
01573 delete[] headerDataCopy;
01574 if (foundRequest != NULL) fRequestsAwaitingResponse.putAtHead(foundRequest);
01575 return;
01576 }
01577
01578
01579 char* responseEnd = bodyStart + contentLength;
01580 numExtraBytesAfterResponse = &fResponseBuffer[fResponseBytesAlreadySeen] - responseEnd;
01581
01582 if (fVerbosityLevel >= 1) {
01583 char saved = *responseEnd;
01584 *responseEnd = '\0';
01585 envir() << "Received a complete "
01586 << (foundRequest != NULL ? foundRequest->commandName() : "(unknown)")
01587 << " response:\n" << fResponseBuffer << "\n";
01588 if (numExtraBytesAfterResponse > 0) envir() << "\t(plus " << numExtraBytesAfterResponse << " additional bytes)\n";
01589 *responseEnd = saved;
01590 }
01591
01592 if (foundRequest != NULL) {
01593 Boolean needToResendCommand = False;
01594 if (responseCode == 200) {
01595
01596 if (strcmp(foundRequest->commandName(), "SETUP") == 0) {
01597 if (!handleSETUPResponse(*foundRequest->subsession(), sessionParamsStr, transportParamsStr, foundRequest->booleanFlags()&0x1)) break;
01598 } else if (strcmp(foundRequest->commandName(), "PLAY") == 0) {
01599 if (!handlePLAYResponse(*foundRequest->session(), *foundRequest->subsession(), scaleParamsStr, rangeParamsStr, rtpInfoParamsStr)) break;
01600 } else if (strcmp(foundRequest->commandName(), "TEARDOWN") == 0) {
01601 if (!handleTEARDOWNResponse(*foundRequest->session(), *foundRequest->subsession())) break;
01602 } else if (strcmp(foundRequest->commandName(), "GET_PARAMETER") == 0) {
01603 if (!handleGET_PARAMETERResponse(foundRequest->contentStr(), bodyStart)) break;
01604 }
01605 } else if (responseCode == 401 && handleAuthenticationFailure(wwwAuthenticateParamsStr)) {
01606
01607 needToResendCommand = True;
01608
01609 if (strcmp(foundRequest->commandName(), "GET") == 0) {
01610
01611
01612
01613 resetTCPSockets();
01614 }
01615 } else if (responseCode == 301 || responseCode == 302) {
01616 resetTCPSockets();
01617 needToResendCommand = True;
01618 }
01619
01620 if (needToResendCommand) {
01621 resetResponseBuffer();
01622 if (!resendCommand(foundRequest)) break;
01623 delete[] headerDataCopy;
01624 return;
01625 }
01626 }
01627
01628 responseSuccess = True;
01629 } while (0);
01630
01631
01632
01633 if (numExtraBytesAfterResponse > 0) {
01634
01635 char* responseEnd = &fResponseBuffer[fResponseBytesAlreadySeen - numExtraBytesAfterResponse];
01636
01637
01638 numBodyBytes -= numExtraBytesAfterResponse;
01639 if (numBodyBytes > 0) {
01640 char saved = *responseEnd;
01641 *responseEnd = '\0';
01642 bodyStart = strDup(bodyStart);
01643 *responseEnd = saved;
01644 }
01645
01646 memmove(fResponseBuffer, responseEnd, numExtraBytesAfterResponse);
01647 fResponseBytesAlreadySeen = numExtraBytesAfterResponse;
01648 fResponseBufferBytesLeft = responseBufferSize - numExtraBytesAfterResponse;
01649 fResponseBuffer[numExtraBytesAfterResponse] = '\0';
01650 } else {
01651 resetResponseBuffer();
01652 }
01653 if (foundRequest != NULL && foundRequest->handler() != NULL) {
01654 int resultCode;
01655 char* resultString;
01656 if (responseSuccess) {
01657 if (responseCode == 200) {
01658 resultCode = 0;
01659 resultString = numBodyBytes > 0 ? strDup(bodyStart) : strDup(publicParamsStr);
01660
01661 } else {
01662 resultCode = responseCode;
01663 resultString = strDup(responseStr);
01664 envir().setResultMsg(responseStr);
01665 }
01666 (*foundRequest->handler())(this, resultCode, resultString);
01667 } else {
01668
01669 handleRequestError(foundRequest);
01670 }
01671 }
01672 delete foundRequest;
01673 delete[] headerDataCopy;
01674 if (numExtraBytesAfterResponse > 0 && numBodyBytes > 0) delete[] bodyStart;
01675 } while (numExtraBytesAfterResponse > 0 && responseSuccess);
01676 }
01677
01678
01680
01681 RTSPClient::RequestRecord::RequestRecord(unsigned cseq, char const* commandName, responseHandler* handler,
01682 MediaSession* session, MediaSubsession* subsession, u_int32_t booleanFlags,
01683 double start, double end, float scale, char const* contentStr)
01684 : fNext(NULL), fCSeq(cseq), fCommandName(commandName), fSession(session), fSubsession(subsession), fBooleanFlags(booleanFlags),
01685 fStart(start), fEnd(end), fAbsStartTime(NULL), fAbsEndTime(NULL), fScale(scale), fContentStr(strDup(contentStr)), fHandler(handler) {
01686 }
01687
01688 RTSPClient::RequestRecord::RequestRecord(unsigned cseq, responseHandler* handler,
01689 char const* absStartTime, char const* absEndTime, float scale,
01690 MediaSession* session, MediaSubsession* subsession)
01691 : fNext(NULL), fCSeq(cseq), fCommandName("PLAY"), fSession(session), fSubsession(subsession), fBooleanFlags(0),
01692 fStart(0.0f), fEnd(-1.0f), fAbsStartTime(strDup(absStartTime)), fAbsEndTime(strDup(absEndTime)), fScale(scale),
01693 fContentStr(NULL), fHandler(handler) {
01694 }
01695
01696 RTSPClient::RequestRecord::~RequestRecord() {
01697
01698 delete fNext;
01699
01700 delete[] fAbsStartTime; delete[] fAbsEndTime;
01701 delete[] fContentStr;
01702 }
01703
01704
01706
01707 RTSPClient::RequestQueue::RequestQueue()
01708 : fHead(NULL), fTail(NULL) {
01709 }
01710
01711 RTSPClient::RequestQueue::RequestQueue(RequestQueue& origQueue)
01712 : fHead(NULL), fTail(NULL) {
01713 RequestRecord* request;
01714 while ((request = origQueue.dequeue()) != NULL) {
01715 enqueue(request);
01716 }
01717 }
01718
01719 RTSPClient::RequestQueue::~RequestQueue() {
01720 delete fHead;
01721 }
01722
01723 void RTSPClient::RequestQueue::enqueue(RequestRecord* request) {
01724 if (fTail == NULL) {
01725 fHead = request;
01726 } else {
01727 fTail->next() = request;
01728 }
01729 fTail = request;
01730 }
01731
01732 RTSPClient::RequestRecord* RTSPClient::RequestQueue::dequeue() {
01733 RequestRecord* request = fHead;
01734 if (fHead == fTail) {
01735 fHead = NULL;
01736 fTail = NULL;
01737 } else {
01738 fHead = fHead->next();
01739 }
01740 if (request != NULL) request->next() = NULL;
01741 return request;
01742 }
01743
01744 void RTSPClient::RequestQueue::putAtHead(RequestRecord* request) {
01745 request->next() = fHead;
01746 fHead = request;
01747 if (fTail == NULL) {
01748 fTail = request;
01749 }
01750 }
01751
01752 RTSPClient::RequestRecord* RTSPClient::RequestQueue::findByCSeq(unsigned cseq) {
01753 RequestRecord* request;
01754 for (request = fHead; request != NULL; request = request->next()) {
01755 if (request->cseq() == cseq) return request;
01756 }
01757 return NULL;
01758 }
01759
01760
01761 #ifdef RTSPCLIENT_SYNCHRONOUS_INTERFACE
01762
01763 RTSPClient* RTSPClient::createNew(UsageEnvironment& env,
01764 int verbosityLevel,
01765 char const* applicationName,
01766 portNumBits tunnelOverHTTPPortNum) {
01767 return new RTSPClient(env, NULL,
01768 verbosityLevel, applicationName, tunnelOverHTTPPortNum);
01769 }
01770
01771 char* RTSPClient::describeURL(char const* url, Authenticator* authenticator,
01772 Boolean allowKasennaProtocol, int timeout) {
01773
01774
01775
01776
01777
01778 char* username; char* password;
01779 if (authenticator == NULL
01780 && parseRTSPURLUsernamePassword(url, username, password)) {
01781 char* result = describeWithPassword(url, username, password, allowKasennaProtocol, timeout);
01782 delete[] username; delete[] password;
01783 return result;
01784 }
01785
01786 setBaseURL(url);
01787 fWatchVariableForSyncInterface = 0;
01788 fTimeoutTask = NULL;
01789 if (timeout > 0) {
01790
01791
01792
01793 fTimeoutTask = envir().taskScheduler().scheduleDelayedTask(timeout*1000000, timeoutHandlerForSyncInterface, this);
01794 }
01795 (void)sendDescribeCommand(responseHandlerForSyncInterface, authenticator);
01796
01797
01798 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01799 if (fResultCode == 0) return fResultString;
01800 delete[] fResultString;
01801 return NULL;
01802 }
01803
01804 char* RTSPClient::describeWithPassword(char const* url,
01805 char const* username, char const* password,
01806 Boolean allowKasennaProtocol, int timeout) {
01807 Authenticator authenticator(username, password);
01808 return describeURL(url, &authenticator, allowKasennaProtocol, timeout);
01809 }
01810
01811 char* RTSPClient::sendOptionsCmd(char const* url,
01812 char* username, char* password,
01813 Authenticator* authenticator,
01814 int timeout) {
01815 char* result = NULL;
01816 Boolean haveAllocatedAuthenticator = False;
01817 if (authenticator == NULL) {
01818
01819
01820 if (username == NULL && password == NULL
01821 && parseRTSPURLUsernamePassword(url, username, password)) {
01822 Authenticator newAuthenticator(username,password);
01823 result = sendOptionsCmd(url, username, password, &newAuthenticator, timeout);
01824 delete[] username; delete[] password;
01825 return result;
01826 } else if (username != NULL && password != NULL) {
01827
01828 authenticator = new Authenticator(username,password);
01829 haveAllocatedAuthenticator = True;
01830
01831 result = sendOptionsCmd(url, username, password, authenticator, timeout);
01832 if (result != NULL) {
01833 delete authenticator;
01834 return result;
01835 }
01836
01837
01838 if (authenticator->realm() == NULL) {
01839
01840 delete authenticator;
01841 return NULL;
01842 }
01843 }
01844 }
01845
01846 setBaseURL(url);
01847 fWatchVariableForSyncInterface = 0;
01848 fTimeoutTask = NULL;
01849 if (timeout > 0) {
01850
01851
01852
01853 fTimeoutTask = envir().taskScheduler().scheduleDelayedTask(timeout*1000000, timeoutHandlerForSyncInterface, this);
01854 }
01855 (void)sendOptionsCommand(responseHandlerForSyncInterface, authenticator);
01856 if (haveAllocatedAuthenticator) delete authenticator;
01857
01858
01859 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01860 if (fResultCode == 0) return fResultString;
01861 delete[] fResultString;
01862 return NULL;
01863 }
01864
01865 Boolean RTSPClient::announceSDPDescription(char const* url,
01866 char const* sdpDescription,
01867 Authenticator* authenticator,
01868 int timeout) {
01869 setBaseURL(url);
01870 fWatchVariableForSyncInterface = 0;
01871 fTimeoutTask = NULL;
01872 if (timeout > 0) {
01873
01874
01875
01876 fTimeoutTask = envir().taskScheduler().scheduleDelayedTask(timeout*1000000, timeoutHandlerForSyncInterface, this);
01877 }
01878 (void)sendAnnounceCommand(sdpDescription, responseHandlerForSyncInterface, authenticator);
01879
01880
01881 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01882 delete[] fResultString;
01883 return fResultCode == 0;
01884 }
01885
01886 Boolean RTSPClient
01887 ::announceWithPassword(char const* url, char const* sdpDescription,
01888 char const* username, char const* password, int timeout) {
01889 Authenticator authenticator(username,password);
01890 return announceSDPDescription(url, sdpDescription, &authenticator, timeout);
01891 }
01892
01893 Boolean RTSPClient::setupMediaSubsession(MediaSubsession& subsession,
01894 Boolean streamOutgoing,
01895 Boolean streamUsingTCP,
01896 Boolean forceMulticastOnUnspecified) {
01897 fWatchVariableForSyncInterface = 0;
01898 fTimeoutTask = NULL;
01899 (void)sendSetupCommand(subsession, responseHandlerForSyncInterface, streamOutgoing, streamUsingTCP, forceMulticastOnUnspecified);
01900
01901
01902 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01903 delete[] fResultString;
01904 return fResultCode == 0;
01905 }
01906
01907 Boolean RTSPClient::playMediaSession(MediaSession& session,
01908 double start, double end, float scale) {
01909 fWatchVariableForSyncInterface = 0;
01910 fTimeoutTask = NULL;
01911 (void)sendPlayCommand(session, responseHandlerForSyncInterface, start, end, scale);
01912
01913
01914 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01915 delete[] fResultString;
01916 return fResultCode == 0;
01917 }
01918
01919 Boolean RTSPClient::playMediaSubsession(MediaSubsession& subsession,
01920 double start, double end, float scale,
01921 Boolean ) {
01922
01923
01924 fWatchVariableForSyncInterface = 0;
01925 fTimeoutTask = NULL;
01926 (void)sendPlayCommand(subsession, responseHandlerForSyncInterface, start, end, scale);
01927
01928
01929 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01930 delete[] fResultString;
01931 return fResultCode == 0;
01932 }
01933
01934 Boolean RTSPClient::pauseMediaSession(MediaSession& session) {
01935 fWatchVariableForSyncInterface = 0;
01936 fTimeoutTask = NULL;
01937 (void)sendPauseCommand(session, responseHandlerForSyncInterface);
01938
01939
01940 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01941 delete[] fResultString;
01942 return fResultCode == 0;
01943 }
01944
01945 Boolean RTSPClient::pauseMediaSubsession(MediaSubsession& subsession) {
01946 fWatchVariableForSyncInterface = 0;
01947 fTimeoutTask = NULL;
01948 (void)sendPauseCommand(subsession, responseHandlerForSyncInterface);
01949
01950
01951 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01952 delete[] fResultString;
01953 return fResultCode == 0;
01954 }
01955
01956 Boolean RTSPClient::recordMediaSubsession(MediaSubsession& subsession) {
01957 fWatchVariableForSyncInterface = 0;
01958 fTimeoutTask = NULL;
01959 (void)sendRecordCommand(subsession, responseHandlerForSyncInterface);
01960
01961
01962 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01963 delete[] fResultString;
01964 return fResultCode == 0;
01965 }
01966
01967 Boolean RTSPClient::setMediaSessionParameter(MediaSession& session,
01968 char const* parameterName,
01969 char const* parameterValue) {
01970 fWatchVariableForSyncInterface = 0;
01971 fTimeoutTask = NULL;
01972 (void)sendSetParameterCommand(session, responseHandlerForSyncInterface, parameterName, parameterValue);
01973
01974
01975 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01976 delete[] fResultString;
01977 return fResultCode == 0;
01978 }
01979
01980 Boolean RTSPClient::getMediaSessionParameter(MediaSession& session,
01981 char const* parameterName,
01982 char*& parameterValue) {
01983 fWatchVariableForSyncInterface = 0;
01984 fTimeoutTask = NULL;
01985 (void)sendGetParameterCommand(session, responseHandlerForSyncInterface, parameterName);
01986
01987
01988 envir().taskScheduler().doEventLoop(&fWatchVariableForSyncInterface);
01989 parameterValue = fResultString;
01990 return fResultCode == 0;
01991 }
01992
01993 Boolean RTSPClient::teardownMediaSession(MediaSession& session) {
01994 fWatchVariableForSyncInterface = 0;
01995 fTimeoutTask = NULL;
01996 (void)sendTeardownCommand(session, NULL);
01997 return True;
01998 }
01999
02000 Boolean RTSPClient::teardownMediaSubsession(MediaSubsession& subsession) {
02001 fWatchVariableForSyncInterface = 0;
02002 fTimeoutTask = NULL;
02003 (void)sendTeardownCommand(subsession, NULL);
02004 return True;
02005 }
02006
02007 Boolean RTSPClient::parseRTSPURLUsernamePassword(char const* url,
02008 char*& username,
02009 char*& password) {
02010 username = password = NULL;
02011 do {
02012
02013 char const* prefix = "rtsp://";
02014 unsigned const prefixLength = 7;
02015 if (_strncasecmp(url, prefix, prefixLength) != 0) break;
02016
02017
02018 unsigned usernameIndex = prefixLength;
02019 unsigned colonIndex = 0, atIndex = 0;
02020 for (unsigned i = usernameIndex; url[i] != '\0' && url[i] != '/'; ++i) {
02021 if (url[i] == ':' && colonIndex == 0) {
02022 colonIndex = i;
02023 } else if (url[i] == '@') {
02024 atIndex = i;
02025 break;
02026 }
02027 }
02028 if (atIndex == 0) break;
02029
02030 char* urlCopy = strDup(url);
02031 urlCopy[atIndex] = '\0';
02032 if (colonIndex > 0) {
02033 urlCopy[colonIndex] = '\0';
02034 password = strDup(&urlCopy[colonIndex+1]);
02035 } else {
02036 password = strDup("");
02037 }
02038 username = strDup(&urlCopy[usernameIndex]);
02039 delete[] urlCopy;
02040
02041 return True;
02042 } while (0);
02043
02044 return False;
02045 }
02046
02047 void RTSPClient::responseHandlerForSyncInterface(RTSPClient* rtspClient, int responseCode, char* responseString) {
02048 if (rtspClient != NULL) rtspClient->responseHandlerForSyncInterface1(responseCode, responseString);
02049 }
02050
02051 void RTSPClient::responseHandlerForSyncInterface1(int responseCode, char* responseString) {
02052
02053 if (fTimeoutTask != NULL) envir().taskScheduler().unscheduleDelayedTask(fTimeoutTask);
02054
02055
02056 fResultCode = responseCode;
02057 fResultString = responseString;
02058
02059
02060 fWatchVariableForSyncInterface = ~0;
02061 }
02062
02063 void RTSPClient::timeoutHandlerForSyncInterface(void* rtspClient) {
02064 if (rtspClient != NULL) ((RTSPClient*)rtspClient)->timeoutHandlerForSyncInterface1();
02065 }
02066
02067 void RTSPClient::timeoutHandlerForSyncInterface1() {
02068
02069
02070
02071 changeResponseHandler(fCSeq, NULL);
02072 fTimeoutTask = NULL;
02073
02074
02075 fResultCode = ~0;
02076 fResultString = NULL;
02077
02078
02079 fWatchVariableForSyncInterface = ~0;
02080 }
02081
02082 #endif