66426a0aada67fa15fcac51d20c33b127adafe61
[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/ReadHelper.hh"
40 #include "Parse.hh"
41 #include "Executor.hh"
42 #include "../Socket/Protocols/INet/INetAddressing.hh"
43 #include "../Utils/Logger.hh"
44
45 //#include "Server.mpp"
46 #include "Server.ih"
47 ///////////////////////////////hh.p////////////////////////////////////////
48
49 namespace senf {
50 namespace console {
51
52     class Client;
53
54     /** \brief Interactive console server
55
56         This class provides an interactive console TCP server.
57
58         \idea To support blocking commands, we could give the Client 'suspend()' and 'resume()'
59             members. suspend() would probably throw some kind of exception to transfer control back
60             to the Client instance. on resume(), the command would be called again, maybe setting
61             some flag or something. Example for use: Host name resolution: Here we can just built
62             our own little host-name cache. When the name is not found, we ask the resolver to
63             resolve it and call 'resume' when the name is found. Since it is in the cache now, the
64             command will now complete.
65
66         \ingroup console_access
67       */
68     class Server
69         : public senf::intrusive_refcount
70     {
71         SENF_LOG_CLASS_AREA();
72         SENF_LOG_DEFAULT_LEVEL( senf::log::NOTICE );
73     public:
74         ///////////////////////////////////////////////////////////////////////////
75         // Types
76         
77         typedef detail::ServerHandle ServerHandle;
78
79         enum Mode { Automatic, Interactive, Noninteractive };
80
81         ///////////////////////////////////////////////////////////////////////////
82
83         ~Server();
84
85         static Server & start(senf::INet4SocketAddress const & address);
86                                         ///< Start server on given IPv4 address/port
87         static Server & start(senf::INet6SocketAddress const & address);
88                                         ///< Start server on given IPv6 address/port
89
90         std::string const & name() const; ///< Get server name
91                                         /**< This information is used in the prompt string. */
92
93         Server & name(std::string const & name); ///< Set server name
94                                         /**< This information is used in the prompt string. */
95
96         DirectoryNode & root() const;   ///< Get root node
97
98         Server & root(DirectoryNode & root); ///< Set root node
99                                         /**< \a node will be the root node for all clients launched
100                                              from this server. */
101
102         Mode mode() const;              ///< Get mode
103                                         /**< \see \ref mode(Mode) */
104         
105         Server & mode(Mode mode);       ///< Set mode
106                                         /**< There are two Server types: 
107                                              \li An interactive server displays a command prompt and
108                                                  optionally supports command-line editing.
109                                              \li A non-interactive server does not display any
110                                                  prompt and does not allow any interactive
111                                                  editing. This type of server is used for (remote)
112                                                  scripting.
113
114                                              The \a mode parameter selects between these modes. In
115                                              \c Automatic (the default), a client connection is
116                                              considered to be interactive if there is no data
117                                              traffic in the first 500ms after the connection is
118                                              opened. */
119
120         void stop();                    ///< Stop the server
121                                         /**< All clients will be closed 
122                                              \warning The Server instance itself will be deleted */
123
124     protected:
125
126     private:
127         Server(ServerHandle handle);
128
129         static Server & start(ServerHandle handle);
130
131         void newClient(int event);
132         void removeClient(Client & client);
133         
134         ServerHandle handle_;
135         DirectoryNode::ptr root_;
136         Mode mode_;
137         
138         typedef std::set< boost::intrusive_ptr<Client> > Clients;
139         Clients clients_;
140         std::string name_;
141         
142         friend class Client;
143     };
144     
145     /** \brief Server client instance
146
147         Whenever a new client connects, a new instance of this class is created. This class shows a
148         command prompt, receives the commands, parses them and then passes (using a CommandParser)
149         and passes the commands to an Executor instance.
150
151         \ingroup console_access
152      */
153     class Client
154         : public senf::intrusive_refcount, 
155           private boost::base_from_member< detail::NonblockingSocketOStream >,
156           public senf::log::IOStreamTarget
157     {
158         typedef boost::base_from_member< detail::NonblockingSocketOStream > out_t;
159
160         SENF_LOG_CLASS_AREA();
161         SENF_LOG_DEFAULT_LEVEL( senf::log::NOTICE );
162
163         static const unsigned INTERACTIVE_TIMEOUT = 500; // milliseconds;
164
165     public:
166         typedef Server::ServerHandle::ClientSocketHandle ClientHandle;
167
168         ~Client();
169
170         void stop();                    ///< Stop the client
171                                         /**< This will close the client socket. */
172
173         std::string const & name() const;
174         ClientHandle handle() const;
175         std::ostream & stream();
176         std::string promptString() const;
177         DirectoryNode & root() const;
178         Server::Mode mode() const;
179
180         static Client & get(std::ostream & os);
181
182     protected:
183         
184     private:
185         Client(Server & server, ClientHandle handle);
186
187         void setInteractive();
188         void setNoninteractive();
189         
190         void translate(std::string & data);
191         unsigned handleInput(std::string input, bool incremental = false);
192         virtual void v_write(senf::log::time_type timestamp, std::string const & stream, 
193                              std::string const & area, unsigned level, 
194                              std::string const & message);
195         
196         Server & server_;
197         ClientHandle handle_;
198         SchedulerBinding binding_;
199         scheduler::TimerEvent timer_;
200         CommandParser parser_;
201         Executor executor_;
202         std::string name_;
203         std::string lastCommand_;
204         boost::scoped_ptr<detail::ClientReader> reader_;
205         Server::Mode mode_;
206
207         friend class Server;
208         friend class detail::ClientReader;
209         friend class detail::NonblockingSocketSink;
210     };
211         
212     /** \brief Output Console Client instance as it's string representation
213         \related Client
214      */
215     std::ostream & operator<<(std::ostream & os, Client const & client);
216
217     /** \brief Output Console Client instance as it's string representation
218         \related Client
219      */
220     std::ostream & operator<<(std::ostream & os, Client * client);
221
222 }}
223
224 ///////////////////////////////hh.e////////////////////////////////////////
225 #include "Server.cci"
226 //#include "Server.ct"
227 //#include "Server.cti"
228 #endif
229
230 \f
231 // Local Variables:
232 // mode: c++
233 // fill-column: 100
234 // comment-column: 40
235 // c-file-style: "senf"
236 // indent-tabs-mode: nil
237 // ispell-local-dictionary: "american"
238 // compile-command: "scons -u test"
239 // End: