diff --git a/src/main/java/org/java_websocket/AbstractWebSocket.java b/src/main/java/org/java_websocket/AbstractWebSocket.java index c3e77a089..f5f20a82e 100644 --- a/src/main/java/org/java_websocket/AbstractWebSocket.java +++ b/src/main/java/org/java_websocket/AbstractWebSocket.java @@ -32,6 +32,7 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import org.java_websocket.framing.CloseFrame; +import org.java_websocket.framing.Framedata; import org.java_websocket.util.NamedThreadFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -83,6 +84,13 @@ public abstract class AbstractWebSocket extends WebSocketAdapter { */ private long connectionLostTimeout = TimeUnit.SECONDS.toNanos(60); + /** + * Attribute for the passive lost connection check + * + * @since 1.5.5 + */ + private boolean connectionLostCheckPassive = false; + /** * Attribute to keep track if the WebSocket Server/Client is running/connected * @@ -107,6 +115,16 @@ public int getConnectionLostTimeout() { } } + /** + * Tests if connection lost check is passive + * + * @return a boolean indicating whether or not the connection lost check is passive + * @since 1.5.5 + */ + public boolean isConnectionLostCheckPassive() { + return connectionLostCheckPassive; + } + /** * Setter for the interval checking for lost connections A value lower or equal 0 results in the * check to be deactivated @@ -115,8 +133,21 @@ public int getConnectionLostTimeout() { * @since 1.3.4 */ public void setConnectionLostTimeout(int connectionLostTimeout) { + setConnectionLostTimeout(connectionLostTimeout, false); + } + + /** + * Setter for the interval checking for lost connections A value lower or equal 0 results in the + * check to be deactivated + * + * @param connectionLostTimeout the interval in seconds + * @param passive true for passive lost connection checks, false for active checks + * @since 1.5.5 + */ + public void setConnectionLostTimeout(int connectionLostTimeout, boolean passive) { synchronized (syncConnectionLost) { this.connectionLostTimeout = TimeUnit.SECONDS.toNanos(connectionLostTimeout); + this.connectionLostCheckPassive = passive; if (this.connectionLostTimeout <= 0) { log.trace("Connection lost timer stopped"); cancelConnectionLostTimer(); @@ -228,11 +259,12 @@ private void executeConnectionLostDetection(WebSocket webSocket, long minimumPon } WebSocketImpl webSocketImpl = (WebSocketImpl) webSocket; if (webSocketImpl.getLastPong() < minimumPongTime) { - log.trace("Closing connection due to no pong received: {}", webSocketImpl); + log.trace("Closing connection due to no {} received: {}", connectionLostCheckPassive ? "ping" : "pong", webSocketImpl); webSocketImpl.closeConnection(CloseFrame.ABNORMAL_CLOSE, - "The connection was closed because the other endpoint did not respond with a pong in time. For more information check: https://github.com/TooTallNate/Java-WebSocket/wiki/Lost-connection-detection"); + "The connection was closed because the other endpoint did not " + (connectionLostCheckPassive ? "send a ping" : "respond with a pong") + " in time. " + + "For more information check: https://github.com/TooTallNate/Java-WebSocket/wiki/Lost-connection-detection"); } else { - if (webSocketImpl.isOpen()) { + if (webSocketImpl.isOpen() && !connectionLostCheckPassive) { webSocketImpl.sendPing(); } else { log.trace("Trying to ping a non open connection: {}", webSocketImpl); @@ -308,4 +340,19 @@ public void setReuseAddr(boolean reuseAddr) { this.reuseAddr = reuseAddr; } + /** + * This overriden implementation will additionally update the last pong time in case + * connection lost checks are passive. + * + * @see org.java_websocket.WebSocketListener#onWebsocketPing(WebSocket, Framedata) + */ + @Override + public void onWebsocketPing(WebSocket conn, Framedata f) { + super.onWebsocketPing(conn, f); + if (connectionLostCheckPassive && conn instanceof WebSocketImpl) { + WebSocketImpl webSocketImpl = (WebSocketImpl) conn; + webSocketImpl.updateLastPong(); + } + } + } diff --git a/src/main/java/org/java_websocket/WebSocketImpl.java b/src/main/java/org/java_websocket/WebSocketImpl.java index aad172127..37523859c 100644 --- a/src/main/java/org/java_websocket/WebSocketImpl.java +++ b/src/main/java/org/java_websocket/WebSocketImpl.java @@ -428,7 +428,11 @@ private void decodeFrames(ByteBuffer socketBuffer) { * @param exception the InvalidDataException causing this problem */ private void closeConnectionDueToWrongHandshake(InvalidDataException exception) { - write(generateHttpResponseDueToError(404)); + if (exception.getHttpErrorCode() != null) { + write(generateHttpResponseDueToError(exception.getHttpErrorCode())); + } else { + write(generateHttpResponseDueToError(404)); + } flushAndClose(exception.getCloseCode(), exception.getMessage(), false); } @@ -451,6 +455,9 @@ private void closeConnectionDueToInternalServerError(RuntimeException exception) private ByteBuffer generateHttpResponseDueToError(int errorCode) { String errorCodeDescription; switch (errorCode) { + case 401: + errorCodeDescription = "401 Authorization Required"; + break; case 404: errorCodeDescription = "404 WebSocket Upgrade Failure"; break; diff --git a/src/main/java/org/java_websocket/exceptions/InvalidDataException.java b/src/main/java/org/java_websocket/exceptions/InvalidDataException.java index c34c8c941..3419d4b40 100644 --- a/src/main/java/org/java_websocket/exceptions/InvalidDataException.java +++ b/src/main/java/org/java_websocket/exceptions/InvalidDataException.java @@ -40,6 +40,8 @@ public class InvalidDataException extends Exception { */ private final int closecode; + private Integer httpErrorCode; + /** * constructor for a InvalidDataException * @@ -49,6 +51,17 @@ public InvalidDataException(int closecode) { this.closecode = closecode; } + /** + * constructor for a InvalidDataException + * + * @param closecode the closecode which will be returned + * @param httpErrorCode the httpErrorCode which will be returned. + */ + public InvalidDataException(int closecode, int httpErrorCode) { + this.closecode = closecode; + this.httpErrorCode = httpErrorCode; + } + /** * constructor for a InvalidDataException. * @@ -60,6 +73,19 @@ public InvalidDataException(int closecode, String s) { this.closecode = closecode; } + /** + * constructor for a InvalidDataException. + * + * @param closecode the closecode which will be returned. + * @param s the detail message. + * @param httpErrorCode the httpErrorCode which will be returned. + */ + public InvalidDataException(int closecode, String s, int httpErrorCode) { + super(s); + this.closecode = closecode; + this.httpErrorCode = httpErrorCode; + } + /** * constructor for a InvalidDataException. * @@ -92,4 +118,13 @@ public int getCloseCode() { return closecode; } + /** + * Getter httpErrorCode + * + * @return the httpErrorCode + */ + public Integer getHttpErrorCode() { + return httpErrorCode; + } + }