123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- /**********
- This library is free software; you can redistribute it and/or modify it under
- the terms of the GNU Lesser General Public License as published by the
- Free Software Foundation; either version 3 of the License, or (at your
- option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
- This library is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
- more details.
- You should have received a copy of the GNU Lesser General Public License
- along with this library; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- **********/
- // "liveMedia"
- // Copyright (c) 1996-2019 Live Networks, Inc. All rights reserved.
- // A RTSP server
- // C++ header
- #ifndef _RTSP_SERVER_HH
- #define _RTSP_SERVER_HH
- #ifndef _GENERIC_MEDIA_SERVER_HH
- #include "GenericMediaServer.hh"
- #endif
- #ifndef _DIGEST_AUTHENTICATION_HH
- #include "DigestAuthentication.hh"
- #endif
- class RTSPServer: public GenericMediaServer {
- public:
- static RTSPServer* createNew(UsageEnvironment& env, Port ourPort = 554,
- UserAuthenticationDatabase* authDatabase = NULL,
- unsigned reclamationSeconds = 65);
- // If ourPort.num() == 0, we'll choose the port number
- // Note: The caller is responsible for reclaiming "authDatabase"
- // If "reclamationSeconds" > 0, then the "RTSPClientSession" state for
- // each client will get reclaimed (and the corresponding RTP stream(s)
- // torn down) if no RTSP commands - or RTCP "RR" packets - from the
- // client are received in at least "reclamationSeconds" seconds.
- static Boolean lookupByName(UsageEnvironment& env, char const* name,
- RTSPServer*& resultServer);
- typedef void (responseHandlerForREGISTER)(RTSPServer* rtspServer, unsigned requestId, int resultCode, char* resultString);
- unsigned registerStream(ServerMediaSession* serverMediaSession,
- char const* remoteClientNameOrAddress, portNumBits remoteClientPortNum,
- responseHandlerForREGISTER* responseHandler,
- char const* username = NULL, char const* password = NULL,
- Boolean receiveOurStreamViaTCP = False,
- char const* proxyURLSuffix = NULL);
- // 'Register' the stream represented by "serverMediaSession" with the given remote client (specifed by name and port number).
- // This is done using our custom "REGISTER" RTSP command.
- // The function returns a unique number that can be used to identify the request; this number is also passed to "responseHandler".
- // When a response is received from the remote client (or the "REGISTER" request fails), the specified response handler
- // (if non-NULL) is called. (Note that the "resultString" passed to the handler was dynamically allocated,
- // and should be delete[]d by the handler after use.)
- // If "receiveOurStreamViaTCP" is True, then we're requesting that the remote client access our stream using RTP/RTCP-over-TCP.
- // (Otherwise, the remote client may choose regular RTP/RTCP-over-UDP streaming.)
- // "proxyURLSuffix" (optional) is used only when the remote client is also a proxy server.
- // It tells the proxy server the suffix that it should use in its "rtsp://" URL (when front-end clients access the stream)
- typedef void (responseHandlerForDEREGISTER)(RTSPServer* rtspServer, unsigned requestId, int resultCode, char* resultString);
- unsigned deregisterStream(ServerMediaSession* serverMediaSession,
- char const* remoteClientNameOrAddress, portNumBits remoteClientPortNum,
- responseHandlerForDEREGISTER* responseHandler,
- char const* username = NULL, char const* password = NULL,
- char const* proxyURLSuffix = NULL);
- // Used to turn off a previous "registerStream()" - using our custom "DEREGISTER" RTSP command.
-
- char* rtspURL(ServerMediaSession const* serverMediaSession, int clientSocket = -1) const;
- // returns a "rtsp://" URL that could be used to access the
- // specified session (which must already have been added to
- // us using "addServerMediaSession()".
- // This string is dynamically allocated; caller should delete[]
- // (If "clientSocket" is non-negative, then it is used (by calling "getsockname()") to determine
- // the IP address to be used in the URL.)
- char* rtspURLPrefix(int clientSocket = -1) const;
- // like "rtspURL()", except that it returns just the common prefix used by
- // each session's "rtsp://" URL.
- // This string is dynamically allocated; caller should delete[]
- UserAuthenticationDatabase* setAuthenticationDatabase(UserAuthenticationDatabase* newDB);
- // Changes the server's authentication database to "newDB", returning a pointer to the old database (if there was one).
- // "newDB" may be NULL (you can use this to disable authentication at runtime, if desired).
- void disableStreamingRTPOverTCP() {
- fAllowStreamingRTPOverTCP = False;
- }
- Boolean setUpTunnelingOverHTTP(Port httpPort);
- // (Attempts to) enable RTSP-over-HTTP tunneling on the specified port.
- // Returns True iff the specified port can be used in this way (i.e., it's not already being used for a separate HTTP server).
- // Note: RTSP-over-HTTP tunneling is described in
- // http://mirror.informatimago.com/next/developer.apple.com/quicktime/icefloe/dispatch028.html
- // and http://images.apple.com/br/quicktime/pdf/QTSS_Modules.pdf
- portNumBits httpServerPortNum() const; // in host byte order. (Returns 0 if not present.)
- protected:
- RTSPServer(UsageEnvironment& env,
- int ourSocket, Port ourPort,
- UserAuthenticationDatabase* authDatabase,
- unsigned reclamationSeconds);
- // called only by createNew();
- virtual ~RTSPServer();
- virtual char const* allowedCommandNames(); // used to implement "RTSPClientConnection::handleCmd_OPTIONS()"
- virtual Boolean weImplementREGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/,
- char const* proxyURLSuffix, char*& responseStr);
- // used to implement "RTSPClientConnection::handleCmd_REGISTER()"
- // Note: "responseStr" is dynamically allocated (or NULL), and should be delete[]d after the call
- virtual void implementCmd_REGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/,
- char const* url, char const* urlSuffix, int socketToRemoteServer,
- Boolean deliverViaTCP, char const* proxyURLSuffix);
- // used to implement "RTSPClientConnection::handleCmd_REGISTER()"
- virtual UserAuthenticationDatabase* getAuthenticationDatabaseForCommand(char const* cmdName);
- virtual Boolean specialClientAccessCheck(int clientSocket, struct sockaddr_in& clientAddr,
- char const* urlSuffix);
- // a hook that allows subclassed servers to do server-specific access checking
- // on each client (e.g., based on client IP address), without using digest authentication.
- virtual Boolean specialClientUserAccessCheck(int clientSocket, struct sockaddr_in& clientAddr,
- char const* urlSuffix, char const *username);
- // another hook that allows subclassed servers to do server-specific access checking
- // - this time after normal digest authentication has already taken place (and would otherwise allow access).
- // (This test can only be used to further restrict access, not to grant additional access.)
- private: // redefined virtual functions
- virtual Boolean isRTSPServer() const;
- public: // should be protected, but some old compilers complain otherwise
- // The state of a TCP connection used by a RTSP client:
- class RTSPClientSession; // forward
- class RTSPClientConnection: public GenericMediaServer::ClientConnection {
- public:
- // A data structure that's used to implement the "REGISTER" command:
- class ParamsForREGISTER {
- public:
- ParamsForREGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/,
- RTSPClientConnection* ourConnection, char const* url, char const* urlSuffix,
- Boolean reuseConnection, Boolean deliverViaTCP, char const* proxyURLSuffix);
- virtual ~ParamsForREGISTER();
- private:
- friend class RTSPClientConnection;
- char const* fCmd;
- RTSPClientConnection* fOurConnection;
- char* fURL;
- char* fURLSuffix;
- Boolean fReuseConnection, fDeliverViaTCP;
- char* fProxyURLSuffix;
- };
- protected: // redefined virtual functions:
- virtual void handleRequestBytes(int newBytesRead);
- protected:
- RTSPClientConnection(RTSPServer& ourServer, int clientSocket, struct sockaddr_in clientAddr);
- virtual ~RTSPClientConnection();
- friend class RTSPServer;
- friend class RTSPClientSession;
- // Make the handler functions for each command virtual, to allow subclasses to reimplement them, if necessary:
- virtual void handleCmd_OPTIONS();
- // You probably won't need to subclass/reimplement this function; reimplement "RTSPServer::allowedCommandNames()" instead.
- virtual void handleCmd_GET_PARAMETER(char const* fullRequestStr); // when operating on the entire server
- virtual void handleCmd_SET_PARAMETER(char const* fullRequestStr); // when operating on the entire server
- virtual void handleCmd_DESCRIBE(char const* urlPreSuffix, char const* urlSuffix, char const* fullRequestStr);
- virtual void handleCmd_REGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/,
- char const* url, char const* urlSuffix, char const* fullRequestStr,
- Boolean reuseConnection, Boolean deliverViaTCP, char const* proxyURLSuffix);
- // You probably won't need to subclass/reimplement this function;
- // reimplement "RTSPServer::weImplementREGISTER()" and "RTSPServer::implementCmd_REGISTER()" instead.
- virtual void handleCmd_bad();
- virtual void handleCmd_notSupported();
- virtual void handleCmd_notFound();
- virtual void handleCmd_sessionNotFound();
- virtual void handleCmd_unsupportedTransport();
- // Support for optional RTSP-over-HTTP tunneling:
- virtual Boolean parseHTTPRequestString(char* resultCmdName, unsigned resultCmdNameMaxSize,
- char* urlSuffix, unsigned urlSuffixMaxSize,
- char* sessionCookie, unsigned sessionCookieMaxSize,
- char* acceptStr, unsigned acceptStrMaxSize);
- virtual void handleHTTPCmd_notSupported();
- virtual void handleHTTPCmd_notFound();
- virtual void handleHTTPCmd_OPTIONS();
- virtual void handleHTTPCmd_TunnelingGET(char const* sessionCookie);
- virtual Boolean handleHTTPCmd_TunnelingPOST(char const* sessionCookie, unsigned char const* extraData, unsigned extraDataSize);
- virtual void handleHTTPCmd_StreamingGET(char const* urlSuffix, char const* fullRequestStr);
- protected:
- void resetRequestBuffer();
- void closeSocketsRTSP();
- static void handleAlternativeRequestByte(void*, u_int8_t requestByte);
- void handleAlternativeRequestByte1(u_int8_t requestByte);
- Boolean authenticationOK(char const* cmdName, char const* urlSuffix, char const* fullRequestStr);
- void changeClientInputSocket(int newSocketNum, unsigned char const* extraData, unsigned extraDataSize);
- // used to implement RTSP-over-HTTP tunneling
- static void continueHandlingREGISTER(ParamsForREGISTER* params);
- virtual void continueHandlingREGISTER1(ParamsForREGISTER* params);
- // Shortcuts for setting up a RTSP response (prior to sending it):
- void setRTSPResponse(char const* responseStr);
- void setRTSPResponse(char const* responseStr, u_int32_t sessionId);
- void setRTSPResponse(char const* responseStr, char const* contentStr);
- void setRTSPResponse(char const* responseStr, u_int32_t sessionId, char const* contentStr);
- RTSPServer& fOurRTSPServer; // same as ::fOurServer
- int& fClientInputSocket; // aliased to ::fOurSocket
- int fClientOutputSocket;
- Boolean fIsActive;
- unsigned char* fLastCRLF;
- unsigned fRecursionCount;
- char const* fCurrentCSeq;
- Authenticator fCurrentAuthenticator; // used if access control is needed
- char* fOurSessionCookie; // used for optional RTSP-over-HTTP tunneling
- unsigned fBase64RemainderCount; // used for optional RTSP-over-HTTP tunneling (possible values: 0,1,2,3)
- };
- // The state of an individual client session (using one or more sequential TCP connections) handled by a RTSP server:
- class RTSPClientSession: public GenericMediaServer::ClientSession {
- protected:
- RTSPClientSession(RTSPServer& ourServer, u_int32_t sessionId);
- virtual ~RTSPClientSession();
- friend class RTSPServer;
- friend class RTSPClientConnection;
- // Make the handler functions for each command virtual, to allow subclasses to redefine them:
- virtual void handleCmd_SETUP(RTSPClientConnection* ourClientConnection,
- char const* urlPreSuffix, char const* urlSuffix, char const* fullRequestStr);
- virtual void handleCmd_withinSession(RTSPClientConnection* ourClientConnection,
- char const* cmdName,
- char const* urlPreSuffix, char const* urlSuffix,
- char const* fullRequestStr);
- virtual void handleCmd_TEARDOWN(RTSPClientConnection* ourClientConnection,
- ServerMediaSubsession* subsession);
- virtual void handleCmd_PLAY(RTSPClientConnection* ourClientConnection,
- ServerMediaSubsession* subsession, char const* fullRequestStr);
- virtual void handleCmd_PAUSE(RTSPClientConnection* ourClientConnection,
- ServerMediaSubsession* subsession);
- virtual void handleCmd_GET_PARAMETER(RTSPClientConnection* ourClientConnection,
- ServerMediaSubsession* subsession, char const* fullRequestStr);
- virtual void handleCmd_SET_PARAMETER(RTSPClientConnection* ourClientConnection,
- ServerMediaSubsession* subsession, char const* fullRequestStr);
- protected:
- void deleteStreamByTrack(unsigned trackNum);
- void reclaimStreamStates();
- Boolean isMulticast() const { return fIsMulticast; }
- // Shortcuts for setting up a RTSP response (prior to sending it):
- void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr) { ourClientConnection->setRTSPResponse(responseStr); }
- void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr, u_int32_t sessionId) { ourClientConnection->setRTSPResponse(responseStr, sessionId); }
- void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr, char const* contentStr) { ourClientConnection->setRTSPResponse(responseStr, contentStr); }
- void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr, u_int32_t sessionId, char const* contentStr) { ourClientConnection->setRTSPResponse(responseStr, sessionId, contentStr); }
- protected:
- RTSPServer& fOurRTSPServer; // same as ::fOurServer
- Boolean fIsMulticast, fStreamAfterSETUP;
- unsigned char fTCPStreamIdCount; // used for (optional) RTP/TCP
- Boolean usesTCPTransport() const { return fTCPStreamIdCount > 0; }
- unsigned fNumStreamStates;
- struct streamState {
- ServerMediaSubsession* subsession;
- int tcpSocketNum;
- void* streamToken;
- } * fStreamStates;
- };
- protected: // redefined virtual functions
- // If you subclass "RTSPClientConnection", then you must also redefine this virtual function in order
- // to create new objects of your subclass:
- virtual ClientConnection* createNewClientConnection(int clientSocket, struct sockaddr_in clientAddr);
- protected:
- // If you subclass "RTSPClientSession", then you must also redefine this virtual function in order
- // to create new objects of your subclass:
- virtual ClientSession* createNewClientSession(u_int32_t sessionId);
- private:
- static void incomingConnectionHandlerHTTP(void*, int /*mask*/);
- void incomingConnectionHandlerHTTP();
- void noteTCPStreamingOnSocket(int socketNum, RTSPClientSession* clientSession, unsigned trackNum);
- void unnoteTCPStreamingOnSocket(int socketNum, RTSPClientSession* clientSession, unsigned trackNum);
- void stopTCPStreamingOnSocket(int socketNum);
- private:
- friend class RTSPClientConnection;
- friend class RTSPClientSession;
- friend class RegisterRequestRecord;
- friend class DeregisterRequestRecord;
- int fHTTPServerSocket; // for optional RTSP-over-HTTP tunneling
- Port fHTTPServerPort; // ditto
- HashTable* fClientConnectionsForHTTPTunneling; // maps client-supplied 'session cookie' strings to "RTSPClientConnection"s
- // (used only for optional RTSP-over-HTTP tunneling)
- HashTable* fTCPStreamingDatabase;
- // maps TCP socket numbers to ids of sessions that are streaming over it (RTP/RTCP-over-TCP)
- HashTable* fPendingRegisterOrDeregisterRequests;
- unsigned fRegisterOrDeregisterRequestCounter;
- UserAuthenticationDatabase* fAuthDB;
- Boolean fAllowStreamingRTPOverTCP; // by default, True
- };
- ////////// A subclass of "RTSPServer" that implements the "REGISTER" command to set up proxying on the specified URL //////////
- class RTSPServerWithREGISTERProxying: public RTSPServer {
- public:
- static RTSPServerWithREGISTERProxying* createNew(UsageEnvironment& env, Port ourPort = 554,
- UserAuthenticationDatabase* authDatabase = NULL,
- UserAuthenticationDatabase* authDatabaseForREGISTER = NULL,
- unsigned reclamationSeconds = 65,
- Boolean streamRTPOverTCP = False,
- int verbosityLevelForProxying = 0,
- char const* backEndUsername = NULL,
- char const* backEndPassword = NULL);
- protected:
- RTSPServerWithREGISTERProxying(UsageEnvironment& env, int ourSocket, Port ourPort,
- UserAuthenticationDatabase* authDatabase, UserAuthenticationDatabase* authDatabaseForREGISTER,
- unsigned reclamationSeconds,
- Boolean streamRTPOverTCP, int verbosityLevelForProxying,
- char const* backEndUsername, char const* backEndPassword);
- // called only by createNew();
- virtual ~RTSPServerWithREGISTERProxying();
- protected: // redefined virtual functions
- virtual char const* allowedCommandNames();
- virtual Boolean weImplementREGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/,
- char const* proxyURLSuffix, char*& responseStr);
- virtual void implementCmd_REGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/,
- char const* url, char const* urlSuffix, int socketToRemoteServer,
- Boolean deliverViaTCP, char const* proxyURLSuffix);
- virtual UserAuthenticationDatabase* getAuthenticationDatabaseForCommand(char const* cmdName);
- private:
- Boolean fStreamRTPOverTCP;
- int fVerbosityLevelForProxying;
- unsigned fRegisteredProxyCounter;
- char* fAllowedCommandNames;
- UserAuthenticationDatabase* fAuthDBForREGISTER;
- char* fBackEndUsername;
- char* fBackEndPassword;
- };
- // A special version of "parseTransportHeader()", used just for parsing the "Transport:" header
- // in an incoming "REGISTER" command:
- void parseTransportHeaderForREGISTER(char const* buf, // in
- Boolean &reuseConnection, // out
- Boolean& deliverViaTCP, // out
- char*& proxyURLSuffix); // out
- #endif
|