Author: kkolinko Date: Thu Jan 7 14:04:28 2016 New Revision: 1723551 URL: http://svn.apache.org/viewvc?rev=1723551&view=rev Log: Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=52028 Add support for automatic binding to a free port by a connector if the special value of zero is used for the port. This is mainly useful in embedded and testing scenarios.
This includes backport of the following revisions from Tomcat 7: r1207695 r1208115 r1208148 r1723441 r1723489 Handling of port number 0 in Jk AJP connector (ChannelSocket, ChannelNioSocket) was changed. Old behaviour was to disable the connector. New behaviour is to bind to a random port number. To disable the connector one can now use a negative port number. I doubt that this "disable" feature was actually used by anyone. Also binding to a random port is not so much different from disabling. Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/Connector.java tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/mbeans-descriptors.xml tomcat/tc6.0.x/trunk/java/org/apache/coyote/AbstractProtocol.java tomcat/tc6.0.x/trunk/java/org/apache/coyote/memory/MemoryProtocolHandler.java tomcat/tc6.0.x/trunk/java/org/apache/jk/common/ChannelNioSocket.java tomcat/tc6.0.x/trunk/java/org/apache/jk/common/ChannelSocket.java tomcat/tc6.0.x/trunk/java/org/apache/jk/server/JkCoyoteHandler.java tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml tomcat/tc6.0.x/trunk/webapps/docs/config/ajp.xml tomcat/tc6.0.x/trunk/webapps/docs/config/http.xml Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/Connector.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/Connector.java?rev=1723551&r1=1723550&r2=1723551&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/Connector.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/Connector.java Thu Jan 7 14:04:28 2016 @@ -659,7 +659,9 @@ public class Connector } /** - * Return the port number on which we listen for requests. + * Return the port number on which this connector is configured to listen + * for requests. The special value of 0 means select a random free port + * when the socket is bound. */ public int getPort() { @@ -682,6 +684,16 @@ public class Connector /** + * Return the port number on which this connector is listening to requests. + * If the special value for {@link #port} of zero is used then this method + * will report the actual port bound. + */ + public int getLocalPort() { + return ((Integer) getProperty("localPort")).intValue(); + } + + + /** * Return the Coyote protocol handler in use. */ public String getProtocol() { @@ -1067,7 +1079,13 @@ public class Connector sb.append(":type="); sb.append(type); sb.append(",port="); - sb.append(getPort()); + int port = getPort(); + if (port > 0) { + sb.append(port); + } else { + sb.append("auto-"); + sb.append(getProperty("nameIndex")); + } if (addressObj != null) { String address = addressObj.toString(); if (address.length() > 0) { @@ -1384,7 +1402,13 @@ public class Connector StringBuilder sb = new StringBuilder("Connector["); sb.append(getProtocol()); sb.append('-'); - sb.append(getPort()); + int port = getPort(); + if (port > 0) { + sb.append(port); + } else { + sb.append("auto-"); + sb.append(getProperty("nameIndex")); + } sb.append(']'); return sb.toString(); } Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/mbeans-descriptors.xml URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/mbeans-descriptors.xml?rev=1723551&r1=1723550&r2=1723551&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/mbeans-descriptors.xml (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/mbeans-descriptors.xml Thu Jan 7 14:04:28 2016 @@ -110,6 +110,11 @@ description="Alias name of this connector's keypair and supporting certificate chain" type="java.lang.String"/> + <attribute name="localPort" + description="The port number on which this connector is listening to requests. If the special value for port of zero is used then this method will report the actual port bound." + type="int" + writeable="false"/> + <attribute name="maxHeaderCount" description="The maximum number of headers that are allowed by the container. 100 by default. A value of less than 0 means no limit." type="int"/> @@ -143,7 +148,7 @@ type="int"/> <attribute name="port" - description="The port number on which we listen for requests" + description="The port number on which this connector is configured to listen for requests. The special value of 0 means select a random free port when the socket is bound." type="int"/> <attribute name="protocol" Modified: tomcat/tc6.0.x/trunk/java/org/apache/coyote/AbstractProtocol.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/coyote/AbstractProtocol.java?rev=1723551&r1=1723550&r2=1723551&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/coyote/AbstractProtocol.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/coyote/AbstractProtocol.java Thu Jan 7 14:04:28 2016 @@ -18,11 +18,26 @@ package org.apache.coyote; import java.net.InetAddress; import java.net.URLEncoder; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.tomcat.util.net.AbstractEndpoint; public abstract class AbstractProtocol implements ProtocolHandler { + /** + * Counter used to generate unique JMX names for connectors using automatic + * port binding. + */ + private static final AtomicInteger nameCounter = new AtomicInteger(0); + + /** + * Unique ID for this connector. Only used if the connector is configured + * to use a random port as the port will change if stop(), start() is + * called. + */ + private int nameIndex = 0; + + protected abstract AbstractEndpoint getEndpoint(); public int getMaxHeaderCount() { @@ -32,6 +47,21 @@ public abstract class AbstractProtocol i getEndpoint().setMaxHeaderCount(maxHeaderCount); } + public int getLocalPort() { + return getEndpoint().getLocalPort(); + } + + public synchronized int getNameIndex() { + if (nameIndex == 0) { + nameIndex = nextNameIndex(); + } + return nameIndex; + } + + public static int nextNameIndex() { + return nameCounter.incrementAndGet(); + } + /** * An utility method, used to implement getName() in subclasses. */ @@ -45,7 +75,18 @@ public abstract class AbstractProtocol i } name.append(URLEncoder.encode(strAddr)).append('-'); } - name.append(port); + if (port == 0) { + // Auto binding is in use. Check if port is known + name.append("auto-"); + name.append(getNameIndex()); + port = getLocalPort(); + if (port != -1) { + name.append('-'); + name.append(port); + } + } else { + name.append(port); + } return name.toString(); } } Modified: tomcat/tc6.0.x/trunk/java/org/apache/coyote/memory/MemoryProtocolHandler.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/coyote/memory/MemoryProtocolHandler.java?rev=1723551&r1=1723550&r2=1723551&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/coyote/memory/MemoryProtocolHandler.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/coyote/memory/MemoryProtocolHandler.java Thu Jan 7 14:04:28 2016 @@ -19,14 +19,15 @@ package org.apache.coyote.memory; import java.io.IOException; import java.util.Iterator; -import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.coyote.AbstractProtocol; import org.apache.coyote.Adapter; import org.apache.coyote.InputBuffer; import org.apache.coyote.OutputBuffer; import org.apache.coyote.ProtocolHandler; import org.apache.coyote.Request; import org.apache.coyote.Response; +import org.apache.tomcat.util.buf.ByteChunk; /** @@ -70,6 +71,20 @@ public class MemoryProtocolHandler return (adapter); } + /** + * Unique ID for this connector. + */ + private int nameIndex = 0; + + public synchronized int getNameIndex() { + if (nameIndex == 0) { + nameIndex = AbstractProtocol.nextNameIndex(); + } + + return nameIndex; + } + + public int getLocalPort() { return -1; } // ------------------------------------------------ ProtocolHandler Methods Modified: tomcat/tc6.0.x/trunk/java/org/apache/jk/common/ChannelNioSocket.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/jk/common/ChannelNioSocket.java?rev=1723551&r1=1723550&r2=1723551&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/jk/common/ChannelNioSocket.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/jk/common/ChannelNioSocket.java Thu Jan 7 14:04:28 2016 @@ -378,40 +378,61 @@ public class ChannelNioSocket extends Jk */ public void init() throws IOException { // Find a port. - if (startPort == 0) { + if (startPort < 0) { port = 0; if(log.isInfoEnabled()) log.info("JK: ajp13 disabling channelNioSocket"); running = true; return; } - int endPort = maxPort; - if (endPort < startPort) - endPort = startPort; ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.configureBlocking(false); - for( int i=startPort; i<=endPort; i++ ) { + + if (startPort == 0) { + // Let operating system to choose a random free port try { InetSocketAddress iddr = null; if( inet == null ) { - iddr = new InetSocketAddress( i); + iddr = new InetSocketAddress(0); } else { - iddr=new InetSocketAddress( inet, i); + iddr=new InetSocketAddress(inet, 0); } sSocket = ssc.socket(); sSocket.bind(iddr); - port=i; - break; } catch( IOException ex ) { - if(log.isInfoEnabled()) - log.info("Port busy " + i + " " + ex.toString()); + log.error("Can't find free port", ex); sSocket = null; + return; } - } - if( sSocket==null ) { - log.error("Can't find free port " + startPort + " " + endPort ); - return; + port = sSocket.getLocalPort(); + } else { + int endPort = maxPort; + if (endPort < startPort) + endPort = startPort; + for( int i=startPort; i<=endPort; i++ ) { + try { + InetSocketAddress iddr = null; + if( inet == null ) { + iddr = new InetSocketAddress( i); + } else { + iddr=new InetSocketAddress( inet, i); + } + sSocket = ssc.socket(); + sSocket.bind(iddr); + port=i; + break; + } catch( IOException ex ) { + if(log.isInfoEnabled()) + log.info("Port busy " + i + " " + ex.toString()); + sSocket = null; + } + } + + if( sSocket==null ) { + log.error("Can't find free port " + startPort + " " + endPort ); + return; + } } if(log.isInfoEnabled()) log.info("JK: ajp13 listening on " + getAddress() + ":" + port ); Modified: tomcat/tc6.0.x/trunk/java/org/apache/jk/common/ChannelSocket.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/jk/common/ChannelSocket.java?rev=1723551&r1=1723550&r2=1723551&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/jk/common/ChannelSocket.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/jk/common/ChannelSocket.java Thu Jan 7 14:04:28 2016 @@ -359,35 +359,52 @@ public class ChannelSocket extends JkHan */ public void init() throws IOException { // Find a port. - if (startPort == 0) { + if (startPort < 0) { port = 0; if(log.isInfoEnabled()) log.info("JK: ajp13 disabling channelSocket"); running = true; return; } - int endPort = maxPort; - if (endPort < startPort) - endPort = startPort; - for( int i=startPort; i<=endPort; i++ ) { + if (startPort == 0) { + // Let operating system to choose a random free port try { if( inet == null ) { - sSocket = new ServerSocket( i, backlog ); + sSocket = new ServerSocket( 0, backlog ); } else { - sSocket=new ServerSocket( i, backlog, inet ); + sSocket=new ServerSocket( 0, backlog, inet ); } - port=i; - break; } catch( IOException ex ) { - if(log.isInfoEnabled()) - log.info("Port busy " + i + " " + ex.toString()); - continue; + log.error("Can't find free port", ex); + sSocket = null; + return; } - } - if( sSocket==null ) { - log.error("Can't find free port " + startPort + " " + endPort ); - return; + port = sSocket.getLocalPort(); + } else { + int endPort = maxPort; + if (endPort < startPort) + endPort = startPort; + for( int i=startPort; i<=endPort; i++ ) { + try { + if( inet == null ) { + sSocket = new ServerSocket( i, backlog ); + } else { + sSocket=new ServerSocket( i, backlog, inet ); + } + port=i; + break; + } catch( IOException ex ) { + if(log.isInfoEnabled()) + log.info("Port busy " + i + " " + ex.toString()); + continue; + } + } + + if( sSocket==null ) { + log.error("Can't find free port " + startPort + " " + endPort ); + return; + } } if(log.isInfoEnabled()) log.info("JK: ajp13 listening on " + getAddress() + ":" + port ); Modified: tomcat/tc6.0.x/trunk/java/org/apache/jk/server/JkCoyoteHandler.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/jk/server/JkCoyoteHandler.java?rev=1723551&r1=1723550&r2=1723551&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/jk/server/JkCoyoteHandler.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/jk/server/JkCoyoteHandler.java Thu Jan 7 14:04:28 2016 @@ -23,15 +23,19 @@ import java.util.Iterator; import javax.management.MBeanServer; import javax.management.ObjectName; +import org.apache.coyote.AbstractProtocol; import org.apache.coyote.Adapter; import org.apache.coyote.ProtocolHandler; import org.apache.coyote.Request; import org.apache.coyote.Response; import org.apache.coyote.RequestInfo; import org.apache.coyote.Constants; +import org.apache.jk.common.ChannelNioSocket; +import org.apache.jk.common.ChannelSocket; import org.apache.jk.core.JkHandler; import org.apache.jk.core.Msg; import org.apache.jk.core.MsgContext; +import org.apache.jk.core.WorkerEnv; import org.apache.tomcat.util.modeler.Registry; /** Plugs Jk into Coyote. Must be named "type=JkHandler,name=container" @@ -44,6 +48,35 @@ public class JkCoyoteHandler extends JkH = org.apache.juli.logging.LogFactory.getLog(JkCoyoteHandler.class); // Set debug on this logger to see the container request time + /** + * Unique ID for this connector. Only used if the connector is configured + * to use a random port as the port will change if stop(), start() is + * called. + */ + private int nameIndex = 0; + + public synchronized int getNameIndex() { + if (nameIndex == 0) { + nameIndex = AbstractProtocol.nextNameIndex(); + } + + return nameIndex; + } + + public int getLocalPort() { + WorkerEnv wEnv = getJkMain().getWorkerEnv(); + for( int i=0; i<wEnv.getHandlerCount(); i++ ) { + JkHandler w = wEnv.getHandler(i); + if( w instanceof ChannelSocket ) { + return ((ChannelSocket) w).getPort(); + } + if( w instanceof ChannelNioSocket ) { + return ((ChannelNioSocket) w).getPort(); + } + } + return -1; + } + // ----------------------------------------------------------- DoPrivileged private boolean paused = false; int epNote; Modified: tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java?rev=1723551&r1=1723550&r2=1723551&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java Thu Jan 7 14:04:28 2016 @@ -16,7 +16,7 @@ */ package org.apache.tomcat.util.net; -public class AbstractEndpoint { +public abstract class AbstractEndpoint { /** * The maximum number of headers in a request that are allowed. @@ -30,4 +30,6 @@ public class AbstractEndpoint { this.maxHeaderCount = maxHeaderCount; } + public abstract int getLocalPort(); + } Modified: tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java?rev=1723551&r1=1723550&r2=1723551&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java Thu Jan 7 14:04:28 2016 @@ -36,6 +36,7 @@ import org.apache.tomcat.jni.Pool; import org.apache.tomcat.jni.SSL; import org.apache.tomcat.jni.SSLContext; import org.apache.tomcat.jni.SSLSocket; +import org.apache.tomcat.jni.Sockaddr; import org.apache.tomcat.jni.Socket; import org.apache.tomcat.jni.Status; import org.apache.tomcat.util.res.StringManager; @@ -517,8 +518,6 @@ public class AprEndpoint extends Abstrac public void setSSLVerifyDepth(int SSLVerifyDepth) { this.SSLVerifyDepth = SSLVerifyDepth; } - // --------------------------------------------------------- Public Methods - protected boolean SSLHonorCipherOrder = false; /** * Set to <code>true</code> to enforce the <i>server's</i> cipher order @@ -542,6 +541,30 @@ public class AprEndpoint extends Abstrac public void setSSLDisableCompression(boolean SSLDisableCompression) { this.SSLDisableCompression = SSLDisableCompression; } public boolean getSSLDisableCompression() { return SSLDisableCompression; } + + /** + * Port in use. + */ + @Override + public int getLocalPort() { + long s = serverSock; + if (s == 0) { + return -1; + } else { + long sa; + try { + sa = Address.get(Socket.APR_LOCAL, s); + Sockaddr addr = Address.getInfo(sa); + return addr.port; + } catch (Exception e) { + return -1; + } + } + } + + + // --------------------------------------------------------- Public Methods + /** * Number of keepalive sockets. */ @@ -1036,9 +1059,9 @@ public class AprEndpoint extends Abstrac try { // Need to create a connection to unlock the accept(); if (address == null) { - saddr = new InetSocketAddress("localhost", port); + saddr = new InetSocketAddress("localhost", getLocalPort()); } else { - saddr = new InetSocketAddress(address,port); + saddr = new InetSocketAddress(address, getLocalPort()); } s = new java.net.Socket(); s.setSoTimeout(soTimeout > 0 ? soTimeout : 60000); @@ -1062,7 +1085,7 @@ public class AprEndpoint extends Abstrac } } catch(Exception e) { if (log.isDebugEnabled()) { - log.debug(sm.getString("endpoint.debug.unlock", "" + port), e); + log.debug(sm.getString("endpoint.debug.unlock", "" + getLocalPort()), e); } } finally { if (s != null) { @@ -1137,7 +1160,7 @@ public class AprEndpoint extends Abstrac if (curThreadsBusy == maxThreads) { log.info(sm.getString("endpoint.info.maxThreads", Integer.toString(maxThreads), address, - Integer.toString(port))); + Integer.toString(getLocalPort()))); } return (newWorkerThread()); } else { Modified: tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java?rev=1723551&r1=1723550&r2=1723551&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java Thu Jan 7 14:04:28 2016 @@ -271,7 +271,21 @@ public class JIoEndpoint extends Abstrac this.unlockTimeout = unlockTimeout; } - + + /** + * Port in use. + */ + @Override + public int getLocalPort() { + ServerSocket s = serverSocket; + if (s == null) { + return -1; + } else { + return s.getLocalPort(); + } + } + + public boolean isRunning() { return running; } @@ -632,9 +646,9 @@ public class JIoEndpoint extends Abstrac try { // Need to create a connection to unlock the accept(); if (address == null) { - saddr = new InetSocketAddress("localhost", port); + saddr = new InetSocketAddress("localhost", getLocalPort()); } else { - saddr = new InetSocketAddress(address,port); + saddr = new InetSocketAddress(address, getLocalPort()); } s = new java.net.Socket(); s.setSoTimeout(soTimeout); @@ -648,7 +662,8 @@ public class JIoEndpoint extends Abstrac } } catch (Exception e) { if (log.isDebugEnabled()) { - log.debug(sm.getString("endpoint.debug.unlock", "" + port), e); + log.debug(sm.getString("endpoint.debug.unlock", + Integer.toString(getLocalPort())), e); } } finally { if (s != null) { @@ -718,7 +733,7 @@ public class JIoEndpoint extends Abstrac if (curThreadsBusy == maxThreads) { log.info(sm.getString("endpoint.info.maxThreads", Integer.toString(maxThreads), address, - Integer.toString(port))); + Integer.toString(getLocalPort()))); } return (newWorkerThread()); } else { Modified: tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java?rev=1723551&r1=1723550&r2=1723551&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java Thu Jan 7 14:04:28 2016 @@ -22,6 +22,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.ServerSocket; import java.net.Socket; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; @@ -690,6 +691,26 @@ public class NioEndpoint extends Abstrac public SSLContext getSSLContext() { return sslContext;} public void setSSLContext(SSLContext c) { sslContext = c;} + + /** + * Port in use. + */ + @Override + public int getLocalPort() { + ServerSocketChannel ssc = serverSock; + if (ssc == null) { + return -1; + } else { + ServerSocket s = ssc.socket(); + if (s == null) { + return -1; + } else { + return s.getLocalPort(); + } + } + } + + // --------------------------------------------------------- OOM Parachute Methods protected void checkParachute() { @@ -982,7 +1003,7 @@ public class NioEndpoint extends Abstrac */ public void destroy() throws Exception { if (log.isDebugEnabled()) { - log.debug("Destroy initiated for "+new InetSocketAddress(address,port)); + log.debug("Destroy initiated for "+new InetSocketAddress(address,getLocalPort())); } if (running) { stop(); @@ -996,7 +1017,7 @@ public class NioEndpoint extends Abstrac releaseCaches(); selectorPool.close(); if (log.isDebugEnabled()) { - log.debug("Destroy completed for "+new InetSocketAddress(address,port)); + log.debug("Destroy completed for "+new InetSocketAddress(address,getLocalPort())); } } @@ -1049,9 +1070,9 @@ public class NioEndpoint extends Abstrac try { // Need to create a connection to unlock the accept(); if (address == null) { - saddr = new InetSocketAddress("localhost", port); + saddr = new InetSocketAddress("localhost", getLocalPort()); } else { - saddr = new InetSocketAddress(address,port); + saddr = new InetSocketAddress(address, getLocalPort()); } s = new java.net.Socket(); s.setSoTimeout(getSocketProperties().getSoTimeout()); @@ -1065,7 +1086,8 @@ public class NioEndpoint extends Abstrac } } catch(Exception e) { if (log.isDebugEnabled()) { - log.debug(sm.getString("endpoint.debug.unlock", "" + port), e); + log.debug(sm.getString("endpoint.debug.unlock", + Integer.toString(getLocalPort())), e); } } finally { if (s != null) { @@ -1192,7 +1214,7 @@ public class NioEndpoint extends Abstrac if (curThreadsBusy == maxThreads) { log.info(sm.getString("endpoint.info.maxThreads", Integer.toString(maxThreads), address, - Integer.toString(port))); + Integer.toString(getLocalPort()))); } return (newWorkerThread()); } else { Modified: tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml?rev=1723551&r1=1723550&r2=1723551&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Thu Jan 7 14:04:28 2016 @@ -115,6 +115,11 @@ <bug>51503</bug>: Add additional validation that prevents a connector from starting if it does not have a valid port number. (kkolinko) </fix> + <add> + <bug>52028</bug>: Add support for automatic binding to a free port by a + connector if the special value of zero is used for the port. This is + mainly useful in embedded and testing scenarios. (kkolinko) + </add> <fix> <bug>52926</bug>: Avoid NPE when an NIO Comet connection times out on one thread at the same time as it is closed on another thread. Modified: tomcat/tc6.0.x/trunk/webapps/docs/config/ajp.xml URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/config/ajp.xml?rev=1723551&r1=1723550&r2=1723551&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/webapps/docs/config/ajp.xml (original) +++ tomcat/tc6.0.x/trunk/webapps/docs/config/ajp.xml Thu Jan 7 14:04:28 2016 @@ -147,7 +147,10 @@ <p>The TCP port number on which this <strong>Connector</strong> will create a server socket and await incoming connections. Your operating system will allow only one server application to listen - to a particular port number on a particular IP address.</p> + to a particular port number on a particular IP address. If the special + value of 0 (zero) is used, then Tomcat will select a free port at random + to use for this connector. This is typically only useful in embedded and + testing applications.</p> </attribute> <attribute name="protocol" required="false"> Modified: tomcat/tc6.0.x/trunk/webapps/docs/config/http.xml URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/config/http.xml?rev=1723551&r1=1723550&r2=1723551&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/webapps/docs/config/http.xml (original) +++ tomcat/tc6.0.x/trunk/webapps/docs/config/http.xml Thu Jan 7 14:04:28 2016 @@ -154,7 +154,10 @@ <p>The TCP port number on which this <strong>Connector</strong> will create a server socket and await incoming connections. Your operating system will allow only one server application to listen - to a particular port number on a particular IP address.</p> + to a particular port number on a particular IP address. If the special + value of 0 (zero) is used, then Tomcat will select a free port at random + to use for this connector. This is typically only useful in embedded and + testing applications.</p> </attribute> <attribute name="protocol" required="false"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org