fix crash on close

This commit is contained in:
dimon4eg 2019-05-11 12:07:25 +03:00
parent 6cd970d0d9
commit ef2e5c7ddb
3 changed files with 57 additions and 59 deletions

View File

@ -149,7 +149,6 @@ namespace ix
// This value needs to be forced when shutting down, it is restored later // This value needs to be forced when shutting down, it is restored later
_automaticReconnection = false; _automaticReconnection = false;
// sync close
close(); close();
if (_thread.joinable()) if (_thread.joinable())
@ -218,72 +217,63 @@ namespace ix
return getReadyState() == WebSocket_ReadyState_Closing; return getReadyState() == WebSocket_ReadyState_Closing;
} }
bool WebSocket::isConnectedOrClosing() const
{
return isConnected() || isClosing();
}
void WebSocket::close() void WebSocket::close()
{ {
_ws.close(); _ws.close();
} }
void WebSocket::reconnectPerpetuallyIfDisconnected() void WebSocket::checkConnection(bool initial)
{ {
uint32_t retries = 0;
WebSocketErrorInfo connectErr;
ix::WebSocketInitResult status;
using millis = std::chrono::duration<double, std::milli>; using millis = std::chrono::duration<double, std::milli>;
uint32_t retries = 0;
millis duration; millis duration;
ix::WebSocketInitResult status;
// Try to connect only once when we don't have automaticReconnection setup // we will try to connect perpertually
if (!isConnectedOrClosing() && !_stop && !_automaticReconnection)
{
status = connect(_handshakeTimeoutSecs);
if (!status.success)
{
duration = millis(calculateRetryWaitMilliseconds(retries++));
connectErr.retries = retries;
connectErr.wait_time = duration.count();
connectErr.reason = status.errorStr;
connectErr.http_status = status.http_status;
_onMessageCallback(WebSocket_MessageType_Error, "", 0,
connectErr, WebSocketOpenInfo(),
WebSocketCloseInfo());
}
}
else
{
// Otherwise try to reconnect perpertually
while (true) while (true)
{ {
if (isConnectedOrClosing() || _stop || !_automaticReconnection) if (isConnected() || isClosing() || _stop)
{ {
break; break;
} }
if (!initial && !_automaticReconnection)
{
// don't attempt to reconnect
break;
}
initial = false;
// Only sleep if we are retrying
if (duration.count() > 0)
{
// to do: make conditional sleeping
std::this_thread::sleep_for(duration);
}
// try to connect (sync connect)
status = connect(_handshakeTimeoutSecs); status = connect(_handshakeTimeoutSecs);
if (!status.success) if (!status.success)
{
WebSocketErrorInfo connectErr;
if (_automaticReconnection)
{ {
duration = millis(calculateRetryWaitMilliseconds(retries++)); duration = millis(calculateRetryWaitMilliseconds(retries++));
connectErr.retries = retries;
connectErr.wait_time = duration.count(); connectErr.wait_time = duration.count();
connectErr.retries = retries;
}
connectErr.reason = status.errorStr; connectErr.reason = status.errorStr;
connectErr.http_status = status.http_status; connectErr.http_status = status.http_status;
_onMessageCallback(WebSocket_MessageType_Error, "", 0, _onMessageCallback(WebSocket_MessageType_Error, "", 0,
connectErr, WebSocketOpenInfo(), connectErr, WebSocketOpenInfo(),
WebSocketCloseInfo()); WebSocketCloseInfo());
// Only sleep if we aren't in the middle of stopping
if (!_stop)
{
std::this_thread::sleep_for(duration);
}
}
} }
} }
} }
@ -292,10 +282,20 @@ namespace ix
{ {
setThreadName(getUrl()); setThreadName(getUrl());
while (getReadyState() != WebSocket_ReadyState_Closed) bool initial = true;
while (true)
{ {
// 1. Make sure we are always connected // 1. Make sure we are always connected
reconnectPerpetuallyIfDisconnected(); checkConnection(initial);
initial = false;
// if here we are closed then checkConnection was not able to connect
if (getReadyState() == WebSocket_ReadyState_Closed)
{
break;
}
// 2. Poll to see if there's any new data available // 2. Poll to see if there's any new data available
WebSocketTransport::PollPostTreatment pollPostTreatment = _ws.poll(); WebSocketTransport::PollPostTreatment pollPostTreatment = _ws.poll();
@ -311,6 +311,7 @@ namespace ix
WebSocketMessageType webSocketMessageType; WebSocketMessageType webSocketMessageType;
switch (messageKind) switch (messageKind)
{ {
default:
case WebSocketTransport::MSG: case WebSocketTransport::MSG:
{ {
webSocketMessageType = WebSocket_MessageType_Message; webSocketMessageType = WebSocket_MessageType_Message;
@ -341,9 +342,6 @@ namespace ix
WebSocket::invokeTrafficTrackerCallback(msg.size(), true); WebSocket::invokeTrafficTrackerCallback(msg.size(), true);
}); });
// If we aren't trying to reconnect automatically, exit if we aren't connected
if (!isConnectedOrClosing() && !_automaticReconnection) return;
} }
} }

View File

@ -99,6 +99,7 @@ namespace ix
// Run asynchronously, by calling start and stop. // Run asynchronously, by calling start and stop.
void start(); void start();
// stop is synchronous
void stop(); void stop();
// Run in blocking mode, by connecting first manually, and then calling run. // Run in blocking mode, by connecting first manually, and then calling run.
@ -135,8 +136,7 @@ namespace ix
bool isConnected() const; bool isConnected() const;
bool isClosing() const; bool isClosing() const;
bool isConnectedOrClosing() const; void checkConnection(bool initial);
void reconnectPerpetuallyIfDisconnected();
std::string readyStateToString(ReadyState readyState); std::string readyStateToString(ReadyState readyState);
static void invokeTrafficTrackerCallback(size_t size, bool incoming); static void invokeTrafficTrackerCallback(size_t size, bool incoming);

View File

@ -12,10 +12,10 @@ namespace ix
{ {
struct WebSocketErrorInfo struct WebSocketErrorInfo
{ {
uint32_t retries; uint32_t retries = 0;
double wait_time; double wait_time = 0;
int http_status; int http_status = 0;
std::string reason; std::string reason;
bool decompressionError; bool decompressionError = false;
}; };
} }