b2cdca6aecd1ce9abcb424456a1c6cb78c66cadc
[senf.git] / senf / Utils / Console / Server.hh
1 // $Id$
2 //
3 // Copyright (C) 2008
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 //
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at 
9 // http://senf.berlios.de/license.html
10 //
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on, 
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
14 //
15 // Software distributed under the License is distributed on an "AS IS" basis, 
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
17 // for the specific language governing rights and limitations under the License.
18 //
19 // The Original Code is Fraunhofer FOKUS code.
20 //
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V. 
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
24 //
25 // Contributor(s):
26 //   Stefan Bund <g0dil@berlios.de>
27
28 /** \file
29     \brief Server public header */
30
31 #ifndef HH_SENF_Scheduler_Console_Server_
32 #define HH_SENF_Scheduler_Console_Server_ 1
33
34 // Custom includes
35 #include <set>
36 #include <boost/utility.hpp>
37 #include <boost/scoped_ptr.hpp>
38 #include <senf/Scheduler/FdEvent.hh>
39 #include <senf/Scheduler/TimerEvent.hh>
40 #include <senf/Socket/Protocols/INet/INetAddressing.hh>
41 #include <senf/Utils/Logger.hh>
42 #include <senf/Utils/intrusive_refcount.hh>
43 #include "Executor.hh"
44
45 //#include "Server.mpp"
46 #include "Server.ih"
47 //-/////////////////////////////////////////////////////////////////////////////////////////////////
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         static Server & start(senf::INet4SocketAddress const & address);
84                                         ///< Start server on given IPv4 address/port
85         static Server & start(senf::INet6SocketAddress const & address);
86                                         ///< Start server on given IPv6 address/port
87
88         std::string const & name() const; ///< Get server name
89                                         /**< This information is used in the prompt string. */
90
91         Server & name(std::string const & name); ///< Set server name
92                                         /**< This information is used in the prompt string. */
93
94         DirectoryNode & root() const;   ///< Get root node
95
96         Server & root(DirectoryNode & root); ///< Set root node
97                                         /**< \a node will be the root node for all clients launched
98                                              from this server. */
99
100         Mode mode() const;              ///< Get mode
101                                         /**< \see \ref mode(Mode) */
102
103         Server & mode(Mode mode);       ///< Set mode
104                                         /**< There are two Server types:
105                                              \li An interactive server displays a command prompt and
106                                                  optionally supports command-line editing.
107                                              \li A non-interactive server does not display any
108                                                  prompt and does not allow any interactive
109                                                  editing. This type of server is used for (remote)
110                                                  scripting.
111
112                                              The \a mode parameter selects between these modes. In
113                                              \c Automatic (the default), a client connection is
114                                              considered to be interactive if there is no data
115                                              traffic in the first 500ms after the connection is
116                                              opened. */
117
118         void stop();                    ///< Stop the server
119                                         /**< All clients will be closed
120                                              \warning The Server instance itself will be deleted */
121
122     protected:
123
124     private:
125         Server(ServerHandle handle);
126
127         static Server & start(ServerHandle handle);
128
129         void newClient(int event);
130         void removeClient(Client & client);
131
132         ServerHandle handle_;
133         scheduler::FdEvent event_;
134         DirectoryNode::ptr root_;
135         Mode mode_;
136
137         typedef std::set< boost::intrusive_ptr<Client> > Clients;
138         Clients clients_;
139         std::string name_;
140
141         friend class Client;
142     };
143
144     /** \brief Server client instance
145
146         Whenever a new client connects, a new instance of this class is created. This class shows a
147         command prompt, receives the commands, parses them and then passes (using a CommandParser)
148         and passes the commands to an Executor instance.
149
150         \ingroup console_access
151      */
152     class Client
153         : public senf::intrusive_refcount,
154           private boost::base_from_member< detail::NonblockingSocketOStream >,
155           public senf::log::IOStreamTarget
156     {
157         typedef boost::base_from_member< detail::NonblockingSocketOStream > out_t;
158
159         SENF_LOG_CLASS_AREA();
160         SENF_LOG_DEFAULT_LEVEL( senf::log::NOTICE );
161
162         static const unsigned INTERACTIVE_TIMEOUT = 500; // milliseconds;
163
164     public:
165         typedef Server::ServerHandle::ClientHandle ClientHandle;
166
167         ~Client();
168
169         void stop();                    ///< Stop the client
170                                         /**< This will close the client socket. */
171
172         std::string const & name() const; ///< Get name of the client instance
173                                         /**< This name is used in the prompt string and is set by
174                                              the server. */
175         ClientHandle handle() const;    ///< Get the client's network socket handle
176         std::ostream & stream();        ///< Get client's output stream
177                                         /**< Data sent to this stream is sent out over the network
178                                              via the client's socket handle. Write operation is
179                                              non-blocking and data may be dropped. Data is written
180                                              using Client::write(). */
181         std::string promptString() const; ///< Get the prompt string
182         DirectoryNode & root() const;   ///< Get configured root node
183         DirectoryNode & cwd() const;    ///< Get current directory
184                                         /**< This is the directory, the console currently is changed
185                                              into by the user of the console. */
186         Server::Mode mode() const;      ///< Get operation mode
187                                         /**< \see Server::mode() */
188         void write(std::string const & data) const;
189                                         ///< Write data to network socket
190                                         /**< The data is automatically filtered depending on the
191                                              type of connection (e.g. on a telnet connection,
192                                              specific bytes are quoted). */
193         std::string const & backtrace() const; ///< Get backtrace of last console error, if any
194         unsigned width() const;         ///< Get console width
195                                         /**< If possible, this will be the width of the connected
196                                              terminal, otherwise a default value (normally 80) is
197                                              returned. */
198
199         static Client & get(std::ostream & os);
200                                         ///< Access client instance
201                                         /**< Allows to access the client instance from console
202                                              command implementations. The first argument to a
203                                              console command is a stream object. \e If this stream
204                                              object belongs to a network console client, this call
205                                              will return the associated Client instance reference.
206                                              \throws std::bad_cast if \a os is not associated with a
207                                                  Client instance. */
208         static unsigned getWidth(std::ostream & os, unsigned defaultWidth = 0,
209                                  unsigned minWidth = 0);
210                                         ///< Get width of client console if possible
211                                         /**< If possible, the width of the client console attached
212                                              to the stream \a os is returned. If this is not
213                                              possible, the \a defaultValue will be used.
214
215                                              If the width obtained this way is smaller than \a
216                                              minWidth, \a defaultValue will be returned instead. */
217
218     protected:
219
220     private:
221         Client(Server & server, ClientHandle handle);
222
223         void setInteractive();
224         void setNoninteractive();
225
226         size_t handleInput(std::string input, bool incremental = false);
227         virtual void v_write(senf::log::time_type timestamp, std::string const & stream,
228                              std::string const & area, unsigned level,
229                              std::string const & message);
230
231         Server & server_;
232         ClientHandle handle_;
233         scheduler::FdEvent readevent_;
234         scheduler::TimerEvent timer_;
235         CommandParser parser_;
236         Executor executor_;
237         std::string name_;
238         boost::scoped_ptr<detail::ClientReader> reader_;
239         Server::Mode mode_;
240         std::string backtrace_;
241
242         friend class Server;
243         friend class detail::ClientReader;
244         friend class detail::NonblockingSocketSink;
245
246         class SysBacktrace
247         {
248             SysBacktrace();
249             static void  backtrace(std::ostream & os);
250             static SysBacktrace instance_;
251         };
252
253     };
254
255     /** \brief Output Console Client instance as it's string representation
256         \related Client
257      */
258     std::ostream & operator<<(std::ostream & os, Client const & client);
259
260     /** \brief Output Console Client instance as it's string representation
261         \related Client
262      */
263     std::ostream & operator<<(std::ostream & os, Client * client);
264
265 }}
266
267 //-/////////////////////////////////////////////////////////////////////////////////////////////////
268 #include "Server.cci"
269 //#include "Server.ct"
270 //#include "Server.cti"
271 #endif
272
273 \f
274 // Local Variables:
275 // mode: c++
276 // fill-column: 100
277 // comment-column: 40
278 // c-file-style: "senf"
279 // indent-tabs-mode: nil
280 // ispell-local-dictionary: "american"
281 // compile-command: "scons -u test"
282 // End: