add in some handshake state tracking into IOState to help track who initiated closes

This commit is contained in:
Jesse McConnell 2012-12-13 12:15:47 -06:00
parent 127f4978a9
commit bf3c5c7922
3 changed files with 90 additions and 3 deletions

View File

@ -36,11 +36,18 @@ public class IOState
private final AtomicBoolean inputClosed; private final AtomicBoolean inputClosed;
private final AtomicBoolean outputClosed; private final AtomicBoolean outputClosed;
private final AtomicBoolean cleanClose;
private final AtomicBoolean remoteCloseInitiated;
private final AtomicBoolean localCloseInitiated;
public IOState() public IOState()
{ {
this.state = ConnectionState.CONNECTING; this.state = ConnectionState.CONNECTING;
this.inputClosed = new AtomicBoolean(false); this.inputClosed = new AtomicBoolean(false);
this.outputClosed = new AtomicBoolean(false); this.outputClosed = new AtomicBoolean(false);
this.remoteCloseInitiated = new AtomicBoolean(false);
this.localCloseInitiated = new AtomicBoolean(false);
this.cleanClose = new AtomicBoolean(false);
} }
public void assertInputOpen() throws IOException public void assertInputOpen() throws IOException
@ -111,11 +118,21 @@ public class IOState
{ {
in = true; in = true;
this.inputClosed.set(true); this.inputClosed.set(true);
if (!localCloseInitiated.get())
{
remoteCloseInitiated.set(true);
}
} }
else else
{ {
out = true; out = true;
this.outputClosed.set(true); this.outputClosed.set(true);
if ( !remoteCloseInitiated.get() )
{
localCloseInitiated.set(true);
}
} }
LOG.debug("onCloseHandshake({},{}), input={}, output={}",incoming,close,in,out); LOG.debug("onCloseHandshake({},{}), input={}, output={}",incoming,close,in,out);
@ -123,6 +140,7 @@ public class IOState
if (in && out) if (in && out)
{ {
LOG.debug("Close Handshake satisfied, disconnecting"); LOG.debug("Close Handshake satisfied, disconnecting");
cleanClose.set(true);
return true; return true;
} }
@ -144,4 +162,24 @@ public class IOState
{ {
this.state = state; this.state = state;
} }
public boolean isCloseInitiated()
{
return remoteCloseInitiated.get() || localCloseInitiated.get();
}
public boolean wasRemoteCloseInitiated()
{
return remoteCloseInitiated.get();
}
public boolean wasLocalCloseInitiated()
{
return localCloseInitiated.get();
}
public boolean wasCleanClose()
{
return cleanClose.get();
}
} }

View File

@ -38,6 +38,7 @@ import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.Generator; import org.eclipse.jetty.websocket.common.Generator;
import org.eclipse.jetty.websocket.common.OpCode; import org.eclipse.jetty.websocket.common.OpCode;
import org.eclipse.jetty.websocket.common.WebSocketFrame; import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.common.io.IOState;
import org.eclipse.jetty.websocket.server.ByteBufferAssert; import org.eclipse.jetty.websocket.server.ByteBufferAssert;
import org.eclipse.jetty.websocket.server.blockhead.BlockheadClient; import org.eclipse.jetty.websocket.server.blockhead.BlockheadClient;
import org.eclipse.jetty.websocket.server.helper.IncomingFramesCapture; import org.eclipse.jetty.websocket.server.helper.IncomingFramesCapture;
@ -55,6 +56,13 @@ public class Fuzzer
SLOW SLOW
} }
public static enum CloseState
{
OPEN,
REMOTE_INITIATED,
LOCAL_INITIATED
}
private static final int KBYTE = 1024; private static final int KBYTE = 1024;
private static final int MBYTE = KBYTE * KBYTE; private static final int MBYTE = KBYTE * KBYTE;
@ -178,7 +186,30 @@ public class Fuzzer
public void expectServerClose(boolean wasClean) throws IOException, InterruptedException public void expectServerClose(boolean wasClean) throws IOException, InterruptedException
{ {
// DOES NOT WORK -- Assert.assertThat("Should have disconnected",client.awaitDisconnect(2,TimeUnit.SECONDS),is(true)); // we expect that the close handshake to have occurred and the server should have closed the connection
try
{
int val = client.read();
Assert.fail("Server has not closed socket");
}
catch (SocketException e)
{
}
IOState ios = client.getIOState();
if (wasClean)
{
Assert.assertTrue(ios.wasRemoteCloseInitiated());
Assert.assertTrue(ios.wasCleanClose());
}
else
{
Assert.assertTrue(ios.wasRemoteCloseInitiated());
}
} }
public SendMode getSendMode() public SendMode getSendMode()
@ -327,4 +358,22 @@ public class Fuzzer
{ {
this.slowSendSegmentSize = segmentSize; this.slowSendSegmentSize = segmentSize;
} }
public CloseState getCloseState()
{
IOState ios = client.getIOState();
if ( ios.wasLocalCloseInitiated() )
{
return CloseState.LOCAL_INITIATED;
}
else if ( ios.wasRemoteCloseInitiated() )
{
return CloseState.REMOTE_INITIATED;
}
else
{
return CloseState.OPEN;
}
}
} }

View File

@ -116,7 +116,7 @@ public class BlockheadClient implements IncomingFrames, OutgoingFrames
private ExtensionStack extensionStack; private ExtensionStack extensionStack;
private IOState ioState; private IOState ioState;
private CountDownLatch disconnectedLatch = new CountDownLatch(1); private CountDownLatch disconnectedLatch = new CountDownLatch(1);
public BlockheadClient(URI destWebsocketURI) throws URISyntaxException public BlockheadClient(URI destWebsocketURI) throws URISyntaxException
{ {
this(WebSocketPolicy.newClientPolicy(),destWebsocketURI); this(WebSocketPolicy.newClientPolicy(),destWebsocketURI);
@ -173,7 +173,7 @@ public class BlockheadClient implements IncomingFrames, OutgoingFrames
public void close(int statusCode, String message) public void close(int statusCode, String message)
{ {
try try
{ {
CloseInfo close = new CloseInfo(statusCode,message); CloseInfo close = new CloseInfo(statusCode,message);
if (ioState.onCloseHandshake(false,close)) if (ioState.onCloseHandshake(false,close))