#define IH_Server_ 1
// Custom includes
-#include <set>
-#include <boost/utility.hpp>
-#include <boost/scoped_ptr.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/iostreams/device/file_descriptor.hpp>
+#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream.hpp>
-#include "../Utils/intrusive_refcount.hh"
-#include "../Socket/Protocols/INet/TCPSocketHandle.hh"
-#include "../Socket/ServerSocketHandle.hh"
-#include "../Scheduler/Scheduler.hh"
-#include "../Scheduler/ReadHelper.hh"
-#include "Parse.hh"
-#include "Executor.hh"
+#include <set>
///////////////////////////////ih.p////////////////////////////////////////
namespace senf {
namespace console {
-namespace detail {
+ class Server;
class Client;
- /** \brief
- */
- class Server
- : boost::noncopyable
+namespace detail {
+
+ class ServerManager
+ : public senf::singleton<ServerManager>
{
- SENF_LOG_CLASS_AREA();
- SENF_LOG_DEFAULT_LEVEL( senf::log::NOTICE );
public:
- ///////////////////////////////////////////////////////////////////////////
- // Types
+ typedef boost::intrusive_ptr<Server> ptr;
- typedef senf::ServerSocketHandle<
- senf::MakeSocketPolicy< senf::TCPv4SocketProtocol::Policy,
- senf::UnspecifiedAddressingPolicy>::policy > ServerHandle;
+ protected:
- ~Server();
+ private:
+ static void add(ptr server);
+ static void remove(ptr server);
- static void start(ServerHandle handle);
+ typedef std::set<ptr> Servers;
+ Servers servers_;
- protected:
+ friend class senf::console::Server;
+ };
- private:
- Server(ServerHandle handle);
+ /** \brief Internal: Nonblocking boost::iostreams::sink
- void newClient(Scheduler::EventId event);
- void removeClient(Client & client);
-
- ServerHandle handle_;
-
- typedef std::set< boost::intrusive_ptr<Client> > Clients;
- Clients clients_;
-
- static boost::scoped_ptr<Server> instance_;
+ The sink discards data if the output socket would.
+
+ \fixme Don't throw exceptions ... set stream error indicator (if at all)
+ */
+ class NonblockingSocketSink
+ : public boost::iostreams::sink
+ {
+ public:
+ typedef ClientSocketHandle<
+ MakeSocketPolicy<StreamFramingPolicy,
+ WriteablePolicy,
+ ConnectedCommunicationPolicy>::policy > Handle;
+
+ NonblockingSocketSink(Client & client);
+ std::streamsize write(const char * s, std::streamsize n);
+
+ Client & client() const;
- friend class Client;
+ private:
+ Client & client_;
};
-
- /** \brief
+
+ typedef boost::iostreams::stream<NonblockingSocketSink> NonblockingSocketOStream;
+
+ typedef senf::ServerSocketHandle<
+ senf::MakeSocketPolicy< senf::TCPv4SocketProtocol::Policy,
+ senf::UnspecifiedAddressingPolicy>::policy > ServerHandle;
+
+ /** \brief Internal: Generic client interface
+
+ The ClientReader encapsulates the interaction of a single network client with the user: It
+ manages prompt display and reading an interactive command.
*/
- class Client
- : public senf::intrusive_refcount
+ class ClientReader
{
- SENF_LOG_CLASS_AREA();
- SENF_LOG_DEFAULT_LEVEL( senf::log::NOTICE );
public:
- typedef Server::ServerHandle::ClientSocketHandle ClientHandle;
+ typedef ServerHandle::ClientSocketHandle ClientHandle;
+
+ virtual ~ClientReader() = 0;
- ~Client();
+ // Called by subclasses to get information from the Client
+
+ Client & client() const;
+ std::string promptString() const;
+ ClientHandle handle() const;
+ std::ostream & stream() const;
+
+ // Called by subclasses to perform actions in the Client
void stopClient();
+ std::string::size_type handleInput(std::string const & input, bool incremental=false) const;
+
+ // Called by the Client
+
+ void disablePrompt();
+ void enablePrompt();
+ void translate(std::string & data);
protected:
-
+ ClientReader(Client & client);
+
private:
- Client(ClientHandle handle);
+ virtual void v_disablePrompt() = 0;
+ virtual void v_enablePrompt() = 0;
+ virtual void v_translate(std::string & data) = 0;
- void clientData(ReadHelper<ClientHandle>::ptr helper);
+ Client & client_;
+ };
+
+ /** \brief Internal: Primitive ClientReader implementation
- ClientHandle handle_;
- std::string tail_;
- SingleCommandParser parser_;
- Executor executor_;
+ This implementation uses the cooked telnet mode to read lines from the console. It does not
+ support explicit line editing or any other advanced features.
+ */
+ class DumbClientReader
+ : public ClientReader
+ {
+ public:
+ DumbClientReader(Client & client);
- typedef boost::iostreams::stream<boost::iostreams::file_descriptor_sink> fdostream;
- fdostream out_;
+ private:
+ virtual void v_disablePrompt();
+ virtual void v_enablePrompt();
+ virtual void v_translate(std::string & data);
- friend class Server;
+ void clientData(senf::ReadHelper<ClientHandle>::ptr helper);
+ void showPrompt();
+
+ std::string tail_;
+ unsigned promptLen_;
+ bool promptActive_;
};
+ /** \brief Internal: Primitive ClientReader implementation
+
+ This implementation uses the cooked telnet mode to read lines from the console. It does not
+ support explicit line editing or any other advanced features.
+ */
+ class NoninteractiveClientReader
+ : public ClientReader
+ {
+ public:
+ NoninteractiveClientReader(Client & client);
+
+ private:
+ virtual void v_disablePrompt();
+ virtual void v_enablePrompt();
+ virtual void v_translate(std::string & data);
+
+ void newData(senf::Scheduler::EventId event);
+
+ SchedulerBinding binding_;
+ std::string buffer_;
+ };
+
}}}
///////////////////////////////ih.e////////////////////////////////////////