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/Socket.hh>
33 #include <senf/Scheduler/Scheduler.hh>
34 #include <senf/Scheduler/ClockService.hh>
36 //#include "Telnet.mpp"
37 ///////////////////////////////hh.p////////////////////////////////////////
42 /** \defgroup telnet_group Telnet protocol
44 The telnet protocol implementation is based on the relevant RFCs:
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
49 BaseTelnetProtocol provides the basic protocol implementation with generic telnet option
50 support. Several other classes provide additional support for further telnet options:
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
55 There are some symbolic constants for telnet option in the senf::term::telnetopt namespace.
58 /** \brief Telnet protocol implementation
60 This class implements the basic telnet protocol. It provides option parsing and negotiation
61 and implements the necessary character quoting.
63 This class is a base class. Several virtual function hooks are provided which will be called
64 by the protocol implementation.
66 The telnet protocol implementation is symmetric: At this level, there is no difference
67 between a telnet client and a telnet server.
69 This telnet protocol base class integrates with the SENF Scheduler, it relies on the
70 scheduler main loop to be active.
72 \section telnethandlers Telnet option handlers
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:
80 : public senf::term::telnethandler::TerminalType,
81 public senf::term::telnethandler::NAWS
83 MyTelnet(Handle handle) : BaseTelnetProtocol(handle) {}
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.
93 Each terminal handler may provide an additional API and/or additional virtual function
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
101 Whenever a subnegotiation for the registered handler is received, the handlers
102 \c v_handleOptionParameters() member is called.
105 class MyTelnetHandler
106 : public senf::term::BaseTelnetProtocol::TelnetHandler
109 // This constant is MANDATORY and gives the option code which this handler services
110 static option_type const OPTION_CODE = MY_OPTION_CODE;
112 void frobble() { // ... }
115 MyTelnetHandler() { registerHandler(this); }
118 virtual void v_init()
120 sendOptionParameters(OPTION_CODE, "my special subnegotiation");
121 incrementRequestCounter();
124 virtual void v_handleOptionParameters(std::string const & data)
126 if (data == "another special subnegotiation")
127 decrementRequestCounter();
134 \ingroup telnet_group
136 class BaseTelnetProtocol
139 static unsigned const DEFAULT_REQUEST_TIMEOUT_MS = 500u;
141 typedef ClientSocketHandle<senf::MakeSocketPolicy<
142 ConnectedCommunicationPolicy,
145 WriteablePolicy>::policy> Handle; ///< Type of socket handle required
147 typedef unsigned char option_type; ///< Type of telnet option numbers
149 struct TelnetHandler;
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. */
158 Handle handle(); ///< Get socket handle
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
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. */
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
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
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
194 explicit BaseTelnetProtocol(Handle handle); ///< Construct telnet protocol handler
195 BaseTelnetProtocol(); ///< Provided for TelnetHandler mixins only
197 virtual ~BaseTelnetProtocol();
199 template <class Handler>
200 void registerHandler(Handler * h, bool request=true);
201 ///< Register a TelnetHandler
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
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.
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
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
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
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);
249 void processCommand();
250 void transmit(char c);
252 void sendWILL(char option);
253 void sendWONT(char option);
254 void sendDO(char option);
255 void sendDONT(char option);
257 void readHandler(int state);
258 void writeHandler(int state);
262 CMD_NONE = static_cast<char>(0),
263 CMD_SE = static_cast<char>(240),
264 CMD_NOP = static_cast<char>(241),
265 CMD_DM = static_cast<char>(242),
266 CMD_BRK = static_cast<char>(243),
267 CMD_IP = static_cast<char>(244),
268 CMD_AO = static_cast<char>(245),
269 CMD_AYT = static_cast<char>(246),
270 CMD_EC = static_cast<char>(247),
271 CMD_EL = static_cast<char>(248),
272 CMD_GA = static_cast<char>(249),
273 CMD_SB = static_cast<char>(250),
274 CMD_WILL = static_cast<char>(251),
275 CMD_WONT = static_cast<char>(252),
276 CMD_DO = static_cast<char>(253),
277 CMD_DONT = static_cast<char>(254),
278 CMD_IAC = static_cast<char>(255),
283 enum WantState { WANTED, ACCEPTED, DISABLED };
284 enum OptionState { NONE, REQUEST_SENT, ACKNOWLEDGED };
287 OptInfo(bool local, option_type option);
289 ///////////////////////////////////////////////////////////////
292 option_type const option;
295 OptionState optionState;
300 OptInfo & getOption(bool local, option_type option);
301 void request(OptInfo & info, bool enabled);
302 void response(OptInfo & info, bool enabled);
304 typedef std::map<std::pair<bool, option_type>, OptInfo> OptionsMap;
307 typedef std::map<option_type, TelnetHandler*> OptionHandlerMap;
308 OptionHandlerMap handlers_;
312 typedef std::vector<char> SendQueue;
313 SendQueue sendQueue_;
315 enum CharState { NORMAL, IAC_SEEN, EXPECT_OPTION, CR_SEEN,
316 SB_OPTION, SB_DATA, SB_IAC_SEEN };
317 CharState charState_;
323 senf::scheduler::FdEvent inputEvent_;
324 senf::scheduler::FdEvent outputEvent_;
326 unsigned pendingRequests_;
328 ClockService::clock_type requestTimeout_;
329 scheduler::TimerEvent timeout_;
331 friend class TelnetHandler;
334 /** \brief Telnet handler base class
336 \see BaseTelnetProtocol
338 struct BaseTelnetProtocol::TelnetHandler
339 : public virtual BaseTelnetProtocol
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
347 /** \brief Telnet option codes
349 See http://www.iana.org/assignments/telnet-options for a list of options
351 \ingroup telnet_group
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; }
360 /** \brief Telnet handlers
362 \ingroup telnet_group */
363 namespace telnethandler {
365 /** \brief Implement TERMINAL_TYPE option
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().
371 The last received terminal type will be returned by the terminalType() member.
373 This implementation only provides server support (querying the terminal type).
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
379 : public BaseTelnetProtocol::TelnetHandler
382 static option_type const OPTION_CODE = telnetopt::TERMINAL_TYPE;
384 void nextTerminalType(); ///< Request another terminal type
385 std::string const & terminalType() const; ///< Return current terminal type
391 virtual void v_init();
392 virtual void v_handleOptionParameters(std::string const & data);
397 /** \brief Implement NAWS (Negotiation About Window Size) option
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.
403 Whenever the window size is changed, the v_windowSizeChanged() function is called. This
404 function must be implemented in a derived class.
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
410 : public BaseTelnetProtocol::TelnetHandler
413 static option_type const OPTION_CODE = telnetopt::NAWS;
415 unsigned width() const; ///< Get current client window width
416 unsigned height() const; ///< Get current client window height
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. */
429 virtual void v_init();
430 virtual void v_handleOptionParameters(std::string const & data);
440 ///////////////////////////////hh.e////////////////////////////////////////
441 #include "Telnet.cci"
443 //#include "Telnet.ct"
444 #include "Telnet.cti"
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"