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 // Implementation of functionality related to the "REGISTER" and "DEREGISTER" commands
20
21 #include "RTSPServer.hh"
22 #include "RTSPCommon.hh"
23 #include "RTSPRegisterSender.hh"
24 #include "ProxyServerMediaSession.hh"
25 #include "GroupsockHelper.hh"
26
27 ////////// Implementation of "RTSPServer::registerStream()": //////////
28
29 static void rtspRegisterResponseHandler(RTSPClient* rtspClient, int resultCode, char* resultString); // forward
30
31 // A class that represents the state of a "REGISTER" request in progress:
32 class RegisterRequestRecord: public RTSPRegisterSender {
33 public:
RegisterRequestRecord(RTSPServer & ourServer,unsigned requestId,char const * remoteClientNameOrAddress,portNumBits remoteClientPortNum,char const * rtspURLToRegister,RTSPServer::responseHandlerForREGISTER * responseHandler,Authenticator * authenticator,Boolean requestStreamingViaTCP,char const * proxyURLSuffix)34 RegisterRequestRecord(RTSPServer& ourServer, unsigned requestId,
35 char const* remoteClientNameOrAddress, portNumBits remoteClientPortNum, char const* rtspURLToRegister,
36 RTSPServer::responseHandlerForREGISTER* responseHandler, Authenticator* authenticator,
37 Boolean requestStreamingViaTCP, char const* proxyURLSuffix)
38 : RTSPRegisterSender(ourServer.envir(), remoteClientNameOrAddress, remoteClientPortNum, rtspURLToRegister,
39 rtspRegisterResponseHandler, authenticator,
40 requestStreamingViaTCP, proxyURLSuffix, True/*reuseConnection*/,
41 #ifdef DEBUG
42 1/*verbosityLevel*/,
43 #else
44 0/*verbosityLevel*/,
45 #endif
46 NULL),
47 fOurServer(ourServer), fRequestId(requestId), fResponseHandler(responseHandler) {
48 // Add ourself to our server's 'pending REGISTER or DEREGISTER requests' table:
49 ourServer.fPendingRegisterOrDeregisterRequests->Add((char const*)this, this);
50 }
51
~RegisterRequestRecord()52 virtual ~RegisterRequestRecord() {
53 // Remove ourself from the server's 'pending REGISTER or DEREGISTER requests' hash table before we go:
54 fOurServer.fPendingRegisterOrDeregisterRequests->Remove((char const*)this);
55 }
56
handleResponse(int resultCode,char * resultString)57 void handleResponse(int resultCode, char* resultString) {
58 if (resultCode == 0) {
59 // The "REGISTER" request succeeded, so use the still-open RTSP socket to await incoming commands from the remote endpoint:
60 int sock;
61 struct sockaddr_storage remoteAddress;
62
63 grabConnection(sock, remoteAddress);
64 if (sock >= 0) {
65 increaseSendBufferTo(envir(), sock, 50*1024); // in anticipation of streaming over it
66 (void)fOurServer.createNewClientConnection(sock, remoteAddress);
67 }
68 }
69
70 if (fResponseHandler != NULL) {
71 // Call our (REGISTER-specific) response handler now:
72 (*fResponseHandler)(&fOurServer, fRequestId, resultCode, resultString);
73 } else {
74 // We need to delete[] "resultString" before we leave:
75 delete[] resultString;
76 }
77
78 // We're completely done with the REGISTER command now, so delete ourself now:
79 Medium::close(this);
80 }
81
82 private:
83 RTSPServer& fOurServer;
84 unsigned fRequestId;
85 RTSPServer::responseHandlerForREGISTER* fResponseHandler;
86 };
87
rtspRegisterResponseHandler(RTSPClient * rtspClient,int resultCode,char * resultString)88 static void rtspRegisterResponseHandler(RTSPClient* rtspClient, int resultCode, char* resultString) {
89 RegisterRequestRecord* registerRequestRecord = (RegisterRequestRecord*)rtspClient;
90
91 registerRequestRecord->handleResponse(resultCode, resultString);
92 }
93
registerStream(ServerMediaSession * serverMediaSession,char const * remoteClientNameOrAddress,portNumBits remoteClientPortNum,responseHandlerForREGISTER * responseHandler,char const * username,char const * password,Boolean receiveOurStreamViaTCP,char const * proxyURLSuffix)94 unsigned RTSPServer::registerStream(ServerMediaSession* serverMediaSession,
95 char const* remoteClientNameOrAddress, portNumBits remoteClientPortNum,
96 responseHandlerForREGISTER* responseHandler,
97 char const* username, char const* password,
98 Boolean receiveOurStreamViaTCP, char const* proxyURLSuffix) {
99 // Create a new "RegisterRequestRecord" that will send the "REGISTER" command.
100 // (This object will automatically get deleted after we get a response to the "REGISTER" command, or if we're deleted.)
101 Authenticator* authenticator = NULL;
102 if (username != NULL) {
103 if (password == NULL) password = "";
104 authenticator = new Authenticator(username, password);
105 }
106 unsigned requestId = ++fRegisterOrDeregisterRequestCounter;
107 char const* url = rtspURL(serverMediaSession);
108 new RegisterRequestRecord(*this, requestId,
109 remoteClientNameOrAddress, remoteClientPortNum, url,
110 responseHandler, authenticator,
111 receiveOurStreamViaTCP, proxyURLSuffix);
112
113 delete[] (char*)url; // we can do this here because it was copied to the "RegisterRequestRecord"
114 delete authenticator; // ditto
115 return requestId;
116 }
117
118 ////////// Implementation of "RTSPServer::deregisterStream()": //////////
119
120 static void rtspDeregisterResponseHandler(RTSPClient* rtspClient, int resultCode, char* resultString); // forward
121
122 // A class that represents the state of a "DEREGISTER" request in progress:
123 class DeregisterRequestRecord: public RTSPDeregisterSender {
124 public:
DeregisterRequestRecord(RTSPServer & ourServer,unsigned requestId,char const * remoteClientNameOrAddress,portNumBits remoteClientPortNum,char const * rtspURLToDeregister,RTSPServer::responseHandlerForDEREGISTER * responseHandler,Authenticator * authenticator,char const * proxyURLSuffix)125 DeregisterRequestRecord(RTSPServer& ourServer, unsigned requestId,
126 char const* remoteClientNameOrAddress, portNumBits remoteClientPortNum, char const* rtspURLToDeregister,
127 RTSPServer::responseHandlerForDEREGISTER* responseHandler, Authenticator* authenticator,
128 char const* proxyURLSuffix)
129 : RTSPDeregisterSender(ourServer.envir(), remoteClientNameOrAddress, remoteClientPortNum, rtspURLToDeregister,
130 rtspDeregisterResponseHandler, authenticator, proxyURLSuffix,
131 #ifdef DEBUG
132 1/*verbosityLevel*/,
133 #else
134 0/*verbosityLevel*/,
135 #endif
136 NULL),
137 fOurServer(ourServer), fRequestId(requestId), fResponseHandler(responseHandler) {
138 // Add ourself to our server's 'pending REGISTER or DEREGISTER requests' table:
139 ourServer.fPendingRegisterOrDeregisterRequests->Add((char const*)this, this);
140 }
141
~DeregisterRequestRecord()142 virtual ~DeregisterRequestRecord() {
143 // Remove ourself from the server's 'pending REGISTER or DEREGISTER requests' hash table before we go:
144 fOurServer.fPendingRegisterOrDeregisterRequests->Remove((char const*)this);
145 }
146
handleResponse(int resultCode,char * resultString)147 void handleResponse(int resultCode, char* resultString) {
148 if (fResponseHandler != NULL) {
149 // Call our (DEREGISTER-specific) response handler now:
150 (*fResponseHandler)(&fOurServer, fRequestId, resultCode, resultString);
151 } else {
152 // We need to delete[] "resultString" before we leave:
153 delete[] resultString;
154 }
155
156 // We're completely done with the DEREGISTER command now, so delete ourself now:
157 Medium::close(this);
158 }
159
160 private:
161 RTSPServer& fOurServer;
162 unsigned fRequestId;
163 RTSPServer::responseHandlerForDEREGISTER* fResponseHandler;
164 };
165
rtspDeregisterResponseHandler(RTSPClient * rtspClient,int resultCode,char * resultString)166 static void rtspDeregisterResponseHandler(RTSPClient* rtspClient, int resultCode, char* resultString) {
167 DeregisterRequestRecord* deregisterRequestRecord = (DeregisterRequestRecord*)rtspClient;
168
169 deregisterRequestRecord->handleResponse(resultCode, resultString);
170 }
171
deregisterStream(ServerMediaSession * serverMediaSession,char const * remoteClientNameOrAddress,portNumBits remoteClientPortNum,responseHandlerForDEREGISTER * responseHandler,char const * username,char const * password,char const * proxyURLSuffix)172 unsigned RTSPServer::deregisterStream(ServerMediaSession* serverMediaSession,
173 char const* remoteClientNameOrAddress, portNumBits remoteClientPortNum,
174 responseHandlerForDEREGISTER* responseHandler,
175 char const* username, char const* password,
176 char const* proxyURLSuffix) {
177 // Create a new "DeregisterRequestRecord" that will send the "DEREGISTER" command.
178 // (This object will automatically get deleted after we get a response to the "DEREGISTER" command, or if we're deleted.)
179 Authenticator* authenticator = NULL;
180 if (username != NULL) {
181 if (password == NULL) password = "";
182 authenticator = new Authenticator(username, password);
183 }
184 unsigned requestId = ++fRegisterOrDeregisterRequestCounter;
185 char const* url = rtspURL(serverMediaSession);
186 new DeregisterRequestRecord(*this, requestId,
187 remoteClientNameOrAddress, remoteClientPortNum, url,
188 responseHandler, authenticator,
189 proxyURLSuffix);
190
191 delete[] (char*)url; // we can do this here because it was copied to the "DeregisterRequestRecord"
192 delete authenticator; // ditto
193 return requestId;
194 }
195
weImplementREGISTER(char const *,char const *,char * & responseStr)196 Boolean RTSPServer::weImplementREGISTER(char const* /*cmd*//*"REGISTER" or "DEREGISTER"*/,
197 char const* /*proxyURLSuffix*/, char*& responseStr) {
198 // By default, servers do not implement our custom "REGISTER"/"DEREGISTER" commands:
199 responseStr = NULL;
200 return False;
201 }
202
implementCmd_REGISTER(char const *,char const *,char const *,int,Boolean,char const *)203 void RTSPServer::implementCmd_REGISTER(char const* /*cmd*//*"REGISTER" or "DEREGISTER"*/,
204 char const* /*url*/, char const* /*urlSuffix*/, int /*socketToRemoteServer*/,
205 Boolean /*deliverViaTCP*/, char const* /*proxyURLSuffix*/) {
206 // By default, this function is a 'noop'
207 }
208
209 // Special mechanism for handling our custom "REGISTER" command:
210
211 RTSPServer::RTSPClientConnection::ParamsForREGISTER
ParamsForREGISTER(char const * cmd,RTSPServer::RTSPClientConnection * ourConnection,char const * url,char const * urlSuffix,Boolean reuseConnection,Boolean deliverViaTCP,char const * proxyURLSuffix)212 ::ParamsForREGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/,
213 RTSPServer::RTSPClientConnection* ourConnection, char const* url, char const* urlSuffix,
214 Boolean reuseConnection, Boolean deliverViaTCP, char const* proxyURLSuffix)
215 : fCmd(strDup(cmd)), fOurConnection(ourConnection), fURL(strDup(url)), fURLSuffix(strDup(urlSuffix)),
216 fReuseConnection(reuseConnection), fDeliverViaTCP(deliverViaTCP), fProxyURLSuffix(strDup(proxyURLSuffix)) {
217 }
218
~ParamsForREGISTER()219 RTSPServer::RTSPClientConnection::ParamsForREGISTER::~ParamsForREGISTER() {
220 delete[] (char*)fCmd; delete[] fURL; delete[] fURLSuffix; delete[] fProxyURLSuffix;
221 }
222
223 #define DELAY_USECS_AFTER_REGISTER_RESPONSE 100000 /*100ms*/
224
225 void RTSPServer
handleCmd_REGISTER(char const * cmd,char const * url,char const * urlSuffix,char const * fullRequestStr,Boolean reuseConnection,Boolean deliverViaTCP,char const * proxyURLSuffix)226 ::RTSPClientConnection::handleCmd_REGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/,
227 char const* url, char const* urlSuffix, char const* fullRequestStr,
228 Boolean reuseConnection, Boolean deliverViaTCP, char const* proxyURLSuffix) {
229 char* responseStr;
230 if (fOurRTSPServer.weImplementREGISTER(cmd, proxyURLSuffix, responseStr)) {
231 // The "REGISTER"/"DEREGISTER" command - if we implement it - may require access control:
232 if (!authenticationOK(cmd, urlSuffix, fullRequestStr)) return;
233
234 // We implement the "REGISTER"/"DEREGISTER" command by first replying to it, then actually
235 // handling it (in a separate event-loop task, that will get called after the reply has
236 // been done).
237 // Hack: If we're going to reuse the command's connection for subsequent RTSP commands, then we
238 // delay the actual handling of the command slightly, to make it less likely that the first
239 // subsequent RTSP command (e.g., "DESCRIBE") will end up in the client's reponse buffer before
240 // the socket (at the far end) gets reused for RTSP command handling.
241 setRTSPResponse(responseStr == NULL ? "200 OK" : responseStr);
242 delete[] responseStr;
243
244 ParamsForREGISTER* registerParams = new ParamsForREGISTER(cmd, this, url, urlSuffix, reuseConnection, deliverViaTCP, proxyURLSuffix);
245 envir().taskScheduler().scheduleDelayedTask(reuseConnection ? DELAY_USECS_AFTER_REGISTER_RESPONSE : 0,
246 (TaskFunc*)continueHandlingREGISTER, registerParams);
247 } else if (responseStr != NULL) {
248 setRTSPResponse(responseStr);
249 delete[] responseStr;
250 } else {
251 handleCmd_notSupported();
252 }
253 }
254
255 // A special version of "parseTransportHeader()", used just for parsing the "Transport:" header in an incoming "REGISTER" command:
parseTransportHeaderForREGISTER(char const * buf,Boolean & reuseConnection,Boolean & deliverViaTCP,char * & proxyURLSuffix)256 void parseTransportHeaderForREGISTER(char const* buf,
257 Boolean &reuseConnection,
258 Boolean& deliverViaTCP,
259 char*& proxyURLSuffix) {
260 // Initialize the result parameters to default values:
261 reuseConnection = False;
262 deliverViaTCP = False;
263 proxyURLSuffix = NULL;
264
265 // First, find "Transport:"
266 while (1) {
267 if (*buf == '\0') return; // not found
268 if (*buf == '\r' && *(buf+1) == '\n' && *(buf+2) == '\r') return; // end of the headers => not found
269 if (_strncasecmp(buf, "Transport:", 10) == 0) break;
270 ++buf;
271 }
272
273 // Then, run through each of the fields, looking for ones we handle:
274 char const* fields = buf + 10;
275 while (*fields == ' ') ++fields;
276 char* field = strDupSize(fields);
277 while (sscanf(fields, "%[^;\r\n]", field) == 1) {
278 if (strcmp(field, "reuse_connection") == 0) {
279 reuseConnection = True;
280 } else if (_strncasecmp(field, "preferred_delivery_protocol=udp", 31) == 0) {
281 deliverViaTCP = False;
282 } else if (_strncasecmp(field, "preferred_delivery_protocol=interleaved", 39) == 0) {
283 deliverViaTCP = True;
284 } else if (_strncasecmp(field, "proxy_url_suffix=", 17) == 0) {
285 delete[] proxyURLSuffix;
286 proxyURLSuffix = strDup(field+17);
287 }
288
289 fields += strlen(field);
290 while (*fields == ';' || *fields == ' ' || *fields == '\t') ++fields; // skip over separating ';' chars or whitespace
291 if (*fields == '\0' || *fields == '\r' || *fields == '\n') break;
292 }
293 delete[] field;
294 }
295
continueHandlingREGISTER(ParamsForREGISTER * params)296 void RTSPServer::RTSPClientConnection::continueHandlingREGISTER(ParamsForREGISTER* params) {
297 params->fOurConnection->continueHandlingREGISTER1(params);
298 }
299
continueHandlingREGISTER1(ParamsForREGISTER * params)300 void RTSPServer::RTSPClientConnection::continueHandlingREGISTER1(ParamsForREGISTER* params) {
301 // Reuse our socket if requested:
302 int socketNumToBackEndServer = params->fReuseConnection ? fClientOutputSocket : -1;
303
304 RTSPServer* ourServer = &fOurRTSPServer; // copy the pointer now, in case we "delete this" below
305
306 if (socketNumToBackEndServer >= 0) {
307 // Because our socket will no longer be used by the server to handle incoming requests, we can now delete this
308 // "RTSPClientConnection" object. We do this now, in case the "implementCmd_REGISTER()" call below would also end up
309 // deleting this.
310 fClientInputSocket = fClientOutputSocket = -1; // so the socket doesn't get closed when we get deleted
311 delete this;
312 }
313
314 ourServer->implementCmd_REGISTER(params->fCmd,
315 params->fURL, params->fURLSuffix, socketNumToBackEndServer,
316 params->fDeliverViaTCP, params->fProxyURLSuffix);
317 delete params;
318 }
319
320
321 ///////// RTSPServerWithREGISTERProxying implementation /////////
322
323 RTSPServerWithREGISTERProxying* RTSPServerWithREGISTERProxying
createNew(UsageEnvironment & env,Port ourPort,UserAuthenticationDatabase * authDatabase,UserAuthenticationDatabase * authDatabaseForREGISTER,unsigned reclamationSeconds,Boolean streamRTPOverTCP,int verbosityLevelForProxying,char const * backEndUsername,char const * backEndPassword)324 ::createNew(UsageEnvironment& env, Port ourPort,
325 UserAuthenticationDatabase* authDatabase, UserAuthenticationDatabase* authDatabaseForREGISTER,
326 unsigned reclamationSeconds,
327 Boolean streamRTPOverTCP, int verbosityLevelForProxying,
328 char const* backEndUsername, char const* backEndPassword) {
329 int ourSocket = setUpOurSocket(env, ourPort);
330 if (ourSocket == -1) return NULL;
331
332 return new RTSPServerWithREGISTERProxying(env, ourSocket, ourPort,
333 authDatabase, authDatabaseForREGISTER,
334 reclamationSeconds,
335 streamRTPOverTCP, verbosityLevelForProxying,
336 backEndUsername, backEndPassword);
337 }
338
339 RTSPServerWithREGISTERProxying
RTSPServerWithREGISTERProxying(UsageEnvironment & env,int ourSocket,Port ourPort,UserAuthenticationDatabase * authDatabase,UserAuthenticationDatabase * authDatabaseForREGISTER,unsigned reclamationSeconds,Boolean streamRTPOverTCP,int verbosityLevelForProxying,char const * backEndUsername,char const * backEndPassword)340 ::RTSPServerWithREGISTERProxying(UsageEnvironment& env, int ourSocket, Port ourPort,
341 UserAuthenticationDatabase* authDatabase, UserAuthenticationDatabase* authDatabaseForREGISTER,
342 unsigned reclamationSeconds,
343 Boolean streamRTPOverTCP, int verbosityLevelForProxying,
344 char const* backEndUsername, char const* backEndPassword)
345 : RTSPServer(env, ourSocket, ourPort, authDatabase, reclamationSeconds),
346 fStreamRTPOverTCP(streamRTPOverTCP), fVerbosityLevelForProxying(verbosityLevelForProxying),
347 fRegisteredProxyCounter(0), fAllowedCommandNames(NULL), fAuthDBForREGISTER(authDatabaseForREGISTER),
348 fBackEndUsername(strDup(backEndUsername)), fBackEndPassword(strDup(backEndPassword)) {
349 }
350
~RTSPServerWithREGISTERProxying()351 RTSPServerWithREGISTERProxying::~RTSPServerWithREGISTERProxying() {
352 delete[] fAllowedCommandNames;
353 delete[] fBackEndUsername; delete[] fBackEndPassword;
354 }
355
allowedCommandNames()356 char const* RTSPServerWithREGISTERProxying::allowedCommandNames() {
357 if (fAllowedCommandNames == NULL) {
358 char const* baseAllowedCommandNames = RTSPServer::allowedCommandNames();
359 char const* newAllowedCommandName = ", REGISTER, DEREGISTER";
360 fAllowedCommandNames = new char[strlen(baseAllowedCommandNames) + strlen(newAllowedCommandName) + 1/* for '\0' */];
361 sprintf(fAllowedCommandNames, "%s%s", baseAllowedCommandNames, newAllowedCommandName);
362 }
363 return fAllowedCommandNames;
364 }
365
366 Boolean RTSPServerWithREGISTERProxying
weImplementREGISTER(char const * cmd,char const * proxyURLSuffix,char * & responseStr)367 ::weImplementREGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/,
368 char const* proxyURLSuffix, char*& responseStr) {
369 // First, check whether we have already proxied a stream as "proxyURLSuffix":
370 if (proxyURLSuffix != NULL) {
371 ServerMediaSession* sms = lookupServerMediaSession(proxyURLSuffix);
372 if ((strcmp(cmd, "REGISTER") == 0 && sms != NULL) ||
373 (strcmp(cmd, "DEREGISTER") == 0 && sms == NULL)) {
374 responseStr = strDup("451 Invalid parameter");
375 return False;
376 }
377 }
378
379 // Otherwise, we will implement it:
380 responseStr = NULL;
381 return True;
382 }
383
384 void RTSPServerWithREGISTERProxying
implementCmd_REGISTER(char const * cmd,char const * url,char const *,int socketToRemoteServer,Boolean deliverViaTCP,char const * proxyURLSuffix)385 ::implementCmd_REGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/,
386 char const* url, char const* /*urlSuffix*/, int socketToRemoteServer,
387 Boolean deliverViaTCP, char const* proxyURLSuffix) {
388 // Continue setting up proxying for the specified URL.
389 // By default:
390 // - We use "registeredProxyStream-N" as the (front-end) stream name (ignoring the back-end stream's 'urlSuffix'),
391 // unless "proxyURLSuffix" is non-NULL (in which case we use that)
392 // - There is no 'username' and 'password' for the back-end stream. (Thus, access-controlled back-end streams will fail.)
393 // - If "fStreamRTPOverTCP" is True, then we request delivery over TCP, regardless of the value of "deliverViaTCP".
394 // (Otherwise, if "fStreamRTPOverTCP" is False, we use the value of "deliverViaTCP" to decide this.)
395 // To change this default behavior, you will need to subclass "RTSPServerWithREGISTERProxying", and reimplement this function.
396
397 char const* proxyStreamName;
398 char proxyStreamNameBuf[100];
399 if (proxyURLSuffix == NULL) {
400 sprintf(proxyStreamNameBuf, "registeredProxyStream-%u", ++fRegisteredProxyCounter);
401 proxyStreamName = proxyStreamNameBuf;
402 } else {
403 proxyStreamName = proxyURLSuffix;
404 }
405
406 if (strcmp(cmd, "REGISTER") == 0) {
407 if (fStreamRTPOverTCP) deliverViaTCP = True;
408 portNumBits tunnelOverHTTPPortNum = deliverViaTCP ? (portNumBits)(~0) : 0;
409 // We don't support streaming from the back-end via RTSP/RTP/RTCP-over-HTTP; only via RTP/RTCP-over-TCP or RTP/RTCP-over-UDP
410
411 ServerMediaSession* sms
412 = ProxyServerMediaSession::createNew(envir(), this, url, proxyStreamName,
413 fBackEndUsername, fBackEndPassword,
414 tunnelOverHTTPPortNum, fVerbosityLevelForProxying, socketToRemoteServer);
415 addServerMediaSession(sms);
416
417 // (Regardless of the verbosity level) announce the fact that we're proxying this new stream, and the URL to use to access it:
418 char* proxyStreamURL = rtspURL(sms);
419 envir() << "Proxying the registered back-end stream \"" << url << "\".\n";
420 envir() << "\tPlay this stream using the URL: " << proxyStreamURL << "\n";
421 delete[] proxyStreamURL;
422 } else { // "DEREGISTER"
423 deleteServerMediaSession(lookupServerMediaSession(proxyStreamName));
424 }
425 }
426
getAuthenticationDatabaseForCommand(char const * cmdName)427 UserAuthenticationDatabase* RTSPServerWithREGISTERProxying::getAuthenticationDatabaseForCommand(char const* cmdName) {
428 if (strcmp(cmdName, "REGISTER") == 0) return fAuthDBForREGISTER;
429
430 return RTSPServer::getAuthenticationDatabaseForCommand(cmdName);
431 }
432