namespace senf {
namespace term {
- /** \brief Telnet server
+ /** \defgroup telnet_group Telnet protocol
- \see
- <a href="http://tools.ietf.org/html/rfc854">RFC 854</a> The Telnet protocol \n
- <a href="http://tools.ietf.org/html/rfc854">RFC 855</a> Telnet option specifications
+ The telnet protocol implementation is based on the relevant RFCs:
+
+ \li <a href="http://tools.ietf.org/html/rfc854">RFC 854</a> The Telnet protocol
+ \li <a href="http://tools.ietf.org/html/rfc854">RFC 855</a> Telnet option specifications
+
+ BaseTelnetProtocol provides the basic protocol implementation with generic telnet option
+ support. Several other classes provide additional support for further telnet options:
+
+ \li telnethandler::TerminalType provides support for the TERMINAL_TYPE option
+ \li telnethandler::NAWS provides support for the NAWS (Negotiation About Window Size) option
+
+ There are some symbolic constants for telnet option in the senf::term::telnetopt namespace.
+ */
+
+ /** \brief Telnet protocol implementation
+
+ This class implements the basic telnet protocol. It provides option parsing and negotiation
+ and implements the necessary character quoting.
+
+ This class is a base class. Several virtual function hooks are provided which will be called
+ by the protocol implementation.
+
+ The telnet protocol implementation is symmetric: At this level, there is no difference
+ between a telnet client and a telnet server.
+
+ This telnet protocol base class integrates with the SENF Scheduler, it relies on the
+ scheduler main loop to be active.
+
+ \section telnethandlers Telnet option handlers
+
+ To support complex telnet option which require subnegotiation, TelnetHandler's are
+ provided. A telnet handler is a class derived from TelnetHandler and then inherited into the
+ target telnet implementation class:
+
+ \code
+ class MyTelnet
+ : public senf::term::telnethandler::TerminalType,
+ public senf::term::telnethandler::NAWS
+ {
+ MyTelnet(Handle handle) : BaseTelnetProtocol(handle) {}
+
+ // ...
+ };
+ \endcode
+
+ It is very important, the BaseTelnetProtocol is \e always inherited by \c public \c virtual
+ inheritance. This allows the BaseTelnetProtocol constructor to be called by the most derived
+ class directly as above.
+
+ Each terminal handler may provide an additional API and/or additional virtual function
+ callbacks.
+
+ To implement a new terminal handler, derive from TelnetHandler and register the
+ handler. BaseTelnetProtocol will automatically request the corresponding option to be
+ enabled and will call the handlers \c v_init() member as soon as the peer as asserted the
+ option.
+
+ Whenever a subnegotiation for the registered handler is received, the handlers
+ \c v_handleOptionParameters() member is called.
+
+ \code
+ class MyTelnetHandler
+ : public senf::term::BaseTelnetProtocol::TelnetHandler
+ {
+ public:
+ // This constant is MANDATORY and gives the option code which this handler services
+ static option_type const OPTION_CODE = MY_OPTION_CODE;
+
+ void frobble() { // ... }
+
+ protected:
+ MyTelnetHandler() { registerHandler(this); }
+
+ private:
+ virtual void v_init()
+ {
+ sendOptionParameters(OPTION_CODE, "my special subnegotiation");
+ incrementRequestCounter();
+ }
+
+ virtual void v_handleOptionParameters(std::string const & data)
+ {
+ if (data == "another special subnegotiation")
+ decrementRequestCounter();
+ }
+ };
+ \endcode
\todo SYNCH handling
+
+ \ingroup telnet_group
*/
class BaseTelnetProtocol
{
ConnectedCommunicationPolicy,
StreamFramingPolicy,
ReadablePolicy,
- WriteablePolicy>::policy> Handle;
+ WriteablePolicy>::policy> Handle; ///< Type of socket handle required
- typedef unsigned char option_type;
+ typedef unsigned char option_type; ///< Type of telnet option numbers
struct TelnetHandler;
- void write(std::string const & s);
- void write(char c);
-
- Handle handle();
-
- void sendNOP();
- void sendBRK();
- void sendIP();
- void sendAO();
- void sendAYT();
- void sendEC();
- void sendEL();
- void sendGA();
+ void write(std::string const & s); ///< Send string to peer
+ /**< The string will be correctly quoted and newline chars
+ will be sent as CR/LF pairs. */
+ void write(char c); ///< Send single character to peer
+ /**< The character will be correctly quoted and newline
+ chars will be sent as CR/LF pairs. */
+
+ Handle handle(); ///< Get socket handle
+
+ void sendNOP(); ///< Send NOP to peer
+ void sendBRK(); ///< Send BReaK to peer
+ void sendIP(); ///< Send InterruptProcess to peer
+ void sendAO(); ///< Send AbortOutput to peer
+ void sendAYT(); ///< Send AreYouThere to peer
+ void sendEC(); ///< Send EraseCharacter to peer
+ void sendEL(); ///< Send EraseLine to peer
+ void sendGA(); ///< Send GoAhead to peer
void sendOptionParameters(option_type option, std::string const & data);
+ ///< Send extended option parameter to peer
+ /**< This will send \a data as extended option parameter of
+ option \a option to peer via a subnegotiation. */
void requestLocalOption(option_type option, bool enabled = true);
+ ///< Request option to be enabled here
+ /**< This will send a WILL \a option request to the peer */
void acceptLocalOption(option_type option, bool enabled = true);
+ ///< Accept a request for an option to be enabled here
+ /**< If the peer sends a DO \a option request, the request
+ will be granted */
void requestPeerOption(option_type option, bool enabled = true);
+ ///< Request peer to enable an option
+ /**< This will send a DO \a option request to the peer */
void acceptPeerOption(option_type option, bool enabled = true);
+ ///< Accept a request by the peer to enable an option
+ /**< If the peer sends a WILL \a option request, the request
+ will be ganted */
- bool localOption(option_type option);
- bool peerOption(option_type option);
+ bool localOption(option_type option); ///< \c true, if \a option locally enabled
+ bool peerOption(option_type option); ///< \c true, if \a option enabled in peer
protected:
- explicit BaseTelnetProtocol(Handle handle);
- BaseTelnetProtocol();
+ explicit BaseTelnetProtocol(Handle handle); ///< Construct telnet protocol handler
+ BaseTelnetProtocol(); ///< Provided for TelnetHandler mixins only
+
virtual ~BaseTelnetProtocol();
template <class Handler>
void registerHandler(Handler * h, bool request=true);
+ ///< Register a TelnetHandler
- void incrementRequestCounter();
- void decrementRequestCounter();
- bool requestsPending();
+ void incrementRequestCounter(); ///< Increment request counter
+ /**< This member may be called by a telnet handler to wait
+ for additional negotiations. It must be paired with a
+ corresponding decrementRequestCounter() call when that
+ negotiation is received. */
+ void decrementRequestCounter(); ///< Decrement request counter
+ /**< \see inrementRequestCounter() */
+ bool requestsPending(); ///< \c true, if there are pending requests
#ifndef DOXYGEN
private:
#endif
- virtual void v_setupComplete() = 0;
- virtual void v_charReceived(char c) = 0;
- virtual void v_eof() = 0;
-
- virtual void v_handleNOP();
- virtual void v_handleBRK();
- virtual void v_handleIP();
- virtual void v_handleAO();
- virtual void v_handleAYT();
- virtual void v_handleEC();
- virtual void v_handleEL();
- virtual void v_handleGA();
+ virtual void v_setupComplete() = 0; ///< Called, when no further requests are pending
+ /**< This callback will be called, when no further
+ negotiations are to be expected. The default
+ negotiation timeout is 500ms. If no reply is received
+ in this time, the request is abandoned and
+ v_setupComplete() is called.
+
+ mixin TelnetHandler's may additionally increment the
+ request counter to wait for specific
+ subnegotiations. v_setupComplete() will be called, when
+ all these negotiations are complete or have timed
+ out. */
+ virtual void v_charReceived(char c) = 0; ///< Called whenever a data character is received
+ virtual void v_eof() = 0; ///< Called on input EOF
+
+ virtual void v_handleNOP(); ///< Called, when the peer sends a NOP
+ virtual void v_handleBRK(); ///< Called, when the peer sends a BReaK
+ virtual void v_handleIP(); ///< Called, when the peer sends an InterruptProcess
+ virtual void v_handleAO(); ///< Called, when the peer sends an AbortOutput
+ virtual void v_handleAYT(); ///< Called, when the peer sends an AreYouThere
+ virtual void v_handleEC(); ///< Called, when the peer sends an EraseCharacter
+ virtual void v_handleEL(); ///< Called, when the peer sends an EraseLine
+ virtual void v_handleGA(); ///< Called, when the peer sends a GoAhead
-#ifdef DOXYGEN
private:
-#endif
void handleChar(char c);
void handleNormalChar(char c);
void handleCommand(char c);
friend class TelnetHandler;
};
+ /** \brief Telnet handler base class
+
+ \see BaseTelnetProtocol
+ */
struct BaseTelnetProtocol::TelnetHandler
: public virtual BaseTelnetProtocol
{
virtual ~TelnetHandler();
- virtual void v_init() = 0;
+ virtual void v_init() = 0; ///< Called, after option has been enabled
virtual void v_handleOptionParameters(std::string const & data) = 0;
+ ///< Called, whenever a subnegotiation is received
};
- // See http://www.iana.org/assignments/telnet-options for a list of options
+ /** \brief Telnet option codes
+
+ See http://www.iana.org/assignments/telnet-options for a list of options
+
+ \ingroup telnet_group
+ */
namespace telnetopt { BaseTelnetProtocol::option_type const ECHO = 1u; }
namespace telnetopt { BaseTelnetProtocol::option_type const TRANSMIT_BINARY = 0u; }
namespace telnetopt { BaseTelnetProtocol::option_type const SUPPRESS_GO_AHEAD = 3u; }
namespace telnetopt { BaseTelnetProtocol::option_type const NAWS = 31u; }
namespace telnetopt { BaseTelnetProtocol::option_type const LINEMODE = 34u; }
+/** \brief Telnet handlers
+
+ \ingroup telnet_group */
namespace telnethandler {
+ /** \brief Implement TERMINAL_TYPE option
+
+ This telnet handler implements the TERMINAL_TYPE option. The handler automatically requests
+ the first terminal type during initialization. Further terminal types may then be reqeusted
+ by calling nextTerminalType().
+
+ The last received terminal type will be returned by the terminalType() member.
+
+ This implementation only provides server support (querying the terminal type).
+
+ \see BaseTelnetProtocol for how to integrate this handler \n
+ <a href="http://tools.ietf.org/html/rfc1091">RFC 1091</a> Telnet Terminal-Type Option
+ */
class TerminalType
: public BaseTelnetProtocol::TelnetHandler
{
public:
static option_type const OPTION_CODE = telnetopt::TERMINAL_TYPE;
- void nextTerminalType();
- std::string const & terminalType() const;
+ void nextTerminalType(); ///< Request another terminal type
+ std::string const & terminalType() const; ///< Return current terminal type
protected:
TerminalType();
std::string type_;
};
+ /** \brief Implement NAWS (Negotiation About Window Size) option
+
+ This telnet handler implements the NAWS option. The client terminals window size will be
+ requested during initialization. The current window size may always be accessed using the
+ width() and height() members.
+
+ Whenever the window size is changed, the v_windowSizeChanged() function is called. This
+ function must be implemented in a derived class.
+
+ \see BaseTelnetProtocol for how to integrate this handler \n
+ <a href="http://tools.ietf.org/html/rfc1073">RFC 1073</a> Telnet Window Size Option
+ */
class NAWS
: public BaseTelnetProtocol::TelnetHandler
{
public:
static option_type const OPTION_CODE = telnetopt::NAWS;
- unsigned width() const;
- unsigned height() const;
+ unsigned width() const; ///< Get current client window width
+ unsigned height() const; ///< Get current client window height
protected:
NAWS();
+# ifndef DOXYGEN
private:
- virtual void v_windowSizeChanged() = 0;
+# endif
+ virtual void v_windowSizeChanged() = 0; ///< Called, whenever window size changes
+ /**< This member is called for every window size change \e
+ after initialization. */
+ private:
virtual void v_init();
virtual void v_handleOptionParameters(std::string const & data);