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