Skip to content
Snippets Groups Projects
Commit 0b84d744 authored by g0dil's avatar g0dil
Browse files

Utils/Console: Implement v_setupComplete() callback and request timeout

parent 98eca199
No related branches found
No related tags found
No related merge requests found
......@@ -41,13 +41,20 @@ prefix_ senf::console::detail::BaseTelnetProtocol::BaseTelnetProtocol(Handle han
senf::scheduler::FdEvent::EV_READ),
outputEvent_ ("senf::console::detail::BaseTelnetProtocol::output",
senf::membind(&BaseTelnetProtocol::writeHandler, this), handle,
senf::scheduler::FdEvent::EV_WRITE, false)
senf::scheduler::FdEvent::EV_WRITE, false),
pendingRequests_ (0u),
requestTimeout_ (ClockService::milliseconds(DEFAULT_REQUEST_TIMEOUT_MS)),
timeout_ ("senf::console::detail::BaseTelnetProtocol::timeout",
senf::membind(&BaseTelnetProtocol::timeout, this))
{}
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)
outputEvent_ ("senf::console::detail::BaseTelnetProtocol::output", 0),
pendingRequests_ (0u),
requestTimeout_ (ClockService::milliseconds(DEFAULT_REQUEST_TIMEOUT_MS)),
timeout_ ("senf::console::detail::BaseTelnetProtocol::timeout", 0)
{}
prefix_ void senf::console::detail::BaseTelnetProtocol::write(std::string const & s)
......@@ -346,6 +353,14 @@ prefix_ void senf::console::detail::BaseTelnetProtocol::writeHandler(int state)
outputEvent_.disable();
}
prefix_ void senf::console::detail::BaseTelnetProtocol::timeout()
{
if (pendingRequests_ > 0u) {
pendingRequests_ = 0u;
v_setupComplete();
}
}
prefix_ senf::console::detail::BaseTelnetProtocol::OptInfo &
senf::console::detail::BaseTelnetProtocol::getOption(bool local, option_type option)
{
......@@ -364,11 +379,14 @@ prefix_ void senf::console::detail::BaseTelnetProtocol::request(OptInfo & info,
transmit((info.local ? CMD_WILL : CMD_DO) + (enabled ? 0 : 1));
transmit(info.option);
info.optionState = OptInfo::REQUEST_SENT;
incrementRequestCounter();
}
}
prefix_ void senf::console::detail::BaseTelnetProtocol::response(OptInfo & info, bool enabled)
{
bool decrementCount (false);
// 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
......@@ -377,6 +395,7 @@ prefix_ void senf::console::detail::BaseTelnetProtocol::response(OptInfo & info,
// This is a response
info.optionState = OptInfo::ACKNOWLEDGED;
info.enabled = enabled;
decrementCount = true;
}
else if (enabled != info.enabled) {
// Request to change the current state
......@@ -401,6 +420,21 @@ prefix_ void senf::console::detail::BaseTelnetProtocol::response(OptInfo & info,
if (i != handlers_.end())
i->second->v_init();
}
if (decrementCount)
// This call must be AFTER calling v_init since v_init might increment the request count
// again. Otherwise v_setupComplete might be called prematurely
decrementRequestCounter();
}
prefix_ void senf::console::detail::BaseTelnetProtocol::decrementRequestCounter()
{
if (pendingRequests_ > 0u) {
-- pendingRequests_;
if (pendingRequests_ == 0u) {
timeout_.disable();
v_setupComplete();
}
}
}
///////////////////////////////////////////////////////////////////////////
......@@ -421,34 +455,42 @@ v_handleOptionParameters(std::string const & data)
{
if (data.size() <= 0)
return;
if (data[0] == '\x00')
v_handleTerminalType(data.substr(1));
if (data[0] == '\x00') {
type_ = data.substr(1);
decrementRequestCounter();
}
}
prefix_ void senf::console::detail::telnethandler::TerminalType::v_init()
{
nextTerminalType();
incrementRequestCounter();
}
///////////////////////////////////////////////////////////////////////////
// senf::console::detail::telnethandler::NAWS
prefix_ senf::console::detail::telnethandler::NAWS::NAWS()
: width_ (0u), height_ (0u)
{
registerHandler(this);
}
prefix_ void senf::console::detail::telnethandler::NAWS::v_init()
{}
{
incrementRequestCounter();
}
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]));
width_ = (static_cast<unsigned char>(data[0])<<8)+static_cast<unsigned char>(data[1]);
height_ = (static_cast<unsigned char>(data[2])<<8)+static_cast<unsigned char>(data[3]);
if (! requestsPending())
v_windowSizeChanged();
decrementRequestCounter();
}
///////////////////////////////cc.e////////////////////////////////////////
......
......@@ -47,12 +47,44 @@ prefix_ senf::console::detail::BaseTelnetProtocol::OptInfo::OptInfo(bool l, opti
prefix_ senf::console::detail::BaseTelnetProtocol::TelnetHandler::~TelnetHandler()
{}
prefix_ std::string const & senf::console::detail::telnethandler::TerminalType::terminalType()
const
{
return type_;
}
///////////////////////////////////////////////////////////////////////////
// senf::console::detail::telnethandler::NAWS
prefix_ unsigned senf::console::detail::telnethandler::NAWS::width()
const
{
return width_;
}
prefix_ unsigned senf::console::detail::telnethandler::NAWS::height()
const
{
return height_;
}
///////////////////////////////////////////////////////////////////////////
// senf::console::detail::BaseTelnetProtocol
prefix_ senf::console::detail::BaseTelnetProtocol::~BaseTelnetProtocol()
{}
prefix_ void senf::console::detail::BaseTelnetProtocol::incrementRequestCounter()
{
++ pendingRequests_;
timeout_.timeout(senf::scheduler::eventTime() + requestTimeout_);
}
prefix_ bool senf::console::detail::BaseTelnetProtocol::requestsPending()
{
return pendingRequests_ > 0u;
}
prefix_ void senf::console::detail::BaseTelnetProtocol::sendNOP()
{
transmit(CMD_IAC);
......
......@@ -31,6 +31,7 @@
#include <map>
#include <senf/Socket.hh>
#include <senf/Scheduler/Scheduler.hh>
#include <senf/Scheduler/ClockService.hh>
//#include "Telnet.mpp"
///////////////////////////////hh.p////////////////////////////////////////
......@@ -50,6 +51,8 @@ namespace detail {
class BaseTelnetProtocol
{
public:
static unsigned const DEFAULT_REQUEST_TIMEOUT_MS = 500u;
typedef ClientSocketHandle<senf::MakeSocketPolicy<
ConnectedCommunicationPolicy,
StreamFramingPolicy,
......@@ -88,11 +91,16 @@ namespace detail {
template <class Handler>
void registerHandler(Handler * h, bool request=true);
void incrementRequestCounter();
void decrementRequestCounter();
bool requestsPending();
private:
#ifndef DOXYGEN
private:
#endif
virtual void v_setupComplete() = 0;
virtual void v_charReceived(char c) = 0;
virtual void v_eof() = 0;
......@@ -127,6 +135,7 @@ namespace detail {
void readHandler(int state);
void writeHandler(int state);
void timeout();
enum Command {
CMD_NONE = 0,
......@@ -193,6 +202,11 @@ namespace detail {
senf::scheduler::FdEvent inputEvent_;
senf::scheduler::FdEvent outputEvent_;
unsigned pendingRequests_;
ClockService::clock_type requestTimeout_;
scheduler::TimerEvent timeout_;
friend class TelnetHandler;
};
......@@ -221,15 +235,16 @@ namespace telnethandler {
static option_type const OPTION_CODE = telnetopt::TERMINAL_TYPE;
void nextTerminalType();
std::string const & terminalType() const;
protected:
TerminalType();
private:
virtual void v_handleTerminalType(std::string const & type) = 0;
virtual void v_init();
virtual void v_handleOptionParameters(std::string const & data);
std::string type_;
};
class NAWS
......@@ -238,14 +253,20 @@ namespace telnethandler {
public:
static option_type const OPTION_CODE = telnetopt::NAWS;
unsigned width() const;
unsigned height() const;
protected:
NAWS();
private:
virtual void v_handleWindowSize(unsigned width, unsigned height) = 0;
virtual void v_windowSizeChanged() = 0;
virtual void v_init();
virtual void v_handleOptionParameters(std::string const & data);
unsigned width_;
unsigned height_;
};
}
......
......@@ -27,7 +27,9 @@
//#include "telnetServer.ih"
// Custom includes
#include <boost/bind.hpp>
#include "Telnet.hh"
#include "../../Scheduler/Scheduler.hh"
#include "../Logger.hh"
#include "../../Socket/Protocols/INet.hh"
......@@ -55,34 +57,49 @@ namespace {
{
SENF_LOG(("Char: " << c));
}
virtual void v_eof()
{
SENF_LOG(("EOF"));
senf::scheduler::terminate();
delete this;
}
virtual void v_handleTerminalType(std::string const & type)
virtual void v_setupComplete()
{
SENF_LOG(("Terminal type: " << type));
SENF_LOG(("Terminal type is '" << terminalType() << "', window size is "
<< width() << "x" << height()));
}
virtual void v_handleWindowSize(unsigned width, unsigned height)
virtual void v_windowSizeChanged()
{
SENF_LOG(("Window size: " << width << "x" << height));
SENF_LOG(("New window size: " << width() << "x" << height()));
}
};
typedef senf::TCPv4ServerSocketHandle ServerHandle;
typedef ServerHandle::ClientHandle ClientHandle;
void connect(ServerHandle handle, int events)
{
if (events != senf::scheduler::FdEvent::EV_READ) {
senf::scheduler::terminate();
return;
}
ClientHandle client (handle.accept());
SENF_LOG(("new client ..."));
new MyTelnet (client);
}
}
int main(int argc, char const ** argv)
{
SENF_LOG(("Starting server."));
senf::log::ConsoleTarget::instance().timeFormat("");
ServerHandle server (ServerHandle::Address("127.0.0.1:22344"));
ClientHandle client (server.accept());
SENF_LOG(("Starting MyTelnet"));
MyTelnet telnet (client);
senf::scheduler::FdEvent serverEvent ("telnetServer", boost::bind(&connect, server, _1),
server, senf::scheduler::FdEvent::EV_READ);
SENF_LOG(("Server started at " << server.local()));
senf::scheduler::process();
......
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