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:
parent
dd137d50e3
commit
fcb2660f0a
2 changed files with 148 additions and 63 deletions
|
@ -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,
|
||||
|
|
186
ircd/net.cc
186
ircd/net.cc
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue