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

📄 rtspserver.cpp

📁 c++实现的流媒体库,和mplayer结合就可以实现多媒体的网络播放,属于开源项目,很值得研究.
💻 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-2007 Live Networks, Inc.  All rights reserved.// A RTSP server// Implementation#include "RTSPServer.hh"#include "RTSPCommon.hh"#include <GroupsockHelper.hh>#if defined(__WIN32__) || defined(_WIN32) || defined(_QNX4)#else#include <signal.h>#define USE_SIGNALS 1#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;  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);  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) {    Medium::close(serverMediaSession);  } else {    serverMediaSession->deleteWhenUnreferenced() = True;  }}void RTSPServer::removeServerMediaSession(char const* streamName) {  removeServerMediaSession(lookupServerMediaSession(streamName));}char* RTSPServer::rtspURLPrefix(int clientSocket) const {  struct sockaddr_in ourAddress;  if (clientSocket < 0) {    // Use our default IP address in the URL:    ourAddress.sin_addr.s_addr = ReceivingInterfaceAddr != 0      ? ReceivingInterfaceAddr      : ourIPAddress(envir()); // hack  } else {    SOCKLEN_T namelen = sizeof ourAddress;    getsockname(clientSocket, (struct sockaddr*)&ourAddress, &namelen);  }  char urlBuffer[100]; // more than big enough for "rtsp://<ip-address>:<port>/"  portNumBits portNumHostOrder = ntohs(fServerPort.num());  if (portNumHostOrder == 554 /* the default port number */) {    sprintf(urlBuffer, "rtsp://%s/", our_inet_ntoa(ourAddress.sin_addr));  } else {    sprintf(urlBuffer, "rtsp://%s:%hu/",	    our_inet_ntoa(ourAddress.sin_addr), portNumHostOrder);  }  return strDup(urlBuffer);}char* RTSPServer::rtspURL(ServerMediaSession const* serverMediaSession, int clientSocket) const {  char* urlPrefix = rtspURLPrefix(clientSocket);  char const* sessionName = serverMediaSession->streamName();  char* resultURL = new char[strlen(urlPrefix) + strlen(sessionName) + 1];  sprintf(resultURL, "%s%s", urlPrefix, sessionName);  delete[] urlPrefix;  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;}Boolean RTSPServer::specialClientAccessCheck(int /*clientSocket*/, struct sockaddr_in& /*clientAddr*/, char const* /*urlSuffix*/) {  // default implementation  return True;}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();}void 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;  }  makeSocketNonBlocking(clientSocket);  increaseSendBufferTo(envir(), clientSocket, 50*1024);#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:  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),    fIsMulticast(False), fSessionIsActive(True), fStreamAfterSETUP(False),    fTCPStreamIdCount(0), fNumStreamStates(0), fStreamStates(NULL) {  // Arrange to handle incoming requests:  resetRequestBuffer();  envir().taskScheduler().turnOnBackgroundReadHandling(fClientSocket,     (TaskScheduler::BackgroundHandlerProc*)&incomingRequestHandler, this);  noteLiveness();}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::resetRequestBuffer() {  fRequestBytesAlreadySeen = 0;  fRequestBufferBytesLeft = sizeof fRequestBuffer;  fLastCRLF = &fRequestBuffer[-3]; // hack}void RTSPServer::RTSPClientSession::incomingRequestHandler(void* instance, int /*mask*/) {  RTSPClientSession* session = (RTSPClientSession*)instance;  session->incomingRequestHandler1();}void RTSPServer::RTSPClientSession::incomingRequestHandler1() {  noteLiveness();  struct sockaddr_in dummy; // 'from' address, meaningless in this case  Boolean endOfMsg = False;  unsigned char* ptr = &fRequestBuffer[fRequestBytesAlreadySeen];    int bytesRead = readSocket(envir(), fClientSocket,			     ptr, fRequestBufferBytesLeft, dummy);  if (bytesRead <= 0 || (unsigned)bytesRead >= fRequestBufferBytesLeft) {    // Either the client socket has died, or the request was too big for us.    // Terminate this connection:#ifdef DEBUG    fprintf(stderr, "RTSPClientSession[%p]::incomingRequestHandler1() read %d bytes (of %d); terminating connection!\n", this, bytesRead, fRequestBufferBytesLeft);#endif    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 (fRequestBytesAlreadySeen > 0) --tmpPtr;      // in case the last read ended with a <CR>  while (tmpPtr < &ptr[bytesRead-1]) {    if (*tmpPtr == '\r' && *(tmpPtr+1) == '\n') {      if (tmpPtr - fLastCRLF == 2) { // This is it:	endOfMsg = 1;	break;      }      fLastCRLF = tmpPtr;    }    ++tmpPtr;  }    fRequestBufferBytesLeft -= bytesRead;  fRequestBytesAlreadySeen += bytesRead;  if (!endOfMsg) return; // subsequent reads will be needed to complete the request  // Parse the request string into command name and 'CSeq',  // then handle the command:  fRequestBuffer[fRequestBytesAlreadySeen] = '\0';  char cmdName[RTSP_PARAM_STRING_MAX];  char urlPreSuffix[RTSP_PARAM_STRING_MAX];  char urlSuffix[RTSP_PARAM_STRING_MAX];  char cseq[RTSP_PARAM_STRING_MAX];  if (!parseRTSPRequestString((char*)fRequestBuffer, fRequestBytesAlreadySeen,			      cmdName, sizeof cmdName,			      urlPreSuffix, sizeof urlPreSuffix,			      urlSuffix, sizeof urlSuffix,			      cseq, sizeof cseq)) {#ifdef DEBUG    fprintf(stderr, "parseRTSPRequestString() failed!\n");#endif    handleCmd_bad(cseq);  } else {#ifdef DEBUG    fprintf(stderr, "parseRTSPRequestString() 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*)fRequestBuffer);    } else if (strcmp(cmdName, "SETUP") == 0) {      handleCmd_SETUP(cseq, urlPreSuffix, urlSuffix, (char const*)fRequestBuffer);    } 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*)fRequestBuffer);    } 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*)fRequestBuffer);  }  resetRequestBuffer(); // to prepare for any subsequent request  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);

⌨️ 快捷键说明

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