You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2015/04/13 15:53:52 UTC

svn commit: r1673191 - in /tomcat/trunk/java/org/apache/tomcat/util/net: Nio2Endpoint.java SecureNio2Channel.java

Author: markt
Date: Mon Apr 13 13:53:52 2015
New Revision: 1673191

URL: http://svn.apache.org/r1673191
Log:
SNI support for NIO2

Modified:
    tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java
    tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java?rev=1673191&r1=1673190&r2=1673191&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java Mon Apr 13 13:53:52 2015
@@ -422,27 +422,15 @@ public class Nio2Endpoint extends Abstra
 
             Nio2Channel channel = (useCaches) ? nioChannels.pop() : null;
             if (channel == null) {
-                // SSL setup
+                SocketBufferHandler bufhandler = new SocketBufferHandler(
+                        socketProperties.getAppReadBufSize(),
+                        socketProperties.getAppWriteBufSize(),
+                        socketProperties.getDirectBuffer());
                 if (isSSLEnabled()) {
-                    SSLEngine engine = createSSLEngine();
-                    int appBufferSize = engine.getSession().getApplicationBufferSize();
-                    SocketBufferHandler bufhandler = new SocketBufferHandler(
-                            Math.max(appBufferSize, socketProperties.getAppReadBufSize()),
-                            Math.max(appBufferSize, socketProperties.getAppWriteBufSize()),
-                            socketProperties.getDirectBuffer());
-                    channel = new SecureNio2Channel(engine, bufhandler, this);
+                    channel = new SecureNio2Channel(bufhandler, this);
                 } else {
-                    SocketBufferHandler bufhandler = new SocketBufferHandler(
-                            socketProperties.getAppReadBufSize(),
-                            socketProperties.getAppWriteBufSize(),
-                            socketProperties.getDirectBuffer());
                     channel = new Nio2Channel(bufhandler);
                 }
-            } else {
-                if (isSSLEnabled()) {
-                    SSLEngine engine = createSSLEngine();
-                    ((SecureNio2Channel) channel).setSSLEngine(engine);
-                }
             }
             Nio2SocketWrapper socketWrapper = new Nio2SocketWrapper(channel, this);
             channel.reset(socket, socketWrapper);

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java?rev=1673191&r1=1673190&r2=1673191&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java Mon Apr 13 13:53:52 2015
@@ -34,6 +34,10 @@ import javax.net.ssl.SSLEngineResult.Han
 import javax.net.ssl.SSLEngineResult.Status;
 import javax.net.ssl.SSLException;
 
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.buf.ByteBufferUtils;
+import org.apache.tomcat.util.net.SNIExtractor.SNIResult;
 import org.apache.tomcat.util.res.StringManager;
 
 /**
@@ -41,8 +45,12 @@ import org.apache.tomcat.util.res.String
  */
 public class SecureNio2Channel extends Nio2Channel  {
 
-    protected static final StringManager sm = StringManager.getManager(
-            SecureNio2Channel.class.getPackage().getName());
+    private static final Log log = LogFactory.getLog(SecureNio2Channel.class);
+    private static final StringManager sm = StringManager.getManager(SecureNio2Channel.class);
+
+    // Value determined by observation of what the SSL Engine requested in
+    // various scenarios
+    private static final int DEFAULT_NET_BUFFER_SIZE = 16921;
 
     protected ByteBuffer netInBuffer;
     protected ByteBuffer netOutBuffer;
@@ -63,18 +71,15 @@ public class SecureNio2Channel extends N
     private CompletionHandler<Integer, SocketWrapperBase<Nio2Channel>> handshakeReadCompletionHandler;
     private CompletionHandler<Integer, SocketWrapperBase<Nio2Channel>> handshakeWriteCompletionHandler;
 
-    public SecureNio2Channel(SSLEngine engine, SocketBufferHandler bufHandler,
-            Nio2Endpoint endpoint0) {
+    public SecureNio2Channel(SocketBufferHandler bufHandler, Nio2Endpoint endpoint) {
         super(bufHandler);
-        sslEngine = engine;
-        endpoint = endpoint0;
-        int netBufSize = sslEngine.getSession().getPacketBufferSize();
+        this.endpoint = endpoint;
         if (endpoint.getSocketProperties().getDirectSslBuffer()) {
-            netInBuffer = ByteBuffer.allocateDirect(netBufSize);
-            netOutBuffer = ByteBuffer.allocateDirect(netBufSize);
+            netInBuffer = ByteBuffer.allocateDirect(DEFAULT_NET_BUFFER_SIZE);
+            netOutBuffer = ByteBuffer.allocateDirect(DEFAULT_NET_BUFFER_SIZE);
         } else {
-            netInBuffer = ByteBuffer.allocate(netBufSize);
-            netOutBuffer = ByteBuffer.allocate(netBufSize);
+            netInBuffer = ByteBuffer.allocate(DEFAULT_NET_BUFFER_SIZE);
+            netOutBuffer = ByteBuffer.allocate(DEFAULT_NET_BUFFER_SIZE);
         }
         handshakeReadCompletionHandler = new CompletionHandler<Integer, SocketWrapperBase<Nio2Channel>>() {
             @Override
@@ -114,18 +119,12 @@ public class SecureNio2Channel extends N
     public void reset(AsynchronousSocketChannel channel, SocketWrapperBase<Nio2Channel> socket)
             throws IOException {
         super.reset(channel, socket);
-        netOutBuffer.position(0);
-        netOutBuffer.limit(0);
-        netInBuffer.position(0);
-        netInBuffer.limit(0);
+        sniComplete = false;
         handshakeComplete = false;
         closed = false;
         closing = false;
         readPending = false;
         writePending = false;
-        //initiate handshake
-        sslEngine.beginHandshake();
-        handshakeStatus = sslEngine.getHandshakeStatus();
     }
 
 
@@ -309,7 +308,70 @@ public class SecureNio2Channel extends N
      * present and, if it is, what host name has been requested. Based on the
      * provided host name, configure the SSLEngine for this connection.
      */
-    private int processSNI() {
+    private int processSNI() throws IOException {
+        // If there is no data to process, trigger a read immediately. This is
+        // an optimisation for the typical case so we don't create an
+        // SNIExtractor only to discover there is no data to process
+        if (netInBuffer.position() == 0) {
+            sc.read(netInBuffer, socket, handshakeReadCompletionHandler);
+            return 1;
+        }
+
+        SNIExtractor extractor = new SNIExtractor(netInBuffer);
+
+        while (extractor.getResult() == SNIResult.UNDERFLOW) {
+            // extractor needed more data to process but netInBuffer was full so
+            // double the size of the buffer and read some more data.
+            log.info(sm.getString("channel.nio.ssl.expandNetInBuffer",
+                    Integer.toString(netInBuffer.capacity() * 2)));
+
+            netInBuffer = ByteBufferUtils.expand(netInBuffer);
+            sc.read(netInBuffer);
+            extractor = new SNIExtractor(netInBuffer);
+        }
+
+        String hostName = null;
+        switch (extractor.getResult()) {
+        case FOUND:
+            hostName = extractor.getSNIValue();
+            break;
+        case NOT_PRESENT:
+            // NO-OP
+            break;
+        case NEED_READ:
+            sc.read(netInBuffer, socket, handshakeReadCompletionHandler);
+            return 1;
+        case UNDERFLOW:
+            // Can't happen. Buffer would have been expanded above.
+            break;
+        }
+
+        // TODO: Extract the correct configuration for the requested host name
+        //       and set up the SSLEngine accordingly. At that point this can
+        //       become a debug level message.
+        log.info("SNI hostname was [" + hostName + "]");
+
+        sslEngine = endpoint.createSSLEngine();
+
+        // Ensure the application buffers (which have to be created earlier) are
+        // big enough.
+        bufHandler.expand(sslEngine.getSession().getApplicationBufferSize());
+        if (netOutBuffer.capacity() < sslEngine.getSession().getApplicationBufferSize()) {
+            // Info for now as we may need to increase DEFAULT_NET_BUFFER_SIZE
+            log.info(sm.getString("channel.nio.ssl.expandNetOutBuffer",
+                    Integer.toString(sslEngine.getSession().getApplicationBufferSize())));
+        }
+        netInBuffer = ByteBufferUtils.expand(netInBuffer, sslEngine.getSession().getPacketBufferSize());
+        netOutBuffer = ByteBufferUtils.expand(netOutBuffer, sslEngine.getSession().getPacketBufferSize());
+
+        // Set limit and position to expected values
+        netOutBuffer.position(0);
+        netOutBuffer.limit(0);
+
+        // Initiate handshake
+        sslEngine.beginHandshake();
+        handshakeStatus = sslEngine.getHandshakeStatus();
+
         return 0;
     }
 



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org