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 | |