X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Console%2FServer.cc;h=53db4e7a280c70854bbac8a984dc4413be9b4595;hb=9cda1b12a3e68538ea8157ca96810f0423123a70;hp=8137f8692e993f3db0a07f4ba1207ef3063b193c;hpb=4fc732480d3ba33ac2589caece3b04224e51d32b;p=senf.git diff --git a/Console/Server.cc b/Console/Server.cc index 8137f86..53db4e7 100644 --- a/Console/Server.cc +++ b/Console/Server.cc @@ -27,7 +27,12 @@ #include "Server.ih" // Custom includes +#include +#include #include +#include +#include +#include #include "../Utils/senfassert.hh" #include "../Utils/membind.hh" #include "../Utils/Logger/SenfLog.hh" @@ -36,51 +41,84 @@ #define prefix_ ///////////////////////////////cc.p//////////////////////////////////////// -prefix_ void senf::console::start(senf::INet4SocketAddress const & address) +/////////////////////////////////////////////////////////////////////////// +// senf::console::detail::NonBlockingSocketSink + +prefix_ std::streamsize senf::console::detail::NonblockingSocketSink::write(const char * s, + std::streamsize n) { - senf::console::detail::Server::start(senf::TCPv4ServerSocketHandle(address)); - SENF_LOG((detail::Server::SENFLogArea)(log::NOTICE)( - "Console server started at " << address )); + try { + if (handle_.writeable()) + handle_.write(s, s+n); + } + catch (SystemException & ex) { + ; + } + return n; } -prefix_ void senf::console::start(senf::INet6SocketAddress const & address) +/////////////////////////////////////////////////////////////////////////// +// senf::console::Server + +prefix_ senf::console::Server & +senf::console::Server::start(senf::INet4SocketAddress const & address) { - senf::console::detail::Server::start(senf::TCPv6ServerSocketHandle(address)); - SENF_LOG((detail::Server::SENFLogArea)(log::NOTICE)( + senf::TCPv4ServerSocketHandle handle (address); + Server & server (senf::console::Server::start(handle)); + SENF_LOG((Server::SENFLogArea)(log::NOTICE)( "Console server started at " << address )); + return server; } -/////////////////////////////////////////////////////////////////////////// -// senf::console::detail::Server +prefix_ senf::console::Server & +senf::console::Server::start(senf::INet6SocketAddress const & address) +{ + senf::TCPv6ServerSocketHandle handle (address); + Server & server (senf::console::Server::start(handle)); + SENF_LOG((Server::SENFLogArea)(log::NOTICE)( + "Console server started at " << address )); + return server; +} -boost::scoped_ptr senf::console::detail::Server::instance_; +prefix_ boost::scoped_ptr & senf::console::Server::instancePtr() +{ + // We cannot make 'instance' a global or class-static variable, since it will then be destructed + // at an unknown time which may fail if the scheduler or the file-handle pool allocators have + // already been destructed. + static boost::scoped_ptr instance; + return instance; +} -prefix_ void senf::console::detail::Server::start(ServerHandle handle) +prefix_ senf::console::Server & senf::console::Server::start(ServerHandle handle) { - SENF_ASSERT( ! instance_ ); - instance_.reset(new Server(handle)); + // Uah .... ensure the scheduler is created before the instance pointer so it get's destructed + // AFTER it. + (void) senf::Scheduler::instance(); + SENF_ASSERT( ! instancePtr() ); + instancePtr().reset(new Server(handle)); + return * instancePtr(); } -prefix_ senf::console::detail::Server::Server(ServerHandle handle) +prefix_ senf::console::Server::Server(ServerHandle handle) : handle_ (handle) { Scheduler::instance().add( handle_, senf::membind(&Server::newClient, this) ); } -prefix_ senf::console::detail::Server::~Server() +prefix_ senf::console::Server::~Server() { Scheduler::instance().remove(handle_); } -prefix_ void senf::console::detail::Server::newClient(Scheduler::EventId event) +prefix_ void senf::console::Server::newClient(Scheduler::EventId event) { ServerHandle::ClientSocketHandle client (handle_.accept()); - boost::intrusive_ptr p (new Client(client)); + boost::intrusive_ptr p (new Client(*this, client, name_)); clients_.insert( p ); SENF_LOG(( "Registered new client " << p.get() )); } -prefix_ void senf::console::detail::Server::removeClient(Client & client) +prefix_ void senf::console::Server::removeClient(Client & client) { SENF_LOG(( "Disposing client " << & client )); // THIS DELETES THE CLIENT INSTANCE !! @@ -88,26 +126,31 @@ prefix_ void senf::console::detail::Server::removeClient(Client & client) } /////////////////////////////////////////////////////////////////////////// -// senf::console::detail::Client +// senf::console::Client -prefix_ senf::console::detail::Client::Client(ClientHandle handle) - : handle_ (handle) +prefix_ senf::console::Client::Client(Server & server, ClientHandle handle, + std::string const & name) + : out_t(handle), senf::log::IOStreamTarget(out_t::member), server_ (server), + handle_ (handle), name_ (name), promptLen_(0) { + showPrompt(); ReadHelper::dispatch( handle_, 16384u, ReadUntil("\n"), senf::membind(&Client::clientData, this) ); + route< senf::SenfLog, senf::log::NOTICE >(); } -prefix_ senf::console::detail::Client::~Client() +prefix_ senf::console::Client::~Client() {} -prefix_ void senf::console::detail::Client::stopClient() +prefix_ void senf::console::Client::stopClient() { // THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER removeClient RETURNS - Server::instance_->removeClient(*this); + server_.removeClient(*this); } -prefix_ void senf::console::detail::Client::clientData(ReadHelper::ptr helper) +prefix_ void senf::console::Client::clientData(ReadHelper::ptr helper) { + promptLen_ = 0; if (helper->error() || handle_.eof()) { // THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER stopClient RETURNS stopClient(); @@ -118,11 +161,53 @@ prefix_ void senf::console::detail::Client::clientData(ReadHelper: tail_ = helper->tail(); boost::trim(data); // Gets rid of superfluous \r or \n characters - SENF_LOG(( this << ": " << data )); + if (data.empty()) + data = lastCommand_; + else + lastCommand_ = data; + + try { + if (! parser_.parse(data, boost::bind( boost::ref(executor_), + boost::ref(out_t::member), + _1 )) ) + out_t::member << "syntax error" << std::endl; + } + catch (Executor::ExitException &) { + // THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER stopClient RETURNS + stopClient(); + return; + } + catch (std::exception & ex) { + out_t::member << ex.what() << std::endl; + } + catch (...) { + out_t::member << "unidentified error (unknown exception thrown)" << std::endl; + } + + showPrompt(); ReadHelper::dispatch( handle_, 16384u, ReadUntil("\n"), senf::membind(&Client::clientData, this) ); } +prefix_ void senf::console::Client::showPrompt() +{ + std::string path (executor_.cwd().path()); + out_t::member << name_ << ":" << path << "# " << std::flush; + promptLen_ = name_.size() + 1 + path.size() + 1; +} + +prefix_ void senf::console::Client::v_write(boost::posix_time::ptime timestamp, + std::string const & stream, + std::string const & area, unsigned level, + std::string const & message) +{ + if (promptLen_) + out_t::member << '\r' << std::string(' ', promptLen_) << '\r'; + IOStreamTarget::v_write(timestamp, stream, area, level, message); + if (promptLen_) + showPrompt(); +} + ///////////////////////////////cc.e//////////////////////////////////////// #undef prefix_ //#include "Server.mpp"