0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-19 00:10:59 +01:00

ircd::net: Elaborate low-level socket interface.

This commit is contained in:
Jason Volk 2018-01-04 14:20:30 -08:00
parent dd137d50e3
commit fcb2660f0a
2 changed files with 148 additions and 63 deletions

View file

@ -67,6 +67,8 @@ struct ircd::net::socket
void call_user(const handler &, const error_code &ec) noexcept;
void handle_timeout(std::weak_ptr<socket> wp, const error_code &ec) noexcept;
void handle_handshake(std::weak_ptr<socket> wp, handler, const error_code &ec) noexcept;
void handle_connect(std::weak_ptr<socket> wp, handler, const error_code &ec) noexcept;
void handle(std::weak_ptr<socket>, handler, const error_code &) noexcept;
public:
@ -103,16 +105,25 @@ struct ircd::net::socket
// Timer for this socket
void set_timeout(const milliseconds &, handler);
void set_timeout(const milliseconds &);
error_code cancel_timeout() noexcept;
milliseconds cancel_timeout() noexcept;
// Asynchronous callback when socket ready
void operator()(const wait_type &, const milliseconds &timeout, handler);
void operator()(const wait_type &, handler);
bool cancel() noexcept;
// Connect to host; synchronous (yield) and asynchronous (callback) variants
void connect(const endpoint &ep, const milliseconds &timeout, handler callback);
void connect(const endpoint &ep, const milliseconds &timeout = 30000ms);
// SSL handshake after connect (untimed)
void handshake(const handshake_type &, handler callback);
void handshake(const handshake_type & = handshake_type::client);
// Connect to host (untimed)
void connect(const endpoint &ep, handler callback);
void connect(const endpoint &ep);
// Connect to host and handshake composit (timed)
void open(const endpoint &ep, const milliseconds &timeout, handler callback);
void open(const endpoint &ep, const milliseconds &timeout);
bool disconnect(const dc &type);
socket(asio::ssl::context &ssl = sslv23_client,

View file

@ -93,7 +93,7 @@ ircd::net::connect(const ip::tcp::endpoint &remote,
const milliseconds &timeout)
{
const auto ret(std::make_shared<socket>());
ret->connect(remote, timeout);
ret->open(remote, timeout);
return ret;
}
@ -847,10 +847,8 @@ catch(const std::exception &e)
return;
}
/// Attempt to connect and ssl handshake remote; yields ircd::ctx; throws timeout
///
void
ircd::net::socket::connect(const ip::tcp::endpoint &ep,
ircd::net::socket::open(const ip::tcp::endpoint &ep,
const milliseconds &timeout)
try
{
@ -861,13 +859,13 @@ try
string(ep),
timeout.count());
sd.async_connect(ep, yield_context{to_asio{}});
connect(ep);
log.debug("socket(%p) connected to remote: %s from local: %s; performing handshake...",
this,
string(ep),
string(local()));
ssl.async_handshake(socket::handshake_type::client, yield_context{to_asio{}});
handshake(handshake_type::client);
log.debug("socket(%p) secure session with %s from local: %s established.",
this,
string(ep),
@ -887,57 +885,48 @@ catch(const std::exception &e)
/// Attempt to connect and ssl handshake; asynchronous, callback when done.
///
void
ircd::net::socket::connect(const ip::tcp::endpoint &ep,
ircd::net::socket::open(const ip::tcp::endpoint &ep,
const milliseconds &timeout,
handler callback)
{
auto handshake_handler{[this, callback(std::move(callback))]
(const error_code &ec)
noexcept
{
if(timedout)
assert(ec == boost::system::errc::operation_canceled);
log.debug("socket(%p) attempting connect to remote: %s for the next %ld$ms",
this,
string(ep),
timeout.count());
if(!timedout)
cancel_timeout();
try
auto handler
{
callback(ec);
}
catch(const std::exception &e)
{
log.critical("socket(%p): connect: unhandled exception from user callback: %s",
(const void *)this,
e.what());
}
}};
auto connect_handler{[this, handshake_handler(std::move(handshake_handler))]
(const error_code &ec)
noexcept
{
// Even though the branch on ec below should cancel the timeout on
// error, the timeout still needs to be canceled if else anything bad
// happens in the remainder of this frame too.
const unwind::exceptional cancels{[this]
{
cancel_timeout();
}};
// A connect error
if(ec)
{
handshake_handler(ec);
return;
}
static const auto handshake{socket::handshake_type::client};
ssl.async_handshake(handshake, std::move(handshake_handler));
}};
std::bind(&socket::handle_connect, this, weak_from(*this), std::move(callback), ph::_1)
};
this->connect(ep, std::move(handler));
set_timeout(timeout);
sd.async_connect(ep, std::move(connect_handler));
}
void
ircd::net::socket::connect(const ip::tcp::endpoint &ep)
{
sd.async_connect(ep, yield_context{to_asio{}});
}
void
ircd::net::socket::connect(const ip::tcp::endpoint &ep,
handler callback)
{
sd.async_connect(ep, std::move(callback));
}
void
ircd::net::socket::handshake(const handshake_type &type)
{
ssl.async_handshake(type, yield_context{to_asio{}});
}
void
ircd::net::socket::handshake(const handshake_type &type,
handler callback)
{
ssl.async_handshake(type, std::move(callback));
}
bool
@ -990,7 +979,6 @@ try
case dc::SSL_NOTIFY:
{
set_timeout(8s);
ssl.async_shutdown([s(shared_from_this())]
(error_code ec)
noexcept
@ -1013,6 +1001,7 @@ try
s.get(),
string(ec));
});
set_timeout(8s);
return true;
}
}
@ -1080,7 +1069,6 @@ ircd::net::socket::operator()(const wait_type &type,
};
assert(connected());
set_timeout(timeout);
switch(type)
{
case wait_type::wait_error:
@ -1102,6 +1090,9 @@ ircd::net::socket::operator()(const wait_type &type,
break;
}
}
// Commit to timeout here in case exception was thrown earlier.
set_timeout(timeout);
}
void
@ -1115,7 +1106,6 @@ noexcept try
// After life_guard is constructed it is safe to use *this in this frame.
const life_guard<socket> s{wp};
log.debug("socket(%p): handle: (%s)",
this,
string(ec));
@ -1160,6 +1150,84 @@ catch(const std::exception &e)
assert(0);
}
void
ircd::net::socket::handle_connect(std::weak_ptr<socket> wp,
handler callback,
const error_code &ec)
noexcept try
{
const life_guard<socket> s{wp};
assert(!timedout || ec == boost::system::errc::operation_canceled);
log.debug("socket(%p) connect from local: %s to remote: %s: %s",
this,
string(local_ipport(*this)),
string(remote_ipport(*this)),
string(ec));
// A connect error
if(ec)
{
cancel_timeout();
call_user(callback, ec);
return;
}
auto handler
{
std::bind(&socket::handle_handshake, this, wp, std::move(callback), ph::_1)
};
handshake(handshake_type::client, std::move(handler));
}
catch(const std::bad_weak_ptr &e)
{
log.warning("socket(%p): belated callback to handle_connect... (%s)",
this,
e.what());
assert(0);
}
catch(const std::exception &e)
{
log.critical("socket(%p): handle_connect: %s",
this,
e.what());
assert(0);
}
void
ircd::net::socket::handle_handshake(std::weak_ptr<socket> wp,
handler callback,
const error_code &ec)
noexcept try
{
const life_guard<socket> s{wp};
assert(!timedout || ec == boost::system::errc::operation_canceled);
log.debug("socket(%p) handshake from local: %s to remote: %s: %s",
this,
string(local_ipport(*this)),
string(remote_ipport(*this)),
string(ec));
if(!timedout)
cancel_timeout();
call_user(callback, ec);
}
catch(const std::bad_weak_ptr &e)
{
log.warning("socket(%p): belated callback to handle_handshake... (%s)",
this,
e.what());
assert(0);
}
catch(const std::exception &e)
{
log.critical("socket(%p): handle_handshake: %s",
this,
e.what());
assert(0);
}
void
ircd::net::socket::handle_timeout(const std::weak_ptr<socket> wp,
const error_code &ec)
@ -1316,14 +1384,20 @@ catch(const boost::system::system_error &e)
return false;
}
ircd::net::error_code
ircd::milliseconds
ircd::net::socket::cancel_timeout()
noexcept
{
const auto ret
{
timer.expires_from_now()
};
boost::system::error_code ec;
timedout = false;
timer.cancel(ec);
return ec;
assert(!ec);
return duration_cast<milliseconds>(ret);
}
void