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

Server.cc

Go to the documentation of this file.
00001 // $Id: Server.cc 1789 2011-05-19 09:31:33Z 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 "Server.hh"
00027 //#include "Server.ih"
00028 
00029 // Custom includes
00030 #include <boost/algorithm/string/trim.hpp>
00031 #include <boost/bind.hpp>
00032 #include <senf/Utils/membind.hh>
00033 #include <senf/Utils/Logger/SenfLog.hh>
00034 #include <senf/Version.hh>
00035 #include "LineEditor.hh"
00036 #include "ScopedDirectory.hh"
00037 #include "Sysdir.hh"
00038 #include "SysInfo.hh"
00039 #include "ParsedCommand.hh"
00040 
00041 //#include "Server.mpp"
00042 #define prefix_
00043 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00044 
00045 #ifdef SENF_DEBUG
00046 #   define BUILD_TYPE "development"
00047 #else
00048 #   define BUILD_TYPE "production"
00049 #endif
00050 
00051 namespace {
00052     senf::console::SysInfo::Proxy addSysInfo (
00053             "SENF: The Simple and Extensible Network Framework\n"
00054             "  © 2006-2011 Fraunhofer Institute for Open Communication Systems, Network Research\n"
00055             "  Contact: senf-dev@lists.berlios.de\n"
00056             "  Version: " SENF_LIB_VERSION " Revision number: " SENF_REVISION "\n"
00057             "  Build-type: " BUILD_TYPE ", SenfLog compile time limit: " +
00058             senf::str(senf::log::LEVELNAMES[senf::SenfLog::compileLimit::value]), 0);
00059 }
00060 
00061 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00062 // senf::console::detail::NonBlockingSocketSink
00063 
00064 prefix_ std::streamsize senf::console::detail::NonblockingSocketSink::write(const char * s,
00065                                                                             std::streamsize n)
00066 {
00067     try {
00068         if (client_.handle().writeable()) {
00069             std::string data (s, n);
00070             client_.write(data);
00071         }
00072     }
00073     catch (...) {}
00074     return n;
00075 }
00076 
00077 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00078 // senf::console::Server
00079 
00080 prefix_ senf::console::Server &
00081 senf::console::Server::start(senf::INet4SocketAddress const & address)
00082 {
00083     senf::TCPv4ServerSocketHandle handle (address);
00084     Server & server (senf::console::Server::start(handle));
00085     SENF_LOG((Server::SENFLogArea)(log::NOTICE)(
00086                  "Console server started at " << address ));
00087     return server;
00088 }
00089 
00090 prefix_ senf::console::Server &
00091 senf::console::Server::start(senf::INet6SocketAddress const & address)
00092 {
00093     senf::TCPv6ServerSocketHandle handle (address);
00094     Server & server (senf::console::Server::start(handle));
00095     SENF_LOG((Server::SENFLogArea)(log::NOTICE)(
00096                  "Console server started at " << address ));
00097     return server;
00098 }
00099 
00100 prefix_ senf::console::Server & senf::console::Server::start(ServerHandle handle)
00101 {
00102     boost::intrusive_ptr<Server> p (new Server(handle));
00103     detail::ServerManager::add(boost::intrusive_ptr<Server>(p));
00104     return *p;
00105 }
00106 
00107 prefix_ senf::console::Server::Server(ServerHandle handle)
00108     : handle_ (handle),
00109       event_ ("senf::console::Server", senf::membind(&Server::newClient, this),
00110               handle_, scheduler::FdEvent::EV_READ),
00111       root_ (senf::console::root().thisptr()), mode_ (Automatic),
00112       name_ (::program_invocation_short_name)
00113 {}
00114 
00115 prefix_ void senf::console::Server::newClient(int event)
00116 {
00117     ServerHandle::ClientHandle client (handle_.accept());
00118     boost::intrusive_ptr<Client> p (new Client(*this, client));
00119     clients_.insert( p );
00120     SENF_LOG(( "Registered new client " << client.peer() ));
00121 }
00122 
00123 prefix_ void senf::console::Server::removeClient(Client & client)
00124 {
00125     SENF_LOG_BLOCK(({
00126                 log << "Disposing client ";
00127                 try {
00128                     log << client.handle().peer();
00129                 }
00130                 catch (senf::SystemException & ex) {
00131                     log << "(dead socket)";
00132                 }
00133             }));
00134     // THIS DELETES THE CLIENT INSTANCE !!
00135     clients_.erase(boost::intrusive_ptr<Client>(&client));
00136 }
00137 
00138 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00139 // senf::console::detail::DumbClientReader
00140 
00141 prefix_ senf::console::detail::DumbClientReader::DumbClientReader(Client & client)
00142     : ClientReader(client), promptLen_ (0), promptActive_ (false)
00143 {
00144     showPrompt();
00145     ReadHelper<ClientHandle>::dispatch( handle(), 16384u, ReadUntil("\n"),
00146                                         senf::membind(&DumbClientReader::clientData, this) );
00147 }
00148 
00149 prefix_ void
00150 senf::console::detail::DumbClientReader::clientData(senf::ReadHelper<ClientHandle>::ptr helper)
00151 {
00152     if (helper->error() || handle().eof()) {
00153         // THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER stopClient RETURNS
00154         stopClient();
00155         return;
00156     }
00157 
00158     promptLen_ = 0;
00159     promptActive_ = false;
00160 
00161     std::string data (tail_ + helper->data());
00162     tail_ = helper->tail();
00163     boost::trim(data); // Gets rid of superfluous  \r or \n characters
00164     handleInput(data);
00165 
00166     showPrompt();
00167     ReadHelper<ClientHandle>::dispatch( handle(), 16384u, ReadUntil("\n"),
00168                                         senf::membind(&DumbClientReader::clientData, this) );
00169 
00170 }
00171 
00172 prefix_ void senf::console::detail::DumbClientReader::showPrompt()
00173 {
00174     std::string prompt (promptString());
00175     prompt += " ";
00176 
00177     stream() << std::flush;
00178     promptLen_ = prompt.size();
00179     promptActive_ = true;
00180     v_write(prompt);
00181 }
00182 
00183 prefix_ void senf::console::detail::DumbClientReader::v_disablePrompt()
00184 {
00185     if (promptActive_ && promptLen_ > 0) {
00186         stream() << '\r' << std::string(' ', promptLen_) << '\r';
00187         promptLen_ = 0;
00188     }
00189 }
00190 
00191 prefix_ void senf::console::detail::DumbClientReader::v_enablePrompt()
00192 {
00193     if (promptActive_ && ! promptLen_)
00194         showPrompt();
00195 }
00196 
00197 prefix_ void senf::console::detail::DumbClientReader::v_write(std::string const & data)
00198 {
00199     try {
00200         handle().write(data);
00201     }
00202     catch (senf::ExceptionMixin & ex) {
00203         SENF_LOG(("unexpected failure writing to socket:" << ex.message()));
00204         try { handle().facet<senf::TCPSocketProtocol>().shutdown(senf::TCPSocketProtocol::ShutRD); }
00205         catch (...) {}
00206     }
00207     catch (std::exception & ex) {
00208         SENF_LOG(("unexpected failure writing to socket:" << ex.what()));
00209         try { handle().facet<senf::TCPSocketProtocol>().shutdown(senf::TCPSocketProtocol::ShutRD); }
00210         catch (...) {}
00211     }
00212     catch (...) {
00213         SENF_LOG(("unexpected failure writing to socket: unknown exception"));
00214         try { handle().facet<senf::TCPSocketProtocol>().shutdown(senf::TCPSocketProtocol::ShutRD); }
00215         catch (...) {}
00216     }
00217 }
00218 
00219 prefix_ unsigned senf::console::detail::DumbClientReader::v_width()
00220     const
00221 {
00222     return 80;
00223 }
00224 
00225 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00226 // senf::console::detail::NoninteractiveClientReader
00227 
00228 prefix_
00229 senf::console::detail::NoninteractiveClientReader::NoninteractiveClientReader(Client & client)
00230     : ClientReader (client),
00231       readevent_ ("senf::console::detail::NoninteractiveClientReader",
00232                   senf::membind(&NoninteractiveClientReader::newData, this),
00233                   handle(), senf::scheduler::FdEvent::EV_READ)
00234 {}
00235 
00236 prefix_ void senf::console::detail::NoninteractiveClientReader::v_disablePrompt()
00237 {}
00238 
00239 prefix_ void senf::console::detail::NoninteractiveClientReader::v_enablePrompt()
00240 {}
00241 
00242 prefix_ void senf::console::detail::NoninteractiveClientReader::v_write(std::string const & data)
00243 {
00244     try {
00245         handle().write(data);
00246     }
00247     catch (senf::ExceptionMixin & ex) {
00248         SENF_LOG(("unexpected failure writing to socket:" << ex.message()));
00249         try { handle().facet<senf::TCPSocketProtocol>().shutdown(senf::TCPSocketProtocol::ShutRD); }
00250         catch (...) {}
00251     }
00252     catch (std::exception & ex) {
00253         SENF_LOG(("unexpected failure writing to socket:" << ex.what()));
00254         try { handle().facet<senf::TCPSocketProtocol>().shutdown(senf::TCPSocketProtocol::ShutRD); }
00255         catch (...) {}
00256     }
00257     catch (...) {
00258         SENF_LOG(("unexpected failure writing to socket: unknown exception"));
00259         try { handle().facet<senf::TCPSocketProtocol>().shutdown(senf::TCPSocketProtocol::ShutRD); }
00260         catch (...) {}
00261     }
00262 }
00263 
00264 prefix_ unsigned senf::console::detail::NoninteractiveClientReader::v_width()
00265     const
00266 {
00267     return 80;
00268 }
00269 
00270 prefix_ void
00271 senf::console::detail::NoninteractiveClientReader::newData(int event)
00272 {
00273     if (event != senf::scheduler::FdEvent::EV_READ || handle().eof()) {
00274         if (! buffer_.empty())
00275             handleInput(buffer_);
00276         stopClient();
00277         return;
00278     }
00279 
00280     std::string::size_type n (buffer_.size());
00281     buffer_.resize(n + handle().available());
00282     buffer_.erase(handle().read(boost::make_iterator_range(buffer_.begin()+n, buffer_.end())),
00283                   buffer_.end());
00284     buffer_.erase(0, handleInput(buffer_, true));
00285     stream() << std::flush;
00286 }
00287 
00288 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00289 // senf::console::Client
00290 
00291 prefix_ senf::console::Client::Client(Server & server, ClientHandle handle)
00292     : out_t(boost::ref(*this)),
00293       senf::log::IOStreamTarget("client-" + senf::str(handle.peer()), out_t::member),
00294       server_ (server), handle_ (handle),
00295       readevent_ ("senf::console::Client::interactive_check",
00296                   boost::bind(&Client::setNoninteractive,this),
00297                   handle, scheduler::FdEvent::EV_READ, false),
00298       timer_ ("senf::console::Client::interactive_timer",
00299               boost::bind(&Client::setInteractive, this),
00300               scheduler::eventTime() + ClockService::milliseconds(INTERACTIVE_TIMEOUT),
00301               false),
00302       name_ (server.name()), reader_ (), mode_ (server.mode())
00303 {
00304     handle_.facet<senf::TCPSocketProtocol>().nodelay();
00305     executor_.chroot(root());
00306     switch (mode_) {
00307     case Server::Interactive :
00308         setInteractive();
00309         break;
00310     case Server::Noninteractive :
00311         setNoninteractive();
00312         break;
00313     case Server::Automatic :
00314         readevent_.enable();
00315         timer_.enable();
00316         break;
00317     }
00318 }
00319 
00320 prefix_ void senf::console::Client::setInteractive()
00321 {
00322     readevent_.disable();
00323     timer_.disable();
00324     mode_ = Server::Interactive;
00325     reader_.reset(new detail::LineEditorSwitcher (*this));
00326     executor_.autocd(true).autocomplete(true);
00327 }
00328 
00329 prefix_ void senf::console::Client::setNoninteractive()
00330 {
00331     readevent_.disable();
00332     timer_.disable();
00333     mode_ = Server::Noninteractive;
00334     reader_.reset(new detail::NoninteractiveClientReader(*this));
00335 }
00336 
00337 prefix_ std::string::size_type senf::console::Client::handleInput(std::string data,
00338                                                                   bool incremental)
00339 {
00340     std::string::size_type n (data.size());
00341 
00342     try {
00343         if (incremental)
00344             n = parser_.parseIncremental(data, boost::bind<void>( boost::ref(executor_),
00345                                                                   boost::ref(stream()),
00346                                                                   _1 ));
00347         else
00348             parser_.parse(data, boost::bind<void>( boost::ref(executor_),
00349                                                    boost::ref(stream()),
00350                                                    _1 ));
00351     }
00352     catch (Executor::ExitException &) {
00353         // This generates an EOF condition on the Handle. This EOF condition is expected to be
00354         // handled gracefully by the ClientReader. We cannot call stop() here, since we are called
00355         // from the client reader callback and that will continue executing after stop() has been
00356         // called. stop() however will delete *this instance ... BANG ...
00357         try { handle_.facet<senf::TCPSocketProtocol>().shutdown(senf::TCPSocketProtocol::ShutRD); }
00358         catch (...) {}
00359     }
00360     catch (std::exception & ex) {
00361         std::string msg (ex.what());
00362         std::string::size_type i (msg.find("-- \n"));
00363         if (i != std::string::npos) {
00364             backtrace_ = msg.substr(0,i);
00365             msg = msg.substr(i+4);
00366         } else
00367             backtrace_.clear();
00368         stream() << msg << std::endl;
00369     }
00370     catch (...) {
00371         stream() << "unidentified error (unknown exception thrown)" << std::endl;
00372     }
00373     return n;
00374 }
00375 
00376 prefix_ void senf::console::Client::v_write(senf::log::time_type timestamp,
00377                                             std::string const & stream,
00378                                             std::string const & area, unsigned level,
00379                                             std::string const & message)
00380 {
00381     reader_->disablePrompt();
00382     IOStreamTarget::v_write(timestamp, stream, area, level, message);
00383     out_t::member << std::flush;
00384     reader_->enablePrompt();
00385 }
00386 
00387 prefix_ unsigned senf::console::Client::getWidth(std::ostream & os, unsigned defaultWidth,
00388                                                  unsigned minWidth)
00389 {
00390     unsigned rv (defaultWidth);
00391     try {
00392         rv = get(os).width();
00393     }
00394     catch (std::bad_cast &) {}
00395     return rv < minWidth ? defaultWidth : rv;
00396 }
00397 
00398 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00399 // senf::console::Client::SysBacktrace
00400 
00401 prefix_ senf::console::Client::SysBacktrace::SysBacktrace()
00402 {
00403     sysdir().add("backtrace", factory::Command(&SysBacktrace::backtrace)
00404                  .doc("Display the backtrace of the last error / exception in this console") );
00405 }
00406 
00407 prefix_ void senf::console::Client::SysBacktrace::backtrace(std::ostream & os)
00408 {
00409     Client & client (Client::get(os));
00410     if (client.backtrace().empty())
00411         os << "(no backtrace)\n";
00412     else
00413         os << client.backtrace();
00414 }
00415 
00416 senf::console::Client::SysBacktrace senf::console::Client::SysBacktrace::instance_;
00417 
00418 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00419 #undef prefix_
00420 //#include "Server.mpp"
00421 
00422 
00423 // Local Variables:
00424 // mode: c++
00425 // fill-column: 100
00426 // comment-column: 40
00427 // c-file-style: "senf"
00428 // indent-tabs-mode: nil
00429 // ispell-local-dictionary: "american"
00430 // compile-command: "scons -u test"
00431 // End:

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