Added HTTPS support to the NIO connector. Works exactly like the Http11Protocol does...
authorfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Fri, 4 Aug 2006 21:13:05 +0000 (21:13 +0000)
committerfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Fri, 4 Aug 2006 21:13:05 +0000 (21:13 +0000)
Rollback info if this breaks something else, it should all be backwards compatible
revision:428882
Files:
  java/org/apache/coyote/http11/Http11NioProtocol.java
  java/org/apache/coyote/http11/Http11NioProcessor.java
  java/org/apache/coyote/http11/InternalNioInputBuffer.java
  java/org/apache/coyote/http11/InternalNioOutputBuffer.java
  java/org/apache/tomcat/util/net/SSLImplementation.java
  java/org/apache/tomcat/util/net/NioChannel.java
  java/org/apache/tomcat/util/net/jsse/JSSESupport.java
  java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java
  java/org/apache/tomcat/util/net/jsse/JSSEFactory.java
  java/org/apache/tomcat/util/net/SecureNioChannel.java
  java/org/apache/tomcat/util/net/NioEndpoint.java

git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk@428884 13f79535-47bb-0310-9956-ffa450edef68

java/org/apache/coyote/http11/Http11NioProcessor.java
java/org/apache/coyote/http11/Http11NioProtocol.java
java/org/apache/coyote/http11/InternalNioInputBuffer.java
java/org/apache/coyote/http11/InternalNioOutputBuffer.java
java/org/apache/tomcat/util/net/NioChannel.java [new file with mode: 0644]
java/org/apache/tomcat/util/net/NioEndpoint.java
java/org/apache/tomcat/util/net/SSLImplementation.java
java/org/apache/tomcat/util/net/SecureNioChannel.java [new file with mode: 0644]
java/org/apache/tomcat/util/net/jsse/JSSEFactory.java
java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java
java/org/apache/tomcat/util/net/jsse/JSSESupport.java

index f03587f..61482b9 100644 (file)
@@ -19,7 +19,7 @@ package org.apache.coyote.http11;
 import java.io.IOException;
 import java.io.InterruptedIOException;
 import java.net.InetAddress;
-import java.nio.channels.SocketChannel;
+import java.nio.channels.SelectionKey;
 import java.util.StringTokenizer;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
@@ -45,11 +45,12 @@ import org.apache.tomcat.util.buf.HexUtils;
 import org.apache.tomcat.util.buf.MessageBytes;
 import org.apache.tomcat.util.http.FastHttpDateFormat;
 import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.net.NioChannel;
 import org.apache.tomcat.util.net.NioEndpoint;
 import org.apache.tomcat.util.net.NioEndpoint.Handler;
 import org.apache.tomcat.util.net.NioEndpoint.Handler.SocketState;
+import org.apache.tomcat.util.net.SSLSupport;
 import org.apache.tomcat.util.res.StringManager;
-import java.nio.channels.SelectionKey;
 
 
 /**
@@ -73,6 +74,10 @@ public class Http11NioProcessor implements ActionHook {
     protected static StringManager sm =
         StringManager.getManager(Constants.Package);
 
+    /**
+     * SSL information.
+     */
+    protected SSLSupport sslSupport;
 
     // ----------------------------------------------------------- Constructors
 
