Author: markt Date: Thu Dec 9 19:49:24 2010 New Revision: 1044110 URL: http://svn.apache.org/viewvc?rev=1044110&view=rev Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=50360 Add an option to control when the socket is bound
Modified: tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java tomcat/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java tomcat/trunk/test/org/apache/tomcat/util/net/TestXxxEndpoint.java tomcat/trunk/webapps/docs/changelog.xml tomcat/trunk/webapps/docs/config/http.xml Modified: tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java?rev=1044110&r1=1044109&r2=1044110&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java Thu Dec 9 19:49:24 2010 @@ -97,6 +97,10 @@ public abstract class AbstractEndpoint { public void recycle(); } + protected enum BindState { + UNBOUND, BOUND_ON_INIT, BOUND_ON_START + } + // Standard SSL Configuration attributes // JSSE // Standard configuration attribute names @@ -143,11 +147,6 @@ public abstract class AbstractEndpoint { protected volatile boolean paused = false; /** - * Track the initialization state of the endpoint. - */ - protected boolean initialized = false; - - /** * Are we using an internal executor */ protected volatile boolean internalExecutor = false; @@ -202,6 +201,17 @@ public abstract class AbstractEndpoint { public int getBacklog() { return backlog; } /** + * Controls when the Endpoint binds the port. <code>true</code>, the default + * binds the port on {...@link #init()} and unbinds it on {...@link #destroy()}. + * If set to <code>false</code> the port is bound on {...@link #start()} and + * unbound on {...@link #stop()}. + */ + private boolean bindOnInit = true; + public boolean getBindOnInit() { return bindOnInit; } + public void setBindOnInit(boolean b) { this.bindOnInit = b; } + private BindState bindState = BindState.UNBOUND; + + /** * Keepalive timeout, if lesser or equal to 0 then soTimeout will be used. */ private int keepAliveTimeout = -1; @@ -503,8 +513,34 @@ public abstract class AbstractEndpoint { } - public abstract void init() throws Exception; - public abstract void start() throws Exception; + // ------------------------------------------------------- Lifecycle methods + + /* + * NOTE: There is no maintenance of state or checking for valid transitions + * within this class other than ensuring that bind/unbind are called in the + * right place. It is expected that the calling code will maintain state and + * prevent invalid state transitions. + */ + + public abstract void bind() throws Exception; + public abstract void unbind() throws Exception; + public abstract void startInternal() throws Exception; + public abstract void stopInternal() throws Exception; + + public final void init() throws Exception { + if (bindOnInit) { + bind(); + bindState = BindState.BOUND_ON_INIT; + } + } + + public final void start() throws Exception { + if (bindState == BindState.UNBOUND) { + bind(); + bindState = BindState.BOUND_ON_START; + } + startInternal(); + } /** * Pause the endpoint, which will stop it accepting new connections. @@ -532,8 +568,21 @@ public abstract class AbstractEndpoint { } } - public abstract void stop() throws Exception; - public abstract void destroy() throws Exception; + public final void stop() throws Exception { + stopInternal(); + if (bindState == BindState.BOUND_ON_START) { + unbind(); + bindState = BindState.UNBOUND; + } + } + + public final void destroy() throws Exception { + if (bindState == BindState.BOUND_ON_INIT) { + unbind(); + bindState = BindState.UNBOUND; + } + } + public String adjustRelativePath(String path, String relativeTo) { String newPath = path; Modified: tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java?rev=1044110&r1=1044109&r2=1044110&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java Thu Dec 9 19:49:24 2010 @@ -365,11 +365,7 @@ public class AprEndpoint extends Abstrac * Initialize the endpoint. */ @Override - public void init() - throws Exception { - - if (initialized) - return; + public void bind() throws Exception { // Create the root APR memory pool try { @@ -518,9 +514,6 @@ public class AprEndpoint extends Abstrac // For now, sendfile is not supported with SSL useSendfile = false; } - - initialized = true; - } @@ -528,12 +521,8 @@ public class AprEndpoint extends Abstrac * Start the APR endpoint, creating acceptor, poller and sendfile threads. */ @Override - public void start() - throws Exception { - // Initialize socket if not done before - if (!initialized) { - init(); - } + public void startInternal() throws Exception { + if (!running) { running = true; paused = false; @@ -602,7 +591,7 @@ public class AprEndpoint extends Abstrac * Stop the endpoint. This will cause all processing threads to stop. */ @Override - public void stop() { + public void stopInternal() { if (!paused) { pause(); } @@ -665,7 +654,7 @@ public class AprEndpoint extends Abstrac * Deallocate APR memory pools, and close server socket. */ @Override - public void destroy() throws Exception { + public void unbind() throws Exception { if (running) { stop(); } @@ -691,8 +680,6 @@ public class AprEndpoint extends Abstrac } handler.recycle(); - - initialized = false; } Modified: tomcat/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java?rev=1044110&r1=1044109&r2=1044110&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java Thu Dec 9 19:49:24 2010 @@ -324,12 +324,8 @@ public class JIoEndpoint extends Abstrac // -------------------- Public methods -------------------- @Override - public void init() - throws Exception { + public void bind() throws Exception { - if (initialized) - return; - // Initialize thread count defaults for acceptor if (acceptorThreadCount == 0) { acceptorThreadCount = 1; @@ -365,15 +361,11 @@ public class JIoEndpoint extends Abstrac } } - initialized = true; } @Override - public void start() throws Exception { - // Initialize socket if not done before - if (!initialized) { - init(); - } + public void startInternal() throws Exception { + if (!running) { running = true; paused = false; @@ -402,7 +394,7 @@ public class JIoEndpoint extends Abstrac } @Override - public void stop() { + public void stopInternal() { if (!paused) { pause(); } @@ -417,7 +409,7 @@ public class JIoEndpoint extends Abstrac * Deallocate APR memory pools, and close server socket. */ @Override - public void destroy() throws Exception { + public void unbind() throws Exception { if (running) { stop(); } @@ -431,7 +423,6 @@ public class JIoEndpoint extends Abstrac serverSocket = null; } handler.recycle(); - initialized = false ; } Modified: tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java?rev=1044110&r1=1044109&r2=1044110&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java Thu Dec 9 19:49:24 2010 @@ -455,11 +455,7 @@ public class NioEndpoint extends Abstrac * Initialize the endpoint. */ @Override - public void init() - throws Exception { - - if (initialized) - return; + public void bind() throws Exception { serverSock = ServerSocketChannel.open(); socketProperties.setProperties(serverSock.socket()); @@ -545,8 +541,6 @@ public class NioEndpoint extends Abstrac if (oomParachute>0) reclaimParachute(true); selectorPool.open(); - initialized = true; - } public KeyManager[] wrap(KeyManager[] managers) { @@ -567,12 +561,8 @@ public class NioEndpoint extends Abstrac * Start the NIO endpoint, creating acceptor, poller threads. */ @Override - public void start() - throws Exception { - // Initialize socket if not done before - if (!initialized) { - init(); - } + public void startInternal() throws Exception { + if (!running) { running = true; paused = false; @@ -607,7 +597,7 @@ public class NioEndpoint extends Abstrac * Stop the endpoint. This will cause all processing threads to stop. */ @Override - public void stop() { + public void stopInternal() { if (!paused) { pause(); } @@ -634,7 +624,7 @@ public class NioEndpoint extends Abstrac * Deallocate NIO memory pools, and close server socket. */ @Override - public void destroy() throws Exception { + public void unbind() throws Exception { if (log.isDebugEnabled()) { log.debug("Destroy initiated for "+new InetSocketAddress(getAddress(),getPort())); } @@ -646,7 +636,6 @@ public class NioEndpoint extends Abstrac serverSock.close(); serverSock = null; sslContext = null; - initialized = false; releaseCaches(); selectorPool.close(); if (log.isDebugEnabled()) { Modified: tomcat/trunk/test/org/apache/tomcat/util/net/TestXxxEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/net/TestXxxEndpoint.java?rev=1044110&r1=1044109&r2=1044110&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/tomcat/util/net/TestXxxEndpoint.java (original) +++ tomcat/trunk/test/org/apache/tomcat/util/net/TestXxxEndpoint.java Thu Dec 9 19:49:24 2010 @@ -20,6 +20,7 @@ package org.apache.tomcat.util.net; import java.io.File; import java.net.ServerSocket; +import org.apache.catalina.connector.Connector; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.TomcatBaseTest; @@ -29,7 +30,7 @@ import org.apache.catalina.startup.Tomca */ public class TestXxxEndpoint extends TomcatBaseTest { - public void disbaletestStartStop() throws Exception { + public void testStartStopBindOnInit() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File(getBuildDirectory(), "webapps/examples"); tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath()); @@ -39,13 +40,52 @@ public class TestXxxEndpoint extends Tom tomcat.start(); tomcat.getConnector().stop(); - // This will throw an exception if the socket is not released - ServerSocket socket = new ServerSocket(port); - socket.close(); + // This will should throw an Exception + Exception e = null; + ServerSocket s = null; + try { + s = new ServerSocket(port); + } catch (Exception e1) { + e = e1; + } finally { + if (s != null) { + try { + s.close(); + } catch (Exception e2) { /* Ignore */ } + } + } + assertNotNull(e); tomcat.getConnector().start(); } - - public void testDummy() throws Exception { - // NO-OP + + public void testStartStopBindOnStart() throws Exception { + Tomcat tomcat = getTomcatInstance(); + Connector c = tomcat.getConnector(); + c.setProperty("bindOnInit", "false"); + + File appDir = new File(getBuildDirectory(), "webapps/examples"); + tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath()); + + int port = getPort(); + + tomcat.start(); + + tomcat.getConnector().stop(); + // This should not throw an Exception + Exception e = null; + ServerSocket s = null; + try { + s = new ServerSocket(port); + } catch (Exception e1) { + e = e1; + } finally { + if (s != null) { + try { + s.close(); + } catch (Exception e2) { /* Ignore */ } + } + } + assertNull(e); + tomcat.getConnector().start(); } } Modified: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1044110&r1=1044109&r2=1044110&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Thu Dec 9 19:49:24 2010 @@ -130,6 +130,16 @@ <bug>50108</bug>: Add get/set methods for Connector property minSpareThreads. Patch provided by Eiji Takahashi. (markt) </add> + <fix> + <bug>50360</bug>: Provide an option to control when the socket + associated with a connector is bound. By default, the socket is bound on + <code>Connector.init()</code> and released on + <code>Connector.destroy()</code> as per the current behaviour but this + can be changed so that the socket is bound on + <code>Connector.start()</code> and released on + <code>Connector.stop()</code>. This fix also includes further Lifecycle + refactoring for Connectors and associated components. (markt) + </fix> </changelog> </subsection> <subsection name="Jasper"> Modified: tomcat/trunk/webapps/docs/config/http.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/http.xml?rev=1044110&r1=1044109&r2=1044110&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/config/http.xml (original) +++ tomcat/trunk/webapps/docs/config/http.xml Thu Dec 9 19:49:24 2010 @@ -265,6 +265,13 @@ associated with the server.</p> </attribute> + <attribute name="bindOnInit" required="false"> + <p>Controls when the socket used by the connector is bound. By default it + is bound when the connector is initiated and unbund when the connector is + destroyed. If set to <code>false</code>, the socket will be bound when the + connector is started and unbound when it is stopped.</p> + </attribute> + <attribute name="compressableMimeType" required="false"> <p>The value is a comma separated list of MIME types for which HTTP compression may be used. --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org