diff --git a/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/HubConnection.java b/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/HubConnection.java index cb6a085a4b..c20e051eab 100644 --- a/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/HubConnection.java +++ b/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/HubConnection.java @@ -517,25 +517,32 @@ public class HubConnection implements AutoCloseable { RuntimeException exception = null; this.state.lock(); try { + ConnectionState connectionState = this.state.getConnectionStateUnsynchronized(true); + + if (connectionState == null) + { + this.logger.error("'stopConnection' called with a null ConnectionState. This is not expected, please file a bug. https://github.com/dotnet/aspnetcore/issues/new?assignees=&labels=&template=bug_report.md"); + return; + } + // errorMessage gets passed in from the transport. An already existing stopError value // should take precedence. - if (this.state.getConnectionStateUnsynchronized(false).stopError != null) { - errorMessage = this.state.getConnectionStateUnsynchronized(false).stopError; + if (connectionState.stopError != null) { + errorMessage = connectionState.stopError; } if (errorMessage != null) { exception = new RuntimeException(errorMessage); logger.error("HubConnection disconnected with an error {}.", errorMessage); } - ConnectionState connectionState = this.state.getConnectionStateUnsynchronized(true); - if (connectionState != null) { - connectionState.cancelOutstandingInvocations(exception); - connectionState.close(); - this.state.setConnectionState(null); - } + this.state.setConnectionState(null); + connectionState.cancelOutstandingInvocations(exception); + connectionState.close(); logger.info("HubConnection stopped."); - this.state.changeState(HubConnectionState.CONNECTED, HubConnectionState.DISCONNECTED); + // We can be in the CONNECTING or CONNECTED state here, depending on if the handshake response was received or not. + // connectionState.close() above will exit the Start call with an error if it's still running + this.state.changeState(HubConnectionState.DISCONNECTED); } finally { this.state.unlock(); } @@ -543,7 +550,11 @@ public class HubConnection implements AutoCloseable { // Do not run these callbacks inside the hubConnectionStateLock if (onClosedCallbackList != null) { for (OnClosedCallback callback : onClosedCallbackList) { - callback.invoke(exception); + try { + callback.invoke(exception); + } catch (Exception ex) { + logger.warn("Invoking 'onClosed' method failed:", ex); + } } } } @@ -1519,6 +1530,16 @@ public class HubConnection implements AutoCloseable { } } + public void changeState(HubConnectionState to) { + this.lock.lock(); + try { + logger.debug("The HubConnection is transitioning from the {} state to the {} state.", this.hubConnectionState, to); + this.hubConnectionState = to; + } finally { + this.lock.unlock(); + } + } + public void lock() { this.lock.lock(); } diff --git a/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/OkHttpWebSocketWrapper.java b/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/OkHttpWebSocketWrapper.java index 3825de8c8d..85c904a7dc 100644 --- a/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/OkHttpWebSocketWrapper.java +++ b/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/OkHttpWebSocketWrapper.java @@ -125,6 +125,9 @@ class OkHttpWebSocketWrapper extends WebSocketWrapper { stateLock.unlock(); } checkStartFailure(null); + + // Send the close frame response if this was a server initiated close, otherwise noops + webSocket.close(1000, ""); } @Override