4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
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
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.
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.
19 // The Original Code is Fraunhofer FOKUS code.
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.
26 // Stefan Bund <g0dil@berlios.de>
29 \brief Telnet public header */
31 #ifndef HH_SENF_Scheduler_Console_Telnet_
32 #define HH_SENF_Scheduler_Console_Telnet_ 1
37 #include <senf/Scheduler/Scheduler.hh>
38 #include <senf/Scheduler/ClockService.hh>
40 //#include "Telnet.mpp"
41 //-/////////////////////////////////////////////////////////////////////////////////////////////////
46 /** \defgroup telnet_group Telnet protocol
48 The telnet protocol implementation is based on the relevant RFCs:
50 \li <a href="http://tools.ietf.org/html/rfc854">RFC 854</a> The Telnet protocol
51 \li <a href="http://tools.ietf.org/html/rfc854">RFC 855</a> Telnet option specifications
53 BaseTelnetProtocol provides the basic protocol implementation with generic telnet option
54 support. Several other classes provide additional support for further telnet options:
56 \li telnethandler::TerminalType provides support for the TERMINAL_TYPE option
57 \li telnethandler::NAWS provides support for the NAWS (Negotiation About Window Size) option
59 There are some symbolic constants for telnet option in the senf::term::telnetopt namespace.
62 /** \brief Telnet protocol implementation
64 This class implements the basic telnet protocol. It provides option parsing and negotiation
65 and implements the necessary character quoting.
67 This class is a base class. Several virtual function hooks are provided which will be called
68 by the protocol implementation.
70 The telnet protocol implementation is symmetric: At this level, there is no difference
71 between a telnet client and a telnet server.
73 This telnet protocol base class integrates with the SENF Scheduler, it relies on the
74 scheduler main loop to be active.
76 \section telnethandlers Telnet option handlers
78 To support complex telnet option which require subnegotiation, TelnetHandler's are
79 provided. A telnet handler is a class derived from TelnetHandler and then inherited into the
80 target telnet implementation class:
84 : public senf::term::telnethandler::TerminalType,
85 public senf::term::telnethandler::NAWS
87 MyTelnet(Handle handle) : BaseTelnetProtocol(handle) {}
93 It is very important, the BaseTelnetProtocol is \e always inherited by \c public \c virtual
94 inheritance. This allows the BaseTelnetProtocol constructor to be called by the most derived
95 class directly as above.
97 Each terminal handler may provide an additional API and/or additional virtual function
100 To implement a new terminal handler, derive from TelnetHandler and register the
101 handler. BaseTelnetProtocol will automatically request the corresponding option to be
102 enabled and will call the handlers \c v_init() member as soon as the peer as asserted the
105 Whenever a subnegotiation for the registered handler is received, the handlers
106 \c v_handleOptionParameters() member is called.
109 class MyTelnetHandler
110 : public senf::term::BaseTelnetProtocol::TelnetHandler
113 // This constant is MANDATORY and gives the option code which this handler services
114 static option_type const OPTION_CODE = MY_OPTION_CODE;
116 void frobble() { // ... }
119 MyTelnetHandler() { registerHandler(this); }
122 virtual void v_init()
124 sendOptionParameters(OPTION_CODE, "my special subnegotiation");
125 incrementRequestCounter();
128 virtual void v_handleOptionParameters(std::string const & data)
130 if (data == "another special subnegotiation")
131 decrementRequestCounter();
138 \ingroup telnet_group
140 class BaseTelnetProtocol
143 static unsigned const DEFAULT_REQUEST_TIMEOUT_MS = 500u;
145 typedef ClientSocketHandle<senf::MakeSocketPolicy<
146 ConnectedCommunicationPolicy,
149 WriteablePolicy>::policy> Handle; ///< Type of socket handle required
151 typedef unsigned char option_type; ///< Type of telnet option numbers
153 struct TelnetHandler;
155 void write(std::string const & s); ///< Send string to peer
156 /**< The string will be correctly quoted and newline chars
157 will be sent as CR/LF pairs. */
158 void write(char c); ///< Send single character to peer
159 /**< The character will be correctly quoted and newline
160 chars will be sent as CR/LF pairs. */
162 Handle handle(); ///< Get socket handle
164 void sendNOP(); ///< Send NOP to peer
165 void sendBRK(); ///< Send BReaK to peer
166 void sendIP(); ///< Send InterruptProcess to peer
167 void sendAO(); ///< Send AbortOutput to peer
168 void sendAYT(); ///< Send AreYouThere to peer
169 void sendEC(); ///< Send EraseCharacter to peer
170 void sendEL(); ///< Send EraseLine to peer
171 void sendGA(); ///< Send GoAhead to peer
173 void sendOptionParameters(option_type option, std::string const & data);
174 ///< Send extended option parameter to peer
175 /**< This will send \a data as extended option parameter of
176 option \a option to peer via a subnegotiation. */
178 void requestLocalOption(option_type option, bool enabled = true);
179 ///< Request option to be enabled here
180 /**< This will send a WILL \a option request to the peer */
181 void acceptLocalOption(option_type option, bool enabled = true);
182 ///< Accept a request for an option to be enabled here
183 /**< If the peer sends a DO \a option request, the request
186 void requestPeerOption(option_type option, bool enabled = true);
187 ///< Request peer to enable an option
188 /**< This will send a DO \a option request to the peer */
189 void acceptPeerOption(option_type option, bool enabled = true);
190 ///< Accept a request by the peer to enable an option
191 /**< If the peer sends a WILL \a option request, the request
194 bool localOption(option_type option); ///< \c true, if \a option locally enabled
195 bool peerOption(option_type option); ///< \c true, if \a option enabled in peer
198 explicit BaseTelnetProtocol(Handle handle); ///< Construct telnet protocol handler
199 BaseTelnetProtocol(); ///< Provided for TelnetHandler mixins only
201 virtual ~BaseTelnetProtocol();
203 template <class Handler>
204 void registerHandler(Handler * h, bool request=true);
205 ///< Register a TelnetHandler
207 void incrementRequestCounter(); ///< Increment request counter
208 /**< This member may be called by a telnet handler to wait
209 for additional negotiations. It must be paired with a
210 corresponding decrementRequestCounter() call when that
211 negotiation is received. */
212 void decrementRequestCounter(); ///< Decrement request counter
213 /**< \see inrementRequestCounter() */
214 bool requestsPending(); ///< \c true, if there are pending requests
219 virtual void v_setupComplete() = 0; ///< Called, when no further requests are pending
220 /**< This callback will be called, when no further
221 negotiations are to be expected. The default
222 negotiation timeout is 500ms. If no reply is received
223 in this time, the request is abandoned and
224 v_setupComplete() is called.
226 mixin TelnetHandler's may additionally increment the
227 request counter to wait for specific
228 subnegotiations. v_setupComplete() will be called, when
229 all these negotiations are complete or have timed
231 virtual void v_charReceived(char c) = 0; ///< Called whenever a data character is received
232 virtual void v_eof() = 0; ///< Called on input EOF
234 virtual void v_handleNOP(); ///< Called, when the peer sends a NOP
235 virtual void v_handleBRK(); ///< Called, when the peer sends a BReaK
236 virtual void v_handleIP(); ///< Called, when the peer sends an InterruptProcess
237 virtual void v_handleAO(); ///< Called, when the peer sends an AbortOutput
238 virtual void v_handleAYT(); ///< Called, when the peer sends an AreYouThere
239 virtual void v_handleEC(); ///< Called, when the peer sends an EraseCharacter
240 virtual void v_handleEL(); ///< Called, when the peer sends an EraseLine
241 virtual void v_handleGA(); ///< Called, when the peer sends a GoAhead
244 void handleChar(char c);
245 void handleNormalChar(char c);
246 void handleCommand(char c);
247 void handleOption(char c);
248 void handleCR(char c);
249 void handleSBOption(char c);
250 void handleSBData(char c);
251 void handleSBIAC(char c);
253 void processCommand();
254 void transmit(char c);
256 void sendWILL(char option);
257 void sendWONT(char option);
258 void sendDO(char option);
259 void sendDONT(char option);
261 void readHandler(int state);
262 void writeHandler(int state);
287 enum WantState { WANTED, ACCEPTED, DISABLED };
288 enum OptionState { NONE, REQUEST_SENT, ACKNOWLEDGED };
291 OptInfo(bool local, option_type option);
293 //-////////////////////////////////////////////////////////////
296 option_type const option;
299 OptionState optionState;
304 OptInfo & getOption(bool local, option_type option);
305 void request(OptInfo & info, bool enabled);
306 void response(OptInfo & info, bool enabled);
308 typedef std::map<std::pair<bool, option_type>, OptInfo> OptionsMap;
311 typedef std::map<option_type, TelnetHandler*> OptionHandlerMap;
312 OptionHandlerMap handlers_;
316 typedef std::vector<char> SendQueue;
317 SendQueue sendQueue_;
319 enum CharState { NORMAL, IAC_SEEN, EXPECT_OPTION, CR_SEEN,
320 SB_OPTION, SB_DATA, SB_IAC_SEEN };
321 CharState charState_;
327 scheduler::FdEvent inputEvent_;
328 scheduler::FdEvent outputEvent_;
330 unsigned pendingRequests_;
332 ClockService::clock_type requestTimeout_;
333 scheduler::TimerEvent timeout_;
335 friend class TelnetHandler;
338 /** \brief Telnet handler base class
340 \see BaseTelnetProtocol
342 struct BaseTelnetProtocol::TelnetHandler
343 : public virtual BaseTelnetProtocol
345 virtual ~TelnetHandler();
346 virtual void v_init() = 0; ///< Called, after option has been enabled
347 virtual void v_handleOptionParameters(std::string const & data) = 0;
348 ///< Called, whenever a subnegotiation is received
351 /** \brief Telnet option codes
353 See http://www.iana.org/assignments/telnet-options for a list of options
355 \ingroup telnet_group
357 namespace telnetopt { BaseTelnetProtocol::option_type const ECHO = 1u; }
358 namespace telnetopt { BaseTelnetProtocol::option_type const TRANSMIT_BINARY = 0u; }
359 namespace telnetopt { BaseTelnetProtocol::option_type const SUPPRESS_GO_AHEAD = 3u; }
360 namespace telnetopt { BaseTelnetProtocol::option_type const TERMINAL_TYPE = 24u; }
361 namespace telnetopt { BaseTelnetProtocol::option_type const NAWS = 31u; }
362 namespace telnetopt { BaseTelnetProtocol::option_type const LINEMODE = 34u; }
364 /** \brief Telnet handlers
366 \ingroup telnet_group */
367 namespace telnethandler {
369 /** \brief Implement TERMINAL_TYPE option
371 This telnet handler implements the TERMINAL_TYPE option. The handler automatically requests
372 the first terminal type during initialization. Further terminal types may then be requested
373 by calling nextTerminalType().
375 The last received terminal type will be returned by the terminalType() member.
377 This implementation only provides server support (querying the terminal type).
379 \see BaseTelnetProtocol for how to integrate this handler \n
380 <a href="http://tools.ietf.org/html/rfc1091">RFC 1091</a> Telnet Terminal-Type Option
383 : public BaseTelnetProtocol::TelnetHandler
386 static option_type const OPTION_CODE = telnetopt::TERMINAL_TYPE;
388 void nextTerminalType(); ///< Request another terminal type
389 std::string const & terminalType() const; ///< Return current terminal type
395 virtual void v_init();
396 virtual void v_handleOptionParameters(std::string const & data);
401 /** \brief Implement NAWS (Negotiation About Window Size) option
403 This telnet handler implements the NAWS option. The client terminals window size will be
404 requested during initialization. The current window size may always be accessed using the
405 width() and height() members.
407 Whenever the window size is changed, the v_windowSizeChanged() function is called. This
408 function must be implemented in a derived class.
410 \see BaseTelnetProtocol for how to integrate this handler \n
411 <a href="http://tools.ietf.org/html/rfc1073">RFC 1073</a> Telnet Window Size Option
414 : public BaseTelnetProtocol::TelnetHandler
417 static option_type const OPTION_CODE = telnetopt::NAWS;
419 unsigned width() const; ///< Get current client window width
420 unsigned height() const; ///< Get current client window height
428 virtual void v_windowSizeChanged() = 0; ///< Called, whenever window size changes
429 /**< This member is called for every window size change \e
430 after initialization. */
433 virtual void v_init();
434 virtual void v_handleOptionParameters(std::string const & data);
444 //-/////////////////////////////////////////////////////////////////////////////////////////////////
445 #include "Telnet.cci"
447 //#include "Telnet.ct"
448 #include "Telnet.cti"
455 // comment-column: 40
456 // c-file-style: "senf"
457 // indent-tabs-mode: nil
458 // ispell-local-dictionary: "american"
459 // compile-command: "scons -u test"