Skip to content

Commit

Permalink
Merge pull request #480 from marci4/lostconnection
Browse files Browse the repository at this point in the history
Lostconnection
  • Loading branch information
marci4 authored May 11, 2017
2 parents 1a7bbdd + 047a3c1 commit 08dd1d8
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 67 deletions.
144 changes: 144 additions & 0 deletions src/main/java/org/java_websocket/AbstractWebSocket.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package org.java_websocket;

import org.java_websocket.framing.CloseFrame;

import java.util.Collection;
import java.util.Timer;
import java.util.TimerTask;


/**
* Base class for additional implementations for the server as well as the client
*/
public abstract class AbstractWebSocket extends WebSocketAdapter {

/**
* Attribute which allows you to deactivate the Nagle's algorithm
*/
private boolean tcpNoDelay;

/**
* Attribute for a timer allowing to check for lost connections
*/
private Timer connectionLostTimer;
/**
* Attribute for a timertask allowing to check for lost connections
*/
private TimerTask connectionLostTimerTask;

/**
* Attribute for the lost connection check interval
*/
private int connectionLostTimeout = 60;

/**
* Get the interval checking for lost connections
* Default is 60 seconds
* @return the interval
*/
public int getConnectionLostTimeout() {
return connectionLostTimeout;
}

/**
* Setter for the interval checking for lost connections
* A value >= 0 results in the check to be deactivated
*
* @param connectionLostTimeout the interval in seconds
*/
public void setConnectionLostTimeout( int connectionLostTimeout ) {
this.connectionLostTimeout = connectionLostTimeout;
if (this.connectionLostTimeout <= 0) {
stopConnectionLostTimer();
} else {
startConnectionLostTimer();
}
}

/**
* Stop the connection lost timer
*/
protected void stopConnectionLostTimer() {
if (connectionLostTimer != null ||connectionLostTimerTask != null) {
if( WebSocketImpl.DEBUG )
System.out.println( "Connection lost timer stoped" );
cancelConnectionLostTimer();
}
}
/**
* Start the connection lost timer
*/
protected void startConnectionLostTimer() {
if (this.connectionLostTimeout <= 0) {
if (WebSocketImpl.DEBUG)
System.out.println("Connection lost timer deactivated");
return;
}
if (WebSocketImpl.DEBUG)
System.out.println("Connection lost timer started");
cancelConnectionLostTimer();
connectionLostTimer = new Timer();
connectionLostTimerTask = new TimerTask() {
@Override
public void run() {
Collection<WebSocket> con = connections();
synchronized ( con ) {
long current = (System.currentTimeMillis()-(connectionLostTimeout * 1500));
for( WebSocket conn : con ) {
if (conn instanceof WebSocketImpl) {
if( ((WebSocketImpl)conn).getLastPong() < current ) {
if (WebSocketImpl.DEBUG)
System.out.println("Closing connection due to no pong received: " + conn.toString());
conn.close( CloseFrame.ABNORMAL_CLOSE );
} else {
conn.sendPing();
}
}
}
}
}
};
connectionLostTimer.scheduleAtFixedRate( connectionLostTimerTask,connectionLostTimeout * 1000, connectionLostTimeout * 1000 );
}

/**
* Getter to get all the currently available connections
* @return the currently available connections
*/
protected abstract Collection<WebSocket> connections();

/**
* Cancel any running timer for the connection lost detection
*/
private void cancelConnectionLostTimer() {
if( connectionLostTimer != null ) {
connectionLostTimer.cancel();
connectionLostTimer = null;
}
if( connectionLostTimerTask != null ) {
connectionLostTimerTask.cancel();
connectionLostTimerTask = null;
}
}

/**
* Tests if TCP_NODELAY is enabled.
*
* @return a boolean indicating whether or not TCP_NODELAY is enabled for new connections.
*/
public boolean isTcpNoDelay() {
return tcpNoDelay;
}

/**
* Setter for tcpNoDelay
* <p>
* Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm) for new connections
*
* @param tcpNoDelay true to enable TCP_NODELAY, false to disable.
*/
public void setTcpNoDelay( boolean tcpNoDelay ) {
this.tcpNoDelay = tcpNoDelay;
}

}
11 changes: 11 additions & 0 deletions src/main/java/org/java_websocket/WebSocket.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.java_websocket.drafts.Draft;
import org.java_websocket.framing.Framedata;
import org.java_websocket.framing.Framedata.Opcode;
import org.java_websocket.framing.FramedataImpl1;