@@ -99,7 +104,7 @@ public class Http11NioProcessor implements ActionHook {
         response.setOutputBuffer(outputBuffer);
         request.setResponse(response);
 
-        ssl = !"off".equalsIgnoreCase(endpoint.getSSLEngine());
+        ssl = endpoint.getSecure();
 
         initializeFilters();
 
@@ -217,7 +222,7 @@ public class Http11NioProcessor implements ActionHook {
     /**
      * Socket associated with the current connection.
      */
-    protected SocketChannel socket = null;
+    protected NioChannel socket = null;
 
 
     /**
@@ -747,7 +752,7 @@ public class Http11NioProcessor implements ActionHook {
             if (request.getAttribute("org.apache.tomcat.comet") == null) {
                 comet = false;
             }
-            SelectionKey key = socket.keyFor(endpoint.getPoller().getSelector());
+            SelectionKey key = socket.getIOChannel().keyFor(endpoint.getPoller().getSelector());
             if ( key != null ) {
                 NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment();
                 if ( attach!=null ) {
@@ -787,7 +792,7 @@ public class Http11NioProcessor implements ActionHook {
      *
      * @throws IOException error during an I/O operation
      */
-    public SocketState process(SocketChannel socket)
+    public SocketState process(NioChannel socket)
         throws IOException {
         RequestInfo rp = request.getRequestProcessor();
         rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
@@ -826,7 +831,7 @@ public class Http11NioProcessor implements ActionHook {
             // Parsing the request header
             try {
                 if( !disableUploadTimeout && keptAlive && soTimeout > 0 ) {
-                    socket.socket().setSoTimeout((int)soTimeout);
+                    socket.getIOChannel().socket().setSoTimeout((int)soTimeout);
                     inputBuffer.readTimeout = soTimeout;
                 }
                 if (!inputBuffer.parseRequestLine
@@ -842,7 +847,7 @@ public class Http11NioProcessor implements ActionHook {
                 request.setStartTime(System.currentTimeMillis());
                 keptAlive = true;
                 if (!disableUploadTimeout) {
-                    socket.socket().setSoTimeout((int)timeout);
+                    socket.getIOChannel().socket().setSoTimeout((int)timeout);
                     inputBuffer.readTimeout = soTimeout;
                 }
                 inputBuffer.parseHeaders();
@@ -892,7 +897,7 @@ public class Http11NioProcessor implements ActionHook {
                     if (request.getAttribute("org.apache.tomcat.comet") != null) {
                         comet = true;
                     }
-                    SelectionKey key = socket.keyFor(endpoint.getPoller().getSelector());
+                    SelectionKey key = socket.getIOChannel().keyFor(endpoint.getPoller().getSelector());
                     if (key != null) {
                         NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment();
                         if (attach != null)  {
@@ -1044,7 +1049,7 @@ public class Http11NioProcessor implements ActionHook {
 
             comet = false;
             cometClose = true;
-            SelectionKey key = socket.keyFor(endpoint.getPoller().getSelector());
+            SelectionKey key = socket.getIOChannel().keyFor(endpoint.getPoller().getSelector());
             if ( key != null ) {
                 NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment();
                 if ( attach!=null && attach.getComet()) {
@@ -1078,7 +1083,7 @@ public class Http11NioProcessor implements ActionHook {
 
             // Get remote host address
             if ((remoteAddr == null) && (socket != null)) {
-                InetAddress inetAddr = socket.socket().getInetAddress();
+                InetAddress inetAddr = socket.getIOChannel().socket().getInetAddress();
                 if (inetAddr != null) {
                     remoteAddr = inetAddr.getHostAddress();
                 }
@@ -1089,7 +1094,7 @@ public class Http11NioProcessor implements ActionHook {
 
             // Get local host name
             if ((localName == null) && (socket != null)) {
-                InetAddress inetAddr = socket.socket().getLocalAddress();
+                InetAddress inetAddr = socket.getIOChannel().socket().getLocalAddress();
                 if (inetAddr != null) {
                     localName = inetAddr.getHostName();
                 }
@@ -1100,7 +1105,7 @@ public class Http11NioProcessor implements ActionHook {
 
             // Get remote host name
             if ((remoteHost == null) && (socket != null)) {
-                InetAddress inetAddr = socket.socket().getInetAddress();
+                InetAddress inetAddr = socket.getIOChannel().socket().getInetAddress();
                 if (inetAddr != null) {
                     remoteHost = inetAddr.getHostName();
                 }
@@ -1117,102 +1122,71 @@ public class Http11NioProcessor implements ActionHook {
         } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) {
 
             if (localAddr == null)
-               localAddr = socket.socket().getLocalAddress().getHostAddress();
+               localAddr = socket.getIOChannel().socket().getLocalAddress().getHostAddress();
 
             request.localAddr().setString(localAddr);
 
         } else if (actionCode == ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE) {
 
             if ((remotePort == -1 ) && (socket !=null)) {
-                remotePort = socket.socket().getPort();
+                remotePort = socket.getIOChannel().socket().getPort();
             }
             request.setRemotePort(remotePort);
 
         } else if (actionCode == ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE) {
 
             if ((localPort == -1 ) && (socket !=null)) {
-                localPort = socket.socket().getLocalPort();
+                localPort = socket.getIOChannel().socket().getLocalPort();
             }
             request.setLocalPort(localPort);
 
         } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) {
 
-//            if (ssl && (socket != 0)) {
-//                try {
-//                    // Cipher suite
-//                    Object sslO = SSLSocket.getInfoS(socket, SSL.SSL_INFO_CIPHER);
-//                    if (sslO != null) {
-//                        request.setAttribute
-//                            (NioEndpoint.CIPHER_SUITE_KEY, sslO);
-//                    }
-//                    // Client certificate chain if present
-//                    int certLength = SSLSocket.getInfoI(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN);
-//                    X509Certificate[] certs = null;
-//                    if (certLength > 0) {
-//                        certs = new X509Certificate[certLength];
-//                        for (int i = 0; i < certLength; i++) {
-//                            byte[] data = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i);
-//                            CertificateFactory cf =
-//                                CertificateFactory.getInstance("X.509");
-//                            ByteArrayInputStream stream = new ByteArrayInputStream(data);
-//                            certs[i] = (X509Certificate) cf.generateCertificate(stream);
-//                        }
-//                    }
-//                    if (certs != null) {
-//                        request.setAttribute
-//                            (NioEndpoint.CERTIFICATE_KEY, certs);
-//                    }
-//                    // User key size
-//                    sslO = new Integer(SSLSocket.getInfoI(socket, SSL.SSL_INFO_CIPHER_USEKEYSIZE));
-//                    if (sslO != null) {
-//                        request.setAttribute
-//                            (NioEndpoint.KEY_SIZE_KEY, sslO);
-//                    }
-//                    // SSL session ID
-//                    sslO = SSLSocket.getInfoS(socket, SSL.SSL_INFO_SESSION_ID);
-//                    if (sslO != null) {
-//                        request.setAttribute
-//                            (NioEndpoint.SESSION_ID_KEY, sslO);
-//                    }
-//                } catch (Exception e) {
-//                    log.warn(sm.getString("http11processor.socket.ssl"), e);
-//                }
-//            }
+            try {
+                if (sslSupport != null) {
+                    Object sslO = sslSupport.getCipherSuite();
+                    if (sslO != null)
+                        request.setAttribute
+                            (SSLSupport.CIPHER_SUITE_KEY, sslO);
+                    sslO = sslSupport.getPeerCertificateChain(false);
+                    if (sslO != null)
+                        request.setAttribute
+                            (SSLSupport.CERTIFICATE_KEY, sslO);
+                    sslO = sslSupport.getKeySize();
+                    if (sslO != null)
+                        request.setAttribute
+                            (SSLSupport.KEY_SIZE_KEY, sslO);
+                    sslO = sslSupport.getSessionId();
+                    if (sslO != null)
+                        request.setAttribute
+                            (SSLSupport.SESSION_ID_KEY, sslO);
+                }
+            } catch (Exception e) {
+                log.warn(sm.getString("http11processor.socket.ssl"), e);
+            }
 
         } else if (actionCode == ActionCode.ACTION_REQ_SSL_CERTIFICATE) {
 
-//            if (ssl && (socket != 0)) {
-//                 // Consume and buffer the request body, so that it does not
-//                 // interfere with the client's handshake messages
-//                InputFilter[] inputFilters = inputBuffer.getFilters();
-//                ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER])
-//                    .setLimit(maxSavePostSize);
-//                inputBuffer.addActiveFilter
-//                    (inputFilters[Constants.BUFFERED_FILTER]);
-//                try {
-//                    // Renegociate certificates
-//                    SSLSocket.renegotiate(socket);
-//                    // Client certificate chain if present
-//                    int certLength = SSLSocket.getInfoI(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN);
-//                    X509Certificate[] certs = null;
-//                    if (certLength > 0) {
-//                        certs = new X509Certificate[certLength];
-//                        for (int i = 0; i < certLength; i++) {
-//                            byte[] data = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i);
-//                            CertificateFactory cf =
-//                                CertificateFactory.getInstance("X.509");
-//                            ByteArrayInputStream stream = new ByteArrayInputStream(data);
-//                            certs[i] = (X509Certificate) cf.generateCertificate(stream);
-//                        }
-//                    }
-//                    if (certs != null) {
-//                        request.setAttribute
-//                            (NioEndpoint.CERTIFICATE_KEY, certs);
-//                    }
-//                } catch (Exception e) {
-//                    log.warn(sm.getString("http11processor.socket.ssl"), e);
-//                }
-//            }
+            if( sslSupport != null) {
+                /*
+                 * Consume and buffer the request body, so that it does not
+                 * interfere with the client's handshake messages
+                 */
+                InputFilter[] inputFilters = inputBuffer.getFilters();
+                ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER])
+                    .setLimit(maxSavePostSize);
+                inputBuffer.addActiveFilter
+                    (inputFilters[Constants.BUFFERED_FILTER]);
+                try {
+                    Object sslO = sslSupport.getPeerCertificateChain(true);
+                    if( sslO != null) {
+                        request.setAttribute
+                            (SSLSupport.CERTIFICATE_KEY, sslO);
+                    }
+                } catch (Exception e) {
+                    log.warn(sm.getString("http11processor.socket.ssl"), e);
+                }
+            }
 
         } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) {
             ByteChunk body = (ByteChunk) param;
@@ -1240,6 +1214,9 @@ public class Http11NioProcessor implements ActionHook {
         this.adapter = adapter;
     }
 
+    public void setSslSupport(SSLSupport sslSupport) {
+        this.sslSupport = sslSupport;
+    }
 
     /**
      * Get the associated adapter.
@@ -1250,6 +1227,9 @@ public class Http11NioProcessor implements ActionHook {
         return adapter;
     }
 
+    public SSLSupport getSslSupport() {
+        return sslSupport;
+    }
 
     // ------------------------------------------------------ Protected Methods
 
index 467849d..e5792b8 100644 (file)
@@ -18,7 +18,6 @@ package org.apache.coyote.http11;
 
 import java.net.InetAddress;
 import java.net.URLEncoder;
-import java.nio.channels.SocketChannel;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.concurrent.ConcurrentHashMap;
@@ -37,6 +36,9 @@ import org.apache.tomcat.util.modeler.Registry;
 import org.apache.tomcat.util.net.NioEndpoint;
 import org.apache.tomcat.util.net.NioEndpoint.Handler;
 import org.apache.tomcat.util.res.StringManager;
+import org.apache.tomcat.util.net.NioChannel;
+import org.apache.tomcat.util.net.SSLImplementation;
+import org.apache.tomcat.util.net.SecureNioChannel;
 
 
 /**
@@ -50,6 +52,8 @@ import org.apache.tomcat.util.res.StringManager;
  */
 public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration
 {
+    protected SSLImplementation sslImplementation = null;
+    
     public Http11NioProtocol() {
         cHandler = new Http11ConnectionHandler( this );
         setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
@@ -113,9 +117,13 @@ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration
     public void init() throws Exception {
         ep.setName(getName());
         ep.setHandler(cHandler);
-
+        ep.setReadBufSize(getMaxHttpHeaderSize());
+        ep.setWriteBufSize(getMaxHttpHeaderSize());
         try {
             ep.init();
+            
+            sslImplementation = SSLImplementation.getInstance("org.apache.tomcat.util.net.jsse.JSSEImplementation");
+            
         } catch (Exception ex) {
             log.error(sm.getString("http11protocol.endpoint.initerror"), ex);
             throw ex;
@@ -188,7 +196,7 @@ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration
 
     // -------------------- Properties--------------------
     protected NioEndpoint ep=new NioEndpoint();
-    protected boolean secure;
+    protected boolean secure = false;
 
     protected Hashtable attributes = new Hashtable();
 
@@ -430,6 +438,7 @@ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration
     }
 
     public void setSecure( boolean b ) {
+        ep.setSecure(b);
         secure=b;
         setAttribute("secure", "" + b);
     }
@@ -489,96 +498,27 @@ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration
 
     // --------------------  SSL related properties --------------------
 
-    /**
-     * SSL engine.
-     */
-    public String getSSLEngine() { return ep.getSSLEngine(); }
-    public void setSSLEngine(String SSLEngine) { ep.setSSLEngine(SSLEngine); }
-
-
-    /**
-     * SSL protocol.
-     */
-    public String getSSLProtocol() { return ep.getSSLProtocol(); }
-    public void setSSLProtocol(String SSLProtocol) { ep.setSSLProtocol(SSLProtocol); }
-
-
-    /**
-     * SSL password (if a cert is encrypted, and no password has been provided, a callback
-     * will ask for a password).
-     */
-    public String getSSLPassword() { return ep.getSSLPassword(); }
-    public void setSSLPassword(String SSLPassword) { ep.setSSLPassword(SSLPassword); }
-
-
-    /**
-     * SSL cipher suite.
-     */
-    public String getSSLCipherSuite() { return ep.getSSLCipherSuite(); }
-    public void setSSLCipherSuite(String SSLCipherSuite) { ep.setSSLCipherSuite(SSLCipherSuite); }
-
-
-    /**
-     * SSL certificate file.
-     */
-    public String getSSLCertificateFile() { return ep.getSSLCertificateFile(); }
-    public void setSSLCertificateFile(String SSLCertificateFile) { ep.setSSLCertificateFile(SSLCertificateFile); }
-
-
-    /**
-     * SSL certificate key file.
-     */
-    public String getSSLCertificateKeyFile() { return ep.getSSLCertificateKeyFile(); }
-    public void setSSLCertificateKeyFile(String SSLCertificateKeyFile) { ep.setSSLCertificateKeyFile(SSLCertificateKeyFile); }
-
-
-    /**
-     * SSL certificate chain file.
-     */
-    public String getSSLCertificateChainFile() { return ep.getSSLCertificateChainFile(); }
-    public void setSSLCertificateChainFile(String SSLCertificateChainFile) { ep.setSSLCertificateChainFile(SSLCertificateChainFile); }
-
-
-    /**
-     * SSL CA certificate path.
-     */
-    public String getSSLCACertificatePath() { return ep.getSSLCACertificatePath(); }
-    public void setSSLCACertificatePath(String SSLCACertificatePath) { ep.setSSLCACertificatePath(SSLCACertificatePath); }
-
-
-    /**
-     * SSL CA certificate file.
-     */
-    public String getSSLCACertificateFile() { return ep.getSSLCACertificateFile(); }
-    public void setSSLCACertificateFile(String SSLCACertificateFile) { ep.setSSLCACertificateFile(SSLCACertificateFile); }
-
-
-    /**
-     * SSL CA revocation path.
-     */
-    public String getSSLCARevocationPath() { return ep.getSSLCARevocationPath(); }
-    public void setSSLCARevocationPath(String SSLCARevocationPath) { ep.setSSLCARevocationPath(SSLCARevocationPath); }
-
-
-    /**
-     * SSL CA revocation file.
-     */
-    public String getSSLCARevocationFile() { return ep.getSSLCARevocationFile(); }
-    public void setSSLCARevocationFile(String SSLCARevocationFile) { ep.setSSLCARevocationFile(SSLCARevocationFile); }
-
-
-    /**
-     * SSL verify client.
-     */
-    public String getSSLVerifyClient() { return ep.getSSLVerifyClient(); }
-    public void setSSLVerifyClient(String SSLVerifyClient) { ep.setSSLVerifyClient(SSLVerifyClient); }
-
-
-    /**
-     * SSL verify depth.
-     */
-    public int getSSLVerifyDepth() { return ep.getSSLVerifyDepth(); }
-    public void setSSLVerifyDepth(int SSLVerifyDepth) { ep.setSSLVerifyDepth(SSLVerifyDepth); }
+    public String getKeystoreFile() { return ep.getKeystoreFile();}
+    public void setKeystoreFile(String s ) { ep.setKeystoreFile(s);}
+    
+    public String getAlgorithm() { return ep.getAlgorithm();}
+    public void setAlgorithm(String s ) { ep.setAlgorithm(s);}
+    
+    public boolean getClientAuth() { return ep.getClientAuth();}
+    public void setClientAuth(boolean b ) { ep.setClientAuth(b);}
+    
+    public String getKeystorePass() { return ep.getKeystorePass();}
+    public void setKeystorePass(String s ) { ep.setKeystorePass(s);}
+    
+    public String getKeystoreType() { return ep.getKeystoreType();}
+    public void setKeystoreType(String s ) { ep.setKeystoreType(s);}
+    
+    public String getSslProtocol() { return ep.getSslProtocol();}
+    public void setSslProtocol(String s) { ep.setSslProtocol(s);}
+    
+    public String getCiphers() { return ep.getCiphers();}
+    public void setCiphers(String s) { ep.setCiphers(s);}
+    
 
     // --------------------  Connection handler --------------------
 
@@ -590,8 +530,8 @@ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration
 
         protected ThreadLocal<Http11NioProcessor> localProcessor = 
             new ThreadLocal<Http11NioProcessor>();
-        protected ConcurrentHashMap<SocketChannel, Http11NioProcessor> connections =
-            new ConcurrentHashMap<SocketChannel, Http11NioProcessor>();
+        protected ConcurrentHashMap<NioChannel, Http11NioProcessor> connections =
+            new ConcurrentHashMap<NioChannel, Http11NioProcessor>();
         protected java.util.Stack<Http11NioProcessor> recycledProcessors = 
             new java.util.Stack<Http11NioProcessor>();
 
@@ -599,7 +539,7 @@ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration
             this.proto = proto;
         }
 
-        public SocketState event(SocketChannel socket, boolean error) {
+        public SocketState event(NioChannel socket, boolean error) {
             Http11NioProcessor result = connections.get(socket);
 
             SocketState state = SocketState.CLOSED; 
@@ -638,7 +578,7 @@ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration
             return state;
         }
 
-        public SocketState process(SocketChannel socket) {
+        public SocketState process(NioChannel socket) {
             Http11NioProcessor processor = null;
             try {
                 processor = (Http11NioProcessor) localProcessor.get();
@@ -651,40 +591,23 @@ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration
                     }
                 }
                 if (processor == null) {
-                    processor =
-                        new Http11NioProcessor(proto.maxHttpHeaderSize, proto.ep);
-                    processor.setAdapter(proto.adapter);
-                    processor.setMaxKeepAliveRequests(proto.maxKeepAliveRequests);
-                    processor.setTimeout(proto.timeout);
-                    processor.setDisableUploadTimeout(proto.disableUploadTimeout);
-                    processor.setCompression(proto.compression);
-                    processor.setCompressionMinSize(proto.compressionMinSize);
-                    processor.setNoCompressionUserAgents(proto.noCompressionUserAgents);
-                    processor.setCompressableMimeTypes(proto.compressableMimeTypes);
-                    processor.setRestrictedUserAgents(proto.restrictedUserAgents);
-                    processor.setSocketBuffer(proto.socketBuffer);
-                    processor.setMaxSavePostSize(proto.maxSavePostSize);
-                    processor.setServer(proto.server);
-                    localProcessor.set(processor);
-                    if (proto.getDomain() != null) {
-                        synchronized (this) {
-                            try {
-                                RequestInfo rp = processor.getRequest().getRequestProcessor();
-                                rp.setGlobalProcessor(global);
-                                ObjectName rpName = new ObjectName
-                                (proto.getDomain() + ":type=RequestProcessor,worker="
-                                        + proto.getName() + ",name=HttpRequest" + count++);
-                                Registry.getRegistry(null, null).registerComponent(rp, rpName, null);
-                            } catch (Exception e) {
-                                log.warn("Error registering request");
-                            }
-                        }
-                    }
+                    processor = createProcessor();
                 }
 
                 if (processor instanceof ActionHook) {
                     ((ActionHook) processor).action(ActionCode.ACTION_START, null);
                 }
+                
+                
+                if (proto.ep.getSecure() && (proto.sslImplementation != null)) {
+                    if (socket instanceof SecureNioChannel) {
+                        SecureNioChannel ch = (SecureNioChannel)socket;
+                        processor.setSslSupport(proto.sslImplementation.getSSLSupport(ch.getSslEngine().getSession()));
+                    }else processor.setSslSupport(null);
+                } else {
+                    processor.setSslSupport(null);
+                }
+
 
                 SocketState state = processor.process(socket);
                 if (state == SocketState.LONG) {
@@ -720,6 +643,38 @@ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration
             }
             return SocketState.CLOSED;
         }
+
+        public Http11NioProcessor createProcessor() {
+            Http11NioProcessor processor = new Http11NioProcessor(proto.maxHttpHeaderSize, proto.ep);
+            processor.setAdapter(proto.adapter);
+            processor.setMaxKeepAliveRequests(proto.maxKeepAliveRequests);
+            processor.setTimeout(proto.timeout);
+            processor.setDisableUploadTimeout(proto.disableUploadTimeout);
+            processor.setCompression(proto.compression);
+            processor.setCompressionMinSize(proto.compressionMinSize);
+            processor.setNoCompressionUserAgents(proto.noCompressionUserAgents);
+            processor.setCompressableMimeTypes(proto.compressableMimeTypes);
+            processor.setRestrictedUserAgents(proto.restrictedUserAgents);
+            processor.setSocketBuffer(proto.socketBuffer);
+            processor.setMaxSavePostSize(proto.maxSavePostSize);
+            processor.setServer(proto.server);
+            localProcessor.set(processor);
+            if (proto.getDomain() != null) {
+                synchronized (this) {
+                    try {
+                        RequestInfo rp = processor.getRequest().getRequestProcessor();
+                        rp.setGlobalProcessor(global);
+                        ObjectName rpName = new ObjectName
+                        (proto.getDomain() + ":type=RequestProcessor,worker="
+                                + proto.getName() + ",name=HttpRequest" + count++);
+                        Registry.getRegistry(null, null).registerComponent(rp, rpName, null);
+                    } catch (Exception e) {
+                        log.warn("Error registering request");
+                    }
+                }
+            }
+            return processor;
+        }
     }
 
     protected static org.apache.commons.logging.Log log
index f34a3f1..247b128 100644 (file)
@@ -22,7 +22,6 @@ import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.CancelledKeyException;
 import java.nio.channels.SelectionKey;
-import java.nio.channels.SocketChannel;
 
 import org.apache.coyote.InputBuffer;
 import org.apache.coyote.Request;
@@ -32,6 +31,7 @@ import org.apache.tomcat.util.http.MimeHeaders;
 import org.apache.tomcat.util.net.NioEndpoint.KeyAttachment;
 import org.apache.tomcat.util.net.NioEndpoint.Poller;
 import org.apache.tomcat.util.res.StringManager;
+import org.apache.tomcat.util.net.NioChannel;
 
 /**
  * Implementation of InputBuffer which provides HTTP request header parsing as
@@ -59,11 +59,11 @@ public class InternalNioInputBuffer implements InputBuffer {
         headers = request.getMimeHeaders();
 
         buf = new byte[headerBufferSize];
-        if (headerBufferSize < (8 * 1024)) {
-            bbuf = ByteBuffer.allocateDirect(6 * 1500);
-        } else {
-            bbuf = ByteBuffer.allocateDirect((headerBufferSize / 1500 + 1) * 1500);
-        }
+//        if (headerBufferSize < (8 * 1024)) {
+//            bbuf = ByteBuffer.allocateDirect(6 * 1500);
+//        } else {
+//            bbuf = ByteBuffer.allocateDirect((headerBufferSize / 1500 + 1) * 1500);
+//        }
 
         inputStreamInputBuffer = new SocketInputBuffer();
 
@@ -145,16 +145,11 @@ public class InternalNioInputBuffer implements InputBuffer {
     protected int end;
 
 
-    /**
-     * Direct byte buffer used to perform actual reading.
-     */
-    protected ByteBuffer bbuf;
-
 
     /**
      * Underlying socket.
      */
-    protected SocketChannel socket;
+    protected NioChannel socket;
 
 
     /**
@@ -195,7 +190,7 @@ public class InternalNioInputBuffer implements InputBuffer {
     /**
      * Set the underlying socket.
      */
-    public void setSocket(SocketChannel socket) {
+    public void setSocket(NioChannel socket) {
         this.socket = socket;
     }
 
@@ -203,7 +198,7 @@ public class InternalNioInputBuffer implements InputBuffer {
     /**
      * Get the underlying socket input stream.
      */
-    public SocketChannel getSocket() {
+    public NioChannel getSocket() {
         return socket;
     }
 
@@ -548,13 +543,14 @@ public class InternalNioInputBuffer implements InputBuffer {
         long start = System.currentTimeMillis();
         boolean timedOut = false;
         do {
-            bbuf.clear();
-            nRead = socket.read(bbuf);
+            
+            socket.getBufHandler().getReadBuffer().clear();
+            nRead = socket.read(socket.getBufHandler().getReadBuffer());
             if (nRead > 0) {
-                bbuf.flip();
-                bbuf.limit(nRead);
+                socket.getBufHandler().getReadBuffer().flip();
+                socket.getBufHandler().getReadBuffer().limit(nRead);
                 expand(nRead + pos);
-                bbuf.get(buf, pos, nRead);
+                socket.getBufHandler().getReadBuffer().get(buf, pos, nRead);
                 lastValid = pos + nRead;
                 return true;
             } else if (nRead == -1) {
@@ -564,7 +560,7 @@ public class InternalNioInputBuffer implements InputBuffer {
             timedOut = (readTimeout != -1) && ((System.currentTimeMillis()-start)>this.readTimeout);
             if ( !timedOut && nRead == 0 ) 
                 try {
-                    final SelectionKey key = socket.keyFor(poller.getSelector());
+                    final SelectionKey key = socket.getIOChannel().keyFor(poller.getSelector());
                     final KeyAttachment att = (KeyAttachment)key.attachment();
                     //to do, add in a check, we might have just timed out on the wait,
                     //so there is no need to register us again.
@@ -596,7 +592,7 @@ public class InternalNioInputBuffer implements InputBuffer {
                             KeyAttachment ka = (KeyAttachment)key.attachment();
                             ka.setError(true); //set to collect this socket immediately
                         }
-                        socket.socket().close();
+                        socket.getIOChannel().socket().close();
                         socket.close();
                         att.setWakeUp(false);
                     } catch (Exception ignore) {}
index 2b76a4c..673bffe 100644 (file)
@@ -18,7 +18,6 @@ package org.apache.coyote.http11;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
-import java.nio.channels.SocketChannel;
 
 import org.apache.coyote.ActionCode;
 import org.apache.coyote.OutputBuffer;
@@ -32,6 +31,7 @@ import org.apache.tomcat.util.res.StringManager;
 import java.nio.channels.SelectionKey;
 import org.apache.tomcat.util.net.NioEndpoint;
 import java.nio.channels.Selector;
+import org.apache.tomcat.util.net.NioChannel;
 
 /**
  * Output buffer.
@@ -74,7 +74,7 @@ public class InternalNioOutputBuffer
         } else {
             bbufLimit = (headerBufferSize / 1500 + 1) * 1500;
         }
-        bbuf = ByteBuffer.allocateDirect(bbufLimit);
+        //bbuf = ByteBuffer.allocateDirect(bbufLimit);
 
         outputStreamOutputBuffer = new SocketOutputBuffer();
 
@@ -143,7 +143,7 @@ public class InternalNioOutputBuffer
     /**
      * Underlying socket.
      */
-    protected SocketChannel socket;
+    protected NioChannel socket;
 
 
     /**
@@ -171,11 +171,6 @@ public class InternalNioOutputBuffer
     protected int lastActiveFilter;
 
 
-    /**
-     * Direct byte buffer used for writing.
-     */
-    protected ByteBuffer bbuf = null;
-
 
     // ------------------------------------------------------------- Properties
 
@@ -183,7 +178,7 @@ public class InternalNioOutputBuffer
     /**
      * Set the underlying socket.
      */
-    public void setSocket(SocketChannel socket) {
+    public void setSocket(NioChannel socket) {
         this.socket = socket;
     }
 
@@ -194,7 +189,7 @@ public class InternalNioOutputBuffer
     /**
      * Get the underlying socket input stream.
      */
-    public SocketChannel getSocket() {
+    public NioChannel getSocket() {
         return socket;
     }
     /**
@@ -316,7 +311,7 @@ public class InternalNioOutputBuffer
 
         // Recycle Request object
         response.recycle();
-        bbuf.clear();
+        socket.getBufHandler().getWriteBuffer().clear();
 
         socket = null;
         pos = 0;
@@ -405,7 +400,7 @@ public class InternalNioOutputBuffer
         while ( bytebuffer.hasRemaining() ) {
             int written = socket.write(bytebuffer);
         }
-        bbuf.clear();
+        socket.getBufHandler().getWriteBuffer().clear();
         this.total = 0;
     } 
 
@@ -571,10 +566,10 @@ public class InternalNioOutputBuffer
 
     int total = 0;
     private synchronized void addToBB(byte[] buf, int offset, int length) throws IOException {
-        if (bbuf.capacity() <= (offset + length)) {
+        if (socket.getBufHandler().getWriteBuffer().capacity() <= (offset + length)) {
             flushBuffer();
         }
-        bbuf.put(buf, offset, length);
+        socket.getBufHandler().getWriteBuffer().put(buf, offset, length);
         total += length;
     }
 
@@ -715,15 +710,15 @@ public class InternalNioOutputBuffer
         throws IOException {
 
         //prevent timeout for async,
-        SelectionKey key = socket.keyFor(selector);
+        SelectionKey key = socket.getIOChannel().keyFor(selector);
         if (key != null) {
             NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment();
             attach.access();
         }
 
         //write to the socket, if there is anything to write
-        if (bbuf.position() > 0) {
-            writeToSocket(bbuf,true);
+        if (socket.getBufHandler().getWriteBuffer().position() > 0) {
+            writeToSocket(socket.getBufHandler().getWriteBuffer(),true);
         }
     }
 
@@ -750,11 +745,11 @@ public class InternalNioOutputBuffer
             byte[] b = chunk.getBuffer();
             while (len > 0) {
                 int thisTime = len;
-                if (bbuf.position() == bbuf.capacity()) {
+                if (socket.getBufHandler().getWriteBuffer().position() == socket.getBufHandler().getWriteBuffer().capacity()) {
                     flushBuffer();
                 }
-                if (thisTime > bbuf.capacity() - bbuf.position()) {
-                    thisTime = bbuf.capacity() - bbuf.position();
+                if (thisTime > socket.getBufHandler().getWriteBuffer().capacity() - socket.getBufHandler().getWriteBuffer().position()) {
+                    thisTime = socket.getBufHandler().getWriteBuffer().capacity() - socket.getBufHandler().getWriteBuffer().position();
                 }
                 addToBB(b,start,thisTime);
                 len = len - thisTime;
diff --git a/java/org/apache/tomcat/util/net/NioChannel.java b/java/org/apache/tomcat/util/net/NioChannel.java
new file mode 100644 (file)
index 0000000..5360ffe
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ *  Copyright 2005-2006 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.tomcat.util.net;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ByteChannel;
+import java.nio.channels.SocketChannel;
+
+import org.apache.tomcat.util.net.SecureNioChannel.ApplicationBufferHandler;
+/**
+ * 
+ * Base class for a SocketChannel wrapper used by the endpoint.
+ * This way, logic for a SSL socket channel remains the same as for
+ * a non SSL, making sure we don't need to code for any exception cases.
+ * 
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class NioChannel implements ByteChannel{
+    
+    protected static ByteBuffer emptyBuf = ByteBuffer.allocate(0);
+
+    protected SocketChannel sc = null;
+
+    protected ApplicationBufferHandler bufHandler;
+
+    public NioChannel(SocketChannel channel, ApplicationBufferHandler bufHandler) throws IOException {
+        this.sc = channel;
+        this.bufHandler = bufHandler;
+    }
+
+
+    /**
+     * Closes this channel.
+     *
+     * @throws IOException If an I/O error occurs
+     * @todo Implement this java.nio.channels.Channel method
+     */
+    public void close() throws IOException {
+        sc.close();
+    }
+
+    public void close(boolean force) throws IOException {
+        close();
+    }
+    /**
+     * Tells whether or not this channel is open.
+     *
+     * @return <tt>true</tt> if, and only if, this channel is open
+     * @todo Implement this java.nio.channels.Channel method
+     */
+    public boolean isOpen() {
+        return sc.isOpen();
+    }
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffer.
+     *
+     * @param src The buffer from which bytes are to be retrieved
+     * @return The number of bytes written, possibly zero
+     * @throws IOException If some other I/O error occurs
+     * @todo Implement this java.nio.channels.WritableByteChannel method
+     */
+    public int write(ByteBuffer src) throws IOException {
+        return sc.write(src);
+    }
+
+    /**
+     * Reads a sequence of bytes from this channel into the given buffer.
+     *
+     * @param dst The buffer into which bytes are to be transferred
+     * @return The number of bytes read, possibly zero, or <tt>-1</tt> if the channel has reached end-of-stream
+     * @throws IOException If some other I/O error occurs
+     * @todo Implement this java.nio.channels.ReadableByteChannel method
+     */
+    public int read(ByteBuffer dst) throws IOException {
+        return sc.read(dst);
+    }
+
+
+    /**
+     * getBufHandler
+     *
+     * @return ApplicationBufferHandler
+     * @todo Implement this org.apache.tomcat.util.net.SecureNioChannel method
+     */
+    public ApplicationBufferHandler getBufHandler() {
+        return bufHandler;
+    }
+
+    /**
+     * getIOChannel
+     *
+     * @return SocketChannel
+     * @todo Implement this org.apache.tomcat.util.net.SecureNioChannel method
+     */
+    public SocketChannel getIOChannel() {
+        return sc;
+    }
+
+    /**
+     * isClosing
+     *
+     * @return boolean
+     * @todo Implement this org.apache.tomcat.util.net.SecureNioChannel method
+     */
+    public boolean isClosing() {
+        return false;
+    }
+
+    /**
+     * isInitHandshakeComplete
+     *
+     * @return boolean
+     * @todo Implement this org.apache.tomcat.util.net.SecureNioChannel method
+     */
+    public boolean isInitHandshakeComplete() {
+        return true;
+    }
+    
+    public int handshake(boolean read, boolean write) throws IOException {
+        return 0;
+    }
+
+
+}
\ No newline at end of file
index 3c15e8a..38894ab 100644 (file)
 
 package org.apache.tomcat.util.net;
 
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
 import java.nio.channels.CancelledKeyException;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
 import java.nio.channels.ServerSocketChannel;
 import java.nio.channels.SocketChannel;
+import java.security.KeyStore;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.Set;
 import java.util.concurrent.Executor;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.TrustManagerFactory;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.tomcat.jni.SSL;
+import org.apache.tomcat.util.net.SecureNioChannel.ApplicationBufferHandler;
 import org.apache.tomcat.util.res.StringManager;
 
 /**
@@ -128,12 +135,9 @@ public class NioEndpoint {
     protected int sequence = 0;
 
 
-    /**
-     * Root APR memory pool.
-     */
-    protected long rootPool = 0;
-
-
+    protected int readBufSize = 8192;
+    protected int writeBufSize = 8192;
+    
     /**
      * Server socket "pointer".
      */
@@ -146,11 +150,7 @@ public class NioEndpoint {
     protected long serverSockPool = 0;
 
 
-    /**
-     * SSL context.
-     */
-    protected long sslContext = 0;
-
+    
 
     // ------------------------------------------------------------- Properties
 
@@ -341,112 +341,51 @@ public class NioEndpoint {
      */
     public int getMinSpareThreads() { return 0; }
 
+    // --------------------  SSL related properties --------------------
+    protected String keystoreFile = System.getProperty("user.home")+"/.keystore";
+    public String getKeystoreFile() { return keystoreFile;}
+    public void setKeystoreFile(String s ) { this.keystoreFile = s;}
 
-    /**
-     * SSL engine.
-     */
-    protected String SSLEngine = "off";
-    public String getSSLEngine() { return SSLEngine; }
-    public void setSSLEngine(String SSLEngine) { this.SSLEngine = SSLEngine; }
-
-
-    /**
-     * SSL protocols.
-     */
-    protected String SSLProtocol = "all";
-    public String getSSLProtocol() { return SSLProtocol; }
-    public void setSSLProtocol(String SSLProtocol) { this.SSLProtocol = SSLProtocol; }
-
-
-    /**
-     * SSL password (if a cert is encrypted, and no password has been provided, a callback
-     * will ask for a password).
-     */
-    protected String SSLPassword = null;
-    public String getSSLPassword() { return SSLPassword; }
-    public void setSSLPassword(String SSLPassword) { this.SSLPassword = SSLPassword; }
-
-
-    /**
-     * SSL cipher suite.
-     */
-    protected String SSLCipherSuite = "ALL";
-    public String getSSLCipherSuite() { return SSLCipherSuite; }
-    public void setSSLCipherSuite(String SSLCipherSuite) { this.SSLCipherSuite = SSLCipherSuite; }
-
-
-    /**
-     * SSL certificate file.
-     */
-    protected String SSLCertificateFile = null;
-    public String getSSLCertificateFile() { return SSLCertificateFile; }
-    public void setSSLCertificateFile(String SSLCertificateFile) { this.SSLCertificateFile = SSLCertificateFile; }
-
-
-    /**
-     * SSL certificate key file.
-     */
-    protected String SSLCertificateKeyFile = null;
-    public String getSSLCertificateKeyFile() { return SSLCertificateKeyFile; }
-    public void setSSLCertificateKeyFile(String SSLCertificateKeyFile) { this.SSLCertificateKeyFile = SSLCertificateKeyFile; }
-
-
-    /**
-     * SSL certificate chain file.
-     */
-    protected String SSLCertificateChainFile = null;
-    public String getSSLCertificateChainFile() { return SSLCertificateChainFile; }
-    public void setSSLCertificateChainFile(String SSLCertificateChainFile) { this.SSLCertificateChainFile = SSLCertificateChainFile; }
-
-
-    /**
-     * SSL CA certificate path.
-     */
-    protected String SSLCACertificatePath = null;
-    public String getSSLCACertificatePath() { return SSLCACertificatePath; }
-    public void setSSLCACertificatePath(String SSLCACertificatePath) { this.SSLCACertificatePath = SSLCACertificatePath; }
-
-
-    /**
-     * SSL CA certificate file.
-     */
-    protected String SSLCACertificateFile = null;
-    public String getSSLCACertificateFile() { return SSLCACertificateFile; }
-    public void setSSLCACertificateFile(String SSLCACertificateFile) { this.SSLCACertificateFile = SSLCACertificateFile; }
-
-
-    /**
-     * SSL CA revocation path.
-     */
-    protected String SSLCARevocationPath = null;
-    public String getSSLCARevocationPath() { return SSLCARevocationPath; }
-    public void setSSLCARevocationPath(String SSLCARevocationPath) { this.SSLCARevocationPath = SSLCARevocationPath; }
-
-
-    /**
-     * SSL CA revocation file.
-     */
-    protected String SSLCARevocationFile = null;
-    public String getSSLCARevocationFile() { return SSLCARevocationFile; }
-    public void setSSLCARevocationFile(String SSLCARevocationFile) { this.SSLCARevocationFile = SSLCARevocationFile; }
-
+    protected String algorithm = "SunX509";
+    public String getAlgorithm() { return algorithm;}
+    public void setAlgorithm(String s ) { this.algorithm = s;}
 
-    /**
-     * SSL verify client.
-     */
-    protected String SSLVerifyClient = "none";
-    public String getSSLVerifyClient() { return SSLVerifyClient; }
-    public void setSSLVerifyClient(String SSLVerifyClient) { this.SSLVerifyClient = SSLVerifyClient; }
+    protected boolean clientAuth = false;
+    public boolean getClientAuth() { return clientAuth;}
+    public void setClientAuth(boolean b ) { this.clientAuth = b;}
+    
+    protected String keystorePass = "changeit";
+    public String getKeystorePass() { return keystorePass;}
+    public void setKeystorePass(String s ) { this.keystorePass = s;}
+    
+    protected String keystoreType = "JKS";
+    public String getKeystoreType() { return keystoreType;}
+    public void setKeystoreType(String s ) { this.keystoreType = s;}
 
+    protected String sslProtocol = "TLS";
+    public String getSslProtocol() { return sslProtocol;}
+    public void setSslProtocol(String s) { sslProtocol = s;}
+    
+    protected String ciphers = null;
+    public String getCiphers() { return ciphers;}
+    public void setCiphers(String s) { ciphers = s;}
+    
+    protected boolean secure = false;
+    public boolean getSecure() { return secure;}
+    public void setSecure(boolean b) { secure = b;}
 
-    /**
-     * SSL verify depth.
-     */
-    protected int SSLVerifyDepth = 10;
-    public int getSSLVerifyDepth() { return SSLVerifyDepth; }
-    public void setSSLVerifyDepth(int SSLVerifyDepth) { this.SSLVerifyDepth = SSLVerifyDepth; }
+    public void setWriteBufSize(int writeBufSize) {
+        this.writeBufSize = writeBufSize;
+    }
 
+    public void setReadBufSize(int readBufSize) {
+        this.readBufSize = readBufSize;
+    }
 
+    protected SSLContext sslContext = null;
+    public SSLContext getSSLContext() { return sslContext;}
+    public void setSSLContext(SSLContext c) { sslContext = c;}
+    
     // --------------------------------------------------------- Public Methods
 
 
@@ -535,47 +474,24 @@ public class NioEndpoint {
         }
 
         // Initialize SSL if needed
-        if (!"off".equalsIgnoreCase(SSLEngine)) {
+        if (secure) {
             // Initialize SSL
-            // FIXME: one per VM call ?
-            if ("on".equalsIgnoreCase(SSLEngine)) {
-                //SSL.initialize(null);
-            } else {
-                //SSL.initialize(SSLEngine);
-            }
-            // SSL protocol
-            int value = SSL.SSL_PROTOCOL_ALL;
-            if ("SSLv2".equalsIgnoreCase(SSLProtocol)) {
-                value = SSL.SSL_PROTOCOL_SSLV2;
-            } else if ("SSLv3".equalsIgnoreCase(SSLProtocol)) {
-                value = SSL.SSL_PROTOCOL_SSLV3;
-            } else if ("TLSv1".equalsIgnoreCase(SSLProtocol)) {
-                value = SSL.SSL_PROTOCOL_TLSV1;
-            } else if ("SSLv2+SSLv3".equalsIgnoreCase(SSLProtocol)) {
-                value = SSL.SSL_PROTOCOL_SSLV2 | SSL.SSL_PROTOCOL_SSLV3;
-            }
-//            // Create SSL Context
-//            sslContext = SSLContext.make(rootPool, value, SSL.SSL_MODE_SERVER);
-//            // List the ciphers that the client is permitted to negotiate
-//            SSLContext.setCipherSuite(sslContext, SSLCipherSuite);
-//            // Load Server key and certificate
-//            SSLContext.setCertificate(sslContext, SSLCertificateFile, SSLCertificateKeyFile, SSLPassword, SSL.SSL_AIDX_RSA);
-//            // Set certificate chain file
-//            SSLContext.setCertificateChainFile(sslContext, SSLCertificateChainFile, false);
-//            // Support Client Certificates
-//            SSLContext.setCACertificate(sslContext, SSLCACertificateFile, SSLCACertificatePath);
-//            // Set revocation
-//            SSLContext.setCARevocation(sslContext, SSLCARevocationFile, SSLCARevocationPath);
-//            // Client certificate verification
-//            value = SSL.SSL_CVERIFY_NONE;
-//            if ("optional".equalsIgnoreCase(SSLVerifyClient)) {
-//                value = SSL.SSL_CVERIFY_OPTIONAL;
-//            } else if ("require".equalsIgnoreCase(SSLVerifyClient)) {
-//                value = SSL.SSL_CVERIFY_REQUIRE;
-//            } else if ("optionalNoCA".equalsIgnoreCase(SSLVerifyClient)) {
-//                value = SSL.SSL_CVERIFY_OPTIONAL_NO_CA;
-//            }
-//            SSLContext.setVerify(sslContext, value, SSLVerifyDepth);
+            char[] passphrase = getKeystorePass().toCharArray();
+
+            KeyStore ks = KeyStore.getInstance(getKeystoreType());
+            ks.load(new FileInputStream(getKeystoreFile()), passphrase);
+            KeyStore ts = KeyStore.getInstance(getKeystoreType());
+            ts.load(new FileInputStream(getKeystoreFile()), passphrase);
+
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance(getAlgorithm());
+            kmf.init(ks, passphrase);
+
+            TrustManagerFactory tmf = TrustManagerFactory.getInstance(getAlgorithm());
+            tmf.init(ts);
+
+            sslContext = SSLContext.getInstance(getSslProtocol());
+            sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
         }
 
         initialized = true;
@@ -671,7 +587,7 @@ public class NioEndpoint {
         serverSock.socket().close();
         serverSock.close();
         serverSock = null;
-        sslContext = 0;
+        sslContext = null;
         initialized = false;
     }
 
@@ -686,6 +602,13 @@ public class NioEndpoint {
         return sequence++;
     }
 
+    public int getWriteBufSize() {
+        return writeBufSize;
+    }
+
+    public int getReadBufSize() {
+        return readBufSize;
+    }
 
     /**
      * Unlock the server socket accept using a bugus connection.
@@ -736,20 +659,24 @@ public class NioEndpoint {
             if (soTimeout > 0)
                 socket.socket().setSoTimeout(soTimeout);
 
-
-            // 2: SSL handshake
+            NioChannel channel = null;
+            // 2: SSL setup
             step = 2;
-            if (sslContext != 0) {
-//                SSLSocket.attach(sslContext, socket);
-//                if (SSLSocket.handshake(socket) != 0) {
-//                    if (log.isDebugEnabled()) {
-//                        log.debug(sm.getString("endpoint.err.handshake") + ": " + SSL.getLastError());
-//                    }
-//                    return false;
-//                }
+            if (sslContext != null) {
+                SSLEngine engine = sslContext.createSSLEngine();
+                engine.setNeedClientAuth(getClientAuth());
+                engine.setUseClientMode(false);
+                int appbufsize = engine.getSession().getApplicationBufferSize();
+                int bufsize = Math.max(Math.max(getReadBufSize(),getWriteBufSize()),appbufsize);
+                NioBufferHandler bufhandler = new NioBufferHandler(bufsize,bufsize);
+                channel = new SecureNioChannel(socket,engine,bufhandler);
+                
+            } else {
+                NioBufferHandler bufhandler = new NioBufferHandler(getReadBufSize(),getWriteBufSize());
+                channel = new NioChannel(socket,bufhandler);
             }
             
-            getPoller().register(socket);
+            getPoller().register(channel);
 
         } catch (Throwable t) {
             if (log.isDebugEnabled()) {
@@ -845,7 +772,7 @@ public class NioEndpoint {
     /**
      * Process given socket.
      */
-    protected boolean processSocket(SocketChannel socket) {
+    protected boolean processSocket(NioChannel socket) {
         try {
             if (executor == null) {
                 getWorkerThread().assign(socket);
@@ -865,7 +792,7 @@ public class NioEndpoint {
     /**
      * Process given socket for an event.
      */
-    protected boolean processSocket(SocketChannel socket, boolean error) {
+    protected boolean processSocket(NioChannel socket, boolean error) {
         try {
             if (executor == null) {
                 getWorkerThread().assign(socket, error);
@@ -996,8 +923,8 @@ public class NioEndpoint {
          *
          * @param socket to add to the poller
          */
-        public void add(final SocketChannel socket) {
-            final SelectionKey key = socket.keyFor(selector);
+        public void add(final NioChannel socket) {
+            final SelectionKey key = socket.getIOChannel().keyFor(selector);
             KeyAttachment att = (KeyAttachment)key.attachment();
             if ( att != null ) att.setWakeUp(false);
             Runnable r = new Runnable() {
@@ -1010,7 +937,7 @@ public class NioEndpoint {
                                 KeyAttachment ka = (KeyAttachment)key.attachment();
                                 ka.setError(true); //set to collect this socket immediately
                             }
-                            socket.socket().close();
+                            socket.getIOChannel().socket().close();
                             socket.close();
                         } catch ( Exception ignore ) {}
                     }
@@ -1036,13 +963,15 @@ public class NioEndpoint {
             return result;
         }
         
-        public void register(final SocketChannel socket)
+        public void register(final NioChannel socket)
         {
-            SelectionKey key = socket.keyFor(selector);
+            SelectionKey key = socket.getIOChannel().keyFor(selector);
             Runnable r = new Runnable() {
                 public void run() {
                     try {
-                        socket.register(selector, SelectionKey.OP_READ, new KeyAttachment());
+                        KeyAttachment ka = new KeyAttachment();
+                        ka.setChannel(socket);
+                        socket.getIOChannel().register(selector, SelectionKey.OP_READ, ka);
                     } catch (Exception x) {
                         log.error("", x);
                     }
@@ -1059,7 +988,7 @@ public class NioEndpoint {
             try {
                 KeyAttachment ka = (KeyAttachment) key.attachment();
                 key.cancel();
-                if (ka != null && ka.getComet()) processSocket( (SocketChannel) key.channel(), true);
+                if (ka != null && ka.getComet()) processSocket( ka.getChannel(), true);
                 key.channel().close();
             } catch (IOException e) {
                 if ( log.isDebugEnabled() ) log.debug("",e);
@@ -1115,9 +1044,8 @@ public class NioEndpoint {
                             sk.attach(attachment);
                             int readyOps = sk.readyOps();
                             sk.interestOps(sk.interestOps() & ~readyOps);
-                            SocketChannel channel = (SocketChannel)sk.channel();
-                            boolean read = sk.isReadable();
-                            if (read) {
+                            NioChannel channel = attachment.getChannel();
+                            if (sk.isReadable() || sk.isWritable() ) {
                                 if ( attachment.getWakeUp() ) {
                                     attachment.setWakeUp(false);
                                     synchronized (attachment.getMutex()) {attachment.getMutex().notifyAll();}
@@ -1126,17 +1054,17 @@ public class NioEndpoint {
                                 } else {
                                     boolean close = (!processSocket(channel));
                                     if ( close ) {
-                                        channel.socket().close();
+                                        channel.getIOChannel().socket().close();
                                         channel.close();
                                     }
                                 }
-                            }
+                            } 
                         } else {
                             //invalid key
                             cancelledKey(sk);
                         }
                     } catch ( CancelledKeyException ckx ) {
-                        if (attachment!=null && attachment.getComet()) processSocket( (SocketChannel) sk.channel(), true);
+                        if (attachment!=null && attachment.getComet()) processSocket( attachment.getChannel(), true);
                         try {
                             sk.channel().close();
                         }catch ( Exception ignore){}
@@ -1203,6 +1131,8 @@ public class NioEndpoint {
         public long getTimeout() {return this.timeout;}
         public boolean getError() { return error; }
         public void setError(boolean error) { this.error = error; }
+        public NioChannel getChannel() { return channel;}
+        public void setChannel(NioChannel channel) { this.channel = channel;}
         protected Object mutex = new Object();
         protected boolean wakeUp = false;
         protected long lastAccess = System.currentTimeMillis();
@@ -1210,6 +1140,7 @@ public class NioEndpoint {
         protected boolean comet = false;
         protected long timeout = -1;
         protected boolean error = false;
+        protected NioChannel channel = null;
 
     }
 
@@ -1226,7 +1157,7 @@ public class NioEndpoint {
 
         protected Thread thread = null;
         protected boolean available = false;
-        protected SocketChannel socket = null;
+        protected NioChannel socket = null;
         protected boolean event = false;
         protected boolean error = false;
 
@@ -1240,7 +1171,7 @@ public class NioEndpoint {
          *
          * @param socket TCP socket to process
          */
-        protected synchronized void assign(SocketChannel socket) {
+        protected synchronized void assign(NioChannel socket) {
 
             // Wait for the Processor to get the previous Socket
             while (available) {
@@ -1260,7 +1191,7 @@ public class NioEndpoint {
         }
 
 
-        protected synchronized void assign(SocketChannel socket, boolean error) {
+        protected synchronized void assign(NioChannel socket, boolean error) {
 
             // Wait for the Processor to get the previous Socket
             while (available) {
@@ -1283,7 +1214,7 @@ public class NioEndpoint {
          * Await a newly assigned Socket from our Connector, or <code>null</code>
          * if we are supposed to shut down.
          */
-        protected synchronized SocketChannel await() {
+        protected synchronized NioChannel await() {
 
             // Wait for the Connector to provide a new Socket
             while (!available) {
@@ -1294,7 +1225,7 @@ public class NioEndpoint {
             }
 
             // Notify the Connector that we have received this Socket
-            SocketChannel socket = this.socket;
+            NioChannel socket = this.socket;
             available = false;
             notifyAll();
 
@@ -1312,27 +1243,62 @@ public class NioEndpoint {
             // Process requests until we receive a shutdown signal
             while (running) {
                 // Wait for the next socket to be assigned
-                SocketChannel socket = await();
+                NioChannel socket = await();
                 if (socket == null)
                     continue;
-
-                // Process the request from this socket
-                if ((event) && (handler.event(socket, error) == Handler.SocketState.CLOSED)) {
-                    // Close socket and pool
-                    try {
-                        socket.socket().close();
-                        socket.close();
-                    }catch ( Exception x ) {
-                        log.error("",x);
-                    }
-                } else if ((!event) && (handler.process(socket) == Handler.SocketState.CLOSED)) {
-                    // Close socket and pool
-                    try {
-                        socket.socket().close();
-                        socket.close();
-                    }catch ( Exception x ) {
-                        log.error("",x);
+                SelectionKey key = socket.getIOChannel().keyFor(getPoller().getSelector());
+                int handshake = -1;
+                try {
+                    handshake = socket.handshake(key.isReadable(), key.isWritable());
+                }catch ( IOException x ) {
+                    handshake = -1;
+                    log.error("Error during SSL handshake",x);
+                }
+                if ( handshake == 0 ) {
+                    // Process the request from this socket
+                    if ((event) && (handler.event(socket, error) == Handler.SocketState.CLOSED)) {
+                        // Close socket and pool
+                        try {
+                            socket.getIOChannel().socket().close();
+                            socket.close();
+                        }catch ( Exception x ) {
+                            log.error("",x);
+                        }
+                    } else if ((!event) && (handler.process(socket) == Handler.SocketState.CLOSED)) {
+                        // Close socket and pool
+                        try {
+                            socket.getIOChannel().socket().close();
+                            socket.close();
+                        }catch ( Exception x ) {
+                            log.error("",x);
+                        }
                     }
+                } else if (handshake == -1 ) {
+                    key.cancel();
+                    try {socket.close(true);}catch (IOException ignore){}
+                } else {
+                    final SelectionKey fk = key;
+                    final int intops = handshake;
+                    //register for handshake ops
+                    Runnable r = new Runnable() {
+                        public void run() {
+                            try {
+                                fk.interestOps(intops);
+                            } catch (CancelledKeyException ckx) {
+                                try {
+                                    if ( fk != null && fk.attachment() != null ) {
+                                        KeyAttachment ka = (KeyAttachment)fk.attachment();
+                                        ka.setError(true); //set to collect this socket immediately
+                                        try {ka.getChannel().getIOChannel().socket().close();}catch(Exception ignore){}
+                                        try {ka.getChannel().close();}catch(Exception ignore){}
+                                        ka.setWakeUp(false);
+                                    }
+                                } catch (Exception ignore) {}
+                            }
+
+                        }
+                    };
+                    getPoller().addEvent(r);
                 }
                 //dereference socket to let GC do its job
                 socket = null;
@@ -1355,7 +1321,21 @@ public class NioEndpoint {
 
     }
 
+    // ------------------------------------------------ Application Buffer Handler
+    public class NioBufferHandler implements ApplicationBufferHandler {
+        protected ByteBuffer readbuf = null;
+        protected ByteBuffer writebuf = null;
+        
+        public NioBufferHandler(int readsize, int writesize) {
+            readbuf = ByteBuffer.allocateDirect(readsize);
+            writebuf = ByteBuffer.allocateDirect(writesize);
+        }
+        
+        public ByteBuffer expand(ByteBuffer buffer, int remaining) {return buffer;}
+        public ByteBuffer getReadBuffer() {return readbuf;}
+        public ByteBuffer getWriteBuffer() {return writebuf;}
 
+    }
 
     // ------------------------------------------------ Handler Inner Interface
 
@@ -1369,8 +1349,8 @@ public class NioEndpoint {
         public enum SocketState {
             OPEN, CLOSED, LONG
         }
-        public SocketState process(SocketChannel socket);
-        public SocketState event(SocketChannel socket, boolean error);
+        public SocketState process(NioChannel socket);
+        public SocketState event(NioChannel socket, boolean error);
     }
 
 
@@ -1439,9 +1419,9 @@ public class NioEndpoint {
      */
     protected class SocketProcessor implements Runnable {
 
-        protected SocketChannel socket = null;
+        protected NioChannel socket = null;
 
-        public SocketProcessor(SocketChannel socket) {
+        public SocketProcessor(NioChannel socket) {
             this.socket = socket;
         }
 
@@ -1451,7 +1431,7 @@ public class NioEndpoint {
             if (handler.process(socket) == Handler.SocketState.CLOSED) {
                 // Close socket and pool
                 try {
-                    socket.socket().close();
+                    socket.getIOChannel().socket().close();
                     socket.close();
                 } catch ( Exception x ) {
                     log.error("",x);
@@ -1473,10 +1453,10 @@ public class NioEndpoint {
      */
     protected class SocketEventProcessor implements Runnable {
 
-        protected SocketChannel socket = null;
+        protected NioChannel socket = null;
         protected boolean error = false; 
 
-        public SocketEventProcessor(SocketChannel socket, boolean error) {
+        public SocketEventProcessor(NioChannel socket, boolean error) {
             this.socket = socket;
             this.error = error;
         }
@@ -1487,7 +1467,7 @@ public class NioEndpoint {
             if (handler.event(socket, error) == Handler.SocketState.CLOSED) {
                 // Close socket and pool
                 try {
-                    socket.socket().close();
+                    socket.getIOChannel().socket().close();
                     socket.close();
                 } catch ( Exception x ) {
                     log.error("",x);
index 859cbd9..4d9169b 100644 (file)
@@ -17,6 +17,7 @@
 package org.apache.tomcat.util.net;
 
 import java.net.Socket;
+import javax.net.ssl.SSLSession;
 
 /* SSLImplementation:
 
@@ -83,4 +84,5 @@ abstract public class SSLImplementation {
     abstract public String getImplementationName();
     abstract public ServerSocketFactory getServerSocketFactory();
     abstract public SSLSupport getSSLSupport(Socket sock);
+    abstract public SSLSupport getSSLSupport(SSLSession session);
 }    
diff --git a/java/org/apache/tomcat/util/net/SecureNioChannel.java b/java/org/apache/tomcat/util/net/SecureNioChannel.java
new file mode 100644 (file)
index 0000000..7b021d8
--- /dev/null
@@ -0,0 +1,408 @@
+package org.apache.tomcat.util.net;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLEngineResult.Status;
+
+/**
+ * 
+ * Implementation of a secure socket channel
+ * @author Filip Hanik
+ * @version 1.0
+ */
+
+public class SecureNioChannel extends NioChannel  {
+    
+    protected ByteBuffer netInBuffer;
+    protected ByteBuffer netOutBuffer;
+    
+    protected SSLEngine sslEngine;
+    
+    protected boolean initHandshakeComplete = false;
+    protected HandshakeStatus initHandshakeStatus; //gets set by begin handshake
+    
+    protected boolean closed = false;
+    protected boolean closing = false;
+    
+    public SecureNioChannel(SocketChannel channel, SSLEngine engine, ApplicationBufferHandler bufHandler) throws IOException {
+        super(channel,bufHandler);
+
+        this.sslEngine = engine;
+
+        
+        int appBufSize = sslEngine.getSession().getApplicationBufferSize();
+        int netBufSize = sslEngine.getSession().getPacketBufferSize();
+        
+        //ensure that the application has a large enough read/write buffers
+        //by doing this, we should not encounter any buffer overflow errors
+        bufHandler.expand(bufHandler.getReadBuffer(), appBufSize);
+        bufHandler.expand(bufHandler.getWriteBuffer(), appBufSize);
+        //allocate network buffers - TODO, add in optional direct buffers
+        this.netInBuffer = ByteBuffer.allocate(netBufSize);
+        this.netOutBuffer = ByteBuffer.allocate(netBufSize);
+        this.netOutBuffer.position(0);
+        this.netOutBuffer.limit(0);
+        this.netInBuffer.position(0);
+        this.netInBuffer.limit(0);
+
+        //initiate handshake
+        sslEngine.beginHandshake();
+        initHandshakeStatus = sslEngine.getHandshakeStatus();
+    }
+    
+//===========================================================================================    
+//                  NIO SSL METHODS
+//===========================================================================================
+    
+    /**
+     * Flushes the buffer to the network
+     * @param buf ByteBuffer
+     * @return boolean true if the buffer has been emptied out, false otherwise
+     * @throws IOException
+     */
+    protected boolean flush(ByteBuffer buf) throws IOException {
+        int remaining = buf.remaining();
+        if ( remaining > 0 ) {
+            int written = sc.write(buf);
+            return written >= remaining;
+        }else {
+            return true;
+        }
+    }
+    
+    /**
+     * Performs SSL handshake, non blocking, but performs NEED_TASK on the same thread.<br>
+     * Hence, you should never call this method using your Acceptor thread, as you would slow down
+     * your system significantly.<br>
+     * The return for this operation is 0 if the handshake is complete and a positive value if it is not complete.
+     * In the event of a positive value coming back, reregister the selection key for the return values interestOps.
+     * @param read boolean - true if the underlying channel is readable
+     * @param write boolean - true if the underlying channel is writable
+     * @return int - 0 if hand shake is complete, otherwise it returns a SelectionKey interestOps value
+     * @throws IOException
+     */
+    public int handshake(boolean read, boolean write) throws IOException {
+        if ( initHandshakeComplete ) return 0; //we have done our initial handshake
+        
+        if (!flush(netOutBuffer)) return SelectionKey.OP_WRITE; //we still have data to write
+        
+        SSLEngineResult handshake = null;
+        
+        while (!initHandshakeComplete) {
+            switch ( initHandshakeStatus ) {
+                case NOT_HANDSHAKING: {
+                    //should never happen
+                    throw new IOException("NOT_HANDSHAKING during handshake");
+                }
+                case FINISHED: {
+                    //we are complete if we have delivered the last package
+                    initHandshakeComplete = !netOutBuffer.hasRemaining();
+                    //return 0 if we are complete, otherwise we still have data to write
+                    return initHandshakeComplete?0:SelectionKey.OP_WRITE; 
+                }
+                case NEED_WRAP: {
+                    //perform the wrap function
+                    handshake = handshakeWrap(write);
+                    if ( handshake.getStatus() == Status.OK ){
+                        if (initHandshakeStatus == HandshakeStatus.NEED_TASK) 
+                            initHandshakeStatus = tasks();
+                    } else {
+                        //wrap should always work with our buffers
+                        throw new IOException("Unexpected status:" + handshake.getStatus() + " during handshake WRAP.");
+                    }
+                    if ( initHandshakeStatus != HandshakeStatus.NEED_UNWRAP || (!flush(netOutBuffer)) ) {
+                        //should actually return OP_READ if we have NEED_UNWRAP
+                        return SelectionKey.OP_WRITE;
+                    }
+                    //fall down to NEED_UNWRAP on the same call, will result in a 
+                    //BUFFER_UNDERFLOW if it needs data
+                }
+                case NEED_UNWRAP: {
+                    //perform the unwrap function
+                    handshake = handshakeUnwrap(read);
+                    if ( handshake.getStatus() == Status.OK ) {
+                        if (initHandshakeStatus == HandshakeStatus.NEED_TASK) 
+                            initHandshakeStatus = tasks();
+                    } else if ( handshake.getStatus() == Status.BUFFER_UNDERFLOW ){
+                        //read more data, reregister for OP_READ
+                        return SelectionKey.OP_READ;
+                    } else {
+                        throw new IOException("Invalid handshake status:"+initHandshakeStatus+" during handshake UNWRAP.");
+                    }//switch
+                    break;
+                }
+                case NEED_TASK: {
+                    initHandshakeStatus = tasks();
+                    break;
+                }
+                default: throw new IllegalStateException("Invalid handshake status:"+initHandshakeStatus);
+            }//switch
+        }//while      
+        //return 0 if we are complete, otherwise reregister for any activity that 
+        //would cause this method to be called again.
+        return initHandshakeComplete?0:(SelectionKey.OP_WRITE|SelectionKey.OP_READ);
+    }
+    
+    /**
+     * Executes all the tasks needed on the same thread.
+     * @return HandshakeStatus
+     */
+    protected SSLEngineResult.HandshakeStatus tasks() {
+        Runnable r = null;
+        while ( (r = sslEngine.getDelegatedTask()) != null) {
+            r.run();
+        }
+        return sslEngine.getHandshakeStatus();
+    }
+
+    /**
+     * Performs the WRAP function
+     * @param doWrite boolean
+     * @return SSLEngineResult
+     * @throws IOException
+     */
+    protected SSLEngineResult handshakeWrap(boolean doWrite) throws IOException {
+        //this should never be called with a network buffer that contains data
+        //so we can clear it here.
+        netOutBuffer.clear();
+        //perform the wrap
+        SSLEngineResult result = sslEngine.wrap(bufHandler.getWriteBuffer(), netOutBuffer);
+        //prepare the results to be written
+        netOutBuffer.flip();
+        //set the status
+        initHandshakeStatus = result.getHandshakeStatus();
+        //optimization, if we do have a writable channel, write it now
+        if ( doWrite ) flush(netOutBuffer);
+        return result;
+    }
+    
+    /**
+     * Perform handshake unwrap
+     * @param doread boolean
+     * @return SSLEngineResult
+     * @throws IOException
+     */
+    protected SSLEngineResult handshakeUnwrap(boolean doread) throws IOException {
+        
+        if (netInBuffer.position() == netInBuffer.limit()) {
+            //clear the buffer if we have emptied it out on data
+            netInBuffer.clear();
+        }
+        if ( doread )  {
+            //if we have data to read, read it
+            int read = sc.read(netInBuffer);
+            if (read == -1) throw new IOException("EOF encountered during handshake.");
+        }        
+        SSLEngineResult result;
+        boolean cont = false;
+        //loop while we can perform pure SSLEngine data
+        do {
+            //prepare the buffer with the incoming data
+            netInBuffer.flip();
+            //call unwrap
+            result = sslEngine.unwrap(netInBuffer, bufHandler.getReadBuffer());
+            //compact the buffer, this is an optional method, wonder what would happen if we didn't
+            netInBuffer.compact();
+            //read in the status
+            initHandshakeStatus = result.getHandshakeStatus();
+            if ( result.getStatus() == SSLEngineResult.Status.OK &&
+                 result.getHandshakeStatus() == HandshakeStatus.NEED_TASK ) {
+                //execute tasks if we need to
+                initHandshakeStatus = tasks();
+            }
+            //perform another unwrap?
+            cont = result.getStatus() == SSLEngineResult.Status.OK &&
+                   initHandshakeStatus == HandshakeStatus.NEED_UNWRAP;
+        }while ( cont );
+        return result;
+    }
+    
+    /**
+     * Sends a SSL close message, will not physically close the connection here.<br>
+     * To close the connection, you could do something like
+     * <pre><code>
+     *   close();
+     *   while (isOpen() && !myTimeoutFunction()) Thread.sleep(25);
+     *   if ( isOpen() ) close(true); //forces a close if you timed out
+     * </code></pre>
+     * @throws IOException if an I/O error occurs
+     * @throws IOException if there is data on the outgoing network buffer and we are unable to flush it
+     * @todo Implement this java.io.Closeable method
+     */
+    public void close() throws IOException {
+        if (closing) return;
+        closing = true;
+        sslEngine.closeOutbound();
+
+        if (!flush(netOutBuffer)) {
+            throw new IOException("Remaining data in the network buffer, can't send SSL close message, force a close with close(true) instead");
+        }
+        //prep the buffer for the close message
+        netOutBuffer.clear();
+        //perform the close, since we called sslEngine.closeOutbound
+        SSLEngineResult handshake = sslEngine.wrap(getEmptyBuf(), netOutBuffer);
+        //we should be in a close state
+        if (handshake.getStatus() != SSLEngineResult.Status.CLOSED) {
+            throw new IOException("Invalid close state, will not send network data.");
+        }
+        //prepare the buffer for writing
+        netOutBuffer.flip();
+        //if there is data to be written
+        flush(netOutBuffer);
+
+        //is the channel closed?
+        closed = (!netOutBuffer.hasRemaining() && (handshake.getHandshakeStatus() != HandshakeStatus.NEED_WRAP));
+    }
+
+    /**
+     * Force a close, can throw an IOException
+     * @param force boolean
+     * @throws IOException
+     */
+    public void close(boolean force) throws IOException {
+        try {
+            close();
+        }finally {
+            closed = true;
+            sc.close();
+        }
+    }
+
+    /**
+     * Reads a sequence of bytes from this channel into the given buffer.
+     *
+     * @param dst The buffer into which bytes are to be transferred
+     * @return The number of bytes read, possibly zero, or <tt>-1</tt> if the channel has reached end-of-stream
+     * @throws IOException If some other I/O error occurs
+     * @throws IllegalArgumentException if the destination buffer is different than bufHandler.getReadBuffer()
+     * @todo Implement this java.nio.channels.ReadableByteChannel method
+     */
+    public int read(ByteBuffer dst) throws IOException {
+        //if we want to take advantage of the expand function, make sure we only use the ApplicationBufferHandler's buffers
+        if ( dst != bufHandler.getReadBuffer() ) throw new IllegalArgumentException("You can only read using the application read buffer provided by the handler.");
+        //are we in the middle of closing or closed?
+        if ( closing || closed) return -1;
+        //did we finish our handshake?
+        if (!initHandshakeComplete) throw new IllegalStateException("Handshake incomplete, you must complete handshake before reading data.");
+
+        //read from the network
+        int netread = sc.read(netInBuffer);
+        //did we reach EOF? if so send EOF up one layer.
+        if (netread == -1) return -1;
+        
+        //the data read
+        int read = 0;
+        //the SSL engine result
+        SSLEngineResult unwrap;
+        do {
+            //prepare the buffer
+            netInBuffer.flip();
+            //unwrap the data
+            unwrap = sslEngine.unwrap(netInBuffer, dst);
+            //compact the buffer
+            netInBuffer.compact();
+            
+            if ( unwrap.getStatus()==Status.OK || unwrap.getStatus()==Status.BUFFER_UNDERFLOW ) {
+                //we did receive some data, add it to our total
+                read += unwrap.bytesProduced();
+                //perform any tasks if needed
+                if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) tasks();
+                //if we need more network data, then bail out for now.
+                if ( unwrap.getStatus() == Status.BUFFER_UNDERFLOW ) break;
+            }else {
+                //here we should trap BUFFER_OVERFLOW and call expand on the buffer
+                //for now, throw an exception, as we initialized the buffers
+                //in the constructor
+                throw new IOException("Unable to unwrap data, invalid status: " + unwrap.getStatus());
+            }
+        } while ( (netInBuffer.position() != 0));
+        return (read);
+    }
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffer.
+     *
+     * @param src The buffer from which bytes are to be retrieved
+     * @return The number of bytes written, possibly zero
+     * @throws IOException If some other I/O error occurs
+     * @todo Implement this java.nio.channels.WritableByteChannel method
+     */
+    public int write(ByteBuffer src) throws IOException {
+        //make sure we can handle expand, and that we only use on buffer
+        if ( src != bufHandler.getWriteBuffer() ) throw new IllegalArgumentException("You can only write using the application write buffer provided by the handler.");
+        //are we closing or closed?
+        if ( closing || closed) throw new IOException("Channel is in closing state.");
+        
+        //the number of bytes written
+        int written = 0;
+        
+        if (!flush(netOutBuffer)) {
+            //we haven't emptied out the buffer yet
+            return written;
+        }
+
+        /*
+         * The data buffer is empty, we can reuse the entire buffer.
+         */
+        netOutBuffer.clear();
+
+        SSLEngineResult result = sslEngine.wrap(src, netOutBuffer);
+        written = result.bytesConsumed();
+        netOutBuffer.flip();
+
+        if (result.getStatus() == Status.OK) {
+            if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) tasks();
+        } else {
+            throw new IOException("Unable to wrap data, invalid engine state: " +result.getStatus());
+        }        
+
+        //force a flush
+        flush(netOutBuffer);
+
+        return written;
+    }
+    
+    /**
+     * Callback interface to be able to expand buffers
+     * when buffer overflow exceptions happen
+     */
+    public static interface ApplicationBufferHandler {
+        public ByteBuffer expand(ByteBuffer buffer, int remaining);
+        public ByteBuffer getReadBuffer();
+        public ByteBuffer getWriteBuffer();
+    }
+
+    public ApplicationBufferHandler getBufHandler() {
+        return bufHandler;
+    }
+
+    public boolean isInitHandshakeComplete() {
+        return initHandshakeComplete;
+    }
+
+    public boolean isClosing() {
+        return closing;
+    }
+
+    public SSLEngine getSslEngine() {
+        return sslEngine;
+    }
+
+    public ByteBuffer getEmptyBuf() {
+        return emptyBuf;
+    }
+
+    public void setBufHandler(ApplicationBufferHandler bufHandler) {
+        this.bufHandler = bufHandler;
+    }
+    
+    public SocketChannel getIOChannel() {
+        return sc;
+    }
+
+}
\ No newline at end of file
index f648520..b3a81ea 100644 (file)
@@ -22,12 +22,14 @@ import javax.net.ssl.SSLSocket;
 
 import org.apache.tomcat.util.net.SSLSupport;
 import org.apache.tomcat.util.net.ServerSocketFactory;
+import javax.net.ssl.SSLSession;
 
 /** 
  * Factory interface to construct components based on the JSSE version
  * in use.
  *
  * @author Bill Barker
+ * @author Filip Hanik
  */
 
 public class JSSEFactory {
@@ -45,5 +47,9 @@ public class JSSEFactory {
     public SSLSupport getSSLSupport(Socket socket) {
         return new JSSESupport((SSLSocket)socket);
     }
+    
+    public SSLSupport getSSLSupport(SSLSession session) {
+        return new JSSESupport(session);
+    }
 
 };
index d421626..5b7d3b3 100644 (file)
@@ -21,6 +21,7 @@ import java.net.Socket;
 import org.apache.tomcat.util.net.SSLImplementation;
 import org.apache.tomcat.util.net.SSLSupport;
 import org.apache.tomcat.util.net.ServerSocketFactory;
+import javax.net.ssl.SSLSession;
 
 /* JSSEImplementation:
 
@@ -58,4 +59,10 @@ public class JSSEImplementation extends SSLImplementation
         SSLSupport ssls = factory.getSSLSupport(s);
         return ssls;
     }
+
+    public SSLSupport getSSLSupport(SSLSession session) {
+        SSLSupport ssls = factory.getSSLSupport(session);
+        return ssls;
+    }
+
 }
index 3dfca75..b61f170 100644 (file)
@@ -32,7 +32,7 @@ import javax.security.cert.X509Certificate;
 
 import org.apache.tomcat.util.net.SSLSupport;
 
-/* JSSESupport
+/** JSSESupport
 
    Concrete implementation class for JSSE
    Support classes.
@@ -42,6 +42,7 @@ import org.apache.tomcat.util.net.SSLSupport;
 
    @author EKR
    @author Craig R. McClanahan
+   @author Filip Hanik
    Parts cribbed from JSSECertCompat       
    Parts cribbed from CertificatesValve
 */
@@ -52,17 +53,22 @@ class JSSESupport implements SSLSupport {
         org.apache.commons.logging.LogFactory.getLog(JSSESupport.class);
 
     protected SSLSocket ssl;
+    protected SSLSession session;
 
     Listener listener = new Listener();
 
     JSSESupport(SSLSocket sock){
         ssl=sock;
+        session = sock.getSession();
         sock.addHandshakeCompletedListener(listener);
     }
+    
+    JSSESupport(SSLSession session) {
+        this.session = session;
+    }
 
     public String getCipherSuite() throws IOException {
         // Look up the current SSLSession
-        SSLSession session = ssl.getSession();
         if (session == null)
             return null;
         return session.getCipherSuite();
@@ -114,7 +120,6 @@ class JSSESupport implements SSLSupport {
     public Object[] getPeerCertificateChain(boolean force)
         throws IOException {
         // Look up the current SSLSession
-       SSLSession session = ssl.getSession();
         if (session == null)
             return null;
 
@@ -177,7 +182,6 @@ class JSSESupport implements SSLSupport {
     public Integer getKeySize() 
         throws IOException {
         // Look up the current SSLSession
-        SSLSession session = ssl.getSession();
         SSLSupport.CipherData c_aux[]=ciphers;
         if (session == null)
             return null;
@@ -200,7 +204,6 @@ class JSSESupport implements SSLSupport {
     public String getSessionId()
         throws IOException {
         // Look up the current SSLSession
-        SSLSession session = ssl.getSession();
         if (session == null)
             return null;
         // Expose ssl_session (getId)