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