public interface WebSocket {
/**
Expand All @@ -30,6 +31,11 @@ public enum READYSTATE {
*/
public static final int DEFAULT_PORT = 80;

/**
* The default wss port of WebSockets, as defined in the spec. If the nullary
* constructor is used, DEFAULT_WSS_PORT will be the port the WebSocketServer
* is binded to. Note that ports under 1024 usually require root permissions.
*/
public static final int DEFAULT_WSS_PORT = 443;

/**
Expand Down Expand Up @@ -90,6 +96,11 @@ public enum READYSTATE {
*/
public abstract void sendFrame( Framedata framedata );

/**
* Send a ping to the other end
* @throws NotYetConnectedException websocket is not yet connected
*/
public void sendPing() throws NotYetConnectedException;
/**
* Allows to send continuous/fragmented frames conveniently. <br>
* For more into on this frame type see http://tools.ietf.org/html/rfc6455#section-5.4<br>
Expand Down
20 changes: 12 additions & 8 deletions src/main/java/org/java_websocket/WebSocketAdapter.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package org.java_websocket;

import java.net.InetSocketAddress;

import org.java_websocket.drafts.Draft;
import org.java_websocket.exceptions.InvalidDataException;
import org.java_websocket.exceptions.InvalidHandshakeException;
import org.java_websocket.framing.CloseFrame;
import org.java_websocket.framing.Framedata;
import org.java_websocket.framing.Framedata.Opcode;
import org.java_websocket.framing.FramedataImpl1;
Expand All @@ -13,6 +12,11 @@
import org.java_websocket.handshake.ServerHandshake;
import org.java_websocket.handshake.ServerHandshakeBuilder;

import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.Timer;
import java.util.TimerTask;

/**
* This class default implements all methods of the WebSocketListener that can be overridden optionally when advances functionalities is needed.<br>
**/
Expand Down Expand Up @@ -75,25 +79,25 @@ public void onWebsocketPong( WebSocket conn, Framedata f ) {
/**
* Gets the XML string that should be returned if a client requests a Flash
* security policy.
*
* <p>
* The default implementation allows access from all remote domains, but
* only on the port that this WebSocketServer is listening on.
*
* <p>
* This is specifically implemented for gitime's WebSocket client for Flash:
* http://github.com/gimite/web-socket-js
*
*
* @return An XML String that comforts to Flash's security policy. You MUST
* not include the null char at the end, it is appended automatically.
* not include the null char at the end, it is appended automatically.
* @throws InvalidDataException thrown when some data that is required to generate the flash-policy like the websocket local port could not be obtained e.g because the websocket is not connected.
*/
@Override
public String getFlashPolicy( WebSocket conn ) throws InvalidDataException {
InetSocketAddress adr = conn.getLocalSocketAddress();
if(null == adr){
if( null == adr ) {
throw new InvalidHandshakeException( "socket not bound" );
}

return "<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"" + adr.getPort() +"\" /></cross-domain-policy>\0";
return "<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"" + adr.getPort() + "\" /></cross-domain-policy>\0";
}

}
21 changes: 21 additions & 0 deletions src/main/java/org/java_websocket/WebSocketImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.java_websocket.framing.CloseFrameBuilder;
import org.java_websocket.framing.Framedata;
import org.java_websocket.framing.Framedata.Opcode;
import org.java_websocket.framing.FramedataImpl1;
import org.java_websocket.handshake.*;
import org.java_websocket.server.WebSocketServer.WebSocketWorker;
import org.java_websocket.util.Charsetfunctions;
Expand Down Expand Up @@ -93,6 +94,11 @@ public class WebSocketImpl implements WebSocket {

private String resourceDescriptor = null;

/**
* Attribute, when the last pong was recieved
*/
private long lastPong = System.currentTimeMillis();

/**
* Creates a websocket with server role
*
Expand Down Expand Up @@ -347,6 +353,7 @@ private void decodeFrames( ByteBuffer socketBuffer ) {
wsl.onWebsocketPing( this, f );
continue;
} else if( curop == Opcode.PONG ) {
lastPong = System.currentTimeMillis();
wsl.onWebsocketPong( this, f );
continue;
} else if( !fin || curop == Opcode.CONTINUOUS ) {
Expand Down Expand Up @@ -612,6 +619,12 @@ public void sendFrame( Framedata framedata ) {
write( draft.createBinaryFrame( framedata ) );
}

public void sendPing() throws NotYetConnectedException {
FramedataImpl1 frame = new FramedataImpl1(Opcode.PING);
frame.setFin(true);
sendFrame(frame);
}

@Override
public boolean hasBufferedData() {
return !this.outQueue.isEmpty();
Expand Down Expand Up @@ -757,4 +770,12 @@ public void close() {
public String getResourceDescriptor() {
return resourceDescriptor;
}

/**
* Getter for the last pong recieved
* @return the timestamp for the last recieved pong
*/
long getLastPong() {
return lastPong;
}
}
Loading

0 comments on commit 08dd1d8

Please sign in to comment.