Search:

SENF Extensible Network Framework

  • Home
  • Download
  • Wiki
  • BerliOS
  • ChangeLog
  • Browse SVN
  • Bug Tracker
  • Overview
  • Examples
  • HowTos
  • Glossary
  • PPI
  • Packets
  • Scheduler
  • Socket
  • Utils
  • Console
  • Daemon
  • Logger
  • Termlib
  • Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

Telnet.cc

Go to the documentation of this file.
00001 // $Id: Telnet.cc 1772 2011-03-10 12:45:21Z tho $
00002 //
00003 // Copyright (C) 2008
00004 // Fraunhofer (FOKUS)
00005 // Competence Center NETwork research (NET), St. Augustin, GERMANY
00006 //     Stefan Bund <g0dil@berlios.de>
00007 //
00008 // This program is free software; you can redistribute it and/or modify
00009 // it under the terms of the GNU General Public License as published by
00010 // the Free Software Foundation; either version 2 of the License, or
00011 // (at your option) any later version.
00012 //
00013 // This program is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 // GNU General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU General Public License
00019 // along with this program; if not, write to the
00020 // Free Software Foundation, Inc.,
00021 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00022 
00026 #include "Telnet.hh"
00027 //#include "Telnet.ih"
00028 
00029 // Custom includes
00030 #include <boost/algorithm/string/case_conv.hpp>
00031 #include <senf/Utils/membind.hh>
00032 #include <senf/Utils/Logger/SenfLog.hh>
00033 
00034 //#include "Telnet.mpp"
00035 #define prefix_
00036 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00037 
00038 prefix_ senf::term::BaseTelnetProtocol::BaseTelnetProtocol(Handle handle)
00039     : handle_ (handle), charState_ (NORMAL), command_ (CMD_NONE), option_ (0),
00040       inputEvent_ ("senf::term::BaseTelnetProtocol::input",
00041                    membind(&BaseTelnetProtocol::readHandler, this), handle,
00042                    scheduler::FdEvent::EV_READ),
00043       outputEvent_ ("senf::term::BaseTelnetProtocol::output",
00044                     membind(&BaseTelnetProtocol::writeHandler, this), handle,
00045                     scheduler::FdEvent::EV_WRITE, false),
00046       pendingRequests_ (0u),
00047       requestTimeout_ (ClockService::milliseconds(DEFAULT_REQUEST_TIMEOUT_MS)),
00048       timeout_ ("senf::term::BaseTelnetProtocol::configTimeout",
00049                 membind(&BaseTelnetProtocol::timeout, this))
00050 {}
00051 
00052 prefix_ senf::term::BaseTelnetProtocol::BaseTelnetProtocol()
00053     : handle_ (), charState_ (NORMAL), command_ (CMD_NONE), option_ (0),
00054       inputEvent_ ("senf::term::BaseTelnetProtocol::input", 0),
00055       outputEvent_ ("senf::term::BaseTelnetProtocol::output", 0),
00056       pendingRequests_ (0u),
00057       requestTimeout_ (ClockService::milliseconds(DEFAULT_REQUEST_TIMEOUT_MS)),
00058       timeout_ ("senf::term::BaseTelnetProtocol::timeout", 0)
00059 {
00060     SENF_ASSERT( false,
00061                  "Missing BaseTelnetProtocol constructor call in derived class "
00062                  "(BaseTelnetProtocol is a VIRTUAL base and MUST be constructed explicitly "
00063                  "in the most derived class." );
00064 }
00065 
00066 prefix_ void senf::term::BaseTelnetProtocol::write(std::string const & s)
00067 {
00068     for (std::string::const_iterator i (s.begin()); i != s.end(); ++i)
00069         write(*i);
00070 }
00071 
00072 prefix_ void senf::term::BaseTelnetProtocol::write(char c)
00073 {
00074     switch (c) {
00075     case '\r':
00076         transmit('\r');
00077         transmit('\0');
00078         break;
00079     case '\n':
00080         transmit('\r');
00081         transmit('\n');
00082         break;
00083     case '\xff':
00084         transmit('\xff');
00085         transmit('\xff');
00086         break;
00087     default:
00088         transmit(c);
00089         break;
00090     }
00091 }
00092 
00093 prefix_ void
00094 senf::term::BaseTelnetProtocol::sendOptionParameters(option_type option,
00095                                                                 std::string const & data)
00096 {
00097     transmit(CMD_IAC);
00098     transmit(CMD_SB);
00099     transmit(option);
00100     for (std::string::const_iterator i (data.begin()); i != data.end(); ++i)
00101         if (*i == '\xff') {
00102             transmit('\xff');
00103             transmit('\xff');
00104         }
00105         else
00106             transmit(*i);
00107     transmit(CMD_IAC);
00108     transmit(CMD_SE);
00109 }
00110 
00111 prefix_ void senf::term::BaseTelnetProtocol::v_handleNOP()
00112 {}
00113 
00114 prefix_ void senf::term::BaseTelnetProtocol::v_handleBRK()
00115 {}
00116 
00117 prefix_ void senf::term::BaseTelnetProtocol::v_handleIP()
00118 {}
00119 
00120 prefix_ void senf::term::BaseTelnetProtocol::v_handleAO()
00121 {}
00122 
00123 prefix_ void senf::term::BaseTelnetProtocol::v_handleAYT()
00124 {}
00125 
00126 prefix_ void senf::term::BaseTelnetProtocol::v_handleEC()
00127 {}
00128 
00129 prefix_ void senf::term::BaseTelnetProtocol::v_handleEL()
00130 {}
00131 
00132 prefix_ void senf::term::BaseTelnetProtocol::v_handleGA()
00133 {}
00134 
00135 prefix_ void senf::term::BaseTelnetProtocol::handleChar(char c)
00136 {
00137     switch (charState_) {
00138     case NORMAL:
00139         handleNormalChar(c);
00140         break;
00141     case IAC_SEEN:
00142         handleCommand(static_cast<unsigned char>(c));
00143         break;
00144     case EXPECT_OPTION:
00145         handleOption(c);
00146         break;
00147     case CR_SEEN:
00148         handleCR(c);
00149         break;
00150     case SB_OPTION:
00151         handleSBOption(c);
00152         break;
00153     case SB_DATA:
00154         handleSBData(c);
00155         break;
00156     case SB_IAC_SEEN:
00157         handleSBIAC(c);
00158         break;
00159     }
00160 }
00161 
00162 prefix_ void senf::term::BaseTelnetProtocol::handleNormalChar(char c)
00163 {
00164     switch (c) {
00165     case '\r':
00166         charState_ = CR_SEEN;
00167         break;
00168     case '\xff':
00169         charState_ = IAC_SEEN;
00170         break;
00171     default:
00172         emit(c);
00173         break;
00174     }
00175 }
00176 
00177 prefix_ void senf::term::BaseTelnetProtocol::handleCommand(char c)
00178 {
00179     switch (static_cast<unsigned char>(c)) {
00180     case CMD_SE:
00181         // Ignore spurious SE commands .. they should only occur while in subnegotiation mode
00182         charState_ = NORMAL;
00183         break;
00184     case CMD_NOP:
00185     case CMD_DM:
00186     case CMD_BRK:
00187     case CMD_IP:
00188     case CMD_AO:
00189     case CMD_AYT:
00190     case CMD_EC:
00191     case CMD_EL:
00192     case CMD_GA:
00193         command_ = Command(static_cast<unsigned char>(c));
00194         processCommand();
00195         charState_ = NORMAL;
00196         break;
00197     case CMD_SB:
00198         command_ = CMD_SB;
00199         charState_ = SB_OPTION;
00200         break;
00201     case CMD_WILL:
00202     case CMD_WONT:
00203     case CMD_DO:
00204     case CMD_DONT:
00205         command_ = Command(static_cast<unsigned char>(c));
00206         charState_ = EXPECT_OPTION;
00207         break;
00208     case CMD_IAC:
00209         charState_ = NORMAL;
00210         emit(CMD_IAC);
00211         break;
00212     default:
00213         emit(CMD_IAC);
00214         charState_ = NORMAL;
00215         handleChar(c);
00216         break;
00217     }
00218 }
00219 
00220 prefix_ void senf::term::BaseTelnetProtocol::handleOption(char c)
00221 {
00222     option_ = c;
00223     processCommand();
00224     charState_ = NORMAL;
00225 }
00226 
00227 prefix_ void senf::term::BaseTelnetProtocol::handleCR(char c)
00228 {
00229     switch (c) {
00230     case '\0':
00231         emit('\r');
00232         charState_ = NORMAL;
00233         break;
00234     case '\n':
00235         emit('\n');
00236         charState_ = NORMAL;
00237         break;
00238     default:
00239         emit('\r');
00240         charState_ = NORMAL;
00241         handleChar(c);
00242         break;
00243     }
00244 }
00245 
00246 prefix_ void senf::term::BaseTelnetProtocol::handleSBOption(char c)
00247 {
00248     option_ = c;
00249     charState_ = SB_DATA;
00250     data_.clear();
00251 }
00252 
00253 prefix_ void senf::term::BaseTelnetProtocol::handleSBData(char c)
00254 {
00255     if (c == '\xff')
00256         charState_ = SB_IAC_SEEN;
00257     else
00258         data_.push_back(c);
00259 }
00260 
00261 prefix_ void senf::term::BaseTelnetProtocol::handleSBIAC(char c)
00262 {
00263     switch (static_cast<unsigned char>(c)) {
00264     case CMD_IAC:
00265         data_.push_back(c);
00266         charState_ = SB_DATA;
00267         break;
00268     case CMD_SE:
00269         processCommand();
00270         charState_ = NORMAL;
00271         break;
00272     default:
00273         charState_ = IAC_SEEN;
00274         handleChar(c);
00275         break;
00276     }
00277 }
00278 
00279 prefix_ void senf::term::BaseTelnetProtocol::processCommand()
00280 {
00281     switch (command_) {
00282     case CMD_NONE:
00283     case CMD_SE:
00284     case CMD_DM:
00285     case CMD_IAC:
00286         break;
00287     case CMD_NOP:
00288         v_handleNOP();
00289         break;
00290     case CMD_BRK:
00291         v_handleBRK();
00292         break;
00293     case CMD_IP:
00294         v_handleIP();
00295         break;
00296     case CMD_AO:
00297         v_handleAO();
00298         break;
00299     case CMD_AYT:
00300         v_handleAYT();
00301         break;
00302     case CMD_EC:
00303         v_handleEC();
00304         break;
00305     case CMD_EL:
00306         v_handleEL();
00307         break;
00308     case CMD_GA:
00309         v_handleGA();
00310         break;
00311     case CMD_SB:
00312     {
00313         OptionHandlerMap::const_iterator i (handlers_.find(option_));
00314         if (i != handlers_.end())
00315             i->second->v_handleOptionParameters(data_);
00316         break;
00317     }
00318     case CMD_WILL:
00319     case CMD_WONT:
00320         response(getOption(false, option_), command_ == CMD_WILL);
00321         break;
00322     case CMD_DO:
00323     case CMD_DONT:
00324         response(getOption(true, option_),  command_ == CMD_DO);
00325         break;
00326     }
00327 }
00328 
00329 prefix_ void senf::term::BaseTelnetProtocol::transmit(char c)
00330 {
00331     sendQueue_.push_back(c);
00332     outputEvent_.enable();
00333 }
00334 
00335 prefix_ void senf::term::BaseTelnetProtocol::readHandler(int state)
00336 {
00337     if (state != scheduler::FdEvent::EV_READ || handle_.eof()) {
00338         inputEvent_.disable();
00339         v_eof();
00340         return;
00341     }
00342     std::string data;
00343     handle_.read(data, 0u);
00344     for (std::string::const_iterator i (data.begin()); i != data.end(); ++i)
00345         handleChar(*i);
00346 }
00347 
00348 prefix_ void senf::term::BaseTelnetProtocol::writeHandler(int state)
00349 {
00350     if (state != scheduler::FdEvent::EV_WRITE) {
00351         outputEvent_.disable();
00352         inputEvent_.disable();
00353         v_eof();
00354         return;
00355     }
00356     sendQueue_.erase(sendQueue_.begin(),
00357                      handle_.write(boost::make_iterator_range(
00358                                        sendQueue_.begin(), sendQueue_.end())));
00359     if (sendQueue_.empty())
00360         outputEvent_.disable();
00361 }
00362 
00363 prefix_ void senf::term::BaseTelnetProtocol::timeout()
00364 {
00365     if (pendingRequests_ > 0u) {
00366         pendingRequests_ = 0u;
00367         v_setupComplete();
00368     }
00369 }
00370 
00371 prefix_ senf::term::BaseTelnetProtocol::OptInfo &
00372 senf::term::BaseTelnetProtocol::getOption(bool local, option_type option)
00373 {
00374     OptionsMap::iterator i (options_.find(std::make_pair(local, option)));
00375     if (i == options_.end())
00376         i = options_.insert(std::make_pair(std::make_pair(local, option),
00377                                            OptInfo(local, option))).first;
00378     return i->second;
00379 }
00380 
00381 prefix_ void senf::term::BaseTelnetProtocol::request(OptInfo & info, bool enabled)
00382 {
00383     info.wantState = enabled ? OptInfo::WANTED : OptInfo::DISABLED;
00384     if (enabled != info.enabled) {
00385         transmit(CMD_IAC);
00386         transmit((info.local ? CMD_WILL : CMD_DO) + (enabled ? 0 : 1));
00387         transmit(info.option);
00388         info.optionState = OptInfo::REQUEST_SENT;
00389         incrementRequestCounter();
00390     }
00391 }
00392 
00393 prefix_ void senf::term::BaseTelnetProtocol::response(OptInfo & info, bool enabled)
00394 {
00395     bool decrementCount (false);
00396 
00397     // If this is a response, we need to unconditionally accept it.  If this is a remote
00398     // configuration request, we accept it if wantState is wither WANTED or ACCEPTED.  If this is a
00399     // response, we never send out a reply. If it is a remote request we send out a reply only if
00400     // either a) we reject the request or b) we accept it AND we have changed our own mode.
00401     if (info.optionState == OptInfo::REQUEST_SENT) {
00402         // This is a response
00403         info.optionState = OptInfo::ACKNOWLEDGED;
00404         info.enabled = enabled;
00405         decrementCount = true;
00406     }
00407     else if (enabled != info.enabled) {
00408         // Request to change the current state
00409         if (!enabled ||
00410             (enabled && (info.wantState == OptInfo::WANTED || info.wantState == OptInfo::ACCEPTED))) {
00411             // accept the request
00412             info.optionState = OptInfo::ACKNOWLEDGED;
00413             info.enabled = enabled;
00414         }   // else reject the request
00415         transmit(CMD_IAC);
00416         transmit((info.local ? CMD_WILL : CMD_DO) + (info.enabled ? 0 : 1));
00417         transmit(info.option);
00418     }
00419     else
00420         return;
00421     if (info.enabled) {
00422         OptionHandlerMap::const_iterator i (handlers_.find(info.option));
00423         if (i != handlers_.end())
00424             i->second->v_init();
00425     }
00426     if (decrementCount)
00427         // This call must be AFTER calling v_init since v_init might increment the request count
00428         // and v_setupComplete() might be called prematurely.
00429         decrementRequestCounter();
00430 }
00431 
00432 prefix_ void senf::term::BaseTelnetProtocol::decrementRequestCounter()
00433 {
00434     if (pendingRequests_ > 0u) {
00435         -- pendingRequests_;
00436         if (pendingRequests_ == 0u) {
00437             timeout_.disable();
00438             v_setupComplete();
00439         }
00440     }
00441 }
00442 
00443 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00444 // senf::term::telnethandler::TerminalType
00445 
00446 prefix_ senf::term::telnethandler::TerminalType::TerminalType()
00447 {
00448     registerHandler(this);
00449 }
00450 
00451 prefix_ void senf::term::telnethandler::TerminalType::nextTerminalType()
00452 {
00453     sendOptionParameters(telnetopt::TERMINAL_TYPE, "\x01");
00454 }
00455 
00456 prefix_ void senf::term::telnethandler::TerminalType::
00457 v_handleOptionParameters(std::string const & data)
00458 {
00459     if (data.size() <= 0)
00460         return;
00461     if (data[0] == '\x00') {
00462         type_ = data.substr(1);
00463         boost::algorithm::to_lower(type_);
00464         decrementRequestCounter();
00465     }
00466 }
00467 
00468 prefix_ void senf::term::telnethandler::TerminalType::v_init()
00469 {
00470     nextTerminalType();
00471     incrementRequestCounter();
00472 }
00473 
00474 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00475 // senf::term::telnethandler::NAWS
00476 
00477 prefix_ senf::term::telnethandler::NAWS::NAWS()
00478     : width_ (0u), height_ (0u)
00479 {
00480     registerHandler(this);
00481 }
00482 
00483 prefix_ void senf::term::telnethandler::NAWS::v_init()
00484 {
00485     incrementRequestCounter();
00486 }
00487 
00488 prefix_ void
00489 senf::term::telnethandler::NAWS::v_handleOptionParameters(std::string const & data)
00490 {
00491     if (data.size() != 4)
00492         return;
00493     width_ = (static_cast<unsigned char>(data[0])<<8)+static_cast<unsigned char>(data[1]);
00494     height_ = (static_cast<unsigned char>(data[2])<<8)+static_cast<unsigned char>(data[3]);
00495     if (! requestsPending())
00496         v_windowSizeChanged();
00497     decrementRequestCounter();
00498 }
00499 
00500 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00501 #undef prefix_
00502 //#include "Telnet.mpp"
00503 
00504 
00505 // Local Variables:
00506 // mode: c++
00507 // fill-column: 100
00508 // comment-column: 40
00509 // c-file-style: "senf"
00510 // indent-tabs-mode: nil
00511 // ispell-local-dictionary: "american"
00512 // compile-command: "scons -u test"
00513 // End:

Contact: senf-dev@lists.berlios.de | © 2006-2010 Fraunhofer Institute for Open Communication Systems, Network Research