Scheduler: Implement Timer helper
[senf.git] / Console / Server.hh
1 // $Id$
2 //
3 // Copyright (C) 2008 
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief Server public header */
25
26 #ifndef HH_Server_
27 #define HH_Server_ 1
28
29 // Custom includes
30 #include <set>
31 #include <boost/utility.hpp>
32 #include <boost/scoped_ptr.hpp>
33 #include <boost/shared_ptr.hpp>
34 #include "../Utils/intrusive_refcount.hh"
35 #include "../Socket/Protocols/INet/TCPSocketHandle.hh"
36 #include "../Socket/ServerSocketHandle.hh"
37 #include "../Scheduler/Scheduler.hh"
38 #include "../Scheduler/Binding.hh"
39 #include "../Scheduler/Timer.hh"
40 #include "../Scheduler/ReadHelper.hh"
41 #include "Parse.hh"
42 #include "Executor.hh"
43 #include "../Socket/Protocols/INet/INetAddressing.hh"
44 #include "../Utils/Logger.hh"
45
46 //#include "Server.mpp"
47 #include "Server.ih"
48 ///////////////////////////////hh.p////////////////////////////////////////
49
50 namespace senf {
51 namespace console {
52
53     class Client;
54
55     /** \brief Interactive console server
56
57         This class provides an interactive console TCP server.
58
59         \todo Add interactivity detection using timeout
60         \idea To support blocking commands, we could give the Client 'suspend()' and 'resume()'
61             members. suspend() would probably throw some kind of exception to transfer control back
62             to the Client instance. on resume(), the command would be called again, maybe setting
63             some flag or something. Example for use: Host name resolution: Here we can just built
64             our own little host-name cache. When the name is not found, we ask the resolver to
65             resolve it and call 'resume' when the name is found. Since it is in the cache now, the
66             command will now complete.
67         
68         \implementation We do \e not provide an \c instance() member so we can easily later extend
69             the server to allow registering more than one instance, e.g. with each instance on a
70             differently firewalled port and with different security restrictions.
71         
72         \ingroup console_access
73       */
74     class Server
75         : boost::noncopyable
76     {
77         SENF_LOG_CLASS_AREA();
78         SENF_LOG_DEFAULT_LEVEL( senf::log::NOTICE );
79     public:
80         ///////////////////////////////////////////////////////////////////////////
81         // Types
82         
83         typedef detail::ServerHandle ServerHandle;
84
85         enum Mode { Automatic, Interactive, Noninteractive };
86
87         ///////////////////////////////////////////////////////////////////////////
88
89         ~Server();
90
91         static Server & start(senf::INet4SocketAddress const & address);
92                                         ///< Start server on given IPv4 address/port
93         static Server & start(senf::INet6SocketAddress const & address);
94                                         ///< Start server on given IPv6 address/port
95
96         std::string const & name() const; ///< Get server name
97                                         /**< This information is used in the prompt string. */
98
99         Server & name(std::string const & name); ///< Set server name
100                                         /**< This information is used in the prompt string. */
101
102         DirectoryNode & root() const;   ///< Get root node
103
104         Server & root(DirectoryNode & root); ///< Set root node
105                                         /**< \a node will be the root node for all clients launched
106                                              from this server. */
107
108         Mode mode() const;              ///< Get mode
109                                         /**< \see \ref mode(Mode) */
110         
111         Server & mode(Mode mode);       ///< Set mode
112                                         /**< There are two Server types: 
113                                              \li An interactive server displays a command prompt and
114                                                  optionally supports command-line editing.
115                                              \li A non-interactive server does not display any
116                                                  prompt and does not allow any interactive
117                                                  editing. This type of server is used for (remote)
118                                                  scripting.
119
120                                              The \a mode parameter selects between these modes. In
121                                              \c Automatic (the default), a client connection is
122                                              considered to be interactive if there is no data
123                                              traffic in the first 500ms after the connection is
124                                              opened. */
125
126         void stop();                    ///< Stop the server
127                                         /**< All clients will be closed */
128
129         
130     protected:
131
132     private:
133         Server(ServerHandle handle);
134
135         static Server & start(ServerHandle handle);
136         static boost::scoped_ptr<Server> & instancePtr();
137
138         void newClient(Scheduler::EventId event);
139         void removeClient(Client & client);
140         
141         ServerHandle handle_;
142         DirectoryNode::ptr root_;
143         Mode mode_;
144         
145         typedef std::set< boost::intrusive_ptr<Client> > Clients;
146         Clients clients_;
147         std::string name_;
148         
149         friend class Client;
150     };
151     
152     /** \brief Server client instance
153
154         Whenever a new client connects, a new instance of this class is created. This class shows a
155         command prompt, receives the commands, parses them and then passes (using a CommandParser)
156         and passes the commands to an Executor instance.
157
158         \ingroup console_access
159      */
160     class Client
161         : public senf::intrusive_refcount, 
162           private boost::base_from_member< detail::NonblockingSocketOStream >,
163           public senf::log::IOStreamTarget
164     {
165         typedef boost::base_from_member< detail::NonblockingSocketOStream > out_t;
166
167         SENF_LOG_CLASS_AREA();
168         SENF_LOG_DEFAULT_LEVEL( senf::log::NOTICE );
169
170         static const unsigned INTERACTIVE_TIMEOUT = 500; // milliseconds;
171
172     public:
173         typedef Server::ServerHandle::ClientSocketHandle ClientHandle;
174
175         ~Client();
176
177         void stop();                    ///< Stop the client
178                                         /**< This will close the client socket. */
179
180         std::string const & name() const;
181         ClientHandle handle() const;
182         std::ostream & stream();
183         std::string promptString() const;
184         DirectoryNode & root() const;
185         Server::Mode mode() const;
186
187         static Client & get(std::ostream & os);
188
189     protected:
190         
191     private:
192         Client(Server & server, ClientHandle handle);
193
194         void setInteractive();
195         void setNoninteractive();
196         
197         void translate(std::string & data);
198         unsigned handleInput(std::string input, bool incremental = false);
199         virtual void v_write(senf::log::time_type timestamp, std::string const & stream, 
200                              std::string const & area, unsigned level, 
201                              std::string const & message);
202         
203         Server & server_;
204         ClientHandle handle_;
205         SchedulerBinding binding_;
206         SchedulerTimer timer_;
207         CommandParser parser_;
208         Executor executor_;
209         std::string name_;
210         std::string lastCommand_;
211         boost::scoped_ptr<detail::ClientReader> reader_;
212         Server::Mode mode_;
213
214         friend class Server;
215         friend class detail::ClientReader;
216         friend class detail::NonblockingSocketSink;
217     };
218         
219     /** \brief Output Console Client instance as it's string representation
220         \related Client
221      */
222     std::ostream & operator<<(std::ostream & os, Client const & client);
223
224     /** \brief Output Console Client instance as it's string representation
225         \related Client
226      */
227     std::ostream & operator<<(std::ostream & os, Client * client);
228
229 }}
230
231 ///////////////////////////////hh.e////////////////////////////////////////
232 #include "Server.cci"
233 //#include "Server.ct"
234 //#include "Server.cti"
235 #endif
236
237 \f
238 // Local Variables:
239 // mode: c++
240 // fill-column: 100
241 // comment-column: 40
242 // c-file-style: "senf"
243 // indent-tabs-mode: nil
244 // ispell-local-dictionary: "american"
245 // compile-command: "scons -u test"
246 // End: