Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

  • Is it possible to disconnect my stream, and then reconnect and reuse it?
  • If so, what procedure do I need to do to allow this?
like image 860
Steve Lorimer Avatar asked Oct 26 '25 08:10

Steve Lorimer


1 Answers

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

like image 158
Steve Lorimer Avatar answered Oct 29 '25 08:10

Steve Lorimer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!