mirror of
https://github.com/matrix-construct/construct
synced 2024-11-29 10:12:39 +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.
|
* 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;
|
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
|
struct P
|
||||||
:conf::top
|
: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 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;
|
using conf::top::top;
|
||||||
}
|
}
|
||||||
|
@ -41,43 +172,79 @@ static P
|
||||||
'P', "listen",
|
'P', "listen",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mapi::header IRCD_MODULE
|
||||||
struct block
|
|
||||||
{
|
{
|
||||||
std::string host;
|
"P-Line - instructions for listening sockets"
|
||||||
std::vector<uint16_t> port;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::map<std::string, block> blocks;
|
void
|
||||||
|
P::del(client::client &,
|
||||||
|
const std::string &label,
|
||||||
|
const std::string &key)
|
||||||
|
{
|
||||||
|
listeners.erase(label);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
P::set(client::client &,
|
P::set(client::client &,
|
||||||
std::string label,
|
std::string label,
|
||||||
std::string key,
|
std::string key,
|
||||||
std::string val)
|
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))
|
switch(hash(key))
|
||||||
{
|
{
|
||||||
case hash("host"):
|
case hash("host"): set_host(listener, std::move(val)); break;
|
||||||
blocks[label].host = val;
|
case hash("port"): set_port(listener, std::move(val)); break;
|
||||||
break;
|
case hash("backlog"): set_backlog(listener, std::move(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;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
conf::log.warning("Unknown P-Line key \"%s\"", key.c_str());
|
conf::log.warning("Unknown P-Line key \"%s\"", key.c_str());
|
||||||
break;
|
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