Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lostconnection #480

Merged
merged 3 commits into from
May 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -96,6 +97,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 @@ -348,6 +354,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 @@ -613,6 +620,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 @@ -758,4 +771,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