From 324e54b81b5236d047ce071b4823ed54dd7b638f Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 11 Feb 2023 13:21:35 +0100 Subject: [PATCH] [websocket-java11] Prevent infinite recursion in disconnect() Guus reports the following infinite recursing causing a StackOverflowError: Exception in thread "main" java.lang.StackOverflowError at org.jivesoftware.smack.websocket.java11.Java11WebSocket.disconnect(Java11WebSocket.java:142) at org.jivesoftware.smack.websocket.XmppWebSocketTransportModule$XmppWebSocketTransport.disconnect(XmppWebSocketTransportModule.java:265) at org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection$CloseConnectionState.transitionInto(ModularXmppClientToServerConnection.java:1086) at org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.attemptEnterState(ModularXmppClientToServerConnection.java:472) at org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.walkStateGraphInternal(ModularXmppClientToServerConnection.java:399) at org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.walkStateGraph(ModularXmppClientToServerConnection.java:339) at org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.shutdown(ModularXmppClientToServerConnection.java:551) at org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.instantShutdown(ModularXmppClientToServerConnection.java:530) at org.jivesoftware.smack.AbstractXMPPConnection.notifyConnectionError(AbstractXMPPConnection.java:1024) at org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.access$100(ModularXmppClientToServerConnection.java:134) at org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection$1.notifyConnectionError(ModularXmppClientToServerConnection.java:185) at org.jivesoftware.smack.websocket.impl.AbstractWebSocket.onWebSocketFailure(AbstractWebSocket.java:128) at org.jivesoftware.smack.websocket.java11.Java11WebSocket.onWebSocketFailure(Java11WebSocket.java:162) at org.jivesoftware.smack.websocket.java11.Java11WebSocket.disconnect(Java11WebSocket.java:146) at org.jivesoftware.smack.websocket.XmppWebSocketTransportModule$XmppWebSocketTransport.disconnect(XmppWebSocketTransportModule.java:265) at org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection$CloseConnectionState.transitionInto(ModularXmppClientToServerConnection.java:1086) at org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection.attemptEnterState(ModularXmppClientToServerConnection.java:472) ... This is because sendClose() in Java11WebSocket.disconnect() throws, potentially because the output stream is already closed. We previously would feed the exception into the onWebSocketFailure(Exception) machinery, which would then again attempt a disconnect. Since a failed sendClose() is nothing that needs special handling, we simply log the exception as error. Furthermore, we only issue sendClose() if the WebSocket's output is still open, i.e., if there is a chance that it actually works. Reported-by: Guus der Kinderen --- .../smack/websocket/java11/Java11WebSocket.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/smack-websocket-java11/src/main/java/org/jivesoftware/smack/websocket/java11/Java11WebSocket.java b/smack-websocket-java11/src/main/java/org/jivesoftware/smack/websocket/java11/Java11WebSocket.java index b259a8916..df31182d4 100644 --- a/smack-websocket-java11/src/main/java/org/jivesoftware/smack/websocket/java11/Java11WebSocket.java +++ b/smack-websocket-java11/src/main/java/org/jivesoftware/smack/websocket/java11/Java11WebSocket.java @@ -1,6 +1,6 @@ /** * - * Copyright 2021 Florian Schmaus + * Copyright 2021-2023 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -139,11 +139,13 @@ public final class Java11WebSocket extends AbstractWebSocket { @Override public void disconnect(int code, String message) { - CompletableFuture completableFuture = webSocket.sendClose(code, message); try { - completableFuture.get(); + if (!webSocket.isOutputClosed()) { + CompletableFuture completableFuture = webSocket.sendClose(code, message); + completableFuture.get(); + } } catch (ExecutionException e) { - onWebSocketFailure(e); + LOGGER.log(Level.WARNING, "Failed to send final close when disconnecting " + this, e); } catch (InterruptedException e) { // This thread should never be interrupted, as it is a Smack internal thread. throw new AssertionError(e);