liveMedia/include/RTSPServer.hh

Go to the documentation of this file.
00001 /**********
00002 This library is free software; you can redistribute it and/or modify it under
00003 the terms of the GNU Lesser General Public License as published by the
00004 Free Software Foundation; either version 2.1 of the License, or (at your
00005 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
00006 
00007 This library is distributed in the hope that it will be useful, but WITHOUT
00008 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00009 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
00010 more details.
00011 
00012 You should have received a copy of the GNU Lesser General Public License
00013 along with this library; if not, write to the Free Software Foundation, Inc.,
00014 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
00015 **********/
00016 // "liveMedia"
00017 // Copyright (c) 1996-2013 Live Networks, Inc.  All rights reserved.
00018 // A RTSP server
00019 // C++ header
00020 
00021 #ifndef _RTSP_SERVER_HH
00022 #define _RTSP_SERVER_HH
00023 
00024 #ifndef _SERVER_MEDIA_SESSION_HH
00025 #include "ServerMediaSession.hh"
00026 #endif
00027 #ifndef _NET_ADDRESS_HH
00028 #include <NetAddress.hh>
00029 #endif
00030 #ifndef _DIGEST_AUTHENTICATION_HH
00031 #include "DigestAuthentication.hh"
00032 #endif
00033 
00034 // A data structure used for optional user/password authentication:
00035 
00036 class UserAuthenticationDatabase {
00037 public:
00038   UserAuthenticationDatabase(char const* realm = NULL,
00039                              Boolean passwordsAreMD5 = False);
00040     // If "passwordsAreMD5" is True, then each password stored into, or removed from,
00041     // the database is actually the value computed
00042     // by md5(<username>:<realm>:<actual-password>)
00043   virtual ~UserAuthenticationDatabase();
00044 
00045   virtual void addUserRecord(char const* username, char const* password);
00046   virtual void removeUserRecord(char const* username);
00047 
00048   virtual char const* lookupPassword(char const* username);
00049       // returns NULL if the user name was not present
00050 
00051   char const* realm() { return fRealm; }
00052   Boolean passwordsAreMD5() { return fPasswordsAreMD5; }
00053 
00054 protected:
00055   HashTable* fTable;
00056   char* fRealm;
00057   Boolean fPasswordsAreMD5;
00058 };
00059 
00060 #ifndef RTSP_BUFFER_SIZE
00061 #define RTSP_BUFFER_SIZE 10000 // for incoming requests, and outgoing responses
00062 #endif
00063 
00064 class RTSPServer: public Medium {
00065 public:
00066   static RTSPServer* createNew(UsageEnvironment& env, Port ourPort = 554,
00067                                UserAuthenticationDatabase* authDatabase = NULL,
00068                                unsigned reclamationTestSeconds = 65);
00069       // If ourPort.num() == 0, we'll choose the port number
00070       // Note: The caller is responsible for reclaiming "authDatabase"
00071       // If "reclamationTestSeconds" > 0, then the "RTSPClientSession" state for
00072       //     each client will get reclaimed (and the corresponding RTP stream(s)
00073       //     torn down) if no RTSP commands - or RTCP "RR" packets - from the
00074       //     client are received in at least "reclamationTestSeconds" seconds.
00075 
00076   static Boolean lookupByName(UsageEnvironment& env, char const* name,
00077                               RTSPServer*& resultServer);
00078 
00079   void addServerMediaSession(ServerMediaSession* serverMediaSession);
00080 
00081   virtual ServerMediaSession* lookupServerMediaSession(char const* streamName);
00082 
00083   void removeServerMediaSession(ServerMediaSession* serverMediaSession);
00084       // Removes the "ServerMediaSession" object from our lookup table, so it will no longer be accessible by new RTSP clients.
00085       // (However, any *existing* RTSP client sessions that use this "ServerMediaSession" object will continue streaming.
00086       //  The "ServerMediaSession" object will not get deleted until all of these RTSP client sessions have closed.)
00087       // (To both delete the "ServerMediaSession" object *and* close all RTSP client sessions that use it,
00088       //  call "deleteServerMediaSession(serverMediaSession)" instead.)
00089   void removeServerMediaSession(char const* streamName);
00090      // ditto
00091 
00092   void closeAllClientSessionsForServerMediaSession(ServerMediaSession* serverMediaSession);
00093       // Closes (from the server) all RTSP client sessions that are currently using this "ServerMediaSession" object.
00094       // Note, however, that the "ServerMediaSession" object remains accessible by new RTSP clients.
00095   void closeAllClientSessionsForServerMediaSession(char const* streamName);
00096      // ditto
00097 
00098   void deleteServerMediaSession(ServerMediaSession* serverMediaSession);
00099       // Equivalent to:
00100       //     "closeAllClientSessionsForServerMediaSession(serverMediaSession); removeServerMediaSession(serverMediaSession);"
00101   void deleteServerMediaSession(char const* streamName);
00102       // Equivalent to:
00103       //     "closeAllClientSessionsForServerMediaSession(streamName); removeServerMediaSession(streamName);
00104 
00105   char* rtspURL(ServerMediaSession const* serverMediaSession, int clientSocket = -1) const;
00106       // returns a "rtsp://" URL that could be used to access the
00107       // specified session (which must already have been added to
00108       // us using "addServerMediaSession()".
00109       // This string is dynamically allocated; caller should delete[]
00110       // (If "clientSocket" is non-negative, then it is used (by calling "getsockname()") to determine
00111       //  the IP address to be used in the URL.)
00112   char* rtspURLPrefix(int clientSocket = -1) const;
00113       // like "rtspURL()", except that it returns just the common prefix used by
00114       // each session's "rtsp://" URL.
00115       // This string is dynamically allocated; caller should delete[]
00116 
00117   UserAuthenticationDatabase* setAuthenticationDatabase(UserAuthenticationDatabase* newDB);
00118       // Changes the server's authentication database to "newDB", returning a pointer to the old database (if there was one).
00119       // "newDB" may be NULL (you can use this to disable authentication at runtime, if desired).
00120 
00121   Boolean setUpTunnelingOverHTTP(Port httpPort);
00122       // (Attempts to) enable RTSP-over-HTTP tunneling on the specified port.
00123       // 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).
00124       // Note: RTSP-over-HTTP tunneling is described in http://developer.apple.com/quicktime/icefloe/dispatch028.html
00125   portNumBits httpServerPortNum() const; // in host byte order.  (Returns 0 if not present.)
00126 
00127 protected:
00128   RTSPServer(UsageEnvironment& env,
00129              int ourSocket, Port ourPort,
00130              UserAuthenticationDatabase* authDatabase,
00131              unsigned reclamationTestSeconds);
00132       // called only by createNew();
00133   virtual ~RTSPServer();
00134 
00135   static int setUpOurSocket(UsageEnvironment& env, Port& ourPort);
00136 
00137   virtual Boolean specialClientAccessCheck(int clientSocket, struct sockaddr_in& clientAddr,
00138                                            char const* urlSuffix);
00139       // a hook that allows subclassed servers to do server-specific access checking
00140       // on each client (e.g., based on client IP address), without using digest authentication.
00141   virtual Boolean specialClientUserAccessCheck(int clientSocket, struct sockaddr_in& clientAddr,
00142                                                char const* urlSuffix, char const *username);
00143       // another hook that allows subclassed servers to do server-specific access checking
00144       // - this time after normal digest authentication has already taken place (and would otherwise allow access).
00145       // (This test can only be used to further restrict access, not to grant additional access.)
00146 
00147 private: // redefined virtual functions
00148   virtual Boolean isRTSPServer() const;
00149 
00150 public: // should be protected, but some old compilers complain otherwise
00151   class RTSPClientSession; // forward
00152   // The state of a TCP connection used by a RTSP client:
00153   class RTSPClientConnection {
00154   public:
00155     RTSPClientConnection(RTSPServer& ourServer, int clientSocket, struct sockaddr_in clientAddr);
00156     virtual ~RTSPClientConnection();
00157   protected:
00158     friend class RTSPClientSession;
00159     // Make the handler functions for each command virtual, to allow subclasses to redefine them:
00160     virtual void handleCmd_OPTIONS();
00161     virtual void handleCmd_GET_PARAMETER(char const* fullRequestStr); // when operating on the entire server
00162     virtual void handleCmd_SET_PARAMETER(char const* fullRequestStr); // when operating on the entire server
00163     virtual void handleCmd_DESCRIBE(char const* urlPreSuffix, char const* urlSuffix,
00164                                     char const* fullRequestStr);
00165     virtual void handleCmd_bad();
00166     virtual void handleCmd_notSupported();
00167     virtual void handleCmd_notFound();
00168     virtual void handleCmd_sessionNotFound();
00169     virtual void handleCmd_unsupportedTransport();
00170     // Support for optional RTSP-over-HTTP tunneling:
00171     virtual Boolean parseHTTPRequestString(char* resultCmdName, unsigned resultCmdNameMaxSize,
00172                                            char* urlSuffix, unsigned urlSuffixMaxSize,
00173                                            char* sessionCookie, unsigned sessionCookieMaxSize,
00174                                            char* acceptStr, unsigned acceptStrMaxSize);
00175     virtual void handleHTTPCmd_notSupported();
00176     virtual void handleHTTPCmd_notFound();
00177     virtual void handleHTTPCmd_TunnelingGET(char const* sessionCookie);
00178     virtual Boolean handleHTTPCmd_TunnelingPOST(char const* sessionCookie, unsigned char const* extraData, unsigned extraDataSize);
00179     virtual void handleHTTPCmd_StreamingGET(char const* urlSuffix, char const* fullRequestStr);
00180   protected:
00181     UsageEnvironment& envir() { return fOurServer.envir(); }
00182     void resetRequestBuffer();
00183     void closeSockets();
00184     static void incomingRequestHandler(void*, int /*mask*/);
00185     void incomingRequestHandler1();
00186     static void handleAlternativeRequestByte(void*, u_int8_t requestByte);
00187     void handleAlternativeRequestByte1(u_int8_t requestByte);
00188     void handleRequestBytes(int newBytesRead);
00189     Boolean authenticationOK(char const* cmdName, char const* urlSuffix, char const* fullRequestStr);
00190     void changeClientInputSocket(int newSocketNum, unsigned char const* extraData, unsigned extraDataSize);
00191       // used to implement RTSP-over-HTTP tunneling
00192     // Shortcuts for setting up a RTSP response (prior to sending it):
00193     void setRTSPResponse(char const* responseStr);
00194     void setRTSPResponse(char const* responseStr, u_int32_t sessionId);
00195     void setRTSPResponse(char const* responseStr, char const* contentStr);
00196     void setRTSPResponse(char const* responseStr, u_int32_t sessionId, char const* contentStr);
00197   protected:
00198     RTSPServer& fOurServer;
00199     Boolean fIsActive;
00200     int fClientInputSocket, fClientOutputSocket;
00201     struct sockaddr_in fClientAddr;
00202     unsigned char fRequestBuffer[RTSP_BUFFER_SIZE];
00203     unsigned fRequestBytesAlreadySeen, fRequestBufferBytesLeft;
00204     unsigned char* fLastCRLF;
00205     unsigned char fResponseBuffer[RTSP_BUFFER_SIZE];
00206     unsigned fRecursionCount;
00207     char const* fCurrentCSeq;
00208     Authenticator fCurrentAuthenticator; // used if access control is needed
00209     char* fOurSessionCookie; // used for optional RTSP-over-HTTP tunneling
00210     unsigned fBase64RemainderCount; // used for optional RTSP-over-HTTP tunneling (possible values: 0,1,2,3)
00211   };
00212 
00213   // The state of an individual client session (using one or more sequential TCP connections) handled by a RTSP server:
00214   class RTSPClientSession {
00215   public:
00216     RTSPClientSession(RTSPServer& ourServer, u_int32_t sessionId);
00217     virtual ~RTSPClientSession();
00218   protected:
00219     friend class RTSPServer;
00220     friend class RTSPClientConnection;
00221     // Make the handler functions for each command virtual, to allow subclasses to redefine them:
00222     virtual void handleCmd_SETUP(RTSPClientConnection* ourClientConnection,
00223                                  char const* urlPreSuffix, char const* urlSuffix, char const* fullRequestStr);
00224     virtual void handleCmd_withinSession(RTSPClientConnection* ourClientConnection,
00225                                          char const* cmdName,
00226                                          char const* urlPreSuffix, char const* urlSuffix,
00227                                          char const* fullRequestStr);
00228     virtual void handleCmd_TEARDOWN(RTSPClientConnection* ourClientConnection,
00229                                     ServerMediaSubsession* subsession);
00230     virtual void handleCmd_PLAY(RTSPClientConnection* ourClientConnection,
00231                                 ServerMediaSubsession* subsession, char const* fullRequestStr);
00232     virtual void handleCmd_PAUSE(RTSPClientConnection* ourClientConnection,
00233                                  ServerMediaSubsession* subsession);
00234     virtual void handleCmd_GET_PARAMETER(RTSPClientConnection* ourClientConnection,
00235                                          ServerMediaSubsession* subsession, char const* fullRequestStr);
00236     virtual void handleCmd_SET_PARAMETER(RTSPClientConnection* ourClientConnection,
00237                                          ServerMediaSubsession* subsession, char const* fullRequestStr);
00238   protected:
00239     UsageEnvironment& envir() { return fOurServer.envir(); }
00240     void reclaimStreamStates();
00241     Boolean isMulticast() const { return fIsMulticast; }
00242     void noteLiveness();
00243     static void noteClientLiveness(RTSPClientSession* clientSession);
00244     static void livenessTimeoutTask(RTSPClientSession* clientSession);
00245   protected:
00246     RTSPServer& fOurServer;
00247     u_int32_t fOurSessionId;
00248     ServerMediaSession* fOurServerMediaSession;
00249     Boolean fIsMulticast, fStreamAfterSETUP;
00250     unsigned char fTCPStreamIdCount; // used for (optional) RTP/TCP
00251     Boolean usesTCPTransport() const { return fTCPStreamIdCount > 0; }
00252     TaskToken fLivenessCheckTask;
00253     unsigned fNumStreamStates;
00254     struct streamState {
00255       ServerMediaSubsession* subsession;
00256       void* streamToken;
00257     } * fStreamStates;
00258   };
00259 
00260 protected:
00261   // If you subclass "RTSPClientConnection", then you must also redefine this virtual function in order
00262   // to create new objects of your subclass:
00263   virtual RTSPClientConnection*
00264   createNewClientConnection(int clientSocket, struct sockaddr_in clientAddr);
00265 
00266   // If you subclass "RTSPClientSession", then you must also redefine this virtual function in order
00267   // to create new objects of your subclass:
00268   virtual RTSPClientSession*
00269   createNewClientSession(u_int32_t sessionId);
00270 
00271   // An iterator over our "ServerMediaSession" objects:
00272   class ServerMediaSessionIterator {
00273   public:
00274     ServerMediaSessionIterator(RTSPServer& server);
00275     virtual ~ServerMediaSessionIterator();
00276     ServerMediaSession* next();
00277   private:
00278     HashTable::Iterator* fOurIterator;
00279   };
00280 
00281 private:
00282   static void incomingConnectionHandlerRTSP(void*, int /*mask*/);
00283   void incomingConnectionHandlerRTSP1();
00284 
00285   static void incomingConnectionHandlerHTTP(void*, int /*mask*/);
00286   void incomingConnectionHandlerHTTP1();
00287 
00288   void incomingConnectionHandler(int serverSocket);
00289 
00290 private:
00291   friend class RTSPClientConnection;
00292   friend class RTSPClientSession;
00293   friend class ServerMediaSessionIterator;
00294   int fRTSPServerSocket;
00295   Port fRTSPServerPort;
00296   int fHTTPServerSocket; // for optional RTSP-over-HTTP tunneling
00297   Port fHTTPServerPort; // ditto
00298   HashTable* fServerMediaSessions; // maps 'stream name' strings to "ServerMediaSession" objects
00299   HashTable* fClientConnections; // the "ClientConnection" objects that we're using
00300   HashTable* fClientConnectionsForHTTPTunneling; // maps client-supplied 'session cookie' strings to "RTSPClientConnection"s
00301     // (used only for optional RTSP-over-HTTP tunneling)
00302   HashTable* fClientSessions; // maps 'session id' strings to "RTSPClientSession" objects
00303   UserAuthenticationDatabase* fAuthDB;
00304   unsigned fReclamationTestSeconds;
00305 };
00306 
00307 #endif

Generated on Mon Apr 29 13:28:01 2013 for live by  doxygen 1.5.2