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

📄 rtspserver.cpp.save

📁 流媒体传输协议的实现代码,非常有用.可以支持rtsp mms等流媒体传输协议
💻 SAVE
📖 第 1 页 / 共 3 页
字号:
  // Try to set the stream's scale factor to this value:  if (subsession == NULL /*aggregate op*/) {    fOurServerMediaSession->testScaleFactor(scale);  } else {    subsession->testScaleFactor(scale);  }  char buf[100];  char* scaleHeader;  if (!sawScaleHeader) {    buf[0] = '\0'; // Because we didn't see a Scale: header, don't send one back  } else {    sprintf(buf, "Scale: %f\r\n", scale);  }  scaleHeader = strDup(buf);  //// Parse the client's "Range:" header, if any:   float rangeStart, rangeEnd;  Boolean sawRangeHeader = parseRangeHeader(fullRequestStr, rangeStart, rangeEnd);  // Use this information, plus the stream's duration (if known), to create  // our own "Range:" header, for the response:  float duration = subsession == NULL /*aggregate op*/    ? fOurServerMediaSession->duration() : subsession->duration();  if (duration < 0.0) {    // We're an aggregate PLAY, but the subsessions have different durations.    // Use the largest of these durations in our header    duration = -duration;  }  if (rangeEnd < 0.0 || rangeEnd > duration) rangeEnd = duration;  if (rangeStart < 0.0) {    rangeStart = 0.0;  } else if (rangeEnd > 0.0 && scale > 0.0 && rangeStart > rangeEnd) {    rangeStart = rangeEnd;  }  char* rangeHeader;  if (!sawRangeHeader) {    buf[0] = '\0'; // Because we didn't see a Range: header, don't send one back  } else if (rangeEnd == 0.0 && scale >= 0.0) {    sprintf(buf, "Range: npt=%.3f-\r\n", rangeStart);  } else {    sprintf(buf, "Range: npt=%.3f-%.3f\r\n", rangeStart, rangeEnd);  }  rangeHeader = strDup(buf);  // Create a "RTP-Info:" line.  It will get filled in from each subsession's state:  char const* rtpInfoFmt =    "%s" // "RTP-Info:", plus any preceding rtpInfo items    "%s" // comma separator, if needed     "url=%s/%s"    ";seq=%d"#ifdef RTPINFO_INCLUDE_RTPTIME    ";rtptime=%u"#endif    ;  unsigned rtpInfoFmtSize = strlen(rtpInfoFmt);  char* rtpInfo = strDup("RTP-Info: ");  unsigned i, numRTPInfoItems = 0;  // Do any required seeking/scaling on each subsession, before starting streaming:  for (i = 0; i < fNumStreamStates; ++i) {    if (subsession == NULL /* means: aggregated operation */	|| subsession == fStreamStates[i].subsession) {      if (sawScaleHeader) {	fStreamStates[i].subsession->setStreamScale(fOurSessionId,						    fStreamStates[i].streamToken,						    scale);      }      if (sawRangeHeader) {	fStreamStates[i].subsession->seekStream(fOurSessionId,						fStreamStates[i].streamToken,						rangeStart);      }    }  }  // Now, start streaming:  for (i = 0; i < fNumStreamStates; ++i) {    if (subsession == NULL /* means: aggregated operation */	|| subsession == fStreamStates[i].subsession) {      unsigned short rtpSeqNum = 0;      unsigned rtpTimestamp = 0;      fStreamStates[i].subsession->startStream(fOurSessionId,					       fStreamStates[i].streamToken,					       rtpSeqNum, rtpTimestamp);      const char *urlSuffix = fStreamStates[i].subsession->trackId();      char* prevRTPInfo = rtpInfo;      unsigned rtpInfoSize = rtpInfoFmtSize	+ strlen(prevRTPInfo)	+ 1	+ rtspURLSize + strlen(urlSuffix)	+ 5 /*max unsigned short len*/#ifdef RTPINFO_INCLUDE_RTPTIME	+ 10 /*max unsigned (32-bit) len*/#endif	+ 2 /*allows for trailing \r\n at final end of string*/;       rtpInfo = new char[rtpInfoSize];      sprintf(rtpInfo, rtpInfoFmt,	      prevRTPInfo,	      numRTPInfoItems++ == 0 ? "" : ",",	      rtspURL, urlSuffix,	      rtpSeqNum#ifdef RTPINFO_INCLUDE_RTPTIME	      ,rtpTimestamp#endif	      );      delete[] prevRTPInfo;    }  }  if (numRTPInfoItems == 0) {    rtpInfo[0] = '\0';  } else {    unsigned rtpInfoLen = strlen(rtpInfo);    rtpInfo[rtpInfoLen] = '\r';    rtpInfo[rtpInfoLen+1] = '\n';    rtpInfo[rtpInfoLen+2] = '\0';  }  // Fill in the response:  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,	   "RTSP/1.0 200 OK\r\n"	   "CSeq: %s\r\n"	   "%s"	   "%s"	   "%s"	   "Session: %d\r\n"	   "%s\r\n",	   cseq,	   dateHeader(),	   scaleHeader,	   rangeHeader,	   fOurSessionId,	   rtpInfo);  delete[] rtpInfo; delete[] rangeHeader;  delete[] scaleHeader; delete[] rtspURL;}void RTSPServer::RTSPClientSession  ::handleCmd_PAUSE(ServerMediaSubsession* subsession, char const* cseq) {  for (unsigned i = 0; i < fNumStreamStates; ++i) {    if (subsession == NULL /* means: aggregated operation */	|| subsession == fStreamStates[i].subsession) {      fStreamStates[i].subsession->pauseStream(fOurSessionId,					       fStreamStates[i].streamToken);    }  }  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,	   "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sSession: %d\r\n\r\n",	   cseq, dateHeader(), fOurSessionId);}void RTSPServer::RTSPClientSession::handleCmd_GET_PARAMETER(ServerMediaSubsession* subsession, char const* cseq,			  char const* /*fullRequestStr*/) {  // We implement "GET_PARAMETER" just as a 'keep alive',  // and send back an empty response:  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,	   "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sSession: %d\r\n\r\n",	   cseq, dateHeader(), fOurSessionId);}static Boolean parseAuthorizationHeader(char const* buf,					char const*& username,					char const*& realm,					char const*& nonce, char const*& uri,					char const*& response) {  // Initialize the result parameters to default values:  username = realm = nonce = uri = response = NULL;  // First, find "Authorization:"  while (1) {    if (*buf == '\0') return False; // not found    if (_strncasecmp(buf, "Authorization: Digest ", 22) == 0) break;    ++buf;  }  // Then, run through each of the fields, looking for ones we handle:  char const* fields = buf + 22;  while (*fields == ' ') ++fields;  char* parameter = strDupSize(fields);  char* value = strDupSize(fields);  while (1) {    value[0] = '\0';    if (sscanf(fields, "%[^=]=\"%[^\"]\"", parameter, value) != 2 &&	sscanf(fields, "%[^=]=\"\"", parameter) != 1) {      break;    }    if (strcmp(parameter, "username") == 0) {      username = strDup(value);    } else if (strcmp(parameter, "realm") == 0) {      realm = strDup(value);    } else if (strcmp(parameter, "nonce") == 0) {      nonce = strDup(value);    } else if (strcmp(parameter, "uri") == 0) {      uri = strDup(value);    } else if (strcmp(parameter, "response") == 0) {      response = strDup(value);    }    fields += strlen(parameter) + 2 /*="*/ + strlen(value) + 1 /*"*/;    while (*fields == ',' || *fields == ' ') ++fields;        // skip over any separating ',' and ' ' chars    if (*fields == '\0' || *fields == '\r' || *fields == '\n') break;  }  delete[] parameter; delete[] value;  return True;}Boolean RTSPServer::RTSPClientSession::authenticationOK(char const* cmdName, char const* cseq,		   char const* fullRequestStr) {  // If we weren't set up with an authentication database, we're OK:  if (fOurServer.fAuthDB == NULL) return True;  char const* username = NULL; char const* realm = NULL; char const* nonce = NULL;  char const* uri = NULL; char const* response = NULL;  Boolean success = False;  do {    // To authenticate, we first need to have a nonce set up    // from a previous attempt:    if (fCurrentAuthenticator.nonce() == NULL) break;    // Next, the request needs to contain an "Authorization:" header,    // containing a username, (our) realm, (our) nonce, uri,    // and response string:    if (!parseAuthorizationHeader(fullRequestStr,				  username, realm, nonce, uri, response)	|| username == NULL	|| realm == NULL || strcmp(realm, fCurrentAuthenticator.realm()) != 0	|| nonce == NULL || strcmp(nonce, fCurrentAuthenticator.nonce()) != 0	|| uri == NULL || response == NULL) {      break;    }    // Next, the username has to be known to us:    char const* password = fOurServer.fAuthDB->lookupPassword(username);#ifdef DEBUG    fprintf(stderr, "lookupPassword(%s) returned password %s\n", username, password);#endif    if (password == NULL) break;    fCurrentAuthenticator.      setUsernameAndPassword(username, password,			     fOurServer.fAuthDB->passwordsAreMD5());    // Finally, compute a digest response from the information that we have,    // and compare it to the one that we were given:    char const* ourResponse      = fCurrentAuthenticator.computeDigestResponse(cmdName, uri);    success = (strcmp(ourResponse, response) == 0);    fCurrentAuthenticator.reclaimDigestResponse(ourResponse);  } while (0);  delete[] (char*)username; delete[] (char*)realm; delete[] (char*)nonce;  delete[] (char*)uri; delete[] (char*)response;  if (success) return True;  // If we get here, there was some kind of authentication failure.  // Send back a "401 Unauthorized" response, with a new random nonce:  fCurrentAuthenticator.setRealmAndRandomNonce(fOurServer.fAuthDB->realm());  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,	   "RTSP/1.0 401 Unauthorized\r\n"	   "CSeq: %s\r\n"	   "%s"	   "WWW-Authenticate: Digest realm=\"%s\", nonce=\"%s\"\r\n\r\n",	   cseq,	   dateHeader(),	   fCurrentAuthenticator.realm(), fCurrentAuthenticator.nonce());  return False;}BooleanRTSPServer::RTSPClientSession  ::parseRequestString(char const* reqStr,		       unsigned reqStrSize,		       char* resultCmdName,		       unsigned resultCmdNameMaxSize,		       char* resultURLPreSuffix,		       unsigned resultURLPreSuffixMaxSize,		       char* resultURLSuffix,		       unsigned resultURLSuffixMaxSize,		       char* resultCSeq,		       unsigned resultCSeqMaxSize) {  // This parser is currently rather dumb; it should be made smarter #####  // Read everything up to the first space as the command name:  Boolean parseSucceeded = False;  unsigned i;  for (i = 0; i < resultCmdNameMaxSize-1 && i < reqStrSize; ++i) {    char c = reqStr[i];    if (c == ' ' || c == '\t') {      parseSucceeded = True;      break;    }    resultCmdName[i] = c;  }  resultCmdName[i] = '\0';  if (!parseSucceeded) return False;        // Skip over the prefix of any "rtsp://" or "rtsp:/" URL that follows:  unsigned j = i+1;  while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; // skip over any additional white space  for (j = i+1; j < reqStrSize-8; ++j) {    if ((reqStr[j] == 'r' || reqStr[j] == 'R')	&& (reqStr[j+1] == 't' || reqStr[j+1] == 'T')	&& (reqStr[j+2] == 's' || reqStr[j+2] == 'S')	&& (reqStr[j+3] == 'p' || reqStr[j+3] == 'P')	&& reqStr[j+4] == ':' && reqStr[j+5] == '/') {      j += 6;      if (reqStr[j] == '/') {	// This is a "rtsp://" URL; skip over the host:port part that follows:	++j;	while (j < reqStrSize && reqStr[j] != '/' && reqStr[j] != ' ') ++j;      } else {	// This is a "rtsp:/" URL; back up to the "/":	--j;      }      i = j;      break;    }  }  // Look for the URL suffix (before the following "RTSP/"):  parseSucceeded = False;  for (unsigned k = i+1; k < reqStrSize-5; ++k) {    if (reqStr[k] == 'R' && reqStr[k+1] == 'T' &&	reqStr[k+2] == 'S' && reqStr[k+3] == 'P' && reqStr[k+4] == '/') {      while (--k >= i && reqStr[k] == ' ') {} // go back over all spaces before "RTSP/"      unsigned k1 = k;      while (k1 > i && reqStr[k1] != '/' && reqStr[k1] != ' ') --k1;      // the URL suffix comes from [k1+1,k]      // Copy "resultURLSuffix":      if (k - k1 + 1 > resultURLSuffixMaxSize) return False; // there's no room      unsigned n = 0, k2 = k1+1;      while (k2 <= k) resultURLSuffix[n++] = reqStr[k2++];      resultURLSuffix[n] = '\0';      // Also look for the URL 'pre-suffix' before this:      unsigned k3 = --k1;      while (k3 > i && reqStr[k3] != '/' && reqStr[k3] != ' ') --k3;      // the URL pre-suffix comes from [k3+1,k1]      // Copy "resultURLPreSuffix":      if (k1 - k3 + 1 > resultURLPreSuffixMaxSize) return False; // there's no room      n = 0; k2 = k3+1;      while (k2 <= k1) resultURLPreSuffix[n++] = reqStr[k2++];      resultURLPreSuffix[n] = '\0';      i = k + 7; // to go past " RTSP/"      parseSucceeded = True;      break;    }  }  if (!parseSucceeded) return False;  // Look for "CSeq:", skip whitespace,  // then read everything up to the next \r or \n as 'CSeq':  parseSucceeded = False;  for (j = i; j < reqStrSize-5; ++j) {    if (reqStr[j] == 'C' && reqStr[j+1] == 'S' && reqStr[j+2] == 'e' &&	reqStr[j+3] == 'q' && reqStr[j+4] == ':') {      j += 5;      unsigned n;      while (j < reqStrSize && (reqStr[j] ==  ' ' || reqStr[j] == '\t')) ++j;      for (n = 0; n < resultCSeqMaxSize-1 && j < reqStrSize; ++n,++j) {	char c = reqStr[j];	if (c == '\r' || c == '\n') {	  parseSucceeded = True;	  break;	}	resultCSeq[n] = c;      }      resultCSeq[n] = '\0';      break;    }  }  if (!parseSucceeded) return False;  return True;}void RTSPServer::RTSPClientSession::livenessTimeoutTask(RTSPClientSession* clientSession) {  // If this gets called, the client session is assumed to have timed out,  // so delete it:  delete clientSession;}void RTSPServer::RTSPClientSession::noteClientLiveness() {  if (fOurServer.fReclamationTestSeconds > 0) {    envir().taskScheduler()      .rescheduleDelayedTask(fLivenessCheckTask,			     fOurServer.fReclamationTestSeconds*1000000,			     (TaskFunc*)livenessTimeoutTask, this);  }}////////// UserAuthenticationDatabase implementation //////////UserAuthenticationDatabase::UserAuthenticationDatabase(char const* realm,						       Boolean passwordsAreMD5)  : fTable(HashTable::create(STRING_HASH_KEYS)),    fRealm(strDup(realm == NULL ? "LIVE.COM Streaming Media" : realm)),    fPasswordsAreMD5(passwordsAreMD5) {}UserAuthenticationDatabase::~UserAuthenticationDatabase() {  delete[] fRealm;  delete fTable;}void UserAuthenticationDatabase::addUserRecord(char const* username,					       char const* password) {  fTable->Add(username, (void*)(strDup(password)));}void UserAuthenticationDatabase::removeUserRecord(char const* username) {  char* password = (char*)(fTable->Lookup(username));  fTable->Remove(username);  delete[] password;}char const* UserAuthenticationDatabase::lookupPassword(char const* username) {  return (char const*)(fTable->Lookup(username));}

⌨️ 快捷键说明

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