4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at
9 // http://senf.berlios.de/license.html
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on,
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
15 // Software distributed under the License is distributed on an "AS IS" basis,
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
17 // for the specific language governing rights and limitations under the License.
19 // The Original Code is Fraunhofer FOKUS code.
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V.
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
26 // Stefan Bund <g0dil@berlios.de>
29 \brief Telnet non-inline non-template implementation */
32 //#include "Telnet.ih"
35 #include <boost/algorithm/string/case_conv.hpp>
36 #include <senf/Utils/membind.hh>
37 #include <senf/Utils/Logger/SenfLog.hh>
39 //#include "Telnet.mpp"
41 //-/////////////////////////////////////////////////////////////////////////////////////////////////
43 prefix_ senf::term::BaseTelnetProtocol::BaseTelnetProtocol(Handle handle)
44 : handle_ (handle), charState_ (NORMAL), command_ (CMD_NONE), option_ (0),
45 inputEvent_ ("senf::term::BaseTelnetProtocol::input",
46 membind(&BaseTelnetProtocol::readHandler, this), handle,
47 scheduler::FdEvent::EV_READ),
48 outputEvent_ ("senf::term::BaseTelnetProtocol::output",
49 membind(&BaseTelnetProtocol::writeHandler, this), handle,
50 scheduler::FdEvent::EV_WRITE, false),
51 pendingRequests_ (0u),
52 requestTimeout_ (ClockService::milliseconds(DEFAULT_REQUEST_TIMEOUT_MS)),
53 timeout_ ("senf::term::BaseTelnetProtocol::configTimeout",
54 membind(&BaseTelnetProtocol::timeout, this))
57 prefix_ senf::term::BaseTelnetProtocol::BaseTelnetProtocol()
58 : handle_ (), charState_ (NORMAL), command_ (CMD_NONE), option_ (0),
59 inputEvent_ ("senf::term::BaseTelnetProtocol::input", 0),
60 outputEvent_ ("senf::term::BaseTelnetProtocol::output", 0),
61 pendingRequests_ (0u),
62 requestTimeout_ (ClockService::milliseconds(DEFAULT_REQUEST_TIMEOUT_MS)),
63 timeout_ ("senf::term::BaseTelnetProtocol::timeout", 0)
66 "Missing BaseTelnetProtocol constructor call in derived class "
67 "(BaseTelnetProtocol is a VIRTUAL base and MUST be constructed explicitly "
68 "in the most derived class." );
71 prefix_ void senf::term::BaseTelnetProtocol::write(std::string const & s)
73 for (std::string::const_iterator i (s.begin()); i != s.end(); ++i)
77 prefix_ void senf::term::BaseTelnetProtocol::write(char c)
99 senf::term::BaseTelnetProtocol::sendOptionParameters(option_type option,
100 std::string const & data)
105 for (std::string::const_iterator i (data.begin()); i != data.end(); ++i)
116 prefix_ void senf::term::BaseTelnetProtocol::v_handleNOP()
119 prefix_ void senf::term::BaseTelnetProtocol::v_handleBRK()
122 prefix_ void senf::term::BaseTelnetProtocol::v_handleIP()
125 prefix_ void senf::term::BaseTelnetProtocol::v_handleAO()
128 prefix_ void senf::term::BaseTelnetProtocol::v_handleAYT()
131 prefix_ void senf::term::BaseTelnetProtocol::v_handleEC()
134 prefix_ void senf::term::BaseTelnetProtocol::v_handleEL()
137 prefix_ void senf::term::BaseTelnetProtocol::v_handleGA()
140 prefix_ void senf::term::BaseTelnetProtocol::handleChar(char c)
142 switch (charState_) {
147 handleCommand(static_cast<unsigned char>(c));
167 prefix_ void senf::term::BaseTelnetProtocol::handleNormalChar(char c)
171 charState_ = CR_SEEN;
174 charState_ = IAC_SEEN;
182 prefix_ void senf::term::BaseTelnetProtocol::handleCommand(char c)
184 switch (static_cast<unsigned char>(c)) {
186 // Ignore spurious SE commands .. they should only occur while in subnegotiation mode
198 command_ = Command(static_cast<unsigned char>(c));
204 charState_ = SB_OPTION;
210 command_ = Command(static_cast<unsigned char>(c));
211 charState_ = EXPECT_OPTION;
225 prefix_ void senf::term::BaseTelnetProtocol::handleOption(char c)
232 prefix_ void senf::term::BaseTelnetProtocol::handleCR(char c)
251 prefix_ void senf::term::BaseTelnetProtocol::handleSBOption(char c)
254 charState_ = SB_DATA;
258 prefix_ void senf::term::BaseTelnetProtocol::handleSBData(char c)
261 charState_ = SB_IAC_SEEN;
266 prefix_ void senf::term::BaseTelnetProtocol::handleSBIAC(char c)
268 switch (static_cast<unsigned char>(c)) {
271 charState_ = SB_DATA;
278 charState_ = IAC_SEEN;
284 prefix_ void senf::term::BaseTelnetProtocol::processCommand()
318 OptionHandlerMap::const_iterator i (handlers_.find(option_));
319 if (i != handlers_.end())
320 i->second->v_handleOptionParameters(data_);
325 response(getOption(false, option_), command_ == CMD_WILL);
329 response(getOption(true, option_), command_ == CMD_DO);
334 prefix_ void senf::term::BaseTelnetProtocol::transmit(char c)
336 sendQueue_.push_back(c);
337 outputEvent_.enable();
340 prefix_ void senf::term::BaseTelnetProtocol::readHandler(int state)
342 if (state != scheduler::FdEvent::EV_READ || handle_.eof()) {
343 inputEvent_.disable();
348 handle_.read(data, 0u);
349 for (std::string::const_iterator i (data.begin()); i != data.end(); ++i)
353 prefix_ void senf::term::BaseTelnetProtocol::writeHandler(int state)
355 if (state != scheduler::FdEvent::EV_WRITE) {
356 outputEvent_.disable();
357 inputEvent_.disable();
361 sendQueue_.erase(sendQueue_.begin(),
362 handle_.write(boost::make_iterator_range(
363 sendQueue_.begin(), sendQueue_.end())));
364 if (sendQueue_.empty())
365 outputEvent_.disable();
368 prefix_ void senf::term::BaseTelnetProtocol::timeout()
370 if (pendingRequests_ > 0u) {
371 pendingRequests_ = 0u;
376 prefix_ senf::term::BaseTelnetProtocol::OptInfo &
377 senf::term::BaseTelnetProtocol::getOption(bool local, option_type option)
379 OptionsMap::iterator i (options_.find(std::make_pair(local, option)));
380 if (i == options_.end())
381 i = options_.insert(std::make_pair(std::make_pair(local, option),
382 OptInfo(local, option))).first;
386 prefix_ void senf::term::BaseTelnetProtocol::request(OptInfo & info, bool enabled)
388 info.wantState = enabled ? OptInfo::WANTED : OptInfo::DISABLED;
389 if (enabled != info.enabled) {
391 transmit((info.local ? CMD_WILL : CMD_DO) + (enabled ? 0 : 1));
392 transmit(info.option);
393 info.optionState = OptInfo::REQUEST_SENT;
394 incrementRequestCounter();
398 prefix_ void senf::term::BaseTelnetProtocol::response(OptInfo & info, bool enabled)
400 bool decrementCount (false);
402 // If this is a response, we need to unconditionally accept it. If this is a remote
403 // configuration request, we accept it if wantState is wither WANTED or ACCEPTED. If this is a
404 // response, we never send out a reply. If it is a remote request we send out a reply only if
405 // either a) we reject the request or b) we accept it AND we have changed our own mode.
406 if (info.optionState == OptInfo::REQUEST_SENT) {
407 // This is a response
408 info.optionState = OptInfo::ACKNOWLEDGED;
409 info.enabled = enabled;
410 decrementCount = true;
412 else if (enabled != info.enabled) {
413 // Request to change the current state
415 (enabled && (info.wantState == OptInfo::WANTED || info.wantState == OptInfo::ACCEPTED))) {
416 // accept the request
417 info.optionState = OptInfo::ACKNOWLEDGED;
418 info.enabled = enabled;
419 } // else reject the request
421 transmit((info.local ? CMD_WILL : CMD_DO) + (info.enabled ? 0 : 1));
422 transmit(info.option);
427 OptionHandlerMap::const_iterator i (handlers_.find(info.option));
428 if (i != handlers_.end())
432 // This call must be AFTER calling v_init since v_init might increment the request count
433 // and v_setupComplete() might be called prematurely.
434 decrementRequestCounter();
437 prefix_ void senf::term::BaseTelnetProtocol::decrementRequestCounter()
439 if (pendingRequests_ > 0u) {
441 if (pendingRequests_ == 0u) {
448 //-/////////////////////////////////////////////////////////////////////////////////////////////////
449 // senf::term::telnethandler::TerminalType
451 prefix_ senf::term::telnethandler::TerminalType::TerminalType()
453 registerHandler(this);
456 prefix_ void senf::term::telnethandler::TerminalType::nextTerminalType()
458 sendOptionParameters(telnetopt::TERMINAL_TYPE, "\x01");
461 prefix_ void senf::term::telnethandler::TerminalType::
462 v_handleOptionParameters(std::string const & data)
464 if (data.size() <= 0)
466 if (data[0] == '\x00') {
467 type_ = data.substr(1);
468 boost::algorithm::to_lower(type_);
469 decrementRequestCounter();
473 prefix_ void senf::term::telnethandler::TerminalType::v_init()
476 incrementRequestCounter();
479 //-/////////////////////////////////////////////////////////////////////////////////////////////////
480 // senf::term::telnethandler::NAWS
482 prefix_ senf::term::telnethandler::NAWS::NAWS()
483 : width_ (0u), height_ (0u)
485 registerHandler(this);
488 prefix_ void senf::term::telnethandler::NAWS::v_init()
490 incrementRequestCounter();
494 senf::term::telnethandler::NAWS::v_handleOptionParameters(std::string const & data)
496 if (data.size() != 4)
498 width_ = (static_cast<unsigned char>(data[0])<<8)+static_cast<unsigned char>(data[1]);
499 height_ = (static_cast<unsigned char>(data[2])<<8)+static_cast<unsigned char>(data[3]);
500 if (! requestsPending())
501 v_windowSizeChanged();
502 decrementRequestCounter();
505 //-/////////////////////////////////////////////////////////////////////////////////////////////////
507 //#include "Telnet.mpp"
513 // comment-column: 40
514 // c-file-style: "senf"
515 // indent-tabs-mode: nil
516 // ispell-local-dictionary: "american"
517 // compile-command: "scons -u test"