mirror of
https://github.com/matrix-construct/construct
synced 2024-12-28 08:24:08 +01:00
ircd: Add listener device.
This commit is contained in:
parent
b5c72c38f0
commit
a7cb94d042
3 changed files with 171 additions and 97 deletions
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
259
ircd/listen.cc
259
ircd/listen.cc
|
@ -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()
|
||||||
|
|
Loading…
Reference in a new issue