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