john_zac
john_zac

Reputation: 1271

Error reconnecting boost beast (asio) websocket and http connection after disconnect

I am creating a client application that connects to a server using a an ssl Websocket connection and an ssl Http (Keep-Alive) connection and I am using boost::beast package to do the same. So as to detect a dead connection i have implemented a simple ping-pong mechanism. These all work fine, but an issue comes up when handling the ping-pong failure. The issue is as follows:

For testing my code i connected to the remote server, sent few messages and then turned off my wifi. As expected after a certain period it detected that it did not receive any message from the server and it tried to do an async_shutdown for the http connection and an async_close for the websocket connection. First thing i noticed was that both these calls block their respective strands until the wifi is back up.

And after the wifi is up, the application tries to reset the stream before reconnect:

void HttpKeepAliveConnection::recreateSocket()
{
    _receivedPongForLastPing = true;
    _sslContext.reset(new boost::asio::ssl::context({boost::asio::ssl::context::sslv23_client}));
    _stream.reset(new HttpStream(_ioContext, *_sslContext));
}

And reset ws variable for websocket:

void WebsocketConnection::recreateSocket()
{
    _receivedPongForLastPing = true;
    _sslContext.reset(new boost::asio::ssl::context({boost::asio::ssl::context::sslv23_client}));
    _ws.reset(new WebSocket(_ioContext, *_sslContext));
}

Unfortunately it fails at either on_connect or on_ssl_handshake. Following are my logs:

156 AsioConnectionBase.cpp:53 (2018-08-06 15:34:38.458536) [0x00007ffff601e700] : Started connect sequence. Connection Name: HttpKeepAliveConn

157 AsioConnectionBase.cpp:122 (2018-08-06 15:34:38.459802) [0x00007ffff481b700] : Failed establishing connection to destination. Connection failed. Connection Name: HttpKeepAliveConn. Host: xxxxxxxxx. Port: 443. Error: Operation canceled

158 APIManager.cpp:175 (2018-08-06 15:34:38.459886) [0x00007ffff481b700] : Received error callback from connection. Restarting connection in a sec. Connection Name: HttpKeepAliveConn

159 AsioConnectionBase.cpp:53 (2018-08-06 15:34:39.460009) [0x00007ffff481b700] : Started connect sequence. Connection Name: HttpKeepAliveConn

160 HttpKeepAliveConnection.cpp:32 (2018-08-06 15:34:39.460515) [0x00007ffff481b700] : Failed ssl handshake. Connection failed.Connection Name: HttpKeepAliveConn. Host: xxxxxxxxx. Port: 443. Error: Bad file descriptor

161 APIManager.cpp:175 (2018-08-06 15:34:39.460674) [0x00007ffff481b700] : Received error callback from connection. Restarting connection in a sec. Connection Name: HttpKeepAliveConn

So I have 2 questions:

  1. How do we close a connection if internet is down and a proper tcp close is not possible.
  2. Before reconnecting what are the variables in boost::beast (or for that matter boost::asio as boost::beast is built on top of asio) that needs to be reset

Have been stuck trying to debug this for couple of hours. Any help is appreciated

EDIT

So I figured out where I went wrong. Both Alan Birtles and Vinnie Falco were right. The way to close a dead ssl connection after your ping timer has expired (and none of the handlers have returned yet) is

  1. In your timer handler
_stream->lowest_layer().close();

For websocket

_ws->lowest_layer().close();
  1. Wait for one of your handlers (typically read handler) to return with error (typically boost::asio::error::operation_aborted error). From there, queue the start of the next reconnect. (Do not queue the reconnect immediately after step 1, it will result in memory issues that I faced. I know this is asio 101, but is easy to forget)

  2. For resetting socket, all that is required is for the stream to be reset

_stream.reset(new HttpStream(_ioContext, _sslContext));

For websocket

_ws.reset(new WebSocket(_ioContext, _sslContext));

Upvotes: 2

Views: 2790

Answers (1)

Vinnie Falco
Vinnie Falco

Reputation: 5353

I don't think asio::ssl::stream can be used again after being closed.

How do we close a connection if internet is down and a proper tcp close is not possible.

Simply allow the socket or stream object to be destroyed.

Upvotes: 1

Related Questions