Author: elecharny
Date: Fri Dec  9 08:03:25 2011
New Revision: 1212269

URL: http://svn.apache.org/viewvc?rev=1212269&view=rev
Log:
First drop of SSL handling : it's not working properly yet, but it's close.

Modified:
    mina/trunk/core/src/main/java/org/apache/mina/session/SslHelper.java
    
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/NioSelectorProcessor.java

Modified: mina/trunk/core/src/main/java/org/apache/mina/session/SslHelper.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/session/SslHelper.java?rev=1212269&r1=1212268&r2=1212269&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/session/SslHelper.java 
(original)
+++ mina/trunk/core/src/main/java/org/apache/mina/session/SslHelper.java Fri 
Dec  9 08:03:25 2011
@@ -20,6 +20,7 @@
 package org.apache.mina.session;
 
 import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
 
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLEngine;
@@ -73,6 +74,12 @@ public class SslHelper
     /** The Handshake status */
     private SSLEngineResult.HandshakeStatus handshakeStatus;
 
+    /** Application cleartext data to be read by application */
+    private ByteBuffer appBuffer;
+
+    /** Incoming buffer accumulating bytes read from the channel */
+    private ByteBuffer sslInBuffer;
+    
     /**
      * Create a new SSL Handler.
      *
@@ -127,15 +134,15 @@ public class SslHelper
         // Initialize the different SslEngine modes
         if (!sslEngine.getUseClientMode()) {
             // Those parameters are only valid when in server mode
-            boolean needClientAuth = 
session.<Boolean>getAttribute(NEED_CLIENT_AUTH);
-            boolean wantClientAuth = 
session.<Boolean>getAttribute(WANT_CLIENT_AUTH);
+            Boolean needClientAuth = 
session.<Boolean>getAttribute(NEED_CLIENT_AUTH);
+            Boolean wantClientAuth = 
session.<Boolean>getAttribute(WANT_CLIENT_AUTH);
 
             // The WantClientAuth superseed the NeedClientAuth, if set.
-            if (needClientAuth) {
+            if ((needClientAuth != null) && (needClientAuth)) {
                 sslEngine.setNeedClientAuth(true);
             }
             
-            if (wantClientAuth) {
+            if ((wantClientAuth != null) && (wantClientAuth)) {
                 sslEngine.setWantClientAuth(true);
             }
         }
@@ -146,4 +153,43 @@ public class SslHelper
             LOGGER.debug("{} SSL Handler Initialization done.", session);
         }
     }
+
+    /**
+     * Get the local AppBuffer
+     * @return The Application Buffer allocated in the SslHelper, if any
+     */
+    public ByteBuffer getAppBuffer() {
+        return appBuffer;
+    }
+
+    public ByteBuffer getSslInBuffer(ByteBuffer inBuffer) {
+        if (sslInBuffer == null) {
+            sslInBuffer = inBuffer;
+        } else {
+            addInBuffer(inBuffer);
+        }
+        
+        return sslInBuffer;
+    }
+
+    public void setInBuffer(ByteBuffer inBuffer) {
+        sslInBuffer = ByteBuffer.allocate(16*1024);
+        sslInBuffer.put(inBuffer);
+    }
+
+    public void addInBuffer(ByteBuffer inBuffer) {
+        if (sslInBuffer.capacity() - sslInBuffer.remaining() < 
inBuffer.remaining()) {
+            // Increase the internal buffer
+            ByteBuffer newBuffer = ByteBuffer.allocate(sslInBuffer.capacity() 
+ inBuffer.remaining());
+            newBuffer.put(sslInBuffer);
+            newBuffer.put(inBuffer);
+            sslInBuffer = newBuffer;
+        } else {
+            sslInBuffer.put(inBuffer);
+        }
+    }
+    
+    public void releaseInBuffer() {
+        sslInBuffer = null;
+    }
 }

Modified: 
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/NioSelectorProcessor.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/NioSelectorProcessor.java?rev=1212269&r1=1212268&r2=1212269&view=diff
==============================================================================
--- 
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/NioSelectorProcessor.java
 (original)
+++ 
mina/trunk/core/src/main/java/org/apache/mina/transport/tcp/NioSelectorProcessor.java
 Fri Dec  9 08:03:25 2011
@@ -37,6 +37,7 @@ import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
 import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
 import javax.net.ssl.SSLException;
 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
 
@@ -75,9 +76,15 @@ public class NioSelectorProcessor implem
 
     private Map<SocketAddress, ServerSocketChannel> serverSocketChannels = new 
ConcurrentHashMap<SocketAddress, ServerSocketChannel>();
 
-    // read buffer for all the incoming bytes
+    /** Read buffer for all the incoming bytes */
     private ByteBuffer readBuffer = ByteBuffer.allocate(64 * 1024);
 
+    /** Application buffer for all the outgoing messages */
+    private ByteBuffer appBuffer = ByteBuffer.allocate(16 * 1024);
+    
+    /** An empty buffer used during the handshake phase */
+    private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);
+
     // the thread polling and processing the I/O events
     private SelectorWorker worker = null;
 
@@ -446,8 +453,9 @@ public class NioSelectorProcessor implem
             LOGGER.debug("readable client {}", key);
             NioTcpSession session = (NioTcpSession) key.attachment();
             SocketChannel channel = session.getSocketChannel();
-            readBuffer.rewind();
+            readBuffer.clear();
             int readCount = channel.read(readBuffer);
+            
             LOGGER.debug("read {} bytes", readCount);
 
             if (readCount < 0) {
@@ -468,32 +476,126 @@ public class NioSelectorProcessor implem
             }
         }
         
-        private void processHandShake( IoSession session, ByteBuffer buffer) 
throws SSLException{
+        private boolean processHandShake(IoSession session, ByteBuffer 
inBuffer) throws SSLException {
             SslHelper sslHelper = session.getAttribute( IoSession.SSL_HELPER );
             
-            SSLEngine engine = sslHelper.getEngine();
+            if (sslHelper == null) {
+                throw new IllegalStateException();
+            }
             
+            SSLEngine engine = sslHelper.getEngine();
             HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            ByteBuffer applicationBuffer = appBuffer;
+            boolean processingData = true;
+            ByteBuffer sslBufferIn = sslHelper.getSslInBuffer(inBuffer);
+            boolean waitingForMore = false;
             
-            while ((hsStatus != HandshakeStatus.FINISHED) && (hsStatus != 
HandshakeStatus.NOT_HANDSHAKING)) {
+            // Start the Handshake
+            engine.beginHandshake();
+            hsStatus = engine.getHandshakeStatus();
+
+            // If the SSLEngine has not be started, then the status will be 
NOT_HANDSHAKING
+            while ((hsStatus != HandshakeStatus.FINISHED) &&
+                   (hsStatus != HandshakeStatus.NOT_HANDSHAKING ) &&
+                   processingData) {
                 switch (hsStatus) {
-                    case NOT_HANDSHAKING :
-                        // This is the very first step. We have to initialize 
the handShake
-                        engine.beginHandshake();
+                    case NEED_TASK :
+                        Runnable runnable;
+                        
+                        while ((runnable = engine.getDelegatedTask()) != null) 
{
+                            // TODO : we may have to use a thread pool here to 
improve the
+                            // performances
+                            runnable.run();
+                        }
+
+                        hsStatus = engine.getHandshakeStatus();
+                        
                         break;
                         
-                    case NEED_TASK :
                     case NEED_WRAP :
-                    case NEED_UNWRAP :
-                    case FINISHED :
                         if ( LOGGER.isDebugEnabled()) {
-                            LOGGER.debug("{} processing the FINISHED state", 
session);
+                            LOGGER.debug("{} processing the NEED_WRAP state", 
session);
+                        }
+                        
+                        int capacity = 
engine.getSession().getPacketBufferSize();
+                        ByteBuffer outBuffer = ByteBuffer.allocate(capacity);
+
+                        while (true) {
+                            SSLEngineResult result = engine.wrap(EMPTY_BUFFER, 
outBuffer);
+                            
+                            if (result.getStatus() == 
SSLEngineResult.Status.BUFFER_OVERFLOW) {
+                                // TODO : increase the AppBuffer size
+                            } else {
+                                break;
+                            }
+                        }
+        
+                        outBuffer.flip();
+                        session.write(outBuffer);
+                        hsStatus = engine.getHandshakeStatus();
+                        
+                        // Now that we have written the response, we can exit 
if there is nothing else to do,
+                        if (engine.isOutboundDone()) {
+                            processingData = false;
                         }
                         
-                        session.changeState(SessionState.SECURED);
                         break;
+                        
+                    case NEED_UNWRAP :
+                        if (engine.isInboundDone()) {
+                            processingData = false;
+                            sslHelper.releaseInBuffer();
+                            break;
+                        }
+
+                        // We will try to unwrap the incoming data, using the 
selector buffers.
+                        SSLEngineResult result = engine.unwrap(sslBufferIn, 
applicationBuffer);
+                        hsStatus = engine.getHandshakeStatus();
+
+                        switch (result.getStatus()) {
+                            case OK :
+                                // We have unwrapped the message. The inBuffer 
can contain
+                                // some more data to be unwrapped. Loop.
+                                break;
+                                
+                            case CLOSED :
+                                // We must exit immediately
+                                sslHelper.releaseInBuffer();
+                                throw new IllegalStateException();
+                                
+                            case BUFFER_OVERFLOW :
+                                // Not enough room in the appData : increase 
the buffer size
+                                ByteBuffer newBuffer = 
ByteBuffer.allocate(applicationBuffer.capacity() + 4 * 1024);
+                                applicationBuffer = newBuffer;
+                                
+                                // And now, try again.
+                                break;
+    
+                            case BUFFER_UNDERFLOW :
+                                // Not enough data in the received data. 
Accumulate and get some more.
+                                processingData = false;
+                                waitingForMore = true;
+                                sslHelper.addInBuffer(sslBufferIn);
+                                break;
+                        }
                 }
             }
+            
+            if (!waitingForMore) {
+                sslHelper.releaseInBuffer();
+            }
+            
+            if (hsStatus == HandshakeStatus.FINISHED) {
+                if ( LOGGER.isDebugEnabled()) {
+                    LOGGER.debug("{} processing the FINISHED state", session);
+                }
+                
+                session.changeState(SessionState.SECURED);
+
+                return true;
+            }
+            
+            return false;
         }
         
         /**
@@ -503,6 +605,7 @@ public class NioSelectorProcessor implem
             if (LOGGER.isDebugEnabled()) {
                 LOGGER.debug("writable session : {}", key.attachment());
             }
+            
             NioTcpSession session = (NioTcpSession) key.attachment();
             session.setNotRegisteredForWrite();
 


Reply via email to