From 80e5a951307676b2039f43e69f792d69c3694a61 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 14 Jul 2010 01:58:48 +0000 Subject: [PATCH] JETTY-1249 i Apply max idle time to all connectors git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@2111 7e9141cc-0065-0410-87d8-b60c137991c4 --- VERSION.txt | 2 +- .../eclipse/jetty/io/nio/ChannelEndPoint.java | 2 + .../jetty/io/nio/SelectChannelEndPoint.java | 1 + .../eclipse/jetty/io/nio/SelectorManager.java | 8 +- .../server/nio/BlockingChannelConnector.java | 139 ++++++++++++++++-- .../jetty/server/ssl/SslSocketConnector.java | 5 - .../server/BlockingChannelTimeoutTest.java | 31 ++++ .../jetty/server/ConnectorTimeoutTest.java | 54 ++++--- .../jetty/server/HttpServerTestBase.java | 22 +-- .../jetty/server/HttpServerTestFixture.java | 6 + .../server/SelectChannelTimeoutTest.java | 29 ++++ .../jetty/server/SocketTimeoutTest.java | 29 ++++ .../jetty/server/ssl/SSLEngineTest.java | 9 +- .../jetty/server/ssl/SslRenegotiateTest.java | 7 +- .../ssl/SslSelectChannelServerTest.java | 70 +++++++++ .../ssl/SslSelectChannelTimeoutTest.java | 58 ++++++++ .../jetty/server/ssl/SslSocketServerTest.java | 70 +++++++++ .../server/ssl/SslSocketTimeoutTest.java | 62 ++++++++ .../jetty/server/ssl/SslUploadTest.java | 5 +- 19 files changed, 541 insertions(+), 68 deletions(-) create mode 100644 jetty-server/src/test/java/org/eclipse/jetty/server/BlockingChannelTimeoutTest.java create mode 100644 jetty-server/src/test/java/org/eclipse/jetty/server/SelectChannelTimeoutTest.java create mode 100644 jetty-server/src/test/java/org/eclipse/jetty/server/SocketTimeoutTest.java create mode 100644 jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslSelectChannelServerTest.java create mode 100644 jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslSelectChannelTimeoutTest.java create mode 100644 jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslSocketServerTest.java create mode 100644 jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslSocketTimeoutTest.java diff --git a/VERSION.txt b/VERSION.txt index 68450484313..90e2ac32d57 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -3,7 +3,7 @@ jetty-7.2-SNAPSHOT + 319370 WebAppClassLoader.Context + 319519 Warn about duplicate configuration files + JETTY-1247 synchronize recylcing of SSL NIO buffers - + JETTY-1249 Apply max idle time + + JETTY-1249 Apply max idle time to all connectors + Added ignore to Logger interface jetty-7.1.5.v20100705 diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java index c9628b86abf..bcd35793bdf 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java @@ -124,6 +124,8 @@ public class ChannelEndPoint implements EndPoint */ public void close() throws IOException { + if (_socket!=null && !_socket.isOutputShutdown()) + _socket.shutdownOutput(); _channel.close(); } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java index 5ee2f548be4..f144e6f3dfa 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java @@ -228,6 +228,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable, { if (_idleTimestamp!=0 && _maxIdleTime!=0 && now>(_idleTimestamp+_maxIdleTime)) { + System.err.println("IDLE "+this); idleExpired(); } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java index 4d9218e503a..193a3586a4c 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java @@ -20,9 +20,6 @@ import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentMap; @@ -52,6 +49,7 @@ public abstract class SelectorManager extends AbstractLifeCycle private static final int __MAX_SELECTS=Integer.getInteger("org.mortbay.io.nio.MAX_SELECTS",25000).intValue(); private static final int __BUSY_PAUSE=Integer.getInteger("org.mortbay.io.nio.BUSY_PAUSE",50).intValue(); private static final int __BUSY_KEY=Integer.getInteger("org.mortbay.io.nio.BUSY_KEY",-1).intValue(); + private static final int __IDLE_TICK=Integer.getInteger("org.mortbay.io.nio.IDLE_TICK",400).intValue(); private int _maxIdleTime; private int _lowResourcesMaxIdleTime; @@ -458,7 +456,7 @@ public abstract class SelectorManager extends AbstractLifeCycle retry_next=_timeout.getTimeToNext(); // workout how low to wait in select - long wait = _changes.size()==0?200L:0L; + long wait = _changes.size()==0?__IDLE_TICK:0L; if (wait > 0 && retry_next >= 0 && wait > retry_next) wait = retry_next; @@ -745,7 +743,7 @@ public abstract class SelectorManager extends AbstractLifeCycle } // Idle tick - if (now-_idleTick>1000) + if (now-_idleTick>__IDLE_TICK) { _idleTick=now; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/nio/BlockingChannelConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/nio/BlockingChannelConnector.java index 3927cb1caf8..252c8dc108f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/nio/BlockingChannelConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/nio/BlockingChannelConnector.java @@ -19,8 +19,12 @@ import java.net.Socket; import java.nio.channels.ByteChannel; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import org.eclipse.jetty.http.HttpException; +import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.ConnectedEndPoint; import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; @@ -46,6 +50,8 @@ import org.eclipse.jetty.util.log.Log; public class BlockingChannelConnector extends AbstractNIOConnector { private transient ServerSocketChannel _acceptChannel; + private final Set _endpoints = Collections.newSetFromMap(new ConcurrentHashMap()); + /* ------------------------------------------------------------ */ /** Constructor. @@ -60,6 +66,46 @@ public class BlockingChannelConnector extends AbstractNIOConnector { return _acceptChannel; } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.server.AbstractConnector#doStart() + */ + @Override + protected void doStart() throws Exception + { + super.doStart(); + getThreadPool().dispatch(new Runnable() + { + + public void run() + { + while (isRunning()) + { + try + { + Thread.sleep(400); + long now=System.currentTimeMillis(); + for (BlockingChannelEndPoint endp : _endpoints) + { + endp.checkIdleTimestamp(now); + } + } + catch(InterruptedException e) + { + Log.ignore(e); + } + catch(Exception e) + { + Log.warn(e); + } + } + } + + }); + + } + /* ------------------------------------------------------------ */ public void open() throws IOException @@ -91,7 +137,7 @@ public class BlockingChannelConnector extends AbstractNIOConnector Socket socket=channel.socket(); configure(socket); - ConnectorEndPoint connection=new ConnectorEndPoint(channel); + BlockingChannelEndPoint connection=new BlockingChannelEndPoint(channel); connection.dispatch(); } @@ -117,13 +163,13 @@ public class BlockingChannelConnector extends AbstractNIOConnector /* ------------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------------- */ - private class ConnectorEndPoint extends ChannelEndPoint implements Runnable, ConnectedEndPoint + private class BlockingChannelEndPoint extends ChannelEndPoint implements Runnable, ConnectedEndPoint { - Connection _connection; - boolean _dispatched=false; - int _sotimeout; + private Connection _connection; + private int _timeout; + private volatile long _idleTimestamp; - ConnectorEndPoint(ByteChannel channel) + BlockingChannelEndPoint(ByteChannel channel) throws IOException { super(channel,BlockingChannelConnector.this._maxIdleTime); @@ -145,36 +191,102 @@ public class BlockingChannelConnector extends AbstractNIOConnector _connection=connection; } + /* ------------------------------------------------------------ */ + public void checkIdleTimestamp(long now) + { + if (_idleTimestamp!=0 && _timeout>0 && now>(_idleTimestamp+_timeout)) + { + System.err.println("IDLE "+this); + idleExpired(); + } + } + + /* ------------------------------------------------------------ */ + protected void idleExpired() + { + try + { + close(); + } + catch (IOException e) + { + Log.ignore(e); + } + } + /* ------------------------------------------------------------ */ void dispatch() throws IOException { if (!getThreadPool().dispatch(this)) { Log.warn("dispatch failed for {}",_connection); - ConnectorEndPoint.this.close(); + BlockingChannelEndPoint.this.close(); } } + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.io.nio.ChannelEndPoint#fill(org.eclipse.jetty.io.Buffer) + */ + @Override + public int fill(Buffer buffer) throws IOException + { + _idleTimestamp=System.currentTimeMillis(); + return super.fill(buffer); + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.io.nio.ChannelEndPoint#flush(org.eclipse.jetty.io.Buffer) + */ + @Override + public int flush(Buffer buffer) throws IOException + { + _idleTimestamp=System.currentTimeMillis(); + return super.flush(buffer); + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.io.nio.ChannelEndPoint#flush(org.eclipse.jetty.io.Buffer, org.eclipse.jetty.io.Buffer, org.eclipse.jetty.io.Buffer) + */ + @Override + public int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException + { + _idleTimestamp=System.currentTimeMillis(); + return super.flush(header,buffer,trailer); + } + + /* ------------------------------------------------------------ */ public void run() { try { + _timeout=getMaxIdleTime(); connectionOpened(_connection); + _endpoints.add(this); while (isOpen()) { + _idleTimestamp=System.currentTimeMillis(); if (_connection.isIdle()) { if (getServer().getThreadPool().isLowOnThreads()) { int lrmit = getLowResourcesMaxIdleTime(); - if (lrmit>=0 && _sotimeout!= lrmit) + if (lrmit>=0 && _timeout!= lrmit) { - _sotimeout=lrmit; - ((SocketChannel)getTransport()).socket().setSoTimeout(_sotimeout); + _timeout=lrmit; } } } + else + { + if (_timeout!=getMaxIdleTime()) + { + _timeout=getMaxIdleTime(); + } + } _connection = _connection.handle(); } @@ -182,24 +294,25 @@ public class BlockingChannelConnector extends AbstractNIOConnector catch (EofException e) { Log.debug("EOF", e); - try{ConnectorEndPoint.this.close();} + try{BlockingChannelEndPoint.this.close();} catch(IOException e2){Log.ignore(e2);} } catch (HttpException e) { Log.debug("BAD", e); - try{ConnectorEndPoint.this.close();} + try{BlockingChannelEndPoint.this.close();} catch(IOException e2){Log.ignore(e2);} } catch(Throwable e) { Log.warn("handle failed",e); - try{ConnectorEndPoint.this.close();} + try{BlockingChannelEndPoint.this.close();} catch(IOException e2){Log.ignore(e2);} } finally { connectionClosed(_connection); + _endpoints.remove(this); } } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSocketConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSocketConnector.java index ca99861cd92..26d97139907 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSocketConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSocketConnector.java @@ -13,16 +13,13 @@ package org.eclipse.jetty.server.ssl; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; -import java.net.SocketAddress; import java.security.KeyStore; import java.security.SecureRandom; -import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -33,7 +30,6 @@ import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; -import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSession; @@ -47,7 +43,6 @@ import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.bio.SocketEndPoint; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.bio.SocketConnector; -import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.resource.Resource; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/BlockingChannelTimeoutTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/BlockingChannelTimeoutTest.java new file mode 100644 index 00000000000..912711eff3d --- /dev/null +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/BlockingChannelTimeoutTest.java @@ -0,0 +1,31 @@ +// ======================================================================== +// Copyright (c) 2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.server; + +import org.eclipse.jetty.server.nio.BlockingChannelConnector; +import org.junit.BeforeClass; + +public class BlockingChannelTimeoutTest extends ConnectorTimeoutTest +{ + + @BeforeClass + public static void init() throws Exception + { + BlockingChannelConnector connector = new BlockingChannelConnector(); + connector.setMaxIdleTime(250); //250 msec max idle + + startServer(connector); + } + +} diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorTimeoutTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorTimeoutTest.java index 143512265d3..8d1c6a6693e 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorTimeoutTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorTimeoutTest.java @@ -13,32 +13,33 @@ package org.eclipse.jetty.server; -import static org.junit.Assert.fail; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertEquals; - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; -import org.eclipse.jetty.server.nio.SelectChannelConnector; +import junit.framework.Assert; + import org.eclipse.jetty.util.IO; -import org.junit.Assert; import org.junit.Test; public abstract class ConnectorTimeoutTest extends HttpServerTestFixture { - + static + { + System.setProperty("org.mortbay.io.nio.IDLE_TICK","100"); + } + + @Test public void testSelectConnectorMaxIdleWithRequest() throws Exception { - /* - * Test not working for Blocking connector configureServer(new EchoHandler()); - Socket client=new Socket(HOST,_connector.getLocalPort()); + Socket client=newSocket(HOST,_connector.getLocalPort()); + client.setSoTimeout(10000); assertFalse(client.isClosed()); @@ -54,37 +55,42 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture "content-length: "+contentB.length+"\r\n"+ "\r\n").getBytes("utf-8")); os.write(contentB); - + + long start = System.currentTimeMillis(); String in = IO.toString(is); System.err.println(in); - Thread.sleep(600); + Thread.sleep(300); assertEquals(-1, is.read()); - */ + + Assert.assertTrue(System.currentTimeMillis()-start>200); + Assert.assertTrue(System.currentTimeMillis()-start<1000); } - @Test public void testSelectConnectorMaxIdleNoRequest() throws Exception { - /* Test is not working for Select and Blocking connectors - gregw to look at the SelectorManager and the idle timeout configureServer(new EchoHandler()); - Socket client=new Socket(HOST,_connector.getLocalPort()); - OutputStream os=client.getOutputStream(); + Socket client=newSocket(HOST,_connector.getLocalPort()); + client.setSoTimeout(10000); + InputStream is=client.getInputStream(); assertFalse(client.isClosed()); - Thread.sleep(1100); + Thread.sleep(500); + long start = System.currentTimeMillis(); try - { - os.write(("xx").getBytes("utf-8")); - Assert.fail("Connection not closed"); - } - catch (IOException e) { - //expected result + IO.toString(is); + assertEquals(-1, is.read()); } - */ + catch(Exception e) + { + // SSL throws + } + Assert.assertTrue(System.currentTimeMillis()-start<200); + + } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java index c495c538359..7e27df9fe58 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java @@ -108,7 +108,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture { configureServer(new HelloWorldHandler()); - Socket client=new Socket(HOST,_connector.getLocalPort()); + Socket client=newSocket(HOST,_connector.getLocalPort()); try { OutputStream os=client.getOutputStream(); @@ -133,7 +133,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture { configureServer(new EchoHandler()); - Socket client=new Socket(HOST,_connector.getLocalPort()); + Socket client=newSocket(HOST,_connector.getLocalPort()); try { OutputStream os=client.getOutputStream(); @@ -166,7 +166,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture { configureServer(new HelloWorldHandler()); - Socket client=new Socket(HOST,_connector.getLocalPort()); + Socket client=newSocket(HOST,_connector.getLocalPort()); try { OutputStream os=client.getOutputStream(); @@ -202,7 +202,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture byte[] bytes=REQUEST2.getBytes(); for (int i=0; i