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

📄 rtspserver.cpp

📁 流媒体传输协议的实现代码,非常有用.可以支持rtsp mms等流媒体传输协议
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/**********This library is free software; you can redistribute it and/or modify it underthe terms of the GNU Lesser General Public License as published by theFree Software Foundation; either version 2.1 of the License, or (at youroption) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)This library is distributed in the hope that it will be useful, but WITHOUTANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESSFOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License formore details.You should have received a copy of the GNU Lesser General Public Licensealong with this library; if not, write to the Free Software Foundation, Inc.,59 Temple Place, Suite 330, Boston, MA  02111-1307  USA**********/// "liveMedia"// Copyright (c) 1996-2004 Live Networks, Inc.  All rights reserved.// A RTSP server// Implementation#include "RTSPServer.hh"#include <GroupsockHelper.hh>#if defined(__WIN32__) || defined(_WIN32) || defined(_QNX4)#define _strncasecmp _strnicmp#define snprintf _snprintf#else#include <signal.h>#define USE_SIGNALS 1#define _strncasecmp strncasecmp#endif#include <time.h> // for "strftime()" and "gmtime()"#define RTPINFO_INCLUDE_RTPTIME 1////////// RTSPServer //////////RTSPServer*RTSPServer::createNew(UsageEnvironment& env, Port ourPort,		      UserAuthenticationDatabase* authDatabase,		      unsigned reclamationTestSeconds) {  int ourSocket = -1;  RTSPServer* newServer = NULL;  do {    int ourSocket = setUpOurSocket(env, ourPort);    if (ourSocket == -1) break;    return new RTSPServer(env, ourSocket, ourPort, authDatabase,			  reclamationTestSeconds);  } while (0);  if (ourSocket != -1) ::closeSocket(ourSocket);  delete newServer;  return NULL;}Boolean RTSPServer::lookupByName(UsageEnvironment& env,				 char const* name,				 RTSPServer*& resultServer) {  resultServer = NULL; // unless we succeed  Medium* medium;  if (!Medium::lookupByName(env, name, medium)) return False;  if (!medium->isRTSPServer()) {    env.setResultMsg(name, " is not a RTSP server");    return False;  }  resultServer = (RTSPServer*)medium;  return True;}void RTSPServer::addServerMediaSession(ServerMediaSession* serverMediaSession) {  if (serverMediaSession == NULL) return;  char const* sessionName = serverMediaSession->streamName();  if (sessionName == NULL) sessionName = "";  ServerMediaSession* existingSession    = (ServerMediaSession*)    (fServerMediaSessions->Add(sessionName,			       (void*)serverMediaSession));  removeServerMediaSession(existingSession); // if any}ServerMediaSession* RTSPServer::lookupServerMediaSession(char const* streamName) {  return (ServerMediaSession*)(fServerMediaSessions->Lookup(streamName));}void RTSPServer::removeServerMediaSession(ServerMediaSession* serverMediaSession) {  if (serverMediaSession == NULL) return;  fServerMediaSessions->Remove(serverMediaSession->streamName());  if (serverMediaSession->referenceCount() == 0) {    delete serverMediaSession;  } else {    serverMediaSession->deleteWhenUnreferenced() = True;  }}void RTSPServer::removeServerMediaSession(char const* streamName) {  removeServerMediaSession(lookupServerMediaSession(streamName));}char* RTSPServer::rtspURL(ServerMediaSession const* serverMediaSession) const {  struct in_addr ourAddress;  ourAddress.s_addr = ReceivingInterfaceAddr != 0    ? ReceivingInterfaceAddr    : ourSourceAddressForMulticast(envir()); // hack  char const* sessionName = serverMediaSession->streamName();  unsigned sessionNameLength = strlen(sessionName);  char* urlBuffer = new char[100 + sessionNameLength];  char* resultURL;  portNumBits portNumHostOrder = ntohs(fServerPort.num());  if (portNumHostOrder == 554 /* the default port number */) {    sprintf(urlBuffer, "rtsp://%s/%s", our_inet_ntoa(ourAddress),	    sessionName);  } else {    sprintf(urlBuffer, "rtsp://%s:%hu/%s",	    our_inet_ntoa(ourAddress), portNumHostOrder,	    sessionName);  }  resultURL = strDup(urlBuffer);  delete[] urlBuffer;  return resultURL;}#define LISTEN_BACKLOG_SIZE 20int RTSPServer::setUpOurSocket(UsageEnvironment& env, Port& ourPort) {  int ourSocket = -1;  do {    ourSocket = setupStreamSocket(env, ourPort);    if (ourSocket < 0) break;    // Make sure we have a big send buffer:    if (!increaseSendBufferTo(env, ourSocket, 50*1024)) break;    // Allow multiple simultaneous connections:    if (listen(ourSocket, LISTEN_BACKLOG_SIZE) < 0) {      env.setResultErrMsg("listen() failed: ");      break;    }    if (ourPort.num() == 0) {      // bind() will have chosen a port for us; return it also:      if (!getSourcePort(env, ourSocket, ourPort)) break;    }    return ourSocket;  } while (0);    if (ourSocket != -1) ::closeSocket(ourSocket);  return -1;}RTSPServer::RTSPServer(UsageEnvironment& env,		       int ourSocket, Port ourPort,		       UserAuthenticationDatabase* authDatabase,		       unsigned reclamationTestSeconds)  : Medium(env),    fServerSocket(ourSocket), fServerPort(ourPort),    fAuthDB(authDatabase), fReclamationTestSeconds(reclamationTestSeconds),    fServerMediaSessions(HashTable::create(STRING_HASH_KEYS)),     fSessionIdCounter(0) {#ifdef USE_SIGNALS  // Ignore the SIGPIPE signal, so that clients on the same host that are killed  // don't also kill us:  signal(SIGPIPE, SIG_IGN);#endif  // Arrange to handle connections from others:  env.taskScheduler().turnOnBackgroundReadHandling(fServerSocket,        (TaskScheduler::BackgroundHandlerProc*)&incomingConnectionHandler,						   this);}RTSPServer::~RTSPServer() {  // Turn off background read handling:  envir().taskScheduler().turnOffBackgroundReadHandling(fServerSocket);  ::closeSocket(fServerSocket);  // Remove all server media sessions (they'll get deleted when they're finished):  while (1) {    ServerMediaSession* serverMediaSession      = (ServerMediaSession*)fServerMediaSessions->RemoveNext();    if (serverMediaSession == NULL) break;    removeServerMediaSession(serverMediaSession);  }  // Finally, delete the session table itself:  delete fServerMediaSessions;}Boolean RTSPServer::isRTSPServer() const {  return True;}void RTSPServer::incomingConnectionHandler(void* instance, int /*mask*/) {  RTSPServer* server = (RTSPServer*)instance;  server->incomingConnectionHandler1();}#define PARAM_STRING_MAX 100void RTSPServer::incomingConnectionHandler1() {  struct sockaddr_in clientAddr;  SOCKLEN_T clientAddrLen = sizeof clientAddr;  int clientSocket = accept(fServerSocket, (struct sockaddr*)&clientAddr,			    &clientAddrLen);  if (clientSocket < 0) {    int err = envir().getErrno();    if (err != EWOULDBLOCK) {        envir().setResultErrMsg("accept() failed: ");    }    return;  }#if defined(DEBUG) || defined(DEBUG_CONNECTIONS)  fprintf(stderr, "accept()ed connection from %s\n", our_inet_ntoa(clientAddr.sin_addr));#endif  // Create a new object for this RTSP session:  // (Later, we need to do some garbage collection on sessions that #####  //  aren't closed down via TEARDOWN) #####  new RTSPClientSession(*this, ++fSessionIdCounter,			clientSocket, clientAddr);}////////// RTSPServer::RTSPClientSession //////////RTSPServer::RTSPClientSession::RTSPClientSession(RTSPServer& ourServer, unsigned sessionId,	      int clientSocket, struct sockaddr_in clientAddr)  : fOurServer(ourServer), fOurSessionId(sessionId),    fOurServerMediaSession(NULL),    fClientSocket(clientSocket), fClientAddr(clientAddr),    fLivenessCheckTask(NULL), fSessionIsActive(True), fStreamAfterSETUP(False),    fTCPStreamIdCount(0), fNumStreamStates(0), fStreamStates(NULL) {  // Arrange to handle incoming requests:  envir().taskScheduler().turnOnBackgroundReadHandling(fClientSocket,     (TaskScheduler::BackgroundHandlerProc*)&incomingRequestHandler, this);  noteClientLiveness();}RTSPServer::RTSPClientSession::~RTSPClientSession() {  // Turn off any liveness checking:  envir().taskScheduler().unscheduleDelayedTask(fLivenessCheckTask);  // Turn off background read handling:  envir().taskScheduler().turnOffBackgroundReadHandling(fClientSocket);  ::closeSocket(fClientSocket);  reclaimStreamStates();  if (fOurServerMediaSession != NULL) {    fOurServerMediaSession->decrementReferenceCount();    if (fOurServerMediaSession->referenceCount() == 0	&& fOurServerMediaSession->deleteWhenUnreferenced()) {      fOurServer.removeServerMediaSession(fOurServerMediaSession);    }  }}void RTSPServer::RTSPClientSession::reclaimStreamStates() {  for (unsigned i = 0; i < fNumStreamStates; ++i) {    if (fStreamStates[i].subsession != NULL) {      fStreamStates[i].subsession->deleteStream(fOurSessionId,						fStreamStates[i].streamToken);    }  }  delete[] fStreamStates; fStreamStates = NULL;  fNumStreamStates = 0;}void RTSPServer::RTSPClientSession::incomingRequestHandler(void* instance, int /*mask*/) {  RTSPClientSession* session = (RTSPClientSession*)instance;  session->incomingRequestHandler1();}void RTSPServer::RTSPClientSession::incomingRequestHandler1() {  noteClientLiveness();  struct sockaddr_in dummy; // 'from' address, meaningless in this case  int bytesLeft = sizeof fBuffer;  int totalBytes = 0;  Boolean endOfMsg = False;  unsigned char* ptr = fBuffer;  unsigned char* lastCRLF = ptr-3;    while (!endOfMsg) {    if (bytesLeft <= 0) {      // command too big      delete this;      return;    }        int bytesRead = readSocket(envir(), fClientSocket,			       ptr, bytesLeft, dummy);    if (bytesRead <= 0) {      // The client socket has apparently died - kill it:      delete this;      return;    }#ifdef DEBUG    ptr[bytesRead] = '\0';    fprintf(stderr, "RTSPClientSession[%p]::incomingRequestHandler1() read %d bytes:%s\n", this, bytesRead, ptr);#endif    // Look for the end of the message: <CR><LF><CR><LF>    unsigned char *tmpPtr = ptr;    if (totalBytes > 0) --tmpPtr; // In case the last read ended with a <CR>    while (tmpPtr < &ptr[bytesRead-1]) {      if (*tmpPtr == '\r' && *(tmpPtr+1) == '\n') {	if (tmpPtr - lastCRLF == 2) { // This is it:	  endOfMsg = 1;	  break;	}	lastCRLF = tmpPtr;      }      ++tmpPtr;    }      bytesLeft -= bytesRead;    totalBytes += bytesRead;    ptr += bytesRead;  }  fBuffer[totalBytes] = '\0';  // Parse the request string into command name and 'CSeq',  // then handle the command:  char cmdName[PARAM_STRING_MAX];  char urlPreSuffix[PARAM_STRING_MAX];  char urlSuffix[PARAM_STRING_MAX];  char cseq[PARAM_STRING_MAX];  if (!parseRequestString((char*)fBuffer, totalBytes,			  cmdName, sizeof cmdName,			  urlPreSuffix, sizeof urlPreSuffix,			  urlSuffix, sizeof urlSuffix,			  cseq, sizeof cseq)) {#ifdef DEBUG    fprintf(stderr, "parseRequestString() failed!\n");#endif    handleCmd_bad(cseq);  } else {#ifdef DEBUG    fprintf(stderr, "parseRequestString() returned cmdName \"%s\", urlPreSuffix \"%s\", urlSuffix \"%s\"\n", cmdName, urlPreSuffix, urlSuffix);#endif    if (strcmp(cmdName, "OPTIONS") == 0) {      handleCmd_OPTIONS(cseq);    } else if (strcmp(cmdName, "DESCRIBE") == 0) {      handleCmd_DESCRIBE(cseq, urlSuffix, (char const*)fBuffer);    } else if (strcmp(cmdName, "SETUP") == 0) {      handleCmd_SETUP(cseq, urlPreSuffix, urlSuffix, (char const*)fBuffer);    } else if (strcmp(cmdName, "TEARDOWN") == 0	       || strcmp(cmdName, "PLAY") == 0	       || strcmp(cmdName, "PAUSE") == 0	       || strcmp(cmdName, "GET_PARAMETER") == 0) {      handleCmd_withinSession(cmdName, urlPreSuffix, urlSuffix, cseq,			      (char const*)fBuffer);    } else {      handleCmd_notSupported(cseq);    }  }    #ifdef DEBUG  fprintf(stderr, "sending response: %s", fResponseBuffer);#endif  send(fClientSocket, (char const*)fResponseBuffer, strlen((char*)fResponseBuffer), 0);  if (strcmp(cmdName, "SETUP") == 0 && fStreamAfterSETUP) {    // The client has asked for streaming to commence now, rather than after a    // subsequent "PLAY" command.  So, simulate the effect of a "PLAY" command:    handleCmd_withinSession("PLAY", urlPreSuffix, urlSuffix, cseq,			    (char const*)fBuffer);  }  if (!fSessionIsActive) delete this;}// Handler routines for specific RTSP commands:// Generate a "Date:" header for use in a RTSP response:static char const* dateHeader() {  static char buf[200];#if !defined(_WIN32_WCE)  time_t tt = time(NULL);  strftime(buf, sizeof buf, "Date: %a, %b %d %Y %H:%M:%S GMT\r\n", gmtime(&tt));#else  // WinCE apparently doesn't have "time()", "strftime()", or "gmtime()",  // so generate the "Date:" header a different, WinCE-specific way.  // (Thanks to Pierre l'Hussiez for this code)  SYSTEMTIME SystemTime;  GetSystemTime(&SystemTime);  WCHAR dateFormat[] = L"ddd, MMM dd yyyy";  WCHAR timeFormat[] = L"HH:mm:ss GMT\r\n";  WCHAR inBuf[200];  DWORD locale = LOCALE_NEUTRAL;    int ret = GetDateFormat(locale, 0, &SystemTime,			  (LPTSTR)dateFormat, (LPTSTR)inBuf, sizeof inBuf);  inBuf[ret - 1] = ' ';  ret = GetTimeFormat(locale, 0, &SystemTime,		      (LPTSTR)timeFormat,		      (LPTSTR)inBuf + ret, (sizeof inBuf) - ret);  wcstombs(buf, inBuf, wcslen(inBuf));#endif  return buf;}static char const* allowedCommandNames  = "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE";void RTSPServer::RTSPClientSession::handleCmd_bad(char const* /*cseq*/) {  // Don't do anything with "cseq", because it might be nonsense  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,	   "RTSP/1.0 400 Bad Request\r\n%sAllow: %s\r\n\r\n",	   dateHeader(), allowedCommandNames);  fSessionIsActive = False; // triggers deletion of ourself after responding}void RTSPServer::RTSPClientSession::handleCmd_notSupported(char const* cseq) {  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,	   "RTSP/1.0 405 Method Not Allowed\r\nCSeq: %s\r\n%sAllow: %s\r\n\r\n",	   cseq, dateHeader(), allowedCommandNames);  fSessionIsActive = False; // triggers deletion of ourself after responding}void RTSPServer::RTSPClientSession::handleCmd_notFound(char const* cseq) {  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,	   "RTSP/1.0 404 Stream Not Found\r\nCSeq: %s\r\n%s\r\n",

⌨️ 快捷键说明

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