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

Reply via email to