4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
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.
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.
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.
24 \brief Telnet public header */
26 #ifndef HH_SENF_Scheduler_Console_Telnet_
27 #define HH_SENF_Scheduler_Console_Telnet_ 1
32 #include <senf/Scheduler/Scheduler.hh>
33 #include <senf/Scheduler/ClockService.hh>
35 //#include "Telnet.mpp"
36 //-/////////////////////////////////////////////////////////////////////////////////////////////////
41 /** \defgroup telnet_group Telnet protocol
43 The telnet protocol implementation is based on the relevant RFCs:
45 \li <a href="http://tools.ietf.org/html/rfc854">RFC 854</a> The Telnet protocol
46 \li <a href="http://tools.ietf.org/html/rfc854">RFC 855</a> Telnet option specifications
48 BaseTelnetProtocol provides the basic protocol implementation with generic telnet option
49 support. Several other classes provide additional support for further telnet options:
51 \li telnethandler::TerminalType provides support for the TERMINAL_TYPE option
52 \li telnethandler::NAWS provides support for the NAWS (Negotiation About Window Size) option
54 There are some symbolic constants for telnet option in the senf::term::telnetopt namespace.
57 /** \brief Telnet protocol implementation
59 This class implements the basic telnet protocol. It provides option parsing and negotiation
60 and implements the necessary character quoting.
62 This class is a base class. Several virtual function hooks are provided which will be called
63 by the protocol implementation.
65 The telnet protocol implementation is symmetric: At this level, there is no difference
66 between a telnet client and a telnet server.
68 This telnet protocol base class integrates with the SENF Scheduler, it relies on the
69 scheduler main loop to be active.
71 \section telnethandlers Telnet option handlers
73 To support complex telnet option which require subnegotiation, TelnetHandler's are
74 provided. A telnet handler is a class derived from TelnetHandler and then inherited into the
75 target telnet implementation class:
79 : public senf::term::telnethandler::TerminalType,
80 public senf::term::telnethandler::NAWS
82 MyTelnet(Handle handle) : BaseTelnetProtocol(handle) {}
88 It is very important, the BaseTelnetProtocol is \e always inherited by \c public \c virtual
89 inheritance. This allows the BaseTelnetProtocol constructor to be called by the most derived
90 class directly as above.
92 Each terminal handler may provide an additional API and/or additional virtual function
95 To implement a new terminal handler, derive from TelnetHandler and register the
96 handler. BaseTelnetProtocol will automatically request the corresponding option to be
97 enabled and will call the handlers \c v_init() member as soon as the peer as asserted the
100 Whenever a subnegotiation for the registered handler is received, the handlers
101 \c v_handleOptionParameters() member is called.
104 class MyTelnetHandler
105 : public senf::term::BaseTelnetProtocol::TelnetHandler
108 // This constant is MANDATORY and gives the option code which this handler services
109 static option_type const OPTION_CODE = MY_OPTION_CODE;
111 void frobble() { // ... }
114 MyTelnetHandler() { registerHandler(this); }
117 virtual void v_init()
119 sendOptionParameters(OPTION_CODE, "my special subnegotiation");
120 incrementRequestCounter();
123 virtual void v_handleOptionParameters(std::string const & data)
125 if (data == "another special subnegotiation")
126 decrementRequestCounter();
133 \ingroup telnet_group
135 class BaseTelnetProtocol
138 static unsigned const DEFAULT_REQUEST_TIMEOUT_MS = 500u;
140 typedef ClientSocketHandle<senf::MakeSocketPolicy<
141 ConnectedCommunicationPolicy,
144 WriteablePolicy>::policy> Handle; ///< Type of socket handle required
146 typedef unsigned char option_type; ///< Type of telnet option numbers
148 struct TelnetHandler;
150 void write(std::string const & s); ///< Send string to peer
151 /**< The string will be correctly quoted and newline chars
152 will be sent as CR/LF pairs. */
153 void write(char c); ///< Send single character to peer
154 /**< The character will be correctly quoted and newline
155 chars will be sent as CR/LF pairs. */
157 Handle handle(); ///< Get socket handle
159 void sendNOP(); ///< Send NOP to peer
160 void sendBRK(); ///< Send BReaK to peer
161 void sendIP(); ///< Send InterruptProcess to peer
162 void sendAO(); ///< Send AbortOutput to peer
163 void sendAYT(); ///< Send AreYouThere to peer
164 void sendEC(); ///< Send EraseCharacter to peer
165 void sendEL(); ///< Send EraseLine to peer
166 void sendGA(); ///< Send GoAhead to peer
168 void sendOptionParameters(option_type option, std::string const & data);
169 ///< Send extended option parameter to peer
170 /**< This will send \a data as extended option parameter of
171 option \a option to peer via a subnegotiation. */
173 void requestLocalOption(option_type option, bool enabled = true);
174 ///< Request option to be enabled here
175 /**< This will send a WILL \a option request to the peer */
176 void acceptLocalOption(option_type option, bool enabled = true);
177 ///< Accept a request for an option to be enabled here
178 /**< If the peer sends a DO \a option request, the request
181 void requestPeerOption(option_type option, bool enabled = true);
182 ///< Request peer to enable an option
183 /**< This will send a DO \a option request to the peer */
184 void acceptPeerOption(option_type option, bool enabled = true);
185 ///< Accept a request by the peer to enable an option
186 /**< If the peer sends a WILL \a option request, the request
189 bool localOption(option_type option); ///< \c true, if \a option locally enabled
190 bool peerOption(option_type option); ///< \c true, if \a option enabled in peer
193 explicit BaseTelnetProtocol(Handle handle); ///< Construct telnet protocol handler
194 BaseTelnetProtocol(); ///< Provided for TelnetHandler mixins only
196 virtual ~BaseTelnetProtocol();
198 template <class Handler>
199 void registerHandler(Handler * h, bool request=true);
200 ///< Register a TelnetHandler
202 void incrementRequestCounter(); ///< Increment request counter
203 /**< This member may be called by a telnet handler to wait
204 for additional negotiations. It must be paired with a
205 corresponding decrementRequestCounter() call when that
206 negotiation is received. */
207 void decrementRequestCounter(); ///< Decrement request counter
208 /**< \see inrementRequestCounter() */
209 bool requestsPending(); ///< \c true, if there are pending requests
214 virtual void v_setupComplete() = 0; ///< Called, when no further requests are pending
215 /**< This callback will be called, when no further
216 negotiations are to be expected. The default
217 negotiation timeout is 500ms. If no reply is received
218 in this time, the request is abandoned and
219 v_setupComplete() is called.
221 mixin TelnetHandler's may additionally increment the
222 request counter to wait for specific
223 subnegotiations. v_setupComplete() will be called, when
224 all these negotiations are complete or have timed
226 virtual void v_charReceived(char c) = 0; ///< Called whenever a data character is received
227 virtual void v_eof() = 0; ///< Called on input EOF
229 virtual void v_handleNOP(); ///< Called, when the peer sends a NOP
230 virtual void v_handleBRK(); ///< Called, when the peer sends a BReaK
231 virtual void v_handleIP(); ///< Called, when the peer sends an InterruptProcess
232 virtual void v_handleAO(); ///< Called, when the peer sends an AbortOutput
233 virtual void v_handleAYT(); ///< Called, when the peer sends an AreYouThere
234 virtual void v_handleEC(); ///< Called, when the peer sends an EraseCharacter
235 virtual void v_handleEL(); ///< Called, when the peer sends an EraseLine
236 virtual void v_handleGA(); ///< Called, when the peer sends a GoAhead
239 void handleChar(char c);
240 void handleNormalChar(char c);
241 void handleCommand(char c);
242 void handleOption(char c);
243 void handleCR(char c);
244 void handleSBOption(char c);
245 void handleSBData(char c);
246 void handleSBIAC(char c);
248 void processCommand();
249 void transmit(char c);
251 void sendWILL(char option);
252 void sendWONT(char option);
253 void sendDO(char option);
254 void sendDONT(char option);
256 void readHandler(int state);
257 void writeHandler(int state);
282 enum WantState { WANTED, ACCEPTED, DISABLED };
283 enum OptionState { NONE, REQUEST_SENT, ACKNOWLEDGED };
286 OptInfo(bool local, option_type option);
288 //-////////////////////////////////////////////////////////////
291 option_type const option;
294 OptionState optionState;
299 OptInfo & getOption(bool local, option_type option);
300 void request(OptInfo & info, bool enabled);
301 void response(OptInfo & info, bool enabled);
303 typedef std::map<std::pair<bool, option_type>, OptInfo> OptionsMap;
306 typedef std::map<option_type, TelnetHandler*> OptionHandlerMap;
307 OptionHandlerMap handlers_;
311 typedef std::vector<char> SendQueue;
312 SendQueue sendQueue_;
314 enum CharState { NORMAL, IAC_SEEN, EXPECT_OPTION, CR_SEEN,
315 SB_OPTION, SB_DATA, SB_IAC_SEEN };
316 CharState charState_;
322 scheduler::FdEvent inputEvent_;
323 scheduler::FdEvent outputEvent_;
325 unsigned pendingRequests_;
327 ClockService::clock_type requestTimeout_;
328 scheduler::TimerEvent timeout_;
330 friend class TelnetHandler;
333 /** \brief Telnet handler base class
335 \see BaseTelnetProtocol
337 struct BaseTelnetProtocol::TelnetHandler
338 : public virtual BaseTelnetProtocol
340 virtual ~TelnetHandler();
341 virtual void v_init() = 0; ///< Called, after option has been enabled
342 virtual void v_handleOptionParameters(std::string const & data) = 0;
343 ///< Called, whenever a subnegotiation is received
346 /** \brief Telnet option codes
348 See http://www.iana.org/assignments/telnet-options for a list of options
350 \ingroup telnet_group
352 namespace telnetopt { BaseTelnetProtocol::option_type const ECHO = 1u; }
353 namespace telnetopt { BaseTelnetProtocol::option_type const TRANSMIT_BINARY = 0u; }
354 namespace telnetopt { BaseTelnetProtocol::option_type const SUPPRESS_GO_AHEAD = 3u; }
355 namespace telnetopt { BaseTelnetProtocol::option_type const TERMINAL_TYPE = 24u; }
356 namespace telnetopt { BaseTelnetProtocol::option_type const NAWS = 31u; }
357 namespace telnetopt { BaseTelnetProtocol::option_type const LINEMODE = 34u; }
359 /** \brief Telnet handlers
361 \ingroup telnet_group */
362 namespace telnethandler {
364 /** \brief Implement TERMINAL_TYPE option
366 This telnet handler implements the TERMINAL_TYPE option. The handler automatically requests
367 the first terminal type during initialization. Further terminal types may then be requested
368 by calling nextTerminalType().
370 The last received terminal type will be returned by the terminalType() member.
372 This implementation only provides server support (querying the terminal type).
374 \see BaseTelnetProtocol for how to integrate this handler \n
375 <a href="http://tools.ietf.org/html/rfc1091">RFC 1091</a> Telnet Terminal-Type Option
378 : public BaseTelnetProtocol::TelnetHandler
381 static option_type const OPTION_CODE = telnetopt::TERMINAL_TYPE;
383 void nextTerminalType(); ///< Request another terminal type
384 std::string const & terminalType() const; ///< Return current terminal type
390 virtual void v_init();
391 virtual void v_handleOptionParameters(std::string const & data);
396 /** \brief Implement NAWS (Negotiation About Window Size) option
398 This telnet handler implements the NAWS option. The client terminals window size will be
399 requested during initialization. The current window size may always be accessed using the
400 width() and height() members.
402 Whenever the window size is changed, the v_windowSizeChanged() function is called. This
403 function must be implemented in a derived class.
405 \see BaseTelnetProtocol for how to integrate this handler \n
406 <a href="http://tools.ietf.org/html/rfc1073">RFC 1073</a> Telnet Window Size Option
409 : public BaseTelnetProtocol::TelnetHandler
412 static option_type const OPTION_CODE = telnetopt::NAWS;
414 unsigned width() const; ///< Get current client window width
415 unsigned height() const; ///< Get current client window height
423 virtual void v_windowSizeChanged() = 0; ///< Called, whenever window size changes
424 /**< This member is called for every window size change \e
425 after initialization. */
428 virtual void v_init();
429 virtual void v_handleOptionParameters(std::string const & data);
439 //-/////////////////////////////////////////////////////////////////////////////////////////////////
440 #include "Telnet.cci"
442 //#include "Telnet.ct"
443 #include "Telnet.cti"
450 // comment-column: 40
451 // c-file-style: "senf"
452 // indent-tabs-mode: nil
453 // ispell-local-dictionary: "american"
454 // compile-command: "scons -u test"