0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-09-30 04:38:52 +02:00

ircd: Add listener device.

This commit is contained in:
Jason Volk 2017-08-23 15:42:19 -06:00
parent b5c72c38f0
commit a7cb94d042
3 changed files with 171 additions and 97 deletions

View file

@ -19,8 +19,6 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "socket.h"
namespace ircd { namespace ircd {
struct listener struct listener
@ -33,7 +31,7 @@ struct listener
std::unique_ptr<struct acceptor> acceptor; std::unique_ptr<struct acceptor> acceptor;
public: public:
listener(const json::doc &options); listener(const json::object &options);
~listener() noexcept; ~listener() noexcept;
}; };

View file

@ -199,3 +199,4 @@ struct client;
#include "js.h" #include "js.h"
#include "client.h" #include "client.h"
#include "mods.h" #include "mods.h"
#include "listen.h"

View file

@ -19,7 +19,7 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <ircd/listen.h> #include <ircd/socket.h>
namespace ircd { namespace ircd {
@ -30,22 +30,31 @@ const size_t DEFAULT_STACK_SIZE
struct listener::acceptor struct listener::acceptor
{ {
using error_code = boost::system::error_code;
static log::log log; static log::log log;
std::string name; std::string name;
size_t backlog; size_t backlog;
asio::ssl::context ssl; asio::ssl::context ssl;
ip::tcp::endpoint ep; ip::tcp::endpoint ep;
ip::tcp::acceptor a; ip::tcp::acceptor a;
ctx::context context;
explicit operator std::string() const; explicit operator std::string() const;
void configure(const json::object &opts);
bool accept(); // Handshake stack
void main(); bool handshake_error(const error_code &ec);
void handshake(const error_code &ec, std::shared_ptr<socket>) noexcept;
acceptor(const json::doc &opts); // Acceptance stack
bool accept_error(const error_code &ec);
void accept(const error_code &ec, std::shared_ptr<socket>) noexcept;
// Accept next
void next();
acceptor(const json::object &opts);
~acceptor() noexcept; ~acceptor() noexcept;
}; };
@ -56,7 +65,7 @@ struct listener::acceptor
// ircd::listener // ircd::listener
// //
ircd::listener::listener(const json::doc &opts) ircd::listener::listener(const json::object &opts)
:acceptor{std::make_unique<struct acceptor>(opts)} :acceptor{std::make_unique<struct acceptor>(opts)}
{ {
} }
@ -77,7 +86,7 @@ ircd::listener::acceptor::log
"listener" "listener"
}; };
ircd::listener::acceptor::acceptor(const json::doc &opts) ircd::listener::acceptor::acceptor(const json::object &opts)
try try
:name :name
{ {
@ -100,23 +109,163 @@ try
{ {
*ircd::ios *ircd::ios
} }
,context
{ {
"listener", static const ip::tcp::acceptor::reuse_address reuse_address{true};
opts.get<size_t>("stack_size", DEFAULT_STACK_SIZE),
std::bind(&acceptor::main, this), configure(opts);
context.POST // defer until ctor body binds the socket
log.debug("%s configured listener SSL",
std::string(*this));
a.open(ep.protocol());
a.set_option(reuse_address);
log.debug("%s opened listener socket",
std::string(*this));
a.bind(ep);
log.debug("%s bound listener socket",
std::string(*this));
a.listen(backlog);
log.debug("%s listening (backlog: %lu)",
std::string(*this),
backlog);
next();
} }
catch(const boost::system::system_error &e)
{ {
log.debug("%s attempting to open listening socket", std::string(*this)); throw error("listener: %s", e.what());
}
ircd::listener::acceptor::~acceptor()
noexcept
{
a.cancel();
}
void
ircd::listener::acceptor::next()
try
{
auto sock(std::make_shared<ircd::socket>(ssl));
log.debug("%s: listening with next socket(%p)",
std::string(*this),
sock.get());
// The context blocks here until the next client is connected.
auto accept(std::bind(&acceptor::accept, this, ph::_1, sock));
a.async_accept(sock->sd, accept);
}
catch(const std::exception &e)
{
log.critical("%s: %s",
std::string(*this),
e.what());
if(ircd::debugmode)
throw;
}
void
ircd::listener::acceptor::accept(const error_code &ec,
const std::shared_ptr<socket> sock)
noexcept try
{
if(accept_error(ec))
return;
log.debug("%s: accepted %s",
std::string(*this),
string(sock->remote()));
static const auto handshake_type(socket::handshake_type::server);
auto handshake(std::bind(&acceptor::handshake, this, ph::_1, sock));
sock->ssl.async_handshake(handshake_type, handshake);
next();
}
catch(const std::exception &e)
{
log.error("%s: in accept(): socket(%p): %s",
std::string(*this),
sock.get(),
e.what());
next();
}
bool
ircd::listener::acceptor::accept_error(const error_code &ec)
{
switch(ec.value())
{
using namespace boost::system::errc;
case success:
return false;
case operation_canceled:
return true;
default:
throw boost::system::system_error(ec);
}
}
void
ircd::listener::acceptor::handshake(const error_code &ec,
const std::shared_ptr<socket> sock)
noexcept try
{
if(handshake_error(ec))
return;
log.debug("%s SSL handshook %s",
std::string(*this),
string(sock->remote()));
add_client(sock);
}
catch(const std::exception &e)
{
log.error("%s: in handshake(): socket(%p)[%s]: %s",
std::string(*this),
sock.get(),
string(sock->remote()),
e.what());
}
bool
ircd::listener::acceptor::handshake_error(const error_code &ec)
{
switch(ec.value())
{
using namespace boost::system::errc;
case success:
return false;
case operation_canceled:
return true;
default:
throw boost::system::system_error(ec);
}
}
void
ircd::listener::acceptor::configure(const json::object &opts)
{
log.debug("%s preparing listener socket configuration...",
std::string(*this));
ssl.set_options ssl.set_options
( (
ssl.default_workarounds | ssl.default_workarounds
ssl.no_sslv2 // | ssl.no_sslv2
//ssl.single_dh_use // | ssl.single_dh_use
); );
//TODO: XXX
ssl.set_password_callback([this] ssl.set_password_callback([this]
(const auto &size, const auto &purpose) (const auto &size, const auto &purpose)
{ {
@ -125,13 +274,10 @@ try
purpose, purpose,
size); size);
//XXX: TODO
return "foobar"; return "foobar";
}); });
a.open(ep.protocol());
a.set_option(ip::tcp::acceptor::reuse_address(true));
a.bind(ep);
if(opts.has("ssl_certificate_chain_file")) if(opts.has("ssl_certificate_chain_file"))
{ {
const std::string filename const std::string filename
@ -183,77 +329,6 @@ try
std::string(*this), std::string(*this),
filename); filename);
} }
a.listen(backlog);
// Allow main() to run and print its log message
ctx::yield();
}
catch(const boost::system::system_error &e)
{
throw error("listener: %s", e.what());
}
ircd::listener::acceptor::~acceptor()
noexcept
{
a.cancel();
}
void
ircd::listener::acceptor::main()
try
{
log.info("%s ready", std::string(*this));
while(accept());
log.info("%s closing", std::string(*this));
}
catch(const ircd::ctx::interrupted &e)
{
log.warning("%s interrupted", std::string(*this));
}
catch(const std::exception &e)
{
log.critical("%s %s", std::string(*this), e.what());
if(ircd::debugmode)
throw;
}
bool
ircd::listener::acceptor::accept()
try
{
auto sock(std::make_shared<ircd::socket>(ssl));
//log.debug("%s listening with socket(%p)", std::string(*this), sock.get());
a.async_accept(sock->sd, yield(continuation()));
//log.debug("%s accepted %s", std::string(*this), string(sock->remote()));
sock->ssl.async_handshake(socket::handshake_type::server, yield(continuation()));
//log.debug("%s SSL shooks hands with %s", std::string(*this), string(sock->remote()));
add_client(std::move(sock));
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:
log.warning("%s: in accept(): %s", std::string(*this), e.what());
return true;
}
}
catch(const std::exception &e)
{
log.error("%s: in accept(): %s", std::string(*this), e.what());
return true;
} }
ircd::listener::acceptor::operator std::string() ircd::listener::acceptor::operator std::string()