diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java index 97195afe488..f14c3b950b4 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java @@ -748,14 +748,30 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa } catch (ClosedSelectorException | ClosedChannelException x) { - LOG.debug(x); + failed(x); } } protected void failed(Throwable failure) { if (failed.compareAndSet(false, true)) + { + timeout.cancel(); + close(); connectionFailed(channel, failure, attachment); + } + } + + private void close() + { + try + { + channel.close(); + } + catch (IOException x) + { + LOG.ignore(x); + } } } @@ -775,19 +791,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa if (channel.isConnectionPending()) { LOG.debug("Channel {} timed out while connecting, closing it", channel); - try - { - // This will unregister the channel from the selector - channel.close(); - } - catch (IOException x) - { - LOG.ignore(x); - } - finally - { - connect.failed(new SocketTimeoutException()); - } + connect.failed(new SocketTimeoutException()); } } } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SelectorManagerTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SelectorManagerTest.java index 4167a2dd079..f1710652910 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/SelectorManagerTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SelectorManagerTest.java @@ -26,6 +26,7 @@ import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.jetty.toolchain.test.annotation.Slow; import org.eclipse.jetty.util.Callback; @@ -67,6 +68,7 @@ public class SelectorManagerTest client.configureBlocking(false); client.connect(address); + final AtomicBoolean timeoutConnection = new AtomicBoolean(); final long connectTimeout = 1000; SelectorManager selectorManager = new SelectorManager(executor, scheduler) { @@ -81,7 +83,8 @@ public class SelectorManagerTest { try { - TimeUnit.MILLISECONDS.sleep(connectTimeout * 2); + if (timeoutConnection.get()) + TimeUnit.MILLISECONDS.sleep(connectTimeout * 2); return super.finishConnect(channel); } catch (InterruptedException e) @@ -113,17 +116,30 @@ public class SelectorManagerTest try { - final CountDownLatch latch = new CountDownLatch(1); + timeoutConnection.set(true); + final CountDownLatch latch1 = new CountDownLatch(1); selectorManager.connect(client, new Callback.Adapter() { @Override public void failed(Throwable x) { - latch.countDown(); + latch1.countDown(); } }); + Assert.assertTrue(latch1.await(connectTimeout * 3, TimeUnit.MILLISECONDS)); - Assert.assertTrue(latch.await(connectTimeout * 3, TimeUnit.MILLISECONDS)); + // Verify that after the failure we can connect successfully + timeoutConnection.set(false); + final CountDownLatch latch2 = new CountDownLatch(1); + selectorManager.connect(client, new Callback.Adapter() + { + @Override + public void failed(Throwable x) + { + latch2.countDown(); + } + }); + Assert.assertTrue(latch2.await(connectTimeout, TimeUnit.MILLISECONDS)); } finally {