Skip to content
Snippets Groups Projects
Commit 64bd91bd authored by g0dil's avatar g0dil
Browse files

Utils/Console: Telnet protocol implementation (including NAWS and TERMINAL-TYPE options)

parent edfc07d2
No related branches found
No related tags found
No related merge requests found
// $Id$
//
// Copyright (C) 2008
// Fraunhofer Institute for Open Communication Systems (FOKUS)
// Competence Center NETwork research (NET), St. Augustin, GERMANY
// Stefan Bund <g0dil@berlios.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
\brief FancyReader public header */
#ifndef HH_SENF_Scheduler_Console_FancyReader_
#define HH_SENF_Scheduler_Console_FancyReader_ 1
// Custom includes
#include "Server.hh"
//#include "FancyReader.mpp"
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
namespace console {
namespace detail {
class FancyClientReader
: public ClientReader
{
};
}}
///////////////////////////////hh.e////////////////////////////////////////
//#include "FancyReader.cci"
//#include "FancyReader.ct"
//#include "FancyReader.cti"
#endif
// Local Variables:
// mode: c++
// fill-column: 100
// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
// End:
...@@ -5,9 +5,11 @@ import SENFSCons ...@@ -5,9 +5,11 @@ import SENFSCons
########################################################################### ###########################################################################
sources, includes = SENFSCons.Glob(env, exclude=['testServer.cc']) sources, includes = SENFSCons.Glob(env, exclude=['testServer.cc', 'telnetServer.cc'])
SENFSCons.StandardTargets(env) SENFSCons.StandardTargets(env)
SENFSCons.Lib(env, sources) SENFSCons.Lib(env, sources)
SENFSCons.Doxygen(env) SENFSCons.Doxygen(env)
SENFSCons.InstallIncludeFiles(env, includes) SENFSCons.InstallIncludeFiles(env, includes)
SENFSCons.Binary(env, "testServer", ['testServer.cc'])
SENFSCons.Binary(env, "telnetServer", ['telnetServer.cc'])
// $Id$
//
// Copyright (C) 2008
// Fraunhofer Institute for Open Communication Systems (FOKUS)
// Competence Center NETwork research (NET), St. Augustin, GERMANY
// Stefan Bund <g0dil@berlios.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
\brief Telnet non-inline non-template implementation */
#include "Telnet.hh"
//#include "Telnet.ih"
// Custom includes
#include "../membind.hh"
#include "../Logger/SenfLog.hh"
//#include "Telnet.mpp"
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
prefix_ senf::console::detail::BaseTelnetProtocol::BaseTelnetProtocol(Handle handle)
: handle_ (handle), charState_ (NORMAL), command_ (CMD_NONE), option_ (0),
inputEvent_ ("senf::console::detail::BaseTelnetProtocol::input",
senf::membind(&BaseTelnetProtocol::readHandler, this), handle,
senf::scheduler::FdEvent::EV_READ),
outputEvent_ ("senf::console::detail::BaseTelnetProtocol::output",
senf::membind(&BaseTelnetProtocol::writeHandler, this), handle,
senf::scheduler::FdEvent::EV_WRITE, false)
{}
prefix_ senf::console::detail::BaseTelnetProtocol::BaseTelnetProtocol()
: handle_ (), charState_ (NORMAL), command_ (CMD_NONE), option_ (0),
inputEvent_ ("senf::console::detail::BaseTelnetProtocol::input", 0),
outputEvent_ ("senf::console::detail::BaseTelnetProtocol::output", 0)
{}
prefix_ void senf::console::detail::BaseTelnetProtocol::write(std::string const & s)
{
for (std::string::const_iterator i (s.begin()); i != s.end(); ++i)
write(*i);
}
prefix_ void senf::console::detail::BaseTelnetProtocol::write(char c)
{
switch (c) {
case '\r':
transmit('\r');
transmit('\0');
break;
case '\n':
transmit('\r');
transmit('\n');
break;
case '\xff':
transmit('\xff');
transmit('\xff');
break;
default:
transmit(c);
break;
}
}
prefix_ void
senf::console::detail::BaseTelnetProtocol::sendOptionParameters(option_type option,
std::string const & data)
{
transmit(CMD_IAC);
transmit(CMD_SB);
transmit(option);
for (std::string::const_iterator i (data.begin()); i != data.end(); ++i)
if (*i == '\xff') {
transmit('\xff');
transmit('\xff');
}
else
transmit(*i);
transmit(CMD_IAC);
transmit(CMD_SE);
}
prefix_ void senf::console::detail::BaseTelnetProtocol::v_handleNOP()
{}
prefix_ void senf::console::detail::BaseTelnetProtocol::v_handleBRK()
{}
prefix_ void senf::console::detail::BaseTelnetProtocol::v_handleIP()
{}
prefix_ void senf::console::detail::BaseTelnetProtocol::v_handleAO()
{}
prefix_ void senf::console::detail::BaseTelnetProtocol::v_handleAYT()
{}
prefix_ void senf::console::detail::BaseTelnetProtocol::v_handleEC()
{}
prefix_ void senf::console::detail::BaseTelnetProtocol::v_handleEL()
{}
prefix_ void senf::console::detail::BaseTelnetProtocol::v_handleGA()
{}
prefix_ void senf::console::detail::BaseTelnetProtocol::handleChar(char c)
{
switch (charState_) {
case NORMAL:
handleNormalChar(c);
break;
case IAC_SEEN:
handleCommand(static_cast<unsigned char>(c));
break;
case EXPECT_OPTION:
handleOption(c);
break;
case CR_SEEN:
handleCR(c);
break;
case SB_OPTION:
handleSBOption(c);
break;
case SB_DATA:
handleSBData(c);
break;
case SB_IAC_SEEN:
handleSBIAC(c);
break;
}
}
prefix_ void senf::console::detail::BaseTelnetProtocol::handleNormalChar(char c)
{
switch (c) {
case '\r':
charState_ = CR_SEEN;
break;
case '\xff':
charState_ = IAC_SEEN;
break;
default:
emit(c);
break;
}
}
prefix_ void senf::console::detail::BaseTelnetProtocol::handleCommand(char c)
{
switch (c) {
case CMD_SE:
// Ignore spurious SE commands .. they should only occur while in subnegotiation mode
charState_ = NORMAL;
break;
case CMD_NOP:
case CMD_DM:
case CMD_BRK:
case CMD_IP:
case CMD_AO:
case CMD_AYT:
case CMD_EC:
case CMD_EL:
case CMD_GA:
command_ = Command(static_cast<unsigned char>(c));
processCommand();
charState_ = NORMAL;
break;
case CMD_SB:
command_ = CMD_SB;
charState_ = SB_OPTION;
break;
case CMD_WILL:
case CMD_WONT:
case CMD_DO:
case CMD_DONT:
command_ = Command(static_cast<unsigned char>(c));
charState_ = EXPECT_OPTION;
break;
case CMD_IAC:
charState_ = NORMAL;
emit(CMD_IAC);
break;
default:
emit(CMD_IAC);
charState_ = NORMAL;
handleChar(c);
break;
}
}
prefix_ void senf::console::detail::BaseTelnetProtocol::handleOption(char c)
{
option_ = c;
processCommand();
charState_ = NORMAL;
}
prefix_ void senf::console::detail::BaseTelnetProtocol::handleCR(char c)
{
switch (c) {
case '\0':
emit('\r');
charState_ = NORMAL;
break;
case '\n':
emit('\n');
charState_ = NORMAL;
break;
default:
emit('\r');
charState_ = NORMAL;
handleChar(c);
break;
}
}
prefix_ void senf::console::detail::BaseTelnetProtocol::handleSBOption(char c)
{
option_ = c;
charState_ = SB_DATA;
data_.clear();
}
prefix_ void senf::console::detail::BaseTelnetProtocol::handleSBData(char c)
{
if (c == '\xff')
charState_ = SB_IAC_SEEN;
else
data_.push_back(c);
}
prefix_ void senf::console::detail::BaseTelnetProtocol::handleSBIAC(char c)
{
switch (c) {
case CMD_IAC:
data_.push_back(c);
charState_ = SB_DATA;
break;
case CMD_SE:
processCommand();
charState_ = NORMAL;
break;
default:
charState_ = IAC_SEEN;
handleChar(c);
break;
}
}
prefix_ void senf::console::detail::BaseTelnetProtocol::processCommand()
{
switch (command_) {
case CMD_NONE:
case CMD_SE:
case CMD_DM:
case CMD_IAC:
break;
case CMD_NOP:
v_handleNOP();
break;
case CMD_BRK:
v_handleBRK();
break;
case CMD_IP:
v_handleIP();
break;
case CMD_AO:
v_handleAO();
break;
case CMD_AYT:
v_handleAYT();
break;
case CMD_EC:
v_handleEC();
break;
case CMD_EL:
v_handleEL();
break;
case CMD_GA:
v_handleGA();
break;
case CMD_SB:
{
OptionHandlerMap::const_iterator i (handlers_.find(option_));
if (i != handlers_.end())
i->second->v_handleOptionParameters(data_);
break;
}
case CMD_WILL:
case CMD_WONT:
response(getOption(false, option_), command_ == CMD_WILL);
break;
case CMD_DO:
case CMD_DONT:
response(getOption(true, option_), command_ == CMD_DO);
break;
}
}
prefix_ void senf::console::detail::BaseTelnetProtocol::transmit(char c)
{
sendQueue_.push_back(c);
outputEvent_.enable();
}
prefix_ void senf::console::detail::BaseTelnetProtocol::readHandler(int state)
{
if (state != senf::scheduler::FdEvent::EV_READ || handle_.eof()) {
inputEvent_.disable();
v_eof();
return;
}
std::string data;
handle_.read(data, 0u);
for (std::string::const_iterator i (data.begin()); i != data.end(); ++i)
handleChar(*i);
}
prefix_ void senf::console::detail::BaseTelnetProtocol::writeHandler(int state)
{
if (state != senf::scheduler::FdEvent::EV_WRITE) {
outputEvent_.disable();
inputEvent_.disable();
v_eof();
return;
}
sendQueue_.erase(sendQueue_.begin(),
handle_.write(std::make_pair(sendQueue_.begin(), sendQueue_.end())));
if (sendQueue_.empty())
outputEvent_.disable();
}
prefix_ senf::console::detail::BaseTelnetProtocol::OptInfo &
senf::console::detail::BaseTelnetProtocol::getOption(bool local, option_type option)
{
OptionsMap::iterator i (options_.find(std::make_pair(local, option)));
if (i == options_.end())
i = options_.insert(std::make_pair(std::make_pair(local, option),
OptInfo(local, option))).first;
return i->second;
}
prefix_ void senf::console::detail::BaseTelnetProtocol::request(OptInfo & info, bool enabled)
{
info.wantState = enabled ? OptInfo::WANTED : OptInfo::DISABLED;
if (enabled != info.enabled) {
transmit(CMD_IAC);
transmit((info.local ? CMD_WILL : CMD_DO) + (enabled ? 0 : 1));
transmit(info.option);
info.optionState = OptInfo::REQUEST_SENT;
}
}
prefix_ void senf::console::detail::BaseTelnetProtocol::response(OptInfo & info, bool enabled)
{
// If this is a response, we need to unconditionally accept it. If this is a remote
// configuration request, we accept it if wantState is wither WANTED or ACCEPTED. If this is a
// response, we never send out a reply. If it is a remote request we send out a reply only if
// either a) we reject the request or b) we accept it AND we have changed our own mode.
if (info.optionState == OptInfo::REQUEST_SENT) {
// This is a response
info.optionState = OptInfo::ACKNOWLEDGED;
info.enabled = enabled;
}
else if (enabled != info.enabled) {
// Request to change the current state
bool accept (enabled);
if (!enabled ||
enabled && (info.wantState == OptInfo::WANTED || info.wantState == OptInfo::ACCEPTED)) {
// Accept the request
info.optionState = OptInfo::ACKNOWLEDGED;
info.enabled = enabled;
}
else
// Reject the request
accept = info.enabled;
transmit(CMD_IAC);
transmit((info.local ? CMD_WILL : CMD_DO) + (accept ? 0 : 1));
transmit(info.option);
}
else
return;
if (info.enabled) {
OptionHandlerMap::const_iterator i (handlers_.find(info.option));
if (i != handlers_.end())
i->second->v_init();
}
}
///////////////////////////////////////////////////////////////////////////
// senf::console::detail::telnethandler::TerminalType
prefix_ senf::console::detail::telnethandler::TerminalType::TerminalType()
{
registerHandler(this);
}
prefix_ void senf::console::detail::telnethandler::TerminalType::nextTerminalType()
{
sendOptionParameters(telnetopt::TERMINAL_TYPE, "\x01");
}
prefix_ void senf::console::detail::telnethandler::TerminalType::
v_handleOptionParameters(std::string const & data)
{
if (data.size() <= 0)
return;
if (data[0] == '\x00')
v_handleTerminalType(data.substr(1));
}
prefix_ void senf::console::detail::telnethandler::TerminalType::v_init()
{
nextTerminalType();
}
///////////////////////////////////////////////////////////////////////////
// senf::console::detail::telnethandler::NAWS
prefix_ senf::console::detail::telnethandler::NAWS::NAWS()
{
registerHandler(this);
}
prefix_ void senf::console::detail::telnethandler::NAWS::v_init()
{}
prefix_ void
senf::console::detail::telnethandler::NAWS::v_handleOptionParameters(std::string const & data)
{
if (data.size() != 4)
return;
v_handleWindowSize(
(static_cast<unsigned char>(data[0])<<8)+static_cast<unsigned char>(data[1]),
(static_cast<unsigned char>(data[2])<<8)+static_cast<unsigned char>(data[3]));
}
///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_
//#include "Telnet.mpp"
// Local Variables:
// mode: c++
// fill-column: 100
// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
// End:
// $Id$
//
// Copyright (C) 2008
// Fraunhofer Institute for Open Communication Systems (FOKUS)
// Competence Center NETwork research (NET), St. Augustin, GERMANY
// Stefan Bund <g0dil@berlios.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
\brief Telnet inline non-template implementation */
//#include "Telnet.ih"
// Custom includes
#define prefix_ inline
///////////////////////////////cci.p///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// senf::console::detail::BaseTelnetProtocol::OptInfo
prefix_ senf::console::detail::BaseTelnetProtocol::OptInfo::OptInfo()
: local (false), option (0u), wantState (DISABLED), optionState (NONE), enabled (false)
{}
prefix_ senf::console::detail::BaseTelnetProtocol::OptInfo::OptInfo(bool l, option_type o)
: local (l), option (o), wantState (DISABLED), optionState (NONE), enabled (false)
{}
///////////////////////////////////////////////////////////////////////////
// senf::console::detail::BaseTelnetProtocol::TelnetHandler
prefix_ senf::console::detail::BaseTelnetProtocol::TelnetHandler::~TelnetHandler()
{}
///////////////////////////////////////////////////////////////////////////
// senf::console::detail::BaseTelnetProtocol
prefix_ senf::console::detail::BaseTelnetProtocol::~BaseTelnetProtocol()
{}
prefix_ void senf::console::detail::BaseTelnetProtocol::sendNOP()
{
transmit(CMD_IAC);
transmit(CMD_NOP);
}
prefix_ void senf::console::detail::BaseTelnetProtocol::sendBRK()
{
transmit(CMD_IAC);
transmit(CMD_BRK);
}
prefix_ void senf::console::detail::BaseTelnetProtocol::sendIP()
{
transmit(CMD_IAC);
transmit(CMD_IP);
}
prefix_ void senf::console::detail::BaseTelnetProtocol::sendAO()
{
transmit(CMD_IAC);
transmit(CMD_AO);
}
prefix_ void senf::console::detail::BaseTelnetProtocol::sendAYT()
{
transmit(CMD_IAC);
transmit(CMD_AYT);
}
prefix_ void senf::console::detail::BaseTelnetProtocol::sendEC()
{
transmit(CMD_IAC);
transmit(CMD_EC);
}
prefix_ void senf::console::detail::BaseTelnetProtocol::sendEL()
{
transmit(CMD_IAC);
transmit(CMD_EL);
}
prefix_ void senf::console::detail::BaseTelnetProtocol::sendGA()
{
transmit(CMD_IAC);
transmit(CMD_GA);
}
prefix_ void senf::console::detail::BaseTelnetProtocol::requestLocalOption(option_type option,
bool enabled)
{
request(getOption(true, option), enabled);
}
prefix_ void senf::console::detail::BaseTelnetProtocol::acceptLocalOption(option_type option,
bool enabled)
{
getOption(true, option).wantState = OptInfo::ACCEPTED;
}
prefix_ void senf::console::detail::BaseTelnetProtocol::requestPeerOption(option_type option,
bool enabled)
{
request(getOption(false, option), enabled);
}
prefix_ void senf::console::detail::BaseTelnetProtocol::acceptPeerOption(option_type option,
bool enabled)
{
getOption(false, option).wantState = OptInfo::ACCEPTED;
}
prefix_ void senf::console::detail::BaseTelnetProtocol::emit(char c)
{
v_charReceived(c);
}
///////////////////////////////cci.e///////////////////////////////////////
#undef prefix_
// Local Variables:
// mode: c++
// fill-column: 100
// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
// End:
// $Id$
//
// Copyright (C) 2008
// Fraunhofer Institute for Open Communication Systems (FOKUS)
// Competence Center NETwork research (NET), St. Augustin, GERMANY
// Stefan Bund <g0dil@berlios.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
\brief Telnet inline template implementation */
//#include "Telnet.ih"
// Custom includes
#define prefix_ inline
///////////////////////////////cti.p///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// senf::console::detail::BaseTelnetProtocol
template <class Handler>
prefix_ void senf::console::detail::BaseTelnetProtocol::registerHandler(Handler * h,
bool request)
{
handlers_.insert(std::make_pair(Handler::OPTION_CODE, h));
if (request)
requestPeerOption(Handler::OPTION_CODE);
}
///////////////////////////////cti.e///////////////////////////////////////
#undef prefix_
// Local Variables:
// mode: c++
// fill-column: 100
// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
// End:
// $Id$
//
// Copyright (C) 2008
// Fraunhofer Institute for Open Communication Systems (FOKUS)
// Competence Center NETwork research (NET), St. Augustin, GERMANY
// Stefan Bund <g0dil@berlios.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
\brief Telnet public header */
#ifndef HH_SENF_Scheduler_Console_Telnet_
#define HH_SENF_Scheduler_Console_Telnet_ 1
// Custom includes
#include <vector>
#include <map>
#include <senf/Socket.hh>
#include <senf/Scheduler/Scheduler.hh>
//#include "Telnet.mpp"
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
namespace console {
namespace detail {
/** \brief Telnet server
\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
\todo SYNCH handling
*/
class BaseTelnetProtocol
{
public:
typedef ClientSocketHandle<senf::MakeSocketPolicy<
ConnectedCommunicationPolicy,
StreamFramingPolicy,
ReadablePolicy,
WriteablePolicy>::policy> Handle;
typedef unsigned char option_type;
struct TelnetHandler;
void write(std::string const & s);
void write(char c);
void sendNOP();
void sendBRK();
void sendIP();
void sendAO();
void sendAYT();
void sendEC();
void sendEL();
void sendGA();
void sendOptionParameters(option_type option, std::string const & data);
void requestLocalOption(option_type option, bool enabled = true);
void acceptLocalOption(option_type option, bool enabled = true);
void requestPeerOption(option_type option, bool enabled = true);
void acceptPeerOption(option_type option, bool enabled = true);
protected:
explicit BaseTelnetProtocol(Handle handle);
BaseTelnetProtocol();
virtual ~BaseTelnetProtocol();
template <class Handler>
void registerHandler(Handler * h, bool request=true);
private:
#ifndef DOXYGEN
private:
#endif
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();
#ifdef DOXYGEN
private:
#endif
void handleChar(char c);
void handleNormalChar(char c);
void handleCommand(char c);
void handleOption(char c);
void handleCR(char c);
void handleSBOption(char c);
void handleSBData(char c);
void handleSBIAC(char c);
void emit(char c);
void processCommand();
void transmit(char c);
void sendWILL(char option);
void sendWONT(char option);
void sendDO(char option);
void sendDONT(char option);
void readHandler(int state);
void writeHandler(int state);
enum Command {
CMD_NONE = 0,
CMD_SE = 240,
CMD_NOP = 241,
CMD_DM = 242,
CMD_BRK = 243,
CMD_IP = 244,
CMD_AO = 245,
CMD_AYT = 246,
CMD_EC = 247,
CMD_EL = 248,
CMD_GA = 249,
CMD_SB = 250,
CMD_WILL = 251,
CMD_WONT = 252,
CMD_DO = 253,
CMD_DONT = 254,
CMD_IAC = 255,
};
struct OptInfo
{
enum WantState { WANTED, ACCEPTED, DISABLED };
enum OptionState { NONE, REQUEST_SENT, ACKNOWLEDGED };
OptInfo();
OptInfo(bool local, option_type option);
///////////////////////////////////////////////////////////////
bool const local;
option_type const option;
WantState wantState;
OptionState optionState;
bool enabled;
};
OptInfo & getOption(bool local, option_type option);
void request(OptInfo & info, bool enabled);
void response(OptInfo & info, bool enabled);
typedef std::map<std::pair<bool, option_type>, OptInfo> OptionsMap;
OptionsMap options_;
typedef std::map<option_type, TelnetHandler*> OptionHandlerMap;
OptionHandlerMap handlers_;
Handle handle_;
typedef std::vector<char> SendQueue;
SendQueue sendQueue_;
enum CharState { NORMAL, IAC_SEEN, EXPECT_OPTION, CR_SEEN,
SB_OPTION, SB_DATA, SB_IAC_SEEN };
CharState charState_;
Command command_;
option_type option_;
std::string data_;
senf::scheduler::FdEvent inputEvent_;
senf::scheduler::FdEvent outputEvent_;
friend class TelnetHandler;
};
struct BaseTelnetProtocol::TelnetHandler
: public virtual BaseTelnetProtocol
{
virtual ~TelnetHandler();
virtual void v_init() = 0;
virtual void v_handleOptionParameters(std::string const & data) = 0;
};
// See http://www.iana.org/assignments/telnet-options for a list of options
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 TERMINAL_TYPE = 24u; }
namespace telnetopt { BaseTelnetProtocol::option_type const NAWS = 31u; }
namespace telnetopt { BaseTelnetProtocol::option_type const LINEMODE = 34u; }
namespace telnethandler {
class TerminalType
: public BaseTelnetProtocol::TelnetHandler
{
public:
static option_type const OPTION_CODE = telnetopt::TERMINAL_TYPE;
void nextTerminalType();
protected:
TerminalType();
private:
virtual void v_handleTerminalType(std::string const & type) = 0;
virtual void v_init();
virtual void v_handleOptionParameters(std::string const & data);
};
class NAWS
: public BaseTelnetProtocol::TelnetHandler
{
public:
static option_type const OPTION_CODE = telnetopt::NAWS;
protected:
NAWS();
private:
virtual void v_handleWindowSize(unsigned width, unsigned height) = 0;
virtual void v_init();
virtual void v_handleOptionParameters(std::string const & data);
};
}
}}}
///////////////////////////////hh.e////////////////////////////////////////
#include "Telnet.cci"
//#include "Telnet.ct"
#include "Telnet.cti"
#endif
// Local Variables:
// mode: c++
// fill-column: 100
// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
// End:
// $Id$
//
// Copyright (C) 2008
// Fraunhofer Institute for Open Communication Systems (FOKUS)
// Competence Center NETwork research (NET), St. Augustin, GERMANY
// Stefan Bund <g0dil@berlios.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
\brief Telnet.test unit tests */
//#include "Telnet.test.hh"
//#include "Telnet.test.ih"
// Custom includes
#include "Telnet.hh"
#include "../../Utils/auto_unit_test.hh"
#include <boost/test/test_tools.hpp>
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
BOOST_AUTO_UNIT_TEST(telnet)
{}
///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_
// Local Variables:
// mode: c++
// fill-column: 100
// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
// End:
// $Id$
//
// Copyright (C) 2008
// Fraunhofer Institute for Open Communication Systems (FOKUS)
// Competence Center NETwork research (NET), St. Augustin, GERMANY
// Stefan Bund <g0dil@berlios.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
\brief telnetServer non-inline non-template implementation */
//#include "telnetServer.hh"
//#include "telnetServer.ih"
// Custom includes
#include "Telnet.hh"
#include "../Logger.hh"
#include "../../Socket/Protocols/INet.hh"
//#include "telnetServer.mpp"
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
namespace {
class MyTelnet
: public virtual senf::console::detail::BaseTelnetProtocol,
public senf::console::detail::telnethandler::TerminalType,
public senf::console::detail::telnethandler::NAWS
{
public:
explicit MyTelnet(Handle handle) : senf::console::detail::BaseTelnetProtocol(handle)
{
requestPeerOption(senf::console::detail::telnetopt::SUPPRESS_GO_AHEAD);
requestLocalOption(senf::console::detail::telnetopt::SUPPRESS_GO_AHEAD);
requestLocalOption(senf::console::detail::telnetopt::ECHO);
}
private:
virtual void v_charReceived(char c)
{
SENF_LOG(("Char: " << c));
}
virtual void v_eof()
{
SENF_LOG(("EOF"));
senf::scheduler::terminate();
}
virtual void v_handleTerminalType(std::string const & type)
{
SENF_LOG(("Terminal type: " << type));
}
virtual void v_handleWindowSize(unsigned width, unsigned height)
{
SENF_LOG(("Window size: " << width << "x" << height));
}
};
typedef senf::TCPv4ServerSocketHandle ServerHandle;
typedef ServerHandle::ClientHandle ClientHandle;
}
int main(int argc, char const ** argv)
{
SENF_LOG(("Starting server."));
ServerHandle server (ServerHandle::Address("127.0.0.1:22344"));
ClientHandle client (server.accept());
SENF_LOG(("Starting MyTelnet"));
MyTelnet telnet (client);
senf::scheduler::process();
return 0;
}
///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_
//#include "telnetServer.mpp"
// Local Variables:
// mode: c++
// fill-column: 100
// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u telnetServer"
// End:
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment