Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public static boolean batch( WebSocketImpl ws, ByteChannel sockchannel ) throws
} while ( buffer != null );
}

if( ws.outQueue.isEmpty() && ws.isFlushAndClose() && ws.getDraft().getRole() == Role.SERVER ) {//
if( ws.outQueue.isEmpty() && ws.isFlushAndClose() && ws.getRole() == Role.SERVER ) {//
synchronized ( ws ) {
ws.closeConnection();
}
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/org/java_websocket/WebSocketAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ public ServerHandshakeBuilder onWebsocketHandshakeReceivedAsServer( WebSocket co
public void onWebsocketHandshakeReceivedAsClient( WebSocket conn, ClientHandshake request, ServerHandshake response ) throws InvalidDataException {
}

/**
* This default implementation does not do anything which will cause the connections to always progress.
*
* @see org.java_websocket.WebSocketListener#onWebsocketHandshakeReceivedAsClientFailed(WebSocket, ClientHandshake, ServerHandshake)
*/
@Override
public void onWebsocketHandshakeReceivedAsClientFailed( WebSocket conn, ClientHandshake request, ServerHandshake response ) {

}

/**
* This default implementation does not do anything which will cause the connections to always progress.
*
Expand Down
82 changes: 64 additions & 18 deletions src/main/java/org/java_websocket/WebSocketImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public class WebSocketImpl implements WebSocket {

private Draft draft = null;

private Role role;
private final Role role;

private Opcode current_continuous_frame_opcode = null;

Expand All @@ -104,13 +104,42 @@ public class WebSocketImpl implements WebSocket {

private String resourceDescriptor = null;

private static BlockingQueue<ByteBuffer> createQueue(){
return new LinkedBlockingQueue<ByteBuffer>();
}

/**
* crates a websocket with server role
* @param listener Listener
* @param drafts Known drafts (may be null to use default drafts)
*/
public static WebSocketImpl createServer( WebSocketListener listener , List<Draft> drafts ) {
return new WebSocketImpl( listener, drafts );
}

/**
* crates a websocket with client role
*
* @param @param listener Listener
* @param draft Draft to use
*/
public static WebSocketImpl createClient( WebSocketListener listener , Draft draft ) {
return new WebSocketImpl( listener, draft );
}

/**
* Constructor for a websocket with server role
* @param listener Listener
* @param drafts Known drafts (may be null to use default drafts)
*/
public WebSocketImpl( WebSocketListener listener , List<Draft> drafts ) {
this( listener, (Draft) null );
this.role = Role.SERVER;
// draft.copyInstance will be called when the draft is first needed
private WebSocketImpl( WebSocketListener listener , List<Draft> drafts ) {
if(null == listener){
throw new IllegalArgumentException( "listener must not be null" );
}
role = Role.SERVER;
wsl = listener;
outQueue = createQueue();
inQueue = createQueue();
if( drafts == null || drafts.isEmpty() ) {
knownDrafts = defaultdraftlist;
} else {
Expand All @@ -119,20 +148,23 @@ public WebSocketImpl( WebSocketListener listener , List<Draft> drafts ) {
}

/**
* crates a websocket with client role
* Constructor for a websocket with client role
*
* @param socket
* may be unbound
* @param @param listener Listener
* @param draft Draft to use
*/
public WebSocketImpl( WebSocketListener listener , Draft draft ) {
if( listener == null || ( draft == null && role == Role.SERVER ) )// socket can be null because we want do be able to create the object without already having a bound channel
throw new IllegalArgumentException( "parameters must not be null" );
this.outQueue = new LinkedBlockingQueue<ByteBuffer>();
inQueue = new LinkedBlockingQueue<ByteBuffer>();
this.wsl = listener;
this.role = Role.CLIENT;
if( draft != null )
this.draft = draft.copyInstance();
private WebSocketImpl( WebSocketListener listener , Draft draft ) {
if(null == listener){
throw new IllegalArgumentException( "listener must not be null" );
}
if(null == draft){
throw new IllegalArgumentException( "draft must not be null" );
}
role = Role.CLIENT;
wsl = listener;
outQueue = createQueue();
inQueue = createQueue();
this.draft = draft.copyInstance();
}

@Deprecated
Expand Down Expand Up @@ -221,6 +253,7 @@ private boolean decodeHandshake( ByteBuffer socketBufferNew ) {
ClientHandshake handshake = (ClientHandshake) tmphandshake;
handshakestate = d.acceptHandshakeAsServer( handshake );
if( handshakestate == HandshakeState.MATCHED ) {
draft = d;
resourceDescriptor = handshake.getResourceDescriptor();
ServerHandshakeBuilder response;
try {
Expand All @@ -234,7 +267,6 @@ private boolean decodeHandshake( ByteBuffer socketBufferNew ) {
return false;
}
write( d.createHandshake( d.postProcessHandshakeResponseAsServer( handshake, response ), role ) );
draft = d;
open( handshake );
return true;
}
Expand Down Expand Up @@ -287,6 +319,16 @@ private boolean decodeHandshake( ByteBuffer socketBufferNew ) {
open( handshake );
return true;
} else {
if (handshake.getHttpStatus() != 101) {
// if HTTP-status is not 101, let client get a chance to obtain the HTTP response
// and take action upon that as per regular HTTP procedures.
// (http://tools.ietf.org/html/rfc6455#section-4.1)
try {
wsl.onWebsocketHandshakeReceivedAsClientFailed(this, handshakerequest, handshake);
} catch (RuntimeException e) {
// do nothing, fall through and close socket
}
}
close( CloseFrame.PROTOCOL_ERROR, "draft " + draft + " refuses handshake" );
}
}
Expand Down Expand Up @@ -719,6 +761,10 @@ public InetSocketAddress getLocalSocketAddress() {
return wsl.getLocalSocketAddress( this );
}

Role getRole() {
return role;
}

@Override
public Draft getDraft() {
return draft;
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/org/java_websocket/WebSocketListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@ public interface WebSocketListener {
*/
public void onWebsocketHandshakeReceivedAsClient( WebSocket conn, ClientHandshake request, ServerHandshake response ) throws InvalidDataException;

/**
* Called on the client side when the socket connection is about to be established, but failed due to the handshake
* could not be verified. E.g. the server rejected the request with a regular HTTP response, and the client
* can then use this callback as a way of obtain that HTTP response, e.g. status code.
*
* @param conn The WebSocket related to this event
* @param request The handshake initially send out to the server by this websocket.
* @param response The handshake the server sent in response to the request.
*/
public void onWebsocketHandshakeReceivedAsClientFailed(WebSocket conn, ClientHandshake request, ServerHandshake response);


/**
* Called on the client side when the socket connection is first established, and the WebSocketImpl
* handshake has just been sent.
Expand Down
32 changes: 21 additions & 11 deletions src/main/java/org/java_websocket/client/WebSocketClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;
Expand Down Expand Up @@ -46,7 +47,8 @@ public abstract class WebSocketClient extends WebSocketAdapter implements Runnab

private Proxy proxy = Proxy.NO_PROXY;

private Thread writeThread;
private WeakReference<Thread> readThread;
private WeakReference<Thread> writeThread;

private Draft draft;

Expand All @@ -57,7 +59,7 @@ public abstract class WebSocketClient extends WebSocketAdapter implements Runnab
private CountDownLatch closeLatch = new CountDownLatch( 1 );

private int connectTimeout = 0;

/** This open a websocket connection as specified by rfc6455 */
public WebSocketClient( URI serverURI ) {
this( serverURI, new Draft_17() );
Expand All @@ -82,7 +84,7 @@ public WebSocketClient( URI serverUri , Draft protocolDraft , Map<String,String>
this.draft = protocolDraft;
this.headers = httpHeaders;
this.connectTimeout = connectTimeout;
this.engine = new WebSocketImpl( this, protocolDraft );
this.engine = WebSocketImpl.createClient( this , protocolDraft );
}

/**
Expand All @@ -104,10 +106,12 @@ public Draft getDraft() {
* Initiates the websocket connection. This method does not block.
*/
public void connect() {
if( writeThread != null )
if( readThread != null )
throw new IllegalStateException( "WebSocketClient objects are not reuseable" );
writeThread = new Thread( this );
writeThread.start();

Thread reader = new Thread(this, "WSC Read");
reader.start();
readThread = new WeakReference<Thread>(reader) ;
}

/**
Expand Down Expand Up @@ -174,8 +178,9 @@ public void run() {
return;
}

writeThread = new Thread( new WebsocketWriteThread() );
writeThread.start();
Thread write = new Thread( new WebsocketWriteThread() );
write.start();
writeThread = new WeakReference<Thread>(write);

byte[] rawbuffer = new byte[ WebSocketImpl.RCVBUF ];
int readBytes;
Expand Down Expand Up @@ -274,8 +279,13 @@ public final void onWebsocketOpen( WebSocket conn, Handshakedata handshake ) {
public final void onWebsocketClose( WebSocket conn, int code, String reason, boolean remote ) {
connectLatch.countDown();
closeLatch.countDown();
if( writeThread != null )
writeThread.interrupt();
if( writeThread != null && writeThread.get() != null) {
writeThread.get().interrupt();
}
if( readThread != null && readThread.get() != null) {
readThread.get().interrupt();
}

try {
if( socket != null )
socket.close();
Expand Down Expand Up @@ -345,7 +355,7 @@ public void onFragment( Framedata frame ) {
private class WebsocketWriteThread implements Runnable {
@Override
public void run() {
Thread.currentThread().setName( "WebsocketWriteThread" );
Thread.currentThread().setName( "WSC Write" );
try {
while ( !Thread.interrupted() ) {
ByteBuffer buffer = engine.outQueue.take();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.nio.channels.ByteChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
Expand Down Expand Up @@ -41,11 +42,13 @@ public ByteChannel wrapChannel( SocketChannel channel, SelectionKey key ) throws

@Override
public WebSocketImpl createWebSocket( WebSocketAdapter a, Draft d, Socket c ) {
return new WebSocketImpl( a, d );
List<Draft> drafts = new ArrayList<Draft>(1);
drafts.add(d);
return WebSocketImpl.createServer( a, drafts );
}

@Override
public WebSocketImpl createWebSocket( WebSocketAdapter a, List<Draft> d, Socket s ) {
return new WebSocketImpl( a, d );
return WebSocketImpl.createServer( a, d );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.net.Socket;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.List;

import org.java_websocket.WebSocketAdapter;
Expand All @@ -13,11 +14,13 @@
public class DefaultWebSocketServerFactory implements WebSocketServerFactory {
@Override
public WebSocketImpl createWebSocket( WebSocketAdapter a, Draft d, Socket s ) {
return new WebSocketImpl( a, d );
List<Draft> drafts = new ArrayList<Draft>(1);
drafts.add(d);
return WebSocketImpl.createServer( a, drafts );
}
@Override
public WebSocketImpl createWebSocket( WebSocketAdapter a, List<Draft> d, Socket s ) {
return new WebSocketImpl( a, d );
return WebSocketImpl.createServer( a, d );
}
@Override
public SocketChannel wrapChannel( SocketChannel channel, SelectionKey key ) {
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/org/java_websocket/server/WebSocketServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,11 @@ public final void onWebsocketOpen( WebSocket conn, Handshakedata handshake ) {
public final void onWebsocketClose( WebSocket conn, int code, String reason, boolean remote ) {
selector.wakeup();
try {
if( removeConnection( conn ) ) {
if(conn.getReadyState() == WebSocket.READYSTATE.NOT_YET_CONNECTED){
// if the WebSocket was never opened (i.e. rejected before opened), then the connection will not have
// been added, so removeConnection should not be called.
onClose( conn, code, reason, remote );
} else if( removeConnection( conn ) ) {
onClose( conn, code, reason, remote );
}
} finally {
Expand Down