00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00026 #include "Server.hh"
00027
00028
00029
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
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
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
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
00135 clients_.erase(boost::intrusive_ptr<Client>(&client));
00136 }
00137
00138
00139
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
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);
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
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
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
00354
00355
00356
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
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
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431