| 1 | /********** |
| 2 | This library is free software; you can redistribute it and/or modify it under |
| 3 | the terms of the GNU Lesser General Public License as published by the |
| 4 | Free Software Foundation; either version 3 of the License, or (at your |
| 5 | option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) |
| 6 | |
| 7 | This library is distributed in the hope that it will be useful, but WITHOUT |
| 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for |
| 10 | more details. |
| 11 | |
| 12 | You should have received a copy of the GNU Lesser General Public License |
| 13 | along with this library; if not, write to the Free Software Foundation, Inc., |
| 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 15 | **********/ |
| 16 | // "liveMedia" |
| 17 | // Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved. |
| 18 | // A RTSP server |
| 19 | // C++ header |
| 20 | |
| 21 | #ifndef _RTSP_SERVER_HH |
| 22 | #define _RTSP_SERVER_HH |
| 23 | |
| 24 | #ifndef _GENERIC_MEDIA_SERVER_HH |
| 25 | #include "GenericMediaServer.hh" |
| 26 | #endif |
| 27 | #ifndef _DIGEST_AUTHENTICATION_HH |
| 28 | #include "DigestAuthentication.hh" |
| 29 | #endif |
| 30 | |
| 31 | class RTSPServer: public GenericMediaServer { |
| 32 | public: |
| 33 | static RTSPServer* createNew(UsageEnvironment& env, Port ourPort = 554, |
| 34 | UserAuthenticationDatabase* authDatabase = NULL, |
| 35 | unsigned reclamationSeconds = 65); |
| 36 | // If ourPort.num() == 0, we'll choose the port number |
| 37 | // Note: The caller is responsible for reclaiming "authDatabase" |
| 38 | // If "reclamationSeconds" > 0, then the "RTSPClientSession" state for |
| 39 | // each client will get reclaimed (and the corresponding RTP stream(s) |
| 40 | // torn down) if no RTSP commands - or RTCP "RR" packets - from the |
| 41 | // client are received in at least "reclamationSeconds" seconds. |
| 42 | |
| 43 | static Boolean lookupByName(UsageEnvironment& env, char const* name, |
| 44 | RTSPServer*& resultServer); |
| 45 | |
| 46 | typedef void (responseHandlerForREGISTER)(RTSPServer* rtspServer, unsigned requestId, int resultCode, char* resultString); |
| 47 | unsigned registerStream(ServerMediaSession* serverMediaSession, |
| 48 | char const* remoteClientNameOrAddress, portNumBits remoteClientPortNum, |
| 49 | responseHandlerForREGISTER* responseHandler, |
| 50 | char const* username = NULL, char const* password = NULL, |
| 51 | Boolean receiveOurStreamViaTCP = False, |
| 52 | char const* proxyURLSuffix = NULL); |
| 53 | // 'Register' the stream represented by "serverMediaSession" with the given remote client (specifed by name and port number). |
| 54 | // This is done using our custom "REGISTER" RTSP command. |
| 55 | // The function returns a unique number that can be used to identify the request; this number is also passed to "responseHandler". |
| 56 | // When a response is received from the remote client (or the "REGISTER" request fails), the specified response handler |
| 57 | // (if non-NULL) is called. (Note that the "resultString" passed to the handler was dynamically allocated, |
| 58 | // and should be delete[]d by the handler after use.) |
| 59 | // If "receiveOurStreamViaTCP" is True, then we're requesting that the remote client access our stream using RTP/RTCP-over-TCP. |
| 60 | // (Otherwise, the remote client may choose regular RTP/RTCP-over-UDP streaming.) |
| 61 | // "proxyURLSuffix" (optional) is used only when the remote client is also a proxy server. |
| 62 | // It tells the proxy server the suffix that it should use in its "rtsp://" URL (when front-end clients access the stream) |
| 63 | |
| 64 | typedef void (responseHandlerForDEREGISTER)(RTSPServer* rtspServer, unsigned requestId, int resultCode, char* resultString); |
| 65 | unsigned deregisterStream(ServerMediaSession* serverMediaSession, |
| 66 | char const* remoteClientNameOrAddress, portNumBits remoteClientPortNum, |
| 67 | responseHandlerForDEREGISTER* responseHandler, |
| 68 | char const* username = NULL, char const* password = NULL, |
| 69 | char const* proxyURLSuffix = NULL); |
| 70 | // Used to turn off a previous "registerStream()" - using our custom "DEREGISTER" RTSP command. |
| 71 | |
| 72 | char* rtspURL(ServerMediaSession const* serverMediaSession, int clientSocket = -1) const; |
| 73 | // returns a "rtsp://" URL that could be used to access the |
| 74 | // specified session (which must already have been added to |
| 75 | // us using "addServerMediaSession()". |
| 76 | // This string is dynamically allocated; caller should delete[] |
| 77 | // (If "clientSocket" is non-negative, then it is used (by calling "getsockname()") to determine |
| 78 | // the IP address to be used in the URL.) |
| 79 | char* rtspURLPrefix(int clientSocket = -1) const; |
| 80 | // like "rtspURL()", except that it returns just the common prefix used by |
| 81 | // each session's "rtsp://" URL. |
| 82 | // This string is dynamically allocated; caller should delete[] |
| 83 | |
| 84 | UserAuthenticationDatabase* setAuthenticationDatabase(UserAuthenticationDatabase* newDB); |
| 85 | // Changes the server's authentication database to "newDB", returning a pointer to the old database (if there was one). |
| 86 | // "newDB" may be NULL (you can use this to disable authentication at runtime, if desired). |
| 87 | |
| 88 | void disableStreamingRTPOverTCP() { |
| 89 | fAllowStreamingRTPOverTCP = False; |
| 90 | } |
| 91 | |
| 92 | Boolean setUpTunnelingOverHTTP(Port httpPort); |
| 93 | // (Attempts to) enable RTSP-over-HTTP tunneling on the specified port. |
| 94 | // 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). |
| 95 | // Note: RTSP-over-HTTP tunneling is described in |
| 96 | // http://mirror.informatimago.com/next/developer.apple.com/quicktime/icefloe/dispatch028.html |
| 97 | // and http://images.apple.com/br/quicktime/pdf/QTSS_Modules.pdf |
| 98 | portNumBits httpServerPortNum() const; // in host byte order. (Returns 0 if not present.) |
| 99 | |
| 100 | protected: |
| 101 | RTSPServer(UsageEnvironment& env, |
| 102 | int ourSocket, Port ourPort, |
| 103 | UserAuthenticationDatabase* authDatabase, |
| 104 | unsigned reclamationSeconds); |
| 105 | // called only by createNew(); |
| 106 | virtual ~RTSPServer(); |
| 107 | |
| 108 | virtual char const* allowedCommandNames(); // used to implement "RTSPClientConnection::handleCmd_OPTIONS()" |
| 109 | virtual Boolean weImplementREGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/, |
| 110 | char const* proxyURLSuffix, char*& responseStr); |
| 111 | // used to implement "RTSPClientConnection::handleCmd_REGISTER()" |
| 112 | // Note: "responseStr" is dynamically allocated (or NULL), and should be delete[]d after the call |
| 113 | virtual void implementCmd_REGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/, |
| 114 | char const* url, char const* urlSuffix, int socketToRemoteServer, |
| 115 | Boolean deliverViaTCP, char const* proxyURLSuffix); |
| 116 | // used to implement "RTSPClientConnection::handleCmd_REGISTER()" |
| 117 | |
| 118 | virtual UserAuthenticationDatabase* getAuthenticationDatabaseForCommand(char const* cmdName); |
| 119 | virtual Boolean specialClientAccessCheck(int clientSocket, struct sockaddr_in& clientAddr, |
| 120 | char const* urlSuffix); |
| 121 | // a hook that allows subclassed servers to do server-specific access checking |
| 122 | // on each client (e.g., based on client IP address), without using digest authentication. |
| 123 | virtual Boolean specialClientUserAccessCheck(int clientSocket, struct sockaddr_in& clientAddr, |
| 124 | char const* urlSuffix, char const *username); |
| 125 | // another hook that allows subclassed servers to do server-specific access checking |
| 126 | // - this time after normal digest authentication has already taken place (and would otherwise allow access). |
| 127 | // (This test can only be used to further restrict access, not to grant additional access.) |
| 128 | |
| 129 | private: // redefined virtual functions |
| 130 | virtual Boolean isRTSPServer() const; |
| 131 | |
| 132 | public: // should be protected, but some old compilers complain otherwise |
| 133 | // The state of a TCP connection used by a RTSP client: |
| 134 | class RTSPClientSession; // forward |
| 135 | class RTSPClientConnection: public GenericMediaServer::ClientConnection { |
| 136 | public: |
| 137 | // A data structure that's used to implement the "REGISTER" command: |
| 138 | class ParamsForREGISTER { |
| 139 | public: |
| 140 | ParamsForREGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/, |
| 141 | RTSPClientConnection* ourConnection, char const* url, char const* urlSuffix, |
| 142 | Boolean reuseConnection, Boolean deliverViaTCP, char const* proxyURLSuffix); |
| 143 | virtual ~ParamsForREGISTER(); |
| 144 | private: |
| 145 | friend class RTSPClientConnection; |
| 146 | char const* fCmd; |
| 147 | RTSPClientConnection* fOurConnection; |
| 148 | char* fURL; |
| 149 | char* fURLSuffix; |
| 150 | Boolean fReuseConnection, fDeliverViaTCP; |
| 151 | char* fProxyURLSuffix; |
| 152 | }; |
| 153 | protected: // redefined virtual functions: |
| 154 | virtual void handleRequestBytes(int newBytesRead); |
| 155 | |
| 156 | protected: |
| 157 | RTSPClientConnection(RTSPServer& ourServer, int clientSocket, struct sockaddr_in clientAddr); |
| 158 | virtual ~RTSPClientConnection(); |
| 159 | |
| 160 | friend class RTSPServer; |
| 161 | friend class RTSPClientSession; |
| 162 | |
| 163 | // Make the handler functions for each command virtual, to allow subclasses to reimplement them, if necessary: |
| 164 | virtual void handleCmd_OPTIONS(); |
| 165 | // You probably won't need to subclass/reimplement this function; reimplement "RTSPServer::allowedCommandNames()" instead. |
| 166 | virtual void handleCmd_GET_PARAMETER(char const* fullRequestStr); // when operating on the entire server |
| 167 | virtual void handleCmd_SET_PARAMETER(char const* fullRequestStr); // when operating on the entire server |
| 168 | virtual void handleCmd_DESCRIBE(char const* urlPreSuffix, char const* urlSuffix, char const* fullRequestStr); |
| 169 | virtual void handleCmd_REGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/, |
| 170 | char const* url, char const* urlSuffix, char const* fullRequestStr, |
| 171 | Boolean reuseConnection, Boolean deliverViaTCP, char const* proxyURLSuffix); |
| 172 | // You probably won't need to subclass/reimplement this function; |
| 173 | // reimplement "RTSPServer::weImplementREGISTER()" and "RTSPServer::implementCmd_REGISTER()" instead. |
| 174 | virtual void handleCmd_bad(); |
| 175 | virtual void handleCmd_notSupported(); |
| 176 | virtual void handleCmd_notFound(); |
| 177 | virtual void handleCmd_sessionNotFound(); |
| 178 | virtual void handleCmd_unsupportedTransport(); |
| 179 | // Support for optional RTSP-over-HTTP tunneling: |
| 180 | virtual Boolean parseHTTPRequestString(char* resultCmdName, unsigned resultCmdNameMaxSize, |
| 181 | char* urlSuffix, unsigned urlSuffixMaxSize, |
| 182 | char* sessionCookie, unsigned sessionCookieMaxSize, |
| 183 | char* acceptStr, unsigned acceptStrMaxSize); |
| 184 | virtual void handleHTTPCmd_notSupported(); |
| 185 | virtual void handleHTTPCmd_notFound(); |
| 186 | virtual void handleHTTPCmd_OPTIONS(); |
| 187 | virtual void handleHTTPCmd_TunnelingGET(char const* sessionCookie); |
| 188 | virtual Boolean handleHTTPCmd_TunnelingPOST(char const* sessionCookie, unsigned char const* , unsigned ); |
| 189 | virtual void handleHTTPCmd_StreamingGET(char const* urlSuffix, char const* fullRequestStr); |
| 190 | protected: |
| 191 | void resetRequestBuffer(); |
| 192 | void closeSocketsRTSP(); |
| 193 | static void handleAlternativeRequestByte(void*, u_int8_t requestByte); |
| 194 | void handleAlternativeRequestByte1(u_int8_t requestByte); |
| 195 | Boolean authenticationOK(char const* cmdName, char const* urlSuffix, char const* fullRequestStr); |
| 196 | void changeClientInputSocket(int newSocketNum, unsigned char const* , unsigned ); |
| 197 | // used to implement RTSP-over-HTTP tunneling |
| 198 | static void continueHandlingREGISTER(ParamsForREGISTER* params); |
| 199 | virtual void continueHandlingREGISTER1(ParamsForREGISTER* params); |
| 200 | |
| 201 | // Shortcuts for setting up a RTSP response (prior to sending it): |
| 202 | void setRTSPResponse(char const* responseStr); |
| 203 | void setRTSPResponse(char const* responseStr, u_int32_t sessionId); |
| 204 | void setRTSPResponse(char const* responseStr, char const* contentStr); |
| 205 | void setRTSPResponse(char const* responseStr, u_int32_t sessionId, char const* contentStr); |
| 206 | |
| 207 | RTSPServer& fOurRTSPServer; // same as ::fOurServer |
| 208 | int& fClientInputSocket; // aliased to ::fOurSocket |
| 209 | int fClientOutputSocket; |
| 210 | Boolean fIsActive; |
| 211 | unsigned char* fLastCRLF; |
| 212 | unsigned fRecursionCount; |
| 213 | char const* fCurrentCSeq; |
| 214 | Authenticator fCurrentAuthenticator; // used if access control is needed |
| 215 | char* fOurSessionCookie; // used for optional RTSP-over-HTTP tunneling |
| 216 | unsigned fBase64RemainderCount; // used for optional RTSP-over-HTTP tunneling (possible values: 0,1,2,3) |
| 217 | }; |
| 218 | |
| 219 | // The state of an individual client session (using one or more sequential TCP connections) handled by a RTSP server: |
| 220 | class RTSPClientSession: public GenericMediaServer::ClientSession { |
| 221 | protected: |
| 222 | RTSPClientSession(RTSPServer& ourServer, u_int32_t sessionId); |
| 223 | virtual ~RTSPClientSession(); |
| 224 | |
| 225 | friend class RTSPServer; |
| 226 | friend class RTSPClientConnection; |
| 227 | // Make the handler functions for each command virtual, to allow subclasses to redefine them: |
| 228 | virtual void handleCmd_SETUP(RTSPClientConnection* ourClientConnection, |
| 229 | char const* urlPreSuffix, char const* urlSuffix, char const* fullRequestStr); |
| 230 | virtual void handleCmd_withinSession(RTSPClientConnection* ourClientConnection, |
| 231 | char const* cmdName, |
| 232 | char const* urlPreSuffix, char const* urlSuffix, |
| 233 | char const* fullRequestStr); |
| 234 | virtual void handleCmd_TEARDOWN(RTSPClientConnection* ourClientConnection, |
| 235 | ServerMediaSubsession* subsession); |
| 236 | virtual void handleCmd_PLAY(RTSPClientConnection* ourClientConnection, |
| 237 | ServerMediaSubsession* subsession, char const* fullRequestStr); |
| 238 | virtual void handleCmd_PAUSE(RTSPClientConnection* ourClientConnection, |
| 239 | ServerMediaSubsession* subsession); |
| 240 | virtual void handleCmd_GET_PARAMETER(RTSPClientConnection* ourClientConnection, |
| 241 | ServerMediaSubsession* subsession, char const* fullRequestStr); |
| 242 | virtual void handleCmd_SET_PARAMETER(RTSPClientConnection* ourClientConnection, |
| 243 | ServerMediaSubsession* subsession, char const* fullRequestStr); |
| 244 | protected: |
| 245 | void deleteStreamByTrack(unsigned trackNum); |
| 246 | void reclaimStreamStates(); |
| 247 | Boolean isMulticast() const { return fIsMulticast; } |
| 248 | |
| 249 | // Shortcuts for setting up a RTSP response (prior to sending it): |
| 250 | void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr) { ourClientConnection->setRTSPResponse(responseStr); } |
| 251 | void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr, u_int32_t sessionId) { ourClientConnection->setRTSPResponse(responseStr, sessionId); } |
| 252 | void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr, char const* contentStr) { ourClientConnection->setRTSPResponse(responseStr, contentStr); } |
| 253 | void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr, u_int32_t sessionId, char const* contentStr) { ourClientConnection->setRTSPResponse(responseStr, sessionId, contentStr); } |
| 254 | |
| 255 | protected: |
| 256 | RTSPServer& fOurRTSPServer; // same as ::fOurServer |
| 257 | Boolean fIsMulticast, fStreamAfterSETUP; |
| 258 | unsigned char fTCPStreamIdCount; // used for (optional) RTP/TCP |
| 259 | Boolean usesTCPTransport() const { return fTCPStreamIdCount > 0; } |
| 260 | unsigned fNumStreamStates; |
| 261 | struct streamState { |
| 262 | ServerMediaSubsession* subsession; |
| 263 | int tcpSocketNum; |
| 264 | void* streamToken; |
| 265 | } * fStreamStates; |
| 266 | }; |
| 267 | |
| 268 | protected: // redefined virtual functions |
| 269 | // If you subclass "RTSPClientConnection", then you must also redefine this virtual function in order |
| 270 | // to create new objects of your subclass: |
| 271 | virtual ClientConnection* createNewClientConnection(int clientSocket, struct sockaddr_in clientAddr); |
| 272 | |
| 273 | protected: |
| 274 | // If you subclass "RTSPClientSession", then you must also redefine this virtual function in order |
| 275 | // to create new objects of your subclass: |
| 276 | virtual ClientSession* createNewClientSession(u_int32_t sessionId); |
| 277 | |
| 278 | private: |
| 279 | static void incomingConnectionHandlerHTTP(void*, int /*mask*/); |
| 280 | void incomingConnectionHandlerHTTP(); |
| 281 | |
| 282 | void noteTCPStreamingOnSocket(int socketNum, RTSPClientSession* clientSession, unsigned trackNum); |
| 283 | void unnoteTCPStreamingOnSocket(int socketNum, RTSPClientSession* clientSession, unsigned trackNum); |
| 284 | void stopTCPStreamingOnSocket(int socketNum); |
| 285 | |
| 286 | private: |
| 287 | friend class RTSPClientConnection; |
| 288 | friend class RTSPClientSession; |
| 289 | friend class RegisterRequestRecord; |
| 290 | friend class DeregisterRequestRecord; |
| 291 | int fHTTPServerSocket; // for optional RTSP-over-HTTP tunneling |
| 292 | Port fHTTPServerPort; // ditto |
| 293 | HashTable* fClientConnectionsForHTTPTunneling; // maps client-supplied 'session cookie' strings to "RTSPClientConnection"s |
| 294 | // (used only for optional RTSP-over-HTTP tunneling) |
| 295 | HashTable* fTCPStreamingDatabase; |
| 296 | // maps TCP socket numbers to ids of sessions that are streaming over it (RTP/RTCP-over-TCP) |
| 297 | HashTable* fPendingRegisterOrDeregisterRequests; |
| 298 | unsigned fRegisterOrDeregisterRequestCounter; |
| 299 | UserAuthenticationDatabase* fAuthDB; |
| 300 | Boolean fAllowStreamingRTPOverTCP; // by default, True |
| 301 | }; |
| 302 | |
| 303 | |
| 304 | ////////// A subclass of "RTSPServer" that implements the "REGISTER" command to set up proxying on the specified URL ////////// |
| 305 | |
| 306 | class RTSPServerWithREGISTERProxying: public RTSPServer { |
| 307 | public: |
| 308 | static RTSPServerWithREGISTERProxying* createNew(UsageEnvironment& env, Port ourPort = 554, |
| 309 | UserAuthenticationDatabase* authDatabase = NULL, |
| 310 | UserAuthenticationDatabase* authDatabaseForREGISTER = NULL, |
| 311 | unsigned reclamationSeconds = 65, |
| 312 | Boolean streamRTPOverTCP = False, |
| 313 | int verbosityLevelForProxying = 0, |
| 314 | char const* backEndUsername = NULL, |
| 315 | char const* backEndPassword = NULL); |
| 316 | |
| 317 | protected: |
| 318 | RTSPServerWithREGISTERProxying(UsageEnvironment& env, int ourSocket, Port ourPort, |
| 319 | UserAuthenticationDatabase* authDatabase, UserAuthenticationDatabase* authDatabaseForREGISTER, |
| 320 | unsigned reclamationSeconds, |
| 321 | Boolean streamRTPOverTCP, int verbosityLevelForProxying, |
| 322 | char const* backEndUsername, char const* backEndPassword); |
| 323 | // called only by createNew(); |
| 324 | virtual ~RTSPServerWithREGISTERProxying(); |
| 325 | |
| 326 | protected: // redefined virtual functions |
| 327 | virtual char const* allowedCommandNames(); |
| 328 | virtual Boolean weImplementREGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/, |
| 329 | char const* proxyURLSuffix, char*& responseStr); |
| 330 | virtual void implementCmd_REGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/, |
| 331 | char const* url, char const* urlSuffix, int socketToRemoteServer, |
| 332 | Boolean deliverViaTCP, char const* proxyURLSuffix); |
| 333 | virtual UserAuthenticationDatabase* getAuthenticationDatabaseForCommand(char const* cmdName); |
| 334 | |
| 335 | private: |
| 336 | Boolean fStreamRTPOverTCP; |
| 337 | int fVerbosityLevelForProxying; |
| 338 | unsigned fRegisteredProxyCounter; |
| 339 | char* fAllowedCommandNames; |
| 340 | UserAuthenticationDatabase* fAuthDBForREGISTER; |
| 341 | char* fBackEndUsername; |
| 342 | char* fBackEndPassword; |
| 343 | }; |
| 344 | |
| 345 | |
| 346 | // A special version of "parseTransportHeader()", used just for parsing the "Transport:" header |
| 347 | // in an incoming "REGISTER" command: |
| 348 | void (char const* buf, // in |
| 349 | Boolean &reuseConnection, // out |
| 350 | Boolean& deliverViaTCP, // out |
| 351 | char*& proxyURLSuffix); // out |
| 352 | |
| 353 | #endif |
| 354 | |