mirror of
https://github.com/matrix-construct/construct
synced 2024-11-26 00:32:35 +01:00
Add P-Line listener module.
This commit is contained in:
parent
89c2e74f3b
commit
5b55e60015
1 changed files with 193 additions and 26 deletions
|
@ -19,19 +19,150 @@
|
|||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <ircd/lex_cast.h>
|
||||
#include <ircd/ctx_ctx.h>
|
||||
|
||||
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<clicli>());
|
||||
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<std::string, listener> 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<uint16_t> port;
|
||||
"P-Line - instructions for listening sockets"
|
||||
};
|
||||
|
||||
std::map<std::string, block> 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<uint16_t>(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<uint16_t>(token));
|
||||
listener.ep = ip::tcp::endpoint(host, port);
|
||||
});
|
||||
*/
|
||||
const auto &port(boost::lexical_cast<uint16_t>(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<size_t>(val);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue