I would like to ensure a proper shutdown of an SSL connection. From this question I found a code snippet to distinguish a graceful shutdown from a short read error:
// const boost::system::error_code &ec
if (ec.category() == asio::error::get_ssl_category() &&
ec.value() == ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ)) {
// -> not a real error, just a normal TLS shutdown
}
The code above makes sense in light of the following code in engine.ipp
:
const boost::system::error_code& engine::map_error_code(
boost::system::error_code& ec) const
{
// We only want to map the error::eof code.
if (ec != boost::asio::error::eof)
return ec;
// If there's data yet to be read, it's an error.
if (BIO_wpending(ext_bio_))
{
ec = boost::system::error_code(
ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ),
boost::asio::error::get_ssl_category());
return ec;
}
// SSL v2 doesn't provide a protocol-level shutdown, so an eof on the
// underlying transport is passed through.
if (ssl_->version == SSL2_VERSION)
return ec;
// Otherwise, the peer should have negotiated a proper shutdown.
if ((::SSL_get_shutdown(ssl_) & SSL_RECEIVED_SHUTDOWN) == 0)
{
ec = boost::system::error_code(
ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ),
boost::asio::error::get_ssl_category());
}
return ec;
}
In the code above the error is remapped, which I then check for specifically. But after reading the function above I don't feel reassured.
It seems that both:
if (BIO_wpending(ext_bio_))
(data to be read), andif ((::SSL_get_shutdown(ssl_) & SSL_RECEIVED_SHUTDOWN) == 0)
(negotiated proper shutdown)
will generate the same error that I'm checking for.
Will my error check miss an error if (BIO_wpending(ext_bio_))
is true? I don't know what exactly this check is looking at. Does it matter?