Console: Multiple network console server support
g0dil [Fri, 30 May 2008 14:45:10 +0000 (14:45 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@863 270642c3-0616-0410-b53a-bc976706d245

Console/Server.cc
Console/Server.cci
Console/Server.hh
Console/Server.ih

index 248e07b..d990bb3 100644 (file)
@@ -83,27 +83,18 @@ senf::console::Server::start(senf::INet6SocketAddress const & address)
     return server;
 }
 
-prefix_ boost::scoped_ptr<senf::console::Server> & senf::console::Server::instancePtr()
-{
-    // We cannot make 'instance' a global or class-static variable, since it will then be destructed
-    // at an unknown time which may fail if the scheduler or the file-handle pool allocators have
-    // already been destructed.
-    static boost::scoped_ptr<senf::console::Server> instance;
-    return instance;
-}
-
 prefix_ senf::console::Server & senf::console::Server::start(ServerHandle handle)
 {
     // Uah .... ensure the scheduler is created before the instance pointer so it get's destructed
     // AFTER it.
     (void) senf::Scheduler::instance();
-    SENF_ASSERT( ! instancePtr() );
-    instancePtr().reset(new Server(handle));
-    return * instancePtr();
+    boost::intrusive_ptr<Server> p (new Server(handle));
+    detail::ServerManager::add(boost::intrusive_ptr<Server>(p));
+    return *p;
 }
 
 prefix_ senf::console::Server::Server(ServerHandle handle)
-    : handle_ (handle), mode_ (Automatic)
+    : handle_ (handle), root_ (root().thisptr()), mode_ (Automatic)
 {
     Scheduler::instance().add( handle_, senf::membind(&Server::newClient, this) );
 }
@@ -238,6 +229,7 @@ prefix_ senf::console::Client::Client(Server & server, ClientHandle handle)
       name_ (server.name()), reader_ (), mode_ (server.mode())
 {
     handle_.facet<senf::TCPSocketProtocol>().nodelay();
+    executor_.chroot(root());
     switch (mode_) {
     case Server::Interactive :
         setInteractive();
index 405347c..e4601f6 100644 (file)
 ///////////////////////////////cci.p///////////////////////////////////////
 
 ///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::ServerManager
+
+prefix_ void senf::console::detail::ServerManager::add(ptr server)
+{
+    instance().servers_.insert(server);
+}
+
+prefix_ void senf::console::detail::ServerManager::remove(ptr server)
+{
+    instance().servers_.erase(instance().servers_.find(server));
+}
+
+///////////////////////////////////////////////////////////////////////////
 // senf::console::detail::NonblockingSocketSink
 
 prefix_ senf::console::detail::NonblockingSocketSink::NonblockingSocketSink(Client & client)
@@ -58,6 +71,12 @@ prefix_ std::string const & senf::console::Server::name()
     return name_;
 }
 
+prefix_ senf::console::DirectoryNode & senf::console::Server::root()
+    const
+{
+    return *root_;
+}
+
 prefix_ senf::console::Server & senf::console::Server::root(DirectoryNode & root)
 {
     root_ = root.thisptr();
@@ -79,7 +98,7 @@ prefix_ senf::console::Server::Mode senf::console::Server::mode()
 prefix_ void senf::console::Server::stop()
 {
     // commit suicide
-    instancePtr().reset(0);
+    detail::ServerManager::remove(boost::intrusive_ptr<Server>(this));
 }
 
 ///////////////////////////////////////////////////////////////////////////
index 52925d0..1756e14 100644 (file)
@@ -56,7 +56,6 @@ namespace console {
 
         This class provides an interactive console TCP server.
 
-        \todo Add interactivity detection using timeout
         \idea To support blocking commands, we could give the Client 'suspend()' and 'resume()'
             members. suspend() would probably throw some kind of exception to transfer control back
             to the Client instance. on resume(), the command would be called again, maybe setting
@@ -64,15 +63,11 @@ namespace console {
             our own little host-name cache. When the name is not found, we ask the resolver to
             resolve it and call 'resume' when the name is found. Since it is in the cache now, the
             command will now complete.
-        
-        \implementation We do \e not provide an \c instance() member so we can easily later extend
-            the server to allow registering more than one instance, e.g. with each instance on a
-            differently firewalled port and with different security restrictions.
-        
+
         \ingroup console_access
       */
     class Server
-        : boost::noncopyable
+        : public senf::intrusive_refcount
     {
         SENF_LOG_CLASS_AREA();
         SENF_LOG_DEFAULT_LEVEL( senf::log::NOTICE );
@@ -124,16 +119,15 @@ namespace console {
                                              opened. */
 
         void stop();                    ///< Stop the server
-                                        /**< All clients will be closed */
+                                        /**< All clients will be closed 
+                                             \warning The Server instance itself will be deleted */
 
-        
     protected:
 
     private:
         Server(ServerHandle handle);
 
         static Server & start(ServerHandle handle);
-        static boost::scoped_ptr<Server> & instancePtr();
 
         void newClient(Scheduler::EventId event);
         void removeClient(Client & client);
index d31f713..b107867 100644 (file)
@@ -29,6 +29,7 @@
 // Custom includes
 #include <boost/iostreams/concepts.hpp>
 #include <boost/iostreams/stream.hpp>
+#include <set>
 
 ///////////////////////////////ih.p////////////////////////////////////////
 
@@ -40,6 +41,24 @@ namespace console {
 
 namespace detail {
 
+    class ServerManager
+        : public senf::singleton<ServerManager>
+    {
+    public:
+        typedef boost::intrusive_ptr<Server> ptr;
+
+    protected:
+
+    private:
+        static void add(ptr server);
+        static void remove(ptr server);
+
+        typedef std::set<ptr> Servers;
+        Servers servers_;
+
+        friend class senf::console::Server;
+    };
+
     /** \brief Internal: Nonblocking boost::iostreams::sink
 
         The sink discards data if the output socket would.