⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtspclient.cpp

📁 流媒体传输协议的实现代码,非常有用.可以支持rtsp mms等流媒体传输协议
💻 CPP
📖 第 1 页 / 共 5 页
字号:
      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";      char* usernamePassword	= new char[strlen(authenticator->username())		  + strlen(authenticator->password()) + 2];      sprintf(usernamePassword, "%s:%s",	      authenticator->username(), authenticator->password());      char* response = base64Encode(usernamePassword);      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);    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) {      envir() << "Received " << tag << " response: " << readBuf << "\n";    }    firstLine = readBuf;    nextLineStart = getLine(firstLine);    if (!parseResponseCode(firstLine, responseCode)) break;        if (responseCode != 200 && checkFor200Response) {      envir().setResultMsg(tag, ": cannot handle response: ", firstLine);      break;    }    return True;  } while (0);  // An error occurred:  return False;}unsigned RTSPClient::getResponse1(char*& responseBuffer,				  unsigned responseBufferSize) {  struct sockaddr_in fromAddress;    if (responseBufferSize == 0) return 0; // just in case...  responseBuffer[0] = '\0'; // ditto  // Begin by reading and checking the first byte of the response.  // If it's '$', then there's an interleaved RTP (or RTCP)-over-TCP  // packet here.  We need to read and discard it first.  Boolean success = False;  while (1) {    unsigned char firstByte;    if (readSocket(envir(), fInputSocketNum, &firstByte, 1, fromAddress)	!= 1) break;    if (firstByte != '$') {      // Normal case: This is the start of a regular response; use it:      responseBuffer[0] = firstByte;      success = True;      break;    } else {      // This is an interleaved packet; read and discard it:      unsigned char streamChannelId;      if (readSocket(envir(), fInputSocketNum, &streamChannelId, 1, fromAddress)	  != 1) break;      unsigned short size;      if (readSocketExact(envir(), fInputSocketNum, (unsigned char*)&size, 2,		     fromAddress) != 2) break;      size = ntohs(size);      if (fVerbosityLevel >= 1) {	envir() << "Discarding interleaved RTP or RTCP packet ("		<< size << " bytes, channel id "		<< streamChannelId << ")\n";      }      unsigned char* tmpBuffer = new unsigned char[size];      if (tmpBuffer == NULL) break;      unsigned bytesRead = 0;      unsigned bytesToRead = size;      unsigned curBytesRead;      while ((curBytesRead = readSocket(envir(), fInputSocketNum,					&tmpBuffer[bytesRead], bytesToRead,					fromAddress)) > 0) {	bytesRead += curBytesRead;	if (bytesRead >= size) break;	bytesToRead -= curBytesRead;      }      delete[] tmpBuffer;      if (bytesRead != size) break;      success = True;    }  }  if (!success) return 0;      // Keep reading data from the socket until we see "\r\n\r\n" (except  // at the start), or until we fill up our buffer.  // Don't read any more than this.  char* p = responseBuffer;  Boolean haveSeenNonCRLF = False;  int bytesRead = 1; // because we've already read the first byte  while (bytesRead < (int)responseBufferSize) {    unsigned bytesReadNow      = readSocket(envir(), fInputSocketNum,		   (unsigned char*)(responseBuffer+bytesRead),		   1, fromAddress);    if (bytesReadNow == 0) {      envir().setResultMsg("RTSP response was truncated");      break;    }    bytesRead += bytesReadNow;        // Check whether we have "\r\n\r\n":    char* lastToCheck = responseBuffer+bytesRead-4;    if (lastToCheck < responseBuffer) continue;    for (; p <= lastToCheck; ++p) {      if (haveSeenNonCRLF) {	if (*p == '\r' && *(p+1) == '\n' &&	    *(p+2) == '\r' && *(p+3) == '\n') {	  responseBuffer[bytesRead] = '\0';	  // Before returning, trim any \r or \n from the start:	  while (*responseBuffer == '\r' || *responseBuffer == '\n') {	    ++responseBuffer;	    --bytesRead;	  }	  return bytesRead;	}      } else {	if (*p != '\r' && *p != '\n') {	  haveSeenNonCRLF = True;	}      }    }  }    envir().setResultMsg("We received a response not ending with <CR><LF><CR><LF>");  return 0;}Boolean RTSPClient::parseResponseCode(char const* line, 				      unsigned& responseCode) {  if (sscanf(line, "%*s%u", &responseCode) != 1) {    envir().setResultMsg("no response code in line: \"", line, "\"");    return False;  }  return True;}Boolean RTSPClient::parseTransportResponse(char const* line, 					   char*& serverAddressStr,					   portNumBits& serverPortNum,					   unsigned char& rtpChannelId,					   unsigned char& rtcpChannelId) {  // Initialize the return parameters to 'not found' values:  serverAddressStr = NULL;  serverPortNum = 0;  rtpChannelId = rtcpChannelId = 0xFF;  char* foundServerAddressStr = NULL;  Boolean foundServerPortNum = False;  Boolean foundChannelIds = False;  unsigned rtpCid, rtcpCid;  // First, check for "Transport:"  if (_strncasecmp(line, "Transport: ", 11) != 0) return False;  line += 11;  // Then, run through each of the fields, looking for ones we handle:  char const* fields = line;  char* field = strDupSize(fields);  while (sscanf(fields, "%[^;]", field) == 1) {    if (sscanf(field, "server_port=%hu", &serverPortNum) == 1) {      foundServerPortNum = True;    } else if (_strncasecmp(field, "source=", 7) == 0) {      delete[] foundServerAddressStr;      foundServerAddressStr = strDup(field+7);    } else if (sscanf(field, "interleaved=%u-%u", &rtpCid, &rtcpCid) == 2) {      rtpChannelId = (unsigned char)rtpCid;      rtcpChannelId = (unsigned char)rtcpCid;      foundChannelIds = True;    }    fields += strlen(field);    while (fields[0] == ';') ++fields; // skip over all leading ';' chars    if (fields[0] == '\0') break;  }  delete[] field;  if (foundServerPortNum || foundChannelIds) {    serverAddressStr = foundServerAddressStr;    return True;  }  delete[] foundServerAddressStr;  return False;}Boolean RTSPClient::parseRTPInfoHeader(char const* line,				       unsigned& trackId,				       u_int16_t& seqNum,				       u_int32_t& timestamp) {  if (_strncasecmp(line, "RTP-Info: ", 10) != 0) return False;  line += 10;  char const* fields = line;  char* field = strDupSize(fields);    while (sscanf(fields, "%[^;]", field) == 1) {    if (sscanf(field, "url=trackID=%u", &trackId) == 1 ||	sscanf(field, "url=trackid=%u", &trackId) == 1 ||	sscanf(field, "seq=%hu", &seqNum) == 1 ||	sscanf(field, "rtptime=%u", &timestamp) == 1) {    }        fields += strlen(field);    if (fields[0] == '\0') break;    ++fields; // skip over the ';'  }  delete[] field;  return True;}Boolean RTSPClient::parseScaleHeader(char const* line, float& scale) {  if (_strncasecmp(line, "Scale: ", 7) != 0) return False;  line += 7;  return sscanf(line, "%f", &scale) == 1;}Boolean RTSPClient::setupHTTPTunneling(char const* urlSuffix) {  if (fVerbosityLevel >= 1) {    envir() << "Requesting RTSP-over-HTTP tunneling (on port "	    << fTunnelOverHTTPPortNum << ")\n\n";  }  if (urlSuffix == NULL || urlSuffix[0] == '\0') urlSuffix = "/";  char* cmd = NULL;  do {    // Create a 'session cookie' string, using MD5:    struct {      struct timeval timestamp;      unsigned counter;    } seedData;    gettimeofday(&seedData.timestamp, NULL);    static unsigned counter = 0;    seedData.counter = ++counter;    char sessionCookie[33];    our_MD5Data((unsigned char*)(&seedData), sizeof seedData, sessionCookie);    // DSS seems to require that the 'session cookie' string be 22 bytes long:    sessionCookie[23] = '\0';        // Begin by sending a HTTP "GET", to set up the server->client link:    char* const getCmdFmt =      "GET %s HTTP/1.0\r\n"      "%s"      "x-sessioncookie: %s\r\n"      "Accept: application/x-rtsp-tunnelled\r\n"      "Pragma: no-cache\r\n"      "Cache-Control: no-cache\r\n"      "\r\n";    unsigned cmdSize = strlen(getCmdFmt)      + strlen(urlSuffix)      + fUserAgentHeaderStrSize      + strlen(sessionCookie);    cmd = new char[cmdSize];    sprintf(cmd, getCmdFmt,	    urlSuffix,	    fUserAgentHeaderStr,	    sessionCookie);    if (!sendRequest(cmd, "HTTP GET", False/*don't base64-encode*/)) break;        // Get the response from the server:    unsigned bytesRead; unsigned responseCode;    char* firstLine; char* nextLineStart;    if (!getResponse("HTTP GET", bytesRead, responseCode, firstLine, nextLineStart)) break;    // Next, set up a second TCP connection (to the same server & port as before)    // for the HTTP-tunneled client->server link.  All future output will be to    // this socket.    fOutputSocketNum = setupStreamSocket(envir(), 0, False /* =>blocking */);    if (fOutputSocketNum < 0) break;        // Connect to the remote endpoint:    struct sockaddr_in remoteName;    remoteName.sin_family = AF_INET;    remoteName.sin_port = htons(fTunnelOverHTTPPortNum);    remoteName.sin_addr.s_addr = fServerAddress;    if (connect(fOutputSocketNum,		(struct sockaddr*)&remoteName, sizeof remoteName) != 0) {      envir().setResultErrMsg("connect() failed: ");      break;    }    // Then, send a HTTP "POST", to set up the client->server link:    char* const postCmdFmt =      "POST %s HTTP/1.0\r\n"      "%s"      "x-sessioncookie: %s\r\n"      "Content-Type: application/x-rtsp-tunnelled\r\n"      "Pragma: no-cache\r\n"      "Cache-Control: no-cache\r\n"      "Content-Length: 32767\r\n"      "Expires: Sun, 9 Jan 1972 00:00:00 GMT\r\n"      "\r\n";    cmdSize = strlen(postCmdFmt)      + strlen(urlSuffix)      + fUserAgentHeaderStrSize      + strlen(sessionCookie);    cmd = new char[cmdSize];    sprintf(cmd, postCmdFmt,	    urlSuffix,	    fUserAgentHeaderStr,	    sessionCookie);    if (!sendRequest(cmd, "HTTP POST", False/*don't base64-encode*/)) break;        // Note that there's no response to the "POST".    delete[] cmd;    return True;  } while (0);  // An error occurred:  delete[] cmd;  return False;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -