Steve Lorimer
Steve Lorimer

Reputation: 28659

boost::beast ssl tcp stream: gracefully disconnect and then reconnect

I have a boost::beast ssl stream data member:

class HttpsClient
{
    ...
    asio::ssl::context _ssl_ctx;
    beast::ssl_stream<beast::tcp_stream> _stream;
};

At construction I initialise the stream with an asio::io_context and an ssl context as follows:

namespace ssl = boost::asio::ssl;

ssl::context sslContext()
{
    ssl::context ssl_ctx {ssl::context::tlsv12_client};
    ssl_ctx.set_verify_mode(ssl::context::verify_peer | ssl::context::verify_fail_if_no_peer_cert);
    ssl_ctx.set_default_verify_paths();
    boost::certify::enable_native_https_server_verification(ssl_ctx);
    return ssl_ctx;
}

HttpsClient::HttpsClient(asio::io_context& ctx)
    : _ssl_ctx(sslContext())
    , _stream(ctx, _ssl_ctx)
{}

My connect function synchronously resolves the endpoint, connects to it, and performs the SSL handshake.

void HttpsClient::connect(const std::string& host, std::uint16_t port, const std::string& path)
{
    tcp::resolver resolver {_stream.get_executor()};
    tcp::resolver::results_type end_point = resolver.resolve(host, std::to_string(port));

    beast::get_lowest_layer(_stream).connect(end_point);
    beast::get_lowest_layer(_stream).socket().set_option(tcp::no_delay {true});

    SSL_set_tlsext_host_name(_stream.native_handle(), host.c_str());
    _stream.handshake(ssl::stream_base::client);
}

Once connected, I start an async_read, and when I want to send a request, I use the synchronously version:

void HttpsClient::write(beast::http::request<beast::http::string_body>& request)
{
    request.prepare_payload();
    http::write(_stream, request);
}

This is all works as expected.

The problem I'm coming up against is that I would like to disconnect and then reconnect the stream.

I have tried several different ways to close the connection:

Cancel outstanding async_read and shutdown the stream:

_stream.next_layer().cancel();
_stream.shutdown();

Once the shutdown completes I am seemingly able to connect again, but attempts to write to the stream fail with "protocol is shutdown".

After receiving "protocol is shutdown" any attempts to reconnect receive "Operation canceled"

Cancel outstanding async_read and close the underlying TCP stream:

_stream.next_layer().cancel();
_stream.next_layer().close();

Once the close completes I am still seemingly able to connect again, but now attempts to write to the stream fail with "wrong version number".

After receiving "wrong version number" any attempts to reconnect receive "unspecified system error"

Questions:

Upvotes: 3

Views: 1526

Answers (1)

Steve Lorimer
Steve Lorimer

Reputation: 28659

This issue relating to websocket, but possibly the ssl stream has similar requirements, says to recreate the entire stream... suggests reusing a disconnected stream is not possible.

Certainly recreating the stream does work, which suggests this is indeed the case

Upvotes: 2

Related Questions