Fixed close of connection upon GO_AWAY frames.

This commit is contained in:
Simone Bordet 2012-02-07 21:52:34 +01:00
parent a8770204b1
commit 81a8c57e3b
3 changed files with 25 additions and 14 deletions

View File

@ -66,9 +66,9 @@ public class StandardSession implements ISession, Parser.Listener, ISession.Cont
private final AtomicInteger pingIds;
private final FrameListener frameListener;
private final Generator generator;
private final AtomicBoolean closed = new AtomicBoolean();
private final AtomicBoolean goAwaySent = new AtomicBoolean();
private final AtomicBoolean goAwayReceived = new AtomicBoolean();
private volatile int lastStreamId;
private volatile boolean rejected;
private boolean flushing;
public StandardSession(Controller controller, int initialStreamId, FrameListener frameListener, Generator generator)
@ -136,7 +136,7 @@ public class StandardSession implements ISession, Parser.Listener, ISession.Cont
try
{
// SPEC v3, 2.2.2
if (!closed.get())
if (!goAwaySent.get())
{
RstStreamFrame frame = new RstStreamFrame(version, rstInfo.getStreamId(), rstInfo.getStreamStatus().getCode(version));
control(null, frame);
@ -203,9 +203,9 @@ public class StandardSession implements ISession, Parser.Listener, ISession.Cont
@Override
public void goAway(short version)
{
if (closed.compareAndSet(false, true))
if (goAwaySent.compareAndSet(false, true))
{
if (!rejected)
if (!goAwayReceived.get())
{
GoAwayFrame frame = new GoAwayFrame(version, lastStreamId, SessionStatus.OK.getCode());
goAway(frame);
@ -232,7 +232,7 @@ public class StandardSession implements ISession, Parser.Listener, ISession.Cont
{
logger.debug("Processing {}", frame);
if (closed.get())
if (goAwaySent.get())
{
logger.debug("Skipped processing of {}", frame);
return;
@ -297,7 +297,7 @@ public class StandardSession implements ISession, Parser.Listener, ISession.Cont
{
logger.debug("Processing {}, {} data bytes", frame, data.remaining());
if (closed.get())
if (goAwaySent.get())
{
logger.debug("Skipped processing of {}", frame);
return;
@ -468,9 +468,16 @@ public class StandardSession implements ISession, Parser.Listener, ISession.Cont
private void onGoAway(GoAwayFrame frame)
{
rejected = true;
notifyOnGoAway(frame);
flush();
if (goAwayReceived.compareAndSet(false, true))
{
notifyOnGoAway(frame);
flush();
// SPDY does not require to send back a response to a GO_AWAY.
// We notified the application of the last good stream id,
// tried our best to flush remaining data, and close.
controller.close(false);
}
}
private void onHeaders(HeadersFrame frame)
@ -688,7 +695,11 @@ public class StandardSession implements ISession, Parser.Listener, ISession.Cont
public void complete()
{
if (frame.getType() == ControlFrameType.GO_AWAY)
controller.close(true);
{
// After sending a GO_AWAY we need to hard close the connection.
// Recipients will know the last good stream id and act accordingly.
controller.close(false);
}
}
@Override

View File

@ -53,7 +53,7 @@ public abstract class AbstractTest
{
server = new Server();
Connector connector = newSPDYServerConnector(listener);
connector.setPort(47443);
connector.setPort(0);
server.addConnector(connector);
server.start();
return new InetSocketAddress(connector.getLocalPort());

View File

@ -41,7 +41,7 @@ import static org.hamcrest.CoreMatchers.instanceOf;
public class GoAwayTest extends AbstractTest
{
@Test
public void testGoAwayOnClientClose() throws Exception
public void testServerReceivesGoAwayOnClientGoAway() throws Exception
{
final CountDownLatch latch = new CountDownLatch(1);
ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter()
@ -71,7 +71,7 @@ public class GoAwayTest extends AbstractTest
}
@Test
public void testGoAwayOnServerClose() throws Exception
public void testClientReceivesGoAwayOnServerGoAway() throws Exception
{
ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter()
{