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 non-inline non-template implementation */
27 //#include "Telnet.ih"
30 #include <boost/algorithm/string/case_conv.hpp>
31 #include <senf/Utils/membind.hh>
32 #include <senf/Utils/Logger/SenfLog.hh>
34 //#include "Telnet.mpp"
36 ///////////////////////////////cc.p////////////////////////////////////////
38 prefix_ senf::term::BaseTelnetProtocol::BaseTelnetProtocol(Handle handle)
39 : handle_ (handle), charState_ (NORMAL), command_ (CMD_NONE), option_ (0),
40 inputEvent_ ("senf::term::BaseTelnetProtocol::input",
41 senf::membind(&BaseTelnetProtocol::readHandler, this), handle,
42 senf::scheduler::FdEvent::EV_READ),
43 outputEvent_ ("senf::term::BaseTelnetProtocol::output",
44 senf::membind(&BaseTelnetProtocol::writeHandler, this), handle,
45 senf::scheduler::FdEvent::EV_WRITE, false),
46 pendingRequests_ (0u),
47 requestTimeout_ (ClockService::milliseconds(DEFAULT_REQUEST_TIMEOUT_MS)),
48 timeout_ ("senf::term::BaseTelnetProtocol::configTimeout",
49 senf::membind(&BaseTelnetProtocol::timeout, this))
52 prefix_ senf::term::BaseTelnetProtocol::BaseTelnetProtocol()
53 : handle_ (), charState_ (NORMAL), command_ (CMD_NONE), option_ (0),
54 inputEvent_ ("senf::term::BaseTelnetProtocol::input", 0),
55 outputEvent_ ("senf::term::BaseTelnetProtocol::output", 0),
56 pendingRequests_ (0u),
57 requestTimeout_ (ClockService::milliseconds(DEFAULT_REQUEST_TIMEOUT_MS)),
58 timeout_ ("senf::term::BaseTelnetProtocol::timeout", 0)
61 "Missing BaseTelnetProtocol constructor call in derived class "
62 "(BaseTelnetProtocol is a VIRTUAL base and MUST be constructed explicitly "
63 "in the most derived class." );
66 prefix_ void senf::term::BaseTelnetProtocol::write(std::string const & s)
68 for (std::string::const_iterator i (s.begin()); i != s.end(); ++i)
72 prefix_ void senf::term::BaseTelnetProtocol::write(char c)
94 senf::term::BaseTelnetProtocol::sendOptionParameters(option_type option,
95 std::string const & data)
100 for (std::string::const_iterator i (data.begin()); i != data.end(); ++i)
111 prefix_ void senf::term::BaseTelnetProtocol::v_handleNOP()
114 prefix_ void senf::term::BaseTelnetProtocol::v_handleBRK()
117 prefix_ void senf::term::BaseTelnetProtocol::v_handleIP()
120 prefix_ void senf::term::BaseTelnetProtocol::v_handleAO()
123 prefix_ void senf::term::BaseTelnetProtocol::v_handleAYT()
126 prefix_ void senf::term::BaseTelnetProtocol::v_handleEC()
129 prefix_ void senf::term::BaseTelnetProtocol::v_handleEL()
132 prefix_ void senf::term::BaseTelnetProtocol::v_handleGA()
135 prefix_ void senf::term::BaseTelnetProtocol::handleChar(char c)
137 switch (charState_) {
142 handleCommand(static_cast<unsigned char>(c));
162 prefix_ void senf::term::BaseTelnetProtocol::handleNormalChar(char c)
166 charState_ = CR_SEEN;
169 charState_ = IAC_SEEN;
177 prefix_ void senf::term::BaseTelnetProtocol::handleCommand(char c)
179 switch (static_cast<unsigned char>(c)) {
181 // Ignore spurious SE commands .. they should only occur while in subnegotiation mode
193 command_ = Command(static_cast<unsigned char>(c));
199 charState_ = SB_OPTION;
205 command_ = Command(static_cast<unsigned char>(c));
206 charState_ = EXPECT_OPTION;
220 prefix_ void senf::term::BaseTelnetProtocol::handleOption(char c)
227 prefix_ void senf::term::BaseTelnetProtocol::handleCR(char c)
246 prefix_ void senf::term::BaseTelnetProtocol::handleSBOption(char c)
249 charState_ = SB_DATA;
253 prefix_ void senf::term::BaseTelnetProtocol::handleSBData(char c)
256 charState_ = SB_IAC_SEEN;
261 prefix_ void senf::term::BaseTelnetProtocol::handleSBIAC(char c)
263 switch (static_cast<unsigned char>(c)) {
266 charState_ = SB_DATA;
273 charState_ = IAC_SEEN;
279 prefix_ void senf::term::BaseTelnetProtocol::processCommand()
313 OptionHandlerMap::const_iterator i (handlers_.find(option_));
314 if (i != handlers_.end())
315 i->second->v_handleOptionParameters(data_);
320 response(getOption(false, option_), command_ == CMD_WILL);
324 response(getOption(true, option_), command_ == CMD_DO);
329 prefix_ void senf::term::BaseTelnetProtocol::transmit(char c)
331 sendQueue_.push_back(c);
332 outputEvent_.enable();
335 prefix_ void senf::term::BaseTelnetProtocol::readHandler(int state)
337 if (state != senf::scheduler::FdEvent::EV_READ || handle_.eof()) {
338 inputEvent_.disable();
343 handle_.read(data, 0u);
344 for (std::string::const_iterator i (data.begin()); i != data.end(); ++i)
348 prefix_ void senf::term::BaseTelnetProtocol::writeHandler(int state)
350 if (state != senf::scheduler::FdEvent::EV_WRITE) {
351 outputEvent_.disable();
352 inputEvent_.disable();
356 sendQueue_.erase(sendQueue_.begin(),
357 handle_.write(boost::make_iterator_range(
358 sendQueue_.begin(), sendQueue_.end())));
359 if (sendQueue_.empty())
360 outputEvent_.disable();
363 prefix_ void senf::term::BaseTelnetProtocol::timeout()
365 if (pendingRequests_ > 0u) {
366 pendingRequests_ = 0u;
371 prefix_ senf::term::BaseTelnetProtocol::OptInfo &
372 senf::term::BaseTelnetProtocol::getOption(bool local, option_type option)
374 OptionsMap::iterator i (options_.find(std::make_pair(local, option)));
375 if (i == options_.end())
376 i = options_.insert(std::make_pair(std::make_pair(local, option),
377 OptInfo(local, option))).first;
381 prefix_ void senf::term::BaseTelnetProtocol::request(OptInfo & info, bool enabled)
383 info.wantState = enabled ? OptInfo::WANTED : OptInfo::DISABLED;
384 if (enabled != info.enabled) {
386 transmit((info.local ? CMD_WILL : CMD_DO) + (enabled ? 0 : 1));
387 transmit(info.option);
388 info.optionState = OptInfo::REQUEST_SENT;
389 incrementRequestCounter();
393 prefix_ void senf::term::BaseTelnetProtocol::response(OptInfo & info, bool enabled)
395 bool decrementCount (false);
397 // If this is a response, we need to unconditionally accept it. If this is a remote
398 // configuration request, we accept it if wantState is wither WANTED or ACCEPTED. If this is a
399 // response, we never send out a reply. If it is a remote request we send out a reply only if
400 // either a) we reject the request or b) we accept it AND we have changed our own mode.
401 if (info.optionState == OptInfo::REQUEST_SENT) {
402 // This is a response
403 info.optionState = OptInfo::ACKNOWLEDGED;
404 info.enabled = enabled;
405 decrementCount = true;
407 else if (enabled != info.enabled) {
408 // Request to change the current state
410 (enabled && (info.wantState == OptInfo::WANTED || info.wantState == OptInfo::ACCEPTED))) {
411 // accept the request
412 info.optionState = OptInfo::ACKNOWLEDGED;
413 info.enabled = enabled;
414 } // else reject the request
416 transmit((info.local ? CMD_WILL : CMD_DO) + (info.enabled ? 0 : 1));
417 transmit(info.option);
422 OptionHandlerMap::const_iterator i (handlers_.find(info.option));
423 if (i != handlers_.end())
427 // This call must be AFTER calling v_init since v_init might increment the request count
428 // and v_setupComplete() might be called prematurely.
429 decrementRequestCounter();
432 prefix_ void senf::term::BaseTelnetProtocol::decrementRequestCounter()
434 if (pendingRequests_ > 0u) {
436 if (pendingRequests_ == 0u) {
443 ///////////////////////////////////////////////////////////////////////////
444 // senf::term::telnethandler::TerminalType
446 prefix_ senf::term::telnethandler::TerminalType::TerminalType()
448 registerHandler(this);
451 prefix_ void senf::term::telnethandler::TerminalType::nextTerminalType()
453 sendOptionParameters(telnetopt::TERMINAL_TYPE, "\x01");
456 prefix_ void senf::term::telnethandler::TerminalType::
457 v_handleOptionParameters(std::string const & data)
459 if (data.size() <= 0)
461 if (data[0] == '\x00') {
462 type_ = data.substr(1);
463 boost::algorithm::to_lower(type_);
464 decrementRequestCounter();
468 prefix_ void senf::term::telnethandler::TerminalType::v_init()
471 incrementRequestCounter();
474 ///////////////////////////////////////////////////////////////////////////
475 // senf::term::telnethandler::NAWS
477 prefix_ senf::term::telnethandler::NAWS::NAWS()
478 : width_ (0u), height_ (0u)
480 registerHandler(this);
483 prefix_ void senf::term::telnethandler::NAWS::v_init()
485 incrementRequestCounter();
489 senf::term::telnethandler::NAWS::v_handleOptionParameters(std::string const & data)
491 if (data.size() != 4)
493 width_ = (static_cast<unsigned char>(data[0])<<8)+static_cast<unsigned char>(data[1]);
494 height_ = (static_cast<unsigned char>(data[2])<<8)+static_cast<unsigned char>(data[3]);
495 if (! requestsPending())
496 v_windowSizeChanged();
497 decrementRequestCounter();
500 ///////////////////////////////cc.e////////////////////////////////////////
502 //#include "Telnet.mpp"
508 // comment-column: 40
509 // c-file-style: "senf"
510 // indent-tabs-mode: nil
511 // ispell-local-dictionary: "american"
512 // compile-command: "scons -u test"