📄 rtspclient.cpp
字号:
delete[] cmd; return False;}Boolean RTSPClient::teardownMediaSession(MediaSession& session) { char* cmd = NULL; do { // First, make sure that we have a RTSP session in progreee if (fLastSessionId == NULL) { envir().setResultMsg(NoSessionErr); break; } // Send the TEARDOWN command: // First, construct an authenticator string: char* authenticatorStr = createAuthenticatorString(&fCurrentAuthenticator, "TEARDOWN", fBaseURL); char const* sessURL = sessionURL(session); char* const cmdFmt = "TEARDOWN %s RTSP/1.0\r\n" "CSeq: %d\r\n" "Session: %s\r\n" "%s" "%s" "\r\n"; unsigned cmdSize = strlen(cmdFmt) + strlen(sessURL) + 20 /* max int len */ + strlen(fLastSessionId) + strlen(authenticatorStr) + fUserAgentHeaderStrSize; cmd = new char[cmdSize]; sprintf(cmd, cmdFmt, sessURL, ++fCSeq, fLastSessionId, authenticatorStr, fUserAgentHeaderStr); delete[] authenticatorStr; if (!sendRequest(cmd, "TEARDOWN")) break; if (fTCPStreamIdCount == 0) { // When TCP streaming, don't look for a response // Get the response from the server: unsigned bytesRead; unsigned responseCode; char* firstLine; char* nextLineStart; if (!getResponse("TEARDOWN", bytesRead, responseCode, firstLine, nextLineStart)) break; // Run through each subsession, deleting its "sessionId": MediaSubsessionIterator iter(session); MediaSubsession* subsession; while ((subsession = iter.next()) != NULL) { delete[] (char*)subsession->sessionId; subsession->sessionId = NULL; } delete[] fLastSessionId; fLastSessionId = NULL; // we're done with this session } delete[] cmd; return True; } while (0); delete[] cmd; return False;}Boolean RTSPClient::teardownMediaSubsession(MediaSubsession& subsession) { char* cmd = NULL; do { // First, make sure that we have a RTSP session in progreee if (subsession.sessionId == NULL) { envir().setResultMsg(NoSessionErr); break; } // Send the TEARDOWN command: // First, construct an authenticator string: char* authenticatorStr = createAuthenticatorString(&fCurrentAuthenticator, "TEARDOWN", fBaseURL); char* const cmdFmt = "TEARDOWN %s%s%s RTSP/1.0\r\n" "CSeq: %d\r\n" "Session: %s\r\n" "%s" "%s" "\r\n"; char const *prefix, *separator, *suffix; constructSubsessionURL(subsession, prefix, separator, suffix); unsigned cmdSize = strlen(cmdFmt) + strlen(prefix) + strlen(separator) + strlen(suffix) + 20 /* max int len */ + strlen(subsession.sessionId) + strlen(authenticatorStr) + fUserAgentHeaderStrSize; cmd = new char[cmdSize]; sprintf(cmd, cmdFmt, prefix, separator, suffix, ++fCSeq, subsession.sessionId, authenticatorStr, fUserAgentHeaderStr); delete[] authenticatorStr; if (!sendRequest(cmd, "TEARDOWN")) break; if (fTCPStreamIdCount == 0) { // When TCP streaming, don't look for a response // Get the response from the server: unsigned bytesRead; unsigned responseCode; char* firstLine; char* nextLineStart; if (!getResponse("TEARDOWN", bytesRead, responseCode, firstLine, nextLineStart)) break; } delete[] (char*)subsession.sessionId; subsession.sessionId = NULL; // we're done with this session delete[] cmd; return True; } while (0); delete[] cmd; return False;}Boolean RTSPClient::openConnectionFromURL(char const* url, Authenticator* authenticator) { do { // Set this as our base URL: delete[] fBaseURL; fBaseURL = strDup(url); if (fBaseURL == NULL) break; // Begin by parsing the URL: NetAddress destAddress; portNumBits urlPortNum; char const* urlSuffix; if (!parseRTSPURL(envir(), url, destAddress, urlPortNum, &urlSuffix)) break; portNumBits destPortNum = fTunnelOverHTTPPortNum == 0 ? urlPortNum : fTunnelOverHTTPPortNum; if (fInputSocketNum < 0) { // We don't yet have a TCP socket. Set one up (blocking) now: fInputSocketNum = fOutputSocketNum = setupStreamSocket(envir(), 0, False /* =>blocking */); if (fInputSocketNum < 0) break; // Connect to the remote endpoint: fServerAddress = *(unsigned*)(destAddress.data()); MAKE_SOCKADDR_IN(remoteName, fServerAddress, htons(destPortNum)); if (connect(fInputSocketNum, (struct sockaddr*)&remoteName, sizeof remoteName) != 0) { envir().setResultErrMsg("connect() failed: "); break; } if (fTunnelOverHTTPPortNum != 0 && !setupHTTPTunneling(urlSuffix, authenticator)) break; } return True; } while (0); fDescribeStatusCode = 1; resetTCPSockets(); return False;}Boolean RTSPClient::parseRTSPURL(UsageEnvironment& env, char const* url, NetAddress& address, portNumBits& portNum, char const** urlSuffix) { do { // Parse the URL as "rtsp://<address>:<port>/<etc>" // (with ":<port>" and "/<etc>" optional) // Also, skip over any "<username>[:<password>]@" preceding <address> char const* prefix = "rtsp://"; unsigned const prefixLength = 7; if (_strncasecmp(url, prefix, prefixLength) != 0) { env.setResultMsg("URL is not of the form \"", prefix, "\""); break; } unsigned const parseBufferSize = 100; char parseBuffer[parseBufferSize]; char const* from = &url[prefixLength]; // Skip over any "<username>[:<password>]@" // (Note that this code fails if <password> contains '@' or '/', but // given that these characters can also appear in <etc>, there seems to // be no way of unambiguously parsing that situation.) char const* from1 = from; while (*from1 != '\0' && *from1 != '/') { if (*from1 == '@') { from = ++from1; break; } ++from1; } char* to = &parseBuffer[0]; unsigned i; for (i = 0; i < parseBufferSize; ++i) { if (*from == '\0' || *from == ':' || *from == '/') { // We've completed parsing the address *to = '\0'; break; } *to++ = *from++; } if (i == parseBufferSize) { env.setResultMsg("URL is too long"); break; } NetAddressList addresses(parseBuffer); if (addresses.numAddresses() == 0) { env.setResultMsg("Failed to find network address for \"", parseBuffer, "\""); break; } address = *(addresses.firstAddress()); portNum = 554; // default value char nextChar = *from; if (nextChar == ':') { int portNumInt; if (sscanf(++from, "%d", &portNumInt) != 1) { env.setResultMsg("No port number follows ':'"); break; } if (portNumInt < 1 || portNumInt > 65535) { env.setResultMsg("Bad port number"); break; } portNum = (portNumBits)portNumInt; while (*from >= '0' && *from <= '9') ++from; // skip over port number } // The remainder of the URL is the suffix: if (urlSuffix != NULL) *urlSuffix = from; return True; } while (0); return False;}Boolean RTSPClient::parseRTSPURLUsernamePassword(char const* url, char*& username, char*& password) { username = password = NULL; // by default do { // Parse the URL as "rtsp://<username>[:<password>]@<whatever>" char const* prefix = "rtsp://"; unsigned const prefixLength = 7; if (_strncasecmp(url, prefix, prefixLength) != 0) break; // Look for the ':' and '@': unsigned usernameIndex = prefixLength; unsigned colonIndex = 0, atIndex = 0; for (unsigned i = usernameIndex; url[i] != '\0' && url[i] != '/'; ++i) { if (url[i] == ':' && colonIndex == 0) { colonIndex = i; } else if (url[i] == '@') { atIndex = i; break; // we're done } } if (atIndex == 0) break; // no '@' found char* urlCopy = strDup(url); urlCopy[atIndex] = '\0'; if (colonIndex > 0) { urlCopy[colonIndex] = '\0'; password = strDup(&urlCopy[colonIndex+1]); } else { password = strDup(""); } username = strDup(&urlCopy[usernameIndex]); delete[] urlCopy; return True; } while (0); return False;}char*RTSPClient::createAuthenticatorString(Authenticator const* authenticator, char const* cmd, char const* url) { if (authenticator != NULL && authenticator->realm() != NULL && authenticator->username() != NULL && authenticator->password() != NULL) { // We've been provided a filled-in authenticator, so use it: char* authenticatorStr; if (authenticator->nonce() != NULL) { // Digest authentication char* const authFmt = "Authorization: Digest username=\"%s\", realm=\"%s\", " "nonce=\"%s\", uri=\"%s\", response=\"%s\"\r\n"; char const* response = authenticator->computeDigestResponse(cmd, url); unsigned authBufSize = strlen(authFmt) + strlen(authenticator->username()) + strlen(authenticator->realm()) + strlen(authenticator->nonce()) + strlen(url) + strlen(response); authenticatorStr = new char[authBufSize]; sprintf(authenticatorStr, authFmt, authenticator->username(), authenticator->realm(), authenticator->nonce(), url, response); authenticator->reclaimDigestResponse(response); } else { // Basic authentication char* const authFmt = "Authorization: Basic %s\r\n"; unsigned usernamePasswordLength = strlen(authenticator->username()) + 1 + strlen(authenticator->password()); char* usernamePassword = new char[usernamePasswordLength+1]; sprintf(usernamePassword, "%s:%s", authenticator->username(), authenticator->password()); char* response = base64Encode(usernamePassword, usernamePasswordLength); unsigned authBufSize = strlen(authFmt) + strlen(response); authenticatorStr = new char[authBufSize]; sprintf(authenticatorStr, authFmt, response); delete[] response; delete[] usernamePassword; } return authenticatorStr; } return strDup("");}void RTSPClient::checkForAuthenticationFailure(unsigned responseCode, char*& nextLineStart, Authenticator* authenticator) { if (responseCode == 401 && authenticator != NULL) { // We have an authentication failure, so fill in "authenticator" // using the contents of a following "WWW-Authenticate:" line. // (Once we compute a 'response' for "authenticator", it can be // used in a subsequent request - that will hopefully succeed.) char* lineStart; while (1) { lineStart = nextLineStart; if (lineStart == NULL) break; nextLineStart = getLine(lineStart); if (lineStart[0] == '\0') break; // this is a blank line char* realm = strDupSize(lineStart); char* nonce = strDupSize(lineStart); Boolean foundAuthenticateHeader = False; if (sscanf(lineStart, "WWW-Authenticate: Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"", realm, nonce) == 2) { authenticator->setRealmAndNonce(realm, nonce); foundAuthenticateHeader = True; } else if (sscanf(lineStart, "WWW-Authenticate: Basic realm=\"%[^\"]\"", realm) == 1) { authenticator->setRealmAndNonce(realm, NULL); // Basic authentication foundAuthenticateHeader = True; } delete[] realm; delete[] nonce; if (foundAuthenticateHeader) break; } }}Boolean RTSPClient::sendRequest(char const* requestString, char const* tag, Boolean base64EncodeIfOverHTTP) { if (fVerbosityLevel >= 1) { envir() << "Sending request: " << requestString << "\n"; } char* newRequestString = NULL; if (fTunnelOverHTTPPortNum != 0 && base64EncodeIfOverHTTP) { requestString = newRequestString = base64Encode(requestString, strlen(requestString)); if (fVerbosityLevel >= 1) { envir() << "\tThe request was base-64 encoded to: " << requestString << "\n\n"; } } Boolean result = send(fOutputSocketNum, requestString, strlen(requestString), 0) >= 0; delete[] newRequestString; if (!result) { if (tag == NULL) tag = ""; char const* errFmt = "%s send() failed: "; unsigned const errLength = strlen(errFmt) + strlen(tag); char* err = new char[errLength]; sprintf(err, errFmt, tag); envir().setResultErrMsg(err); delete[] err; } return result;}Boolean RTSPClient::getResponse(char const* tag, unsigned& bytesRead, unsigned& responseCode, char*& firstLine, char*& nextLineStart, Boolean checkFor200Response) { do { char* readBuf = fResponseBuffer; bytesRead = getResponse1(readBuf, fResponseBufferSize); if (bytesRead == 0) { envir().setResultErrMsg("Failed to read response: "); break; } if (fVerbosityLevel >= 1) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -