From 5b55e600157079821ccf8ddd3f93f75350756d75 Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Fri, 9 Sep 2016 14:31:24 -0700 Subject: [PATCH] Add P-Line listener module. --- modules/conf/listen.cc | 219 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 193 insertions(+), 26 deletions(-) diff --git a/modules/conf/listen.cc b/modules/conf/listen.cc index f85b59f66..328629478 100644 --- a/modules/conf/listen.cc +++ b/modules/conf/listen.cc @@ -19,19 +19,150 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include +#include +#include +#include +namespace ip = boost::asio::ip; using namespace ircd; -mapi::header IRCD_MODULE +struct clicli { - "P-Line - configuration directives for listening sockets" + ip::tcp::socket socket; + + clicli(): socket{*ircd::ios} {} }; +const size_t STACK_SIZE +{ + 256_KiB // can be optimized +}; + +struct listener +{ + std::string name; + size_t backlog; + ip::address host; + ip::tcp::endpoint ep; + ctx::dock cond; + ircd::context context; + ip::tcp::acceptor acceptor; + + bool configured() const; + + private: + bool accept(); + void main(); + + public: + listener(const std::string &name = {}); + listener(listener &&) = default; +}; + +listener::listener(const std::string &name) +:name +{ + name +} +,backlog +{ + boost::asio::socket_base::max_connections +} +,context +{ + STACK_SIZE, std::bind(&listener::main, this) +} +,acceptor +{ + *ios +} +{ +} + +bool +listener::configured() +const +{ + return ep != ip::tcp::endpoint{}; +} + +void +listener::main() +try +{ + // The listener context starts after there is a valid configuration + cond.wait([this] + { + return configured(); + }); + + conf::log.debug("Attempting bind() to [%s]:%u", + ep.address().to_string().c_str(), + ep.port()); + + acceptor.open(ep.protocol()); + acceptor.set_option(ip::tcp::acceptor::reuse_address(true)); + acceptor.bind(ep); + acceptor.listen(backlog); + + conf::log.info("Listener bound to [%s]:%u", + ep.address().to_string().c_str(), + ep.port()); + + while(accept()); + + conf::log.info("Listener closing @ [%s]:%u", + ep.address().to_string().c_str(), + ep.port()); +} +catch(const std::exception &e) +{ + conf::log.error("Listener closing @ [%s]:%u: %s", + ep.address().to_string().c_str(), + ep.port(), + e.what()); +} + +bool +listener::accept() +try +{ + auto clit(std::make_unique()); + acceptor.async_accept(clit->socket, yield(continuation())); + printf("Got client!\n"); + return true; +} +catch(const boost::system::system_error &e) +{ + switch(e.code().value()) + { + using namespace boost::system::errc; + + case success: return true; + case operation_canceled: return false; + default: throw; + } +} +catch(const std::exception &e) +{ + conf::log.error("Listener @ [%s]:%u: accept(): %s", + ep.address().to_string().c_str(), + ep.port(), + e.what()); + return true; +} + +std::map listeners; + struct P :conf::top { + void set_backlog(listener &, std::string); + void set_host(listener &, std::string); + void set_port(listener &, std::string); + void set(client::client &, std::string label, std::string key, std::string val) override; + void del(client::client &, const std::string &label, const std::string &key) override; using conf::top::top; } @@ -41,43 +172,79 @@ static P 'P', "listen", }; - -struct block +mapi::header IRCD_MODULE { - std::string host; - std::vector port; + "P-Line - instructions for listening sockets" }; -std::map blocks; +void +P::del(client::client &, + const std::string &label, + const std::string &key) +{ + listeners.erase(label); +} void P::set(client::client &, std::string label, std::string key, std::string val) +try { + auto it(listeners.lower_bound(label)); + if(it == end(listeners) || it->second.name != label) + it = listeners.emplace_hint(it, label, label); + + auto &listener(it->second); switch(hash(key)) { - case hash("host"): - blocks[label].host = val; - break; - - case hash("port"): - if(!val) - { - blocks[label].port.clear(); - break; - } - - tokens(val, ", ", [&](const std::string &token) - { - const auto &val(boost::lexical_cast(token)); - blocks[label].port.emplace_back(val); - }); - break; - + case hash("host"): set_host(listener, std::move(val)); break; + case hash("port"): set_port(listener, std::move(val)); break; + case hash("backlog"): set_backlog(listener, std::move(val)); break; default: conf::log.warning("Unknown P-Line key \"%s\"", key.c_str()); break; } } +catch(const std::exception &e) +{ + conf::log.error("P-Line \"%s\" set \"%s\": %s", + label.c_str(), + key.c_str(), + e.what()); + throw; +} + +void +P::set_port(listener &listener, + std::string val) +{ + static const auto any(ip::address::from_string("0.0.0.0")); + const auto &host(listener.host.is_unspecified()? any : listener.host); +/* + tokens(val, ", ", [&] + (const std::string &token) + { + const auto &port(boost::lexical_cast(token)); + listener.ep = ip::tcp::endpoint(host, port); + }); +*/ + const auto &port(boost::lexical_cast(val)); + listener.ep = ip::tcp::endpoint(host, port); + listener.cond.notify_all(); +} + +void +P::set_host(listener &listener, + std::string val) +{ + listener.host = ip::address::from_string(val); +} + +void +P::set_backlog(listener &listener, + std::string val) +{ + listener.backlog = boost::lexical_cast(val); +}