Fix documentation build under maverick (doxygen 1.7.1)
[senf.git] / senf / Utils / Termlib / Telnet.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 Telnet public header */
25
26 #ifndef HH_SENF_Scheduler_Console_Telnet_
27 #define HH_SENF_Scheduler_Console_Telnet_ 1
28
29 // Custom includes
30 #include <vector>
31 #include <map>
32 #include <senf/Socket.hh>
33 #include <senf/Scheduler/Scheduler.hh>
34 #include <senf/Scheduler/ClockService.hh>
35
36 //#include "Telnet.mpp"
37 //-/////////////////////////////////////////////////////////////////////////////////////////////////
38
39 namespace senf {
40 namespace term {
41
42     /** \defgroup telnet_group Telnet protocol
43
44         The telnet protocol implementation is based on the relevant RFCs:
45
46         \li <a href="http://tools.ietf.org/html/rfc854">RFC 854</a> The Telnet protocol
47         \li <a href="http://tools.ietf.org/html/rfc854">RFC 855</a> Telnet option specifications
48
49         BaseTelnetProtocol provides the basic protocol implementation with generic telnet option
50         support. Several other classes provide additional support for further telnet options:
51
52         \li telnethandler::TerminalType provides support for the TERMINAL_TYPE option
53         \li telnethandler::NAWS provides support for the NAWS (Negotiation About Window Size) option
54
55         There are some symbolic constants for telnet option in the senf::term::telnetopt namespace.
56      */
57
58     /** \brief Telnet protocol implementation
59
60         This class implements the basic telnet protocol. It provides option parsing and negotiation
61         and implements the necessary character quoting.
62
63         This class is a base class. Several virtual function hooks are provided which will be called
64         by the protocol implementation.
65
66         The telnet protocol implementation is symmetric: At this level, there is no difference
67         between a telnet client and a telnet server.
68
69         This telnet protocol base class integrates with the SENF Scheduler, it relies on the
70         scheduler main loop to be active.
71
72         \section telnethandlers Telnet option handlers
73
74         To support complex telnet option which require subnegotiation, TelnetHandler's are
75         provided. A telnet handler is a class derived from TelnetHandler and then inherited into the
76         target telnet implementation class:
77
78         \code
79         class MyTelnet
80             : public senf::term::telnethandler::TerminalType,
81               public senf::term::telnethandler::NAWS
82         {
83             MyTelnet(Handle handle) : BaseTelnetProtocol(handle) {}
84
85             // ...
86         };
87         \endcode
88
89         It is very important, the BaseTelnetProtocol is \e always inherited by \c public \c virtual
90         inheritance. This allows the BaseTelnetProtocol constructor to be called by the most derived
91         class directly as above.
92
93         Each terminal handler may provide an additional API and/or additional virtual function
94         callbacks.
95
96         To implement a new terminal handler, derive from TelnetHandler and register the
97         handler. BaseTelnetProtocol will automatically request the corresponding option to be
98         enabled and will call the handlers \c v_init() member as soon as the peer as asserted the
99         option.
100
101         Whenever a subnegotiation for the registered handler is received, the handlers
102         \c v_handleOptionParameters() member is called.
103
104         \code
105         class MyTelnetHandler
106             : public senf::term::BaseTelnetProtocol::TelnetHandler
107         {
108         public:
109             // This constant is MANDATORY and gives the option code which this handler services
110             static option_type const OPTION_CODE = MY_OPTION_CODE;
111
112             void frobble() { // ... }
113
114         protected:
115             MyTelnetHandler() { registerHandler(this); }
116
117         private:
118             virtual void v_init()
119             {
120                 sendOptionParameters(OPTION_CODE, "my special subnegotiation");
121                 incrementRequestCounter();
122             }
123
124             virtual void v_handleOptionParameters(std::string const & data)
125             {
126                 if (data == "another special subnegotiation")
127                     decrementRequestCounter();
128             }
129         };
130         \endcode
131
132         \todo SYNCH handling
133
134         \ingroup telnet_group
135      */
136     class BaseTelnetProtocol
137     {
138     public:
139         static unsigned const DEFAULT_REQUEST_TIMEOUT_MS = 500u;
140
141         typedef ClientSocketHandle<senf::MakeSocketPolicy<
142             ConnectedCommunicationPolicy,
143             StreamFramingPolicy,
144             ReadablePolicy,
145             WriteablePolicy>::policy> Handle; ///< Type of socket handle required
146
147         typedef unsigned char option_type; ///< Type of telnet option numbers
148
149         struct TelnetHandler;
150
151         void write(std::string const & s); ///< Send string to peer
152                                         /**< The string will be correctly quoted and newline chars
153                                              will be sent as CR/LF pairs. */
154         void write(char c);             ///< Send single character to peer
155                                         /**< The character will be correctly quoted and newline
156                                              chars will be sent as CR/LF pairs. */
157
158         Handle handle();                ///< Get socket handle
159
160         void sendNOP();                 ///< Send NOP to peer
161         void sendBRK();                 ///< Send BReaK to peer
162         void sendIP();                  ///< Send InterruptProcess to peer
163         void sendAO();                  ///< Send AbortOutput to peer
164         void sendAYT();                 ///< Send AreYouThere to peer
165         void sendEC();                  ///< Send EraseCharacter to peer
166         void sendEL();                  ///< Send EraseLine to peer
167         void sendGA();                  ///< Send GoAhead to peer
168
169         void sendOptionParameters(option_type option, std::string const & data);
170                                         ///< Send extended option parameter to peer
171                                         /**< This will send \a data as extended option parameter of
172                                              option \a option to peer via a subnegotiation. */
173
174         void requestLocalOption(option_type option, bool enabled = true);
175                                         ///< Request option to be enabled here
176                                         /**< This will send a WILL \a option request to the peer */
177         void acceptLocalOption(option_type option, bool enabled = true);
178                                         ///< Accept a request for an option to be enabled here
179                                         /**< If the peer sends a DO \a option request, the request
180                                              will be granted */
181
182         void requestPeerOption(option_type option, bool enabled = true);
183                                         ///< Request peer to enable an option
184                                         /**< This will send a DO \a option request to the peer */
185         void acceptPeerOption(option_type option, bool enabled = true);
186                                         ///< Accept a request by the peer to enable an option
187                                         /**< If the peer sends a WILL \a option request, the request
188                                              will be ganted */
189
190         bool localOption(option_type option); ///< \c true, if \a option locally enabled
191         bool peerOption(option_type option); ///< \c true, if \a option enabled in peer
192
193     protected:
194         explicit BaseTelnetProtocol(Handle handle); ///< Construct telnet protocol handler
195         BaseTelnetProtocol();           ///< Provided for TelnetHandler mixins only
196
197         virtual ~BaseTelnetProtocol();
198
199         template <class Handler>
200         void registerHandler(Handler * h, bool request=true);
201                                         ///< Register a TelnetHandler
202
203         void incrementRequestCounter(); ///< Increment request counter
204                                         /**< This member may be called by a telnet handler to wait
205                                              for additional negotiations. It must be paired with a
206                                              corresponding decrementRequestCounter() call when that
207                                              negotiation is received. */
208         void decrementRequestCounter(); ///< Decrement request counter
209                                         /**< \see inrementRequestCounter() */
210         bool requestsPending();         ///< \c true, if there are pending requests
211
212 #ifndef DOXYGEN
213     private:
214 #endif
215         virtual void v_setupComplete() = 0; ///< Called, when no further requests are pending
216                                         /**< This callback will be called, when no further
217                                              negotiations are to be expected. The default
218                                              negotiation timeout is 500ms. If no reply is received
219                                              in this time, the request is abandoned and
220                                              v_setupComplete() is called.
221
222                                              mixin TelnetHandler's may additionally increment the
223                                              request counter to wait for specific
224                                              subnegotiations. v_setupComplete() will be called, when
225                                              all these negotiations are complete or have timed
226                                              out. */
227         virtual void v_charReceived(char c) = 0; ///< Called whenever a data character is received
228         virtual void v_eof() = 0;       ///< Called on input EOF
229
230         virtual void v_handleNOP();     ///< Called, when the peer sends a NOP
231         virtual void v_handleBRK();     ///< Called, when the peer sends a BReaK
232         virtual void v_handleIP();      ///< Called, when the peer sends an InterruptProcess
233         virtual void v_handleAO();      ///< Called, when the peer sends an AbortOutput
234         virtual void v_handleAYT();     ///< Called, when the peer sends an AreYouThere
235         virtual void v_handleEC();      ///< Called, when the peer sends an EraseCharacter
236         virtual void v_handleEL();      ///< Called, when the peer sends an EraseLine
237         virtual void v_handleGA();      ///< Called, when the peer sends a GoAhead
238
239     private:
240         void handleChar(char c);
241         void handleNormalChar(char c);
242         void handleCommand(char c);
243         void handleOption(char c);
244         void handleCR(char c);
245         void handleSBOption(char c);
246         void handleSBData(char c);
247         void handleSBIAC(char c);
248         void emit(char c);
249         void processCommand();
250         void transmit(char c);
251
252         void sendWILL(char option);
253         void sendWONT(char option);
254         void sendDO(char option);
255         void sendDONT(char option);
256
257         void readHandler(int state);
258         void writeHandler(int state);
259         void timeout();
260
261         enum Command {
262             CMD_NONE = 0,
263             CMD_SE = 240,
264             CMD_NOP = 241,
265             CMD_DM = 242,
266             CMD_BRK = 243,
267             CMD_IP = 244,
268             CMD_AO = 245,
269             CMD_AYT = 246,
270             CMD_EC = 247,
271             CMD_EL = 248,
272             CMD_GA = 249,
273             CMD_SB = 250,
274             CMD_WILL = 251,
275             CMD_WONT = 252,
276             CMD_DO = 253,
277             CMD_DONT = 254,
278             CMD_IAC = 255,
279         };
280
281         struct OptInfo
282         {
283             enum WantState { WANTED, ACCEPTED, DISABLED };
284             enum OptionState { NONE, REQUEST_SENT, ACKNOWLEDGED };
285
286             OptInfo();
287             OptInfo(bool local, option_type option);
288
289             //-////////////////////////////////////////////////////////////
290
291             bool const local;
292             option_type const option;
293
294             WantState wantState;
295             OptionState optionState;
296             bool enabled;
297
298         };
299
300         OptInfo & getOption(bool local, option_type option);
301         void request(OptInfo & info, bool enabled);
302         void response(OptInfo & info, bool enabled);
303
304         typedef std::map<std::pair<bool, option_type>, OptInfo> OptionsMap;
305         OptionsMap options_;
306
307         typedef std::map<option_type, TelnetHandler*> OptionHandlerMap;
308         OptionHandlerMap handlers_;
309
310         Handle handle_;
311
312         typedef std::vector<char> SendQueue;
313         SendQueue sendQueue_;
314
315         enum CharState { NORMAL, IAC_SEEN, EXPECT_OPTION, CR_SEEN,
316                          SB_OPTION, SB_DATA, SB_IAC_SEEN };
317         CharState charState_;
318
319         Command command_;
320         option_type option_;
321         std::string data_;
322
323         senf::scheduler::FdEvent inputEvent_;
324         senf::scheduler::FdEvent outputEvent_;
325
326         unsigned pendingRequests_;
327
328         ClockService::clock_type requestTimeout_;
329         scheduler::TimerEvent timeout_;
330
331         friend class TelnetHandler;
332     };
333
334     /** \brief Telnet handler base class
335
336         \see BaseTelnetProtocol
337      */
338     struct BaseTelnetProtocol::TelnetHandler
339         : public virtual BaseTelnetProtocol
340     {
341         virtual ~TelnetHandler();
342         virtual void v_init() = 0;      ///< Called, after option has been enabled
343         virtual void v_handleOptionParameters(std::string const & data) = 0;
344                                         ///< Called, whenever a subnegotiation is received
345     };
346
347     /** \brief Telnet option codes
348
349         See http://www.iana.org/assignments/telnet-options for a list of options
350
351         \ingroup telnet_group
352      */
353     namespace telnetopt { BaseTelnetProtocol::option_type const ECHO = 1u; }
354     namespace telnetopt { BaseTelnetProtocol::option_type const TRANSMIT_BINARY = 0u; }
355     namespace telnetopt { BaseTelnetProtocol::option_type const SUPPRESS_GO_AHEAD = 3u; }
356     namespace telnetopt { BaseTelnetProtocol::option_type const TERMINAL_TYPE = 24u; }
357     namespace telnetopt { BaseTelnetProtocol::option_type const NAWS = 31u; }
358     namespace telnetopt { BaseTelnetProtocol::option_type const LINEMODE = 34u; }
359
360 /** \brief Telnet handlers
361
362     \ingroup telnet_group */
363 namespace telnethandler {
364
365     /** \brief Implement TERMINAL_TYPE option
366
367         This telnet handler implements the TERMINAL_TYPE option. The handler automatically requests
368         the first terminal type during initialization. Further terminal types may then be reqeusted
369         by calling nextTerminalType().
370
371         The last received terminal type will be returned by the terminalType() member.
372
373         This implementation only provides server support (querying the terminal type).
374
375         \see BaseTelnetProtocol for how to integrate this handler \n
376             <a href="http://tools.ietf.org/html/rfc1091">RFC 1091</a> Telnet Terminal-Type Option
377      */
378     class TerminalType
379         : public BaseTelnetProtocol::TelnetHandler
380     {
381     public:
382         static option_type const OPTION_CODE = telnetopt::TERMINAL_TYPE;
383
384         void nextTerminalType();        ///< Request another terminal type
385         std::string const & terminalType() const; ///< Return current terminal type
386
387     protected:
388         TerminalType();
389
390     private:
391         virtual void v_init();
392         virtual void v_handleOptionParameters(std::string const & data);
393
394         std::string type_;
395     };
396
397     /** \brief Implement NAWS (Negotiation About Window Size) option
398
399         This telnet handler implements the NAWS option. The client terminals window size will be
400         requested during initialization. The current window size may always be accessed using the
401         width() and height() members.
402
403         Whenever the window size is changed, the v_windowSizeChanged() function is called. This
404         function must be implemented in a derived class.
405
406         \see BaseTelnetProtocol for how to integrate this handler \n
407             <a href="http://tools.ietf.org/html/rfc1073">RFC 1073</a> Telnet Window Size Option
408      */
409     class NAWS
410         : public BaseTelnetProtocol::TelnetHandler
411     {
412     public:
413         static option_type const OPTION_CODE = telnetopt::NAWS;
414
415         unsigned width() const;         ///< Get current client window width
416         unsigned height() const;        ///< Get current client window height
417
418     protected:
419         NAWS();
420
421 #   ifndef DOXYGEN
422     private:
423 #   endif
424         virtual void v_windowSizeChanged() = 0; ///< Called, whenever window size changes
425                                         /**< This member is called for every window size change \e
426                                              after initialization. */
427
428     private:
429         virtual void v_init();
430         virtual void v_handleOptionParameters(std::string const & data);
431
432         unsigned width_;
433         unsigned height_;
434     };
435
436 }
437
438 }}
439
440 //-/////////////////////////////////////////////////////////////////////////////////////////////////
441 #include "Telnet.cci"
442
443 //#include "Telnet.ct"
444 #include "Telnet.cti"
445 #endif
446
447 \f
448 // Local Variables:
449 // mode: c++
450 // fill-column: 100
451 // comment-column: 40
452 // c-file-style: "senf"
453 // indent-tabs-mode: nil
454 // ispell-local-dictionary: "american"
455 // compile-command: "scons -u test"
456 // End: