Utils/Console: Console UDPServer
[senf.git] / Utils / Console / Server.cc
index 04b54be..58a3dcc 100644 (file)
@@ -27,6 +27,7 @@
 #include "Server.ih"
 
 // Custom includes
+#include <errno.h>
 #include <iostream>
 #include <boost/algorithm/string/trim.hpp>
 #include <boost/iostreams/device/file_descriptor.hpp>
 #include "../../Utils/senfassert.hh"
 #include "../../Utils/membind.hh"
 #include "../../Utils/Logger/SenfLog.hh"
-#include "Readline.hh"
+#include "LineEditor.hh"
+#include "ScopedDirectory.hh"
+#include "Sysdir.hh"
+#include "ParsedCommand.hh"
 
 //#include "Server.mpp"
 #define prefix_
@@ -50,8 +54,7 @@ prefix_ std::streamsize senf::console::detail::NonblockingSocketSink::write(cons
     try {
         if (client_.handle().writeable()) {
             std::string data (s, n);
-            client_.translate(data);
-            client_.handle().write( data );
+            client_.write(data);
         }
     }
     catch (SystemException & ex) {
@@ -94,7 +97,8 @@ prefix_ senf::console::Server::Server(ServerHandle handle)
     : handle_ (handle), 
       event_ ("senf::console::Server", senf::membind(&Server::newClient, this),
               handle_, scheduler::FdEvent::EV_READ),
-      root_ (senf::console::root().thisptr()), mode_ (Automatic)
+      root_ (senf::console::root().thisptr()), mode_ (Automatic),
+      name_ (::program_invocation_short_name)
 {}
 
 prefix_ void senf::console::Server::newClient(int event)
@@ -102,12 +106,12 @@ prefix_ void senf::console::Server::newClient(int event)
     ServerHandle::ClientHandle client (handle_.accept());
     boost::intrusive_ptr<Client> p (new Client(*this, client));
     clients_.insert( p );
-    SENF_LOG(( "Registered new client " << p.get() ));
+    SENF_LOG(( "Registered new client " << client.peer() ));
 }
 
 prefix_ void senf::console::Server::removeClient(Client & client)
 {
-    SENF_LOG(( "Disposing client " << & client ));
+    SENF_LOG(( "Disposing client " << client.handle().peer() ));
     // THIS DELETES THE CLIENT INSTANCE !!
     clients_.erase(boost::intrusive_ptr<Client>(&client));
 }
@@ -149,6 +153,7 @@ senf::console::detail::DumbClientReader::clientData(senf::ReadHelper<ClientHandl
 prefix_ void senf::console::detail::DumbClientReader::showPrompt()
 {
     std::string prompt (promptString());
+    prompt += " ";
 
     stream() << std::flush;
     handle().write(prompt);
@@ -170,8 +175,16 @@ prefix_ void senf::console::detail::DumbClientReader::v_enablePrompt()
         showPrompt();
 }
 
-prefix_ void senf::console::detail::DumbClientReader::v_translate(std::string & data)
-{}
+prefix_ void senf::console::detail::DumbClientReader::v_write(std::string const & data)
+{
+    handle().write(data);
+}
+
+prefix_ unsigned senf::console::detail::DumbClientReader::v_width()
+    const
+{
+    return 80;
+}
 
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::detail::NoninteractiveClientReader
@@ -190,8 +203,16 @@ prefix_ void senf::console::detail::NoninteractiveClientReader::v_disablePrompt(
 prefix_ void senf::console::detail::NoninteractiveClientReader::v_enablePrompt()
 {}
 
-prefix_ void senf::console::detail::NoninteractiveClientReader::v_translate(std::string & data)
-{}
+prefix_ void senf::console::detail::NoninteractiveClientReader::v_write(std::string const & data)
+{
+    handle().write(data);
+}
+
+prefix_ unsigned senf::console::detail::NoninteractiveClientReader::v_width()
+    const
+{
+    return 80;
+}
 
 prefix_ void
 senf::console::detail::NoninteractiveClientReader::newData(int event)
@@ -215,8 +236,9 @@ senf::console::detail::NoninteractiveClientReader::newData(int event)
 // senf::console::Client
 
 prefix_ senf::console::Client::Client(Server & server, ClientHandle handle)
-    : out_t(boost::ref(*this)), senf::log::IOStreamTarget(out_t::member), server_ (server),
-      handle_ (handle), 
+    : out_t(boost::ref(*this)), 
+      senf::log::IOStreamTarget("client-" + senf::str(handle.peer()), out_t::member), 
+      server_ (server), handle_ (handle), 
       readevent_ ("senf::console::Client::interactive_check", 
                   boost::bind(&Client::setNoninteractive,this), 
                   handle, scheduler::FdEvent::EV_READ, false),
@@ -247,7 +269,7 @@ prefix_ void senf::console::Client::setInteractive()
     readevent_.disable();
     timer_.disable();
     mode_ = Server::Interactive;
-    reader_.reset(new detail::SafeReadlineClientReader (*this));
+    reader_.reset(new detail::LineEditorSwitcher (*this));
     executor_.autocd(true).autocomplete(true);
 }
 
@@ -259,17 +281,13 @@ prefix_ void senf::console::Client::setNoninteractive()
     reader_.reset(new detail::NoninteractiveClientReader(*this));
 }
 
-prefix_ void senf::console::Client::translate(std::string & data)
-{
-    reader_->translate(data);
-}
-
 prefix_ std::string::size_type senf::console::Client::handleInput(std::string data,
                                                                   bool incremental)
 {
-    if (data.empty() && ! incremental)
+    if (data.empty() && ! incremental) {
         data = lastCommand_;
-    else
+        stream() << "repeat: " << data << std::endl;
+    } else
         lastCommand_ = data;
 
     std::string::size_type n (data.size());
@@ -285,14 +303,21 @@ prefix_ std::string::size_type senf::console::Client::handleInput(std::string da
                                                    _1 ));
     }
     catch (Executor::ExitException &) {
-        // This generates an EOF condition on the Handle. This EOF condition is expected
-        // to be handled gracefully by the ClientReader. We cannot call stop() here, since we
-        // are called from the client reader callback and that will continue executing even if we
-        // call stop here ...
+        // This generates an EOF condition on the Handle. This EOF condition is expected to be
+        // handled gracefully by the ClientReader. We cannot call stop() here, since we are called
+        // from the client reader callback and that will continue executing after stop() has been
+        // called. stop() however will delete *this instance ... BANG ...
         handle_.facet<senf::TCPSocketProtocol>().shutdown(senf::TCPSocketProtocol::ShutRD);
     }
     catch (std::exception & ex) {
-        stream() << ex.what() << std::endl;
+        std::string msg (ex.what());
+        std::string::size_type i (msg.find("-- \n"));
+        if (i != std::string::npos) {
+            backtrace_ = msg.substr(0,i);
+            msg = msg.substr(i+4);
+        } else 
+            backtrace_.clear();
+        stream() << msg << std::endl;
     }
     catch (...) {
         stream() << "unidentified error (unknown exception thrown)" << std::endl;
@@ -311,33 +336,26 @@ prefix_ void senf::console::Client::v_write(senf::log::time_type timestamp,
     reader_->enablePrompt();
 }
 
-prefix_ std::ostream & senf::console::operator<<(std::ostream & os, Client const & client)
-{
-    typedef ClientSocketHandle< MakeSocketPolicy<
-        INet4AddressingPolicy,ConnectedCommunicationPolicy>::policy > V4Socket;
-    typedef ClientSocketHandle< MakeSocketPolicy<
-        INet6AddressingPolicy,ConnectedCommunicationPolicy>::policy > V6Socket;
+///////////////////////////////////////////////////////////////////////////
+// senf::console::Client::SysBacktrace
 
-    try {
-        if (check_socket_cast<V4Socket>(client.handle()))
-            os << dynamic_socket_cast<V4Socket>(client.handle()).peer();
-        else if (check_socket_cast<V6Socket>(client.handle()))
-            os << dynamic_socket_cast<V6Socket>(client.handle()).peer();
-        else
-            os << static_cast<void const *>(&client);
-    }
-    catch (SystemException &) {
-        os << "0.0.0.0:0";
-    }
-        
-    return os;
+prefix_ senf::console::Client::SysBacktrace::SysBacktrace()
+{
+    sysdir().node().add("backtrace", &SysBacktrace::backtrace)
+        .doc("Display the backtrace of the last error / exception in this console");
 }
 
-prefix_ std::ostream & senf::console::operator<<(std::ostream & os, Client * client)
+prefix_ void senf::console::Client::SysBacktrace::backtrace(std::ostream & os)
 {
-    return os << *client;
+    Client & client (Client::get(os));
+    if (client.backtrace().empty())
+        os << "(no backtrace)\n";
+    else
+        os << client.backtrace();
 }
 
+senf::console::Client::SysBacktrace senf::console::Client::SysBacktrace::instance_;
+
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_
 //#include "Server.mpp"