Subject: [Boost-bugs] [Boost C++ Libraries] #13587: ssl::stream::async_shutdown() never completes when async_read is active
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2018-06-06 07:46:10
#13587: ssl::stream::async_shutdown() never completes when async_read is active
-------------------------------------------+----------------------------
Reporter: anonymous | Owner: chris_kohlhoff
Type: Bugs | Status: new
Milestone: To Be Determined | Component: asio
Version: Boost 1.67.0 | Severity: Problem
Keywords: async_shutdown ssl async_read |
-------------------------------------------+----------------------------
I have a connected ssl::stream. If I do an asio::async_read followed by an
async_shutdown on the stream, the read operation will complete with
stream_truncated error (as expected) but the async_shutdown operation
never completes (i.e. handler never gets called). See a minimal reproduce
below.
Environment: Debian stretch, gcc 6.3.0, Boost 1.67, BoringSSL.
My questions:
1. Is it allowed to call async_shutdown on an ssl::stream when there is an
async_read pending?
2. If yes, is the above behavior expected?
3. If not, how do I gracefully shutdown an SSL stream when an async_read
is pending? And is this restriction documented anywhere?
Code:
{{{
#include <boost/asio.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/error.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.hpp>
void
fail(boost::system::error_code ec, char const* what)
{
std::cerr << what << ": " << ec.message() << "\n";
}
class session : public std::enable_shared_from_this<session>
{
tcp::resolver resolver_;
ssl::stream<tcp::socket> stream_;
std::string buffer_;
public:
explicit
session(boost::asio::io_context& ioc, ssl::context& ctx)
: resolver_(ioc)
, stream_(ioc, ctx)
{
}
void
run(
char const* host,
char const* port)
{
// Set SNI Hostname (many hosts need this to handshake
successfully)
if(! SSL_set_tlsext_host_name(stream_.native_handle(), host))
{
boost::system::error_code
ec{static_cast<int>(::ERR_get_error()),
boost::asio::error::get_ssl_category()};
std::cerr << ec.message() << "\n";
return;
}
resolver_.async_resolve(
host,
port,
std::bind(
&session::on_resolve,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2));
}
void
on_resolve(
boost::system::error_code ec,
tcp::resolver::results_type results)
{
if(ec)
return fail(ec, "resolve");
boost::asio::async_connect(
stream_.next_layer(),
results.begin(),
results.end(),
std::bind(
&session::on_connect,
shared_from_this(),
std::placeholders::_1));
}
void
on_connect(boost::system::error_code ec)
{
if(ec)
return fail(ec, "connect");
stream_.async_handshake(
ssl::stream_base::client,
std::bind(
&session::on_handshake,
shared_from_this(),
std::placeholders::_1));
}
void
on_handshake(boost::system::error_code ec)
{
if(ec)
return fail(ec, "handshake");
std::cout << "Connected" << std::endl;
boost::asio::async_read(stream_,
boost::asio::dynamic_buffer(buffer_),
std::bind(
&session::on_read,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2));
stream_.async_shutdown(
std::bind(
&session::on_shutdown,
shared_from_this(),
std::placeholders::_1));
}
void
on_read(
boost::system::error_code ec,
std::size_t)
{
if(ec)
return fail(ec, "read");
std::cout << "Message received" << std::endl;
}
void
on_shutdown(boost::system::error_code ec)
{
std::cout << "Closed" << std::endl;
}
};
int main(int argc, char** argv)
{
boost::asio::io_context ioc;
ssl::context ctx{ssl::context::sslv23_client};
std::make_shared<session>(ioc, ctx)->run("www.google.com", "443");
ioc.run();
return EXIT_SUCCESS;
}
}}}
The program will output
{{{
Connected
read: stream truncated
}}}
and hangs.
-- Ticket URL: <https://svn.boost.org/trac10/ticket/13587> Boost C++ Libraries <http://www.boost.org/> Boost provides free peer-reviewed portable C++ source libraries.
This archive was generated by hypermail 2.1.7 : 2018-06-06 07:51:15 UTC