1/**********
2This library is free software; you can redistribute it and/or modify it under
3the terms of the GNU Lesser General Public License as published by the
4Free Software Foundation; either version 3 of the License, or (at your
5option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
6
7This library is distributed in the hope that it will be useful, but WITHOUT
8ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
10more details.
11
12You should have received a copy of the GNU Lesser General Public License
13along with this library; if not, write to the Free Software Foundation, Inc.,
1451 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
31class RTSPServer: public GenericMediaServer {
32public:
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
100protected:
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
129private: // redefined virtual functions
130 virtual Boolean isRTSPServer() const;
131
132public: // 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* extraData, unsigned extraDataSize);
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* extraData, unsigned extraDataSize);
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
268protected: // 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
273protected:
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
278private:
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
286private:
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
306class RTSPServerWithREGISTERProxying: public RTSPServer {
307public:
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
317protected:
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
326protected: // 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
335private:
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:
348void parseTransportHeaderForREGISTER(char const* buf, // in
349 Boolean &reuseConnection, // out
350 Boolean& deliverViaTCP, // out
351 char*& proxyURLSuffix); // out
352
353#endif
354