X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Console%2FServer.hh;h=59111e63970543f0a124a1b81393421ade5a24bc;hb=9cda1b12a3e68538ea8157ca96810f0423123a70;hp=09bfbaf224f811f3a45c8093f58517ef52ff10e6;hpb=4fc732480d3ba33ac2589caece3b04224e51d32b;p=senf.git diff --git a/Console/Server.hh b/Console/Server.hh index 09bfbaf..59111e6 100644 --- a/Console/Server.hh +++ b/Console/Server.hh @@ -27,21 +27,143 @@ #define HH_Server_ 1 // Custom includes +#include +#include +#include +#include +#include "../Utils/intrusive_refcount.hh" +#include "../Socket/Protocols/INet/TCPSocketHandle.hh" +#include "../Socket/ServerSocketHandle.hh" +#include "../Scheduler/Scheduler.hh" +#include "../Scheduler/ReadHelper.hh" +#include "Parse.hh" +#include "Executor.hh" #include "../Socket/Protocols/INet/INetAddressing.hh" +#include "../Utils/Logger.hh" //#include "Server.mpp" +#include "Server.ih" ///////////////////////////////hh.p//////////////////////////////////////// namespace senf { namespace console { - void start(senf::INet4SocketAddress const & address); - void start(senf::INet6SocketAddress const & address); + class Client; + + /** \brief Interactive console server + + This class provides an interactive console TCP server. + + \todo Add readline support + \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 + some flag or something. Example for use: Host name resolution: Here we can just built + 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. + */ + class Server + : boost::noncopyable + { + SENF_LOG_CLASS_AREA(); + SENF_LOG_DEFAULT_LEVEL( senf::log::NOTICE ); + public: + /////////////////////////////////////////////////////////////////////////// + // Types + + typedef senf::ServerSocketHandle< + senf::MakeSocketPolicy< senf::TCPv4SocketProtocol::Policy, + senf::UnspecifiedAddressingPolicy>::policy > ServerHandle; + + ~Server(); + + static Server & start(senf::INet4SocketAddress const & address); + ///< Start server on given IPv4 address/port + static Server & start(senf::INet6SocketAddress const & address); + ///< Start server on given IPv6 address/port + void name(std::string const & name); ///< Set server name + /**< This information is used in the prompt string. */ + + protected: + + private: + Server(ServerHandle handle); + + static Server & start(ServerHandle handle); + static boost::scoped_ptr & instancePtr(); + + void newClient(Scheduler::EventId event); + void removeClient(Client & client); + + ServerHandle handle_; + + typedef std::set< boost::intrusive_ptr > Clients; + Clients clients_; + std::string name_; + + friend class Client; + }; + + /** \brief Server client instance + + Whenever a new client connects, a new instance of this class is created. This class shows a + command prompt, receives the commands, parses them and then passes (using a CommandParser) + and passes the commands to an Executor instance. + + \fixme Fix Client::clientData implementation + \fixme Don't register a new ReadHelper every round + */ + class Client + : public senf::intrusive_refcount, + private boost::base_from_member< detail::NonblockingSocketOStream >, + public senf::log::IOStreamTarget + { + typedef boost::base_from_member< detail::NonblockingSocketOStream > out_t; + + SENF_LOG_CLASS_AREA(); + SENF_LOG_DEFAULT_LEVEL( senf::log::NOTICE ); + public: + typedef Server::ServerHandle::ClientSocketHandle ClientHandle; + + ~Client(); + + void stopClient(); ///< Stop the client + /**< This will close the client socket. */ + + protected: + + private: + Client(Server & server, ClientHandle handle, std::string const & name); + + void clientData(ReadHelper::ptr helper); + void showPrompt(); + + virtual void v_write(boost::posix_time::ptime timestamp, std::string const & stream, + std::string const & area, unsigned level, + std::string const & message); + + Server & server_; + ClientHandle handle_; + std::string tail_; + CommandParser parser_; + Executor executor_; + std::string name_; + unsigned promptLen_; + std::string lastCommand_; + + friend class Server; + }; }} ///////////////////////////////hh.e//////////////////////////////////////// -//#include "Server.cci" +#include "Server.cci" //#include "Server.ct" //#include "Server.cti" #endif