From fdc3169942c1a9523eb0fca3e2742d14612ca57c Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Sun, 14 Oct 2007 03:36:34 +0000 Subject: Beginings of a Telnet Protocol handler, I finally solved the general Option negotiation issues that plagued the earlier version, now I just have to actually process data. --- src/protocoltelnet.cpp | 131 +++++++++++++++++++++++++++++++++++++++++++++++++ src/protocoltelnet.h | 90 +++++++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 src/protocoltelnet.cpp create mode 100644 src/protocoltelnet.h diff --git a/src/protocoltelnet.cpp b/src/protocoltelnet.cpp new file mode 100644 index 0000000..b0209db --- /dev/null +++ b/src/protocoltelnet.cpp @@ -0,0 +1,131 @@ +#include "bu/protocoltelnet.h" +#include "bu/client.h" + +#define CODE_SE '\xf0' /**< End of subnegotiation params. */ +#define CODE_NOP '\xf1' /**< No operation (keep-alive). */ +#define CODE_DM '\xf2' /**< Datastream side of a Synch. */ +#define CODE_BRK '\xf3' /**< Break character. */ +#define CODE_IP '\xf4' /**< Interrupt Process character. */ +#define CODE_AO '\xf5' /**< Abort Output character. */ +#define CODE_AYT '\xf6' /**< Are You There? character. */ +#define CODE_EC '\xf7' /**< Erase Character character. */ +#define CODE_EL '\xf8' /**< Erase Line character. */ +#define CODE_GA '\xf9' /**< Go Ahead signal. */ +#define CODE_SB '\xfa' /**< Begin subnegotiation options. */ +#define CODE_WILL '\xfb' /**< Desire to do something. */ +#define CODE_WONT '\xfc' /**< Refuse to perform. */ +#define CODE_DO '\xfd' /**< Request option. */ +#define CODE_DONT '\xfe' /**< Demand a stop. */ + +#define CODE_IAC '\xff' /**< Interpret-As-Command. */ + +#define OPT_BINARY '\x00' /**< Binary mode (file transfers?). */ +#define OPT_ECHO '\x01' /**< (local) Echo mode. */ + +Bu::ProtocolTelnet::ProtocolTelnet() : + oBinary( *this, OPT_BINARY ), + oEcho( *this, OPT_ECHO ) +{ +} + +Bu::ProtocolTelnet::~ProtocolTelnet() +{ +} + +void Bu::ProtocolTelnet::onNewConnection( Bu::Client *pClient ) +{ +} + +void Bu::ProtocolTelnet::onNewData( Bu::Client *pClient ) +{ +} + + + +Bu::ProtocolTelnet::Option::Option( Bu::ProtocolTelnet &rPT, char cCode ) : + rPT( rPT ), + fOpts( 0 ), + cCode( cCode ) +{ + rPT.hOpts.insert( cCode, this ); +} + +Bu::ProtocolTelnet::Option::~Option() +{ +} + +void Bu::ProtocolTelnet::Option::localEnable( bool bSet ) +{ + if( bSet == (bool)(!(fOpts&fLocalCant)) ) return; + + if( bSet ) + fOpts &= ~fLocalCant; + else + fOpts |= fLocalCant; +} + +void Bu::ProtocolTelnet::Option::localSet( bool bSet ) +{ + if( bSet == (bool)(fOpts&fLocalIs) ) return; + + char buf[2]; + + if( bSet ) + { + buf[0] = CODE_WILL; + buf[1] = cCode; + rPT.pClient->write( buf, 2 ); + } + else + { + buf[0] = CODE_WONT; + buf[1] = cCode; + rPT.pClient->write( buf, 2 ); + } +} + +bool Bu::ProtocolTelnet::Option::isLocalEnabled() +{ + return (bool)(!(fOpts&fLocalCant)); +} + +bool Bu::ProtocolTelnet::Option::isLocalSet() +{ + return (bool)(fOpts&fLocalIs); +} + +void Bu::ProtocolTelnet::Option::remoteEnable( bool bSet ) +{ + return; +} + +void Bu::ProtocolTelnet::Option::remoteSet( bool bSet ) +{ + if( bSet == (bool)(fOpts&fRemoteIs) ) return; + + char buf[2]; + + if( bSet ) + { + buf[0] = CODE_DO; + buf[1] = cCode; + rPT.pClient->write( buf, 2 ); + } + else + { + buf[0] = CODE_DONT; + buf[1] = cCode; + rPT.pClient->write( buf, 2 ); + } +} + +bool Bu::ProtocolTelnet::Option::isRemoteEnabled() +{ + return (bool)(!(fOpts&fRemoteCant)); +} + +bool Bu::ProtocolTelnet::Option::isRemoteSet() +{ + return (bool)(fOpts&fRemoteIs); +} + diff --git a/src/protocoltelnet.h b/src/protocoltelnet.h new file mode 100644 index 0000000..3a606b5 --- /dev/null +++ b/src/protocoltelnet.h @@ -0,0 +1,90 @@ +#ifndef BU_PROTOCOL_TELNET_H +#define BU_PROTOCOL_TELNET_H + +#include "bu/protocol.h" +#include "bu/hash.h" + +namespace Bu +{ + class ProtocolTelnet : public Protocol + { + public: + ProtocolTelnet(); + virtual ~ProtocolTelnet(); + + virtual void onNewConnection( class Bu::Client *pClient ); + virtual void onNewData( class Bu::Client *pClient ); + + enum OptMode + { + optOff, + optOn, + optDesire, + optRefuse + }; + + OptMode getLocalOptBinary(); + void setLocalOptBinary( OptMode eMode ); + OptMode getRemoteOptBinary(); + void setRemoteOptBinary( OptMode eMode ); + + OptMode getLocalOptEcho(); + void setLocalOptEcho( OptMode eMode ); + OptMode getRemoteOptEcho(); + void setRemoteOptEcho( OptMode eMode ); + + private: + /** + * Represents a basic telnet option, either on or off, no parameters. + * Each Option can negotiate effectively on it's own, and has two + * parameters in each of two classes. Both local and remote can be + * enabled/disabled and set/unset. Enabled represents the ability to + * set the option, disabling an option should also unset it. Set or + * unset represent wether the option is being used, if it is allowed. + */ + class Option + { + friend class Bu::ProtocolTelnet; + private: + Option( ProtocolTelnet &rPT, char cCode ); + virtual ~Option(); + + public: + void localEnable( bool bSet=true ); + void localSet( bool bSet=true ); + + bool isLocalEnabled(); + bool isLocalSet(); + + void remoteEnable( bool bSet=true ); + void remoteSet( bool bSet=true ); + + bool isRemoteEnabled(); + bool isRemoteSet(); + + private: + enum + { + fLocalCant = 0x01, /**< Local can't/won't allow option. */ + fLocalIs = 0x02, /**< Local is using option. */ + fRemoteCant = 0x04, /**< Remote can't/won't allow option. */ + fRemoteIs = 0x08 /**< Remote is using option. */ + }; + + ProtocolTelnet &rPT; + char fOpts; + char cCode; + }; + + Hash hOpts; + + Option oBinary; + Option oEcho; + + Client *pClient; + + friend class Bu::ProtocolTelnet::Option; + }; +} + +#endif -- cgit v1.2.3