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