Author: trustin
Date: Mon Nov 12 19:37:37 2007
New Revision: 594412

URL: http://svn.apache.org/viewvc?rev=594412&view=rev
Log:
* Added IoBuffer.minimumCapacity(...)
* Added IoBuffer.shrink()
* Fixed issue: DIRMINA-471 (Reduce SSL buffers overhead)
** The change uses the new feature of 2.0 so it won't be backported to 1.x.

Removed:
    mina/trunk/core/src/main/java/org/apache/mina/filter/ssl/SslBufferUtil.java
Modified:
    mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoBuffer.java
    mina/trunk/core/src/main/java/org/apache/mina/common/IoBuffer.java
    mina/trunk/core/src/main/java/org/apache/mina/common/IoBufferWrapper.java
    mina/trunk/core/src/main/java/org/apache/mina/filter/ssl/SslFilter.java
    mina/trunk/core/src/main/java/org/apache/mina/filter/ssl/SslHandler.java

Modified: 
mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoBuffer.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoBuffer.java?rev=594412&r1=594411&r2=594412&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoBuffer.java 
(original)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/AbstractIoBuffer.java 
Mon Nov 12 19:37:37 2007
@@ -42,11 +42,11 @@
 public abstract class AbstractIoBuffer extends IoBuffer {
     
     private final IoBufferAllocator allocator;
-    private final int initialCapacity;
     private final boolean derived;
     private boolean autoExpand;
     private boolean autoShrink;
     private boolean recapacityAllowed = true;
+    private int minimumCapacity;
 
     /**
      * We don't have any access to Buffer.markValue(), so we need to track it 
down,
@@ -62,7 +62,7 @@
         this.allocator = allocator;
         this.recapacityAllowed = true;
         this.derived = false;
-        this.initialCapacity = initialCapacity;
+        this.minimumCapacity = initialCapacity;
     }
     
     /**
@@ -72,7 +72,7 @@
         this.allocator = parent.allocator;
         this.recapacityAllowed = false;
         this.derived = true;
-        this.initialCapacity = parent.initialCapacity;
+        this.minimumCapacity = parent.minimumCapacity;
     }
 
     @Override
@@ -91,6 +91,21 @@
     protected abstract void buf(ByteBuffer newBuf);
 
     @Override
+    public int minimumCapacity() {
+        return minimumCapacity;
+    }
+    
+    @Override
+    public IoBuffer minimumCapacity(int minimumCapacity) {
+        if (minimumCapacity < 0) {
+            throw new IllegalArgumentException(
+                    "minimumCapacity: " + minimumCapacity);
+        }
+        this.minimumCapacity = minimumCapacity;
+        return this;
+    }
+
+    @Override
     public int capacity() {
         return buf().capacity();
     }
@@ -185,6 +200,58 @@
         }
         return this;
     }
+    
+    @Override
+    public IoBuffer shrink() {
+
+        if (!recapacityAllowed) {
+            throw new IllegalStateException(
+                    "Derived buffers and their parent can't be expanded.");
+        }
+        
+        int position = position();
+        int capacity = capacity();
+        int limit = limit();
+        if (capacity == limit) {
+            return this;
+        }
+
+        int newCapacity = capacity;
+        int minCapacity = Math.max(minimumCapacity, limit);
+        for (;;) {
+            if (newCapacity >>> 1 < minCapacity) {
+                break;
+            }
+            newCapacity >>>= 1;
+        }
+        
+        newCapacity = Math.max(minCapacity, newCapacity);
+        
+        if (newCapacity == capacity) {
+            return this;
+        }
+
+        // Shrink and compact:
+        //// Save the state.
+        ByteOrder bo = order();
+
+        //// Reallocate.
+        ByteBuffer oldBuf = buf();
+        ByteBuffer newBuf = 
+            allocator.allocateNioBuffer(newCapacity, isDirect());
+        oldBuf.position(0);
+        oldBuf.limit(limit);
+        newBuf.put(oldBuf);
+        buf(newBuf);
+        
+        //// Restore the state.
+        buf().position(position);
+        buf().limit(limit);
+        buf().order(bo);
+        mark = -1;
+        
+        return this;
+    }
 
     @Override
     public int position() {
@@ -308,9 +375,9 @@
             return this;
         }
 
-        if (isAutoShrink() && remaining <= capacity >>> 2 && capacity > 
initialCapacity) {
+        if (isAutoShrink() && remaining <= capacity >>> 2 && capacity > 
minimumCapacity) {
             int newCapacity = capacity;
-            int minCapacity = Math.max(initialCapacity, remaining << 1);
+            int minCapacity = Math.max(minimumCapacity, remaining << 1);
             for (;;) {
                 if (newCapacity >>> 1 < minCapacity) {
                     break;
@@ -318,7 +385,11 @@
                 newCapacity >>>= 1;
             }
             
-            newCapacity = Math.max(initialCapacity, newCapacity);
+            newCapacity = Math.max(minCapacity, newCapacity);
+            
+            if (newCapacity == capacity) {
+                return this;
+            }
 
             // Shrink and compact:
             //// Save the state.

Modified: mina/trunk/core/src/main/java/org/apache/mina/common/IoBuffer.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/IoBuffer.java?rev=594412&r1=594411&r2=594412&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/common/IoBuffer.java 
(original)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/IoBuffer.java Mon Nov 
12 19:37:37 2007
@@ -318,6 +318,22 @@
     public abstract boolean isReadOnly();
 
     /**
+     * Returns the minimum capacity of this buffer which is used to determine
+     * the new capacity of the buffer shrunk by [EMAIL PROTECTED] #compact()} 
and
+     * [EMAIL PROTECTED] #shrink()} operation.  The default value is the 
initial capacity
+     * of the buffer.
+     */
+    public abstract int minimumCapacity();
+    
+    /**
+     * Sets the minimum capacity of this buffer which is used to determine
+     * the new capacity of the buffer shrunk by [EMAIL PROTECTED] #compact()} 
and
+     * [EMAIL PROTECTED] #shrink()} operation.  The default value is the 
initial capacity
+     * of the buffer.
+     */
+    public abstract IoBuffer minimumCapacity(int minimumCapacity);
+
+    /**
      * @see ByteBuffer#capacity()
      */
     public abstract int capacity();
@@ -369,7 +385,16 @@
      * <tt>true</tt>.
      */
     public abstract IoBuffer expand(int position, int expectedRemaining);
-
+    
+    /**
+     * Changes the capacity of this buffer so this buffer occupies as less
+     * memory as possible while retaining the position, limit and the
+     * buffer content between the position and limit.  The capacity of the
+     * buffer never becomes less than [EMAIL PROTECTED] #minimumCapacity()}.
+     * The mark is discarded once the capacity changes.
+     */
+    public abstract IoBuffer shrink();
+    
     /**
      * @see java.nio.Buffer#position()
      */

Modified: 
mina/trunk/core/src/main/java/org/apache/mina/common/IoBufferWrapper.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/IoBufferWrapper.java?rev=594412&r1=594411&r2=594412&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/common/IoBufferWrapper.java 
(original)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/IoBufferWrapper.java 
Mon Nov 12 19:37:37 2007
@@ -617,6 +617,17 @@
     }
 
     @Override
+    public int minimumCapacity() {
+        return buf.minimumCapacity();
+    }
+
+    @Override
+    public IoBuffer minimumCapacity(int minimumCapacity) {
+        buf.minimumCapacity(minimumCapacity);
+        return this;
+    }
+
+    @Override
     public IoBuffer capacity(int newCapacity) {
         buf.capacity(newCapacity);
         return this;
@@ -655,6 +666,12 @@
     @Override
     public IoBuffer setAutoShrink(boolean autoShrink) {
         buf.setAutoShrink(autoShrink);
+        return this;
+    }
+
+    @Override
+    public IoBuffer shrink() {
+        buf.shrink();
         return this;
     }
 }

Modified: 
mina/trunk/core/src/main/java/org/apache/mina/filter/ssl/SslFilter.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/ssl/SslFilter.java?rev=594412&r1=594411&r2=594412&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/ssl/SslFilter.java 
(original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/ssl/SslFilter.java Mon 
Nov 12 19:37:37 2007
@@ -384,13 +384,6 @@
         SslHandler handler = getSslSessionHandler(session);
         try {
             synchronized (handler) {
-                if (isSslStarted(session)) {
-                    if (handler.getLogger().isDebugEnabled()) {
-                        handler.getLogger().debug(" Closed: "
-                                + getSslSessionHandler(session));
-                    }
-                }
-
                 // release resources
                 handler.destroy();
             }
@@ -411,11 +404,6 @@
                 handler.scheduleMessageReceived(nextFilter, message);
             } else {
                 IoBuffer buf = (IoBuffer) message;
-                if (handler.getLogger().isDebugEnabled()) {
-                    handler.getLogger().debug(" Data Read: " + handler + " ("
-                            + buf + ')');
-                }
-
                 try {
                     // forward read encrypted data to SSL handler
                     handler.messageReceived(nextFilter, buf.buf());
@@ -425,10 +413,6 @@
 
                     if (handler.isInboundDone()) {
                         if (handler.isOutboundDone()) {
-                            if (handler.getLogger().isDebugEnabled()) {
-                                handler.getLogger().debug(" SSL Session 
closed.");
-                            }
-
                             handler.destroy();
                         } else {
                             initiateClosure(nextFilter, session);
@@ -543,46 +527,22 @@
                 // Otherwise, encrypt the buffer.
                 IoBuffer buf = (IoBuffer) writeRequest.getMessage();
 
-                if (handler.getLogger().isDebugEnabled()) {
-                    handler.getLogger().debug(" Filtered Write: " + handler);
-                }
-
                 if (handler.isWritingEncryptedData()) {
                     // data already encrypted; simply return buffer
-                    if (handler.getLogger().isDebugEnabled()) {
-                        handler.getLogger().debug("   already encrypted: "
-                                + buf);
-                    }
-                    handler.scheduleFilterWrite(nextFilter,
-                            writeRequest);
+                    handler.scheduleFilterWrite(nextFilter, writeRequest);
                 } else if (handler.isHandshakeComplete()) {
                     // SSL encrypt
-                    if (handler.getLogger().isDebugEnabled()) {
-                        handler.getLogger().debug(" encrypt: " + buf);
-                    }
-
                     int pos = buf.position();
                     handler.encrypt(buf.buf());
                     buf.position(pos);
-                    IoBuffer encryptedBuffer = SslHandler.copy(handler
-                            .getOutNetBuffer());
-
-                    if (handler.getLogger().isDebugEnabled()) {
-                        handler.getLogger().debug(" encrypted buf: "
-                                + encryptedBuffer);
-                    }
-                    handler.scheduleFilterWrite(nextFilter,
-                            new EncryptedWriteRequest(writeRequest,
-                                    encryptedBuffer));
+                    IoBuffer encryptedBuffer = handler.fetchOutNetBuffer();
+                    handler.scheduleFilterWrite(
+                            nextFilter,
+                            new EncryptedWriteRequest(
+                                    writeRequest, encryptedBuffer));
                 } else {
-                    if (!session.isConnected()) {
-                        if (handler.getLogger().isDebugEnabled()) {
-                            handler.getLogger().debug(" Write request on 
closed session.");
-                        }
-                    } else {
-                        if (handler.getLogger().isDebugEnabled()) {
-                            handler.getLogger().debug(" Handshaking is not 
complete yet. Buffering write request.");
-                        }
+                    if (session.isConnected()) {
+                        // Handshake not complete yet.
                         handler.schedulePreHandshakeWriteRequest(nextFilter,
                                 writeRequest);
                     }
@@ -680,25 +640,11 @@
     }
 
     private void handleAppDataRead(NextFilter nextFilter, SslHandler handler) {
-        handler.getAppBuffer().flip();
-        if (!handler.getAppBuffer().hasRemaining()) {
-            handler.getAppBuffer().clear();
-            return;
-        }
-
-        if (handler.getLogger().isDebugEnabled()) {
-            handler.getLogger().debug(" appBuffer: " + handler.getAppBuffer());
-        }
-
         // forward read app data
-        IoBuffer readBuffer = SslHandler.copy(handler.getAppBuffer());
-        handler.getAppBuffer().clear();
-        if (handler.getLogger().isDebugEnabled()) {
-            handler.getLogger().debug(" app data read: " + readBuffer + " ("
-                    + readBuffer.getHexDump() + ')');
+        IoBuffer readBuffer = handler.fetchAppBuffer();
+        if (readBuffer.hasRemaining()) {
+            handler.scheduleMessageReceived(nextFilter, readBuffer);
         }
-
-        handler.scheduleMessageReceived(nextFilter, readBuffer);
     }
 
     private SslHandler getSslSessionHandler(IoSession session) {

Modified: 
mina/trunk/core/src/main/java/org/apache/mina/filter/ssl/SslHandler.java
URL: 
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/filter/ssl/SslHandler.java?rev=594412&r1=594411&r2=594412&view=diff
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/filter/ssl/SslHandler.java 
(original)
+++ mina/trunk/core/src/main/java/org/apache/mina/filter/ssl/SslHandler.java 
Mon Nov 12 19:37:37 2007
@@ -29,7 +29,6 @@
 import javax.net.ssl.SSLEngineResult;
 import javax.net.ssl.SSLException;
 import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.SSLSession;
 
 import org.apache.mina.common.DefaultWriteFuture;
 import org.apache.mina.common.DefaultWriteRequest;
@@ -56,54 +55,39 @@
  * @version $Rev$, $Date$
  */
 class SslHandler {
+    
     private final Logger logger;
-
     private final SslFilter parent;
-
     private final SSLContext ctx;
-
     private final IoSession session;
-
     private final Queue<IoFilterEvent> preHandshakeEventQueue = new 
CircularQueue<IoFilterEvent>();
-
     private final Queue<IoFilterEvent> filterWriteEventQueue = new 
ConcurrentLinkedQueue<IoFilterEvent>();
-
     private final Queue<IoFilterEvent> messageReceivedEventQueue = new 
ConcurrentLinkedQueue<IoFilterEvent>();
-
     private SSLEngine sslEngine;
 
     /**
      * Encrypted data from the net
      */
-    private ByteBuffer inNetBuffer;
+    private IoBuffer inNetBuffer;
 
     /**
      * Encrypted data to be written to the net
      */
-    private ByteBuffer outNetBuffer;
+    private IoBuffer outNetBuffer;
 
     /**
      * Applicaton cleartext data to be read by application
      */
-    private ByteBuffer appBuffer;
+    private IoBuffer appBuffer;
 
     /**
      * Empty buffer used during initial handshake and close operations
      */
-    private final ByteBuffer emptyBuffer = ByteBuffer.allocate(0);
+    private final IoBuffer emptyBuffer = IoBuffer.allocate(0);
 
-    /**
-     * Handshake status
-     */
     private SSLEngineResult.HandshakeStatus handshakeStatus;
-
     private boolean initialHandshakeComplete;
-
-    /**
-     * Handshake complete?
-     */
     private boolean handshakeComplete;
-
     private boolean writingEncryptedData;
 
     /**
@@ -121,10 +105,6 @@
         init();
     }
 
-    public Logger getLogger() {
-        return logger;
-    }
-
     public void init() throws SSLException {
         if (sslEngine != null) {
             return;
@@ -156,19 +136,10 @@
         }
 
         sslEngine.beginHandshake();
-        handshakeStatus = 
sslEngine.getHandshakeStatus();//SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
+        handshakeStatus = sslEngine.getHandshakeStatus();
+        
         handshakeComplete = false;
         initialHandshakeComplete = false;
-
-        SslBufferUtil.initiate(sslEngine);
-
-        appBuffer = SslBufferUtil.getApplicationBuffer();
-
-        inNetBuffer = SslBufferUtil.getPacketBuffer();
-        outNetBuffer = SslBufferUtil.getPacketBuffer();
-        outNetBuffer.position(0);
-        outNetBuffer.limit(0);
-
         writingEncryptedData = false;
     }
 
@@ -188,20 +159,33 @@
                     "Unexpected exception from SSLEngine.closeInbound().", e);
         }
 
+        
+        if (outNetBuffer != null) {
+            
outNetBuffer.capacity(sslEngine.getSession().getPacketBufferSize());
+        } else {
+            createOutNetBuffer(0);
+        }
         try {
             do {
                 outNetBuffer.clear();
-            } while (sslEngine.wrap(emptyBuffer, outNetBuffer).bytesProduced() 
> 0);
+            } while (sslEngine.wrap(emptyBuffer.buf(), 
outNetBuffer.buf()).bytesProduced() > 0);
         } catch (SSLException e) {
-            logger.debug(
-                    "Unexpected exception from SSLEngine.wrap().", e);
+            // Ignore.
+        } finally {
+            destroyOutNetBuffer();
         }
+
         sslEngine.closeOutbound();
         sslEngine = null;
 
         preHandshakeEventQueue.clear();
     }
 
+    private void destroyOutNetBuffer() {
+        outNetBuffer.free();
+        outNetBuffer = null;
+    }
+
     public SslFilter getParent() {
         return parent;
     }
@@ -249,10 +233,6 @@
         IoFilterEvent scheduledWrite;
 
         while ((scheduledWrite = preHandshakeEventQueue.poll()) != null) {
-            if (logger.isDebugEnabled()) {
-                logger.debug( " Flushing buffered write request: "
-                        + scheduledWrite.getParameter());
-            }
             parent.filterWrite(scheduledWrite.getNextFilter(), session,
                     (WriteRequest) scheduledWrite.getParameter());
         }
@@ -297,21 +277,11 @@
      * @throws SSLException on errors
      */
     public void messageReceived(NextFilter nextFilter, ByteBuffer buf) throws 
SSLException {
-        if (buf.limit() > inNetBuffer.remaining()) {
-            // We have to expand inNetBuffer
-            inNetBuffer = SslBufferUtil.expandBuffer(inNetBuffer,
-                    inNetBuffer.capacity() + buf.limit() * 2);
-            // We also expand app. buffer (twice the size of in net. buffer)
-            appBuffer = SslBufferUtil.expandBuffer(appBuffer, inNetBuffer
-                    .capacity() * 2);
-            if (logger.isDebugEnabled()) {
-                logger.debug( " expanded inNetBuffer:"
-                        + inNetBuffer);
-                logger.debug( " expanded appBuffer:" + appBuffer);
-            }
-        }
-
         // append buf to inNetBuffer
+        if (inNetBuffer == null) {
+            inNetBuffer = 
IoBuffer.allocate(buf.remaining()).setAutoExpand(true);
+        }
+        
         inNetBuffer.put(buf);
         if (!handshakeComplete) {
             handshake(nextFilter);
@@ -321,8 +291,9 @@
 
         if (isInboundDone()) {
             // Rewind the MINA buffer if not all data is processed and inbound 
is finished.
-            buf.position(buf.position() - inNetBuffer.position());
-            inNetBuffer.clear();
+            int inNetBufferPosition = inNetBuffer == null? 0 : 
inNetBuffer.position();
+            buf.position(buf.position() - inNetBufferPosition);
+            inNetBuffer = null;
         }
     }
 
@@ -331,7 +302,9 @@
      *
      * @return buffer with data
      */
-    public ByteBuffer getAppBuffer() {
+    public IoBuffer fetchAppBuffer() {
+        IoBuffer appBuffer = this.appBuffer.flip();
+        this.appBuffer = null;
         return appBuffer;
     }
 
@@ -340,8 +313,14 @@
      *
      * @return buffer with data
      */
-    public ByteBuffer getOutNetBuffer() {
-        return outNetBuffer;
+    public IoBuffer fetchOutNetBuffer() {
+        IoBuffer answer = outNetBuffer;
+        if (answer == null) {
+            return emptyBuffer;
+        }
+        
+        outNetBuffer = null;
+        return answer.shrink();
     }
 
     /**
@@ -354,36 +333,27 @@
         if (!handshakeComplete) {
             throw new IllegalStateException();
         }
+        
+        if (!src.hasRemaining()) {
+            if (outNetBuffer == null) {
+                outNetBuffer = emptyBuffer;
+            }
+            return;
+        }
 
-        // The data buffer is (must be) empty, we can reuse the entire
-        // buffer.
-        outNetBuffer.clear();
+        createOutNetBuffer(src.remaining());
 
         // Loop until there is no more data in src
         while (src.hasRemaining()) {
 
-            if (src.remaining() > (outNetBuffer.capacity() - outNetBuffer
-                    .position()) / 2) {
-                // We have to expand outNetBuffer
-                // Note: there is no way to know the exact size required, but 
enrypted data
-                // shouln't need to be larger than twice the source data size?
-                outNetBuffer = SslBufferUtil.expandBuffer(outNetBuffer, src
-                        .capacity() * 2);
-                if (logger.isDebugEnabled()) {
-                    logger.debug( " expanded outNetBuffer:"
-                            + outNetBuffer);
-                }
-            }
-
-            SSLEngineResult result = sslEngine.wrap(src, outNetBuffer);
-            if (logger.isDebugEnabled()) {
-                logger.debug( " Wrap res:" + result);
-            }
-
+            SSLEngineResult result = sslEngine.wrap(src, outNetBuffer.buf());
             if (result.getStatus() == SSLEngineResult.Status.OK) {
                 if (result.getHandshakeStatus() == 
SSLEngineResult.HandshakeStatus.NEED_TASK) {
                     doTasks();
                 }
+            } else if (result.getStatus() == 
SSLEngineResult.Status.BUFFER_OVERFLOW) {
+                outNetBuffer.capacity(outNetBuffer.capacity() << 1);
+                outNetBuffer.limit(outNetBuffer.capacity());
             } else {
                 throw new SSLException("SSLEngine error during encrypt: "
                         + result.getStatus() + " src: " + src
@@ -408,10 +378,19 @@
 
         sslEngine.closeOutbound();
 
-        // By RFC 2616, we can "fire and forget" our close_notify
-        // message, so that's what we'll do here.
-        outNetBuffer.clear();
-        SSLEngineResult result = sslEngine.wrap(emptyBuffer, outNetBuffer);
+        createOutNetBuffer(0);
+        SSLEngineResult result;
+        for (;;) {
+            result = sslEngine.wrap(emptyBuffer.buf(), outNetBuffer.buf());
+            if (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) {
+                outNetBuffer.capacity(outNetBuffer.capacity() << 1);
+                outNetBuffer.limit(outNetBuffer.capacity());
+                System.out.println("new capacity: " + outNetBuffer.limit());
+            } else {
+                break;
+            }
+        }
+
         if (result.getStatus() != SSLEngineResult.Status.CLOSED) {
             throw new SSLException("Improper close state: " + result);
         }
@@ -463,21 +442,10 @@
      * Perform any handshaking processing.
      */
     public void handshake(NextFilter nextFilter) throws SSLException {
-        if (logger.isDebugEnabled()) {
-            logger.debug( " doHandshake()");
-        }
-
         for (; ;) {
             if (handshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED) {
-                session.setAttribute(SslFilter.SSL_SESSION, sslEngine
-                        .getSession());
-                if (logger.isDebugEnabled()) {
-                    SSLSession sslSession = sslEngine.getSession();
-                    logger.debug(
-                            "  handshakeStatus=FINISHED");
-                    logger.debug( "  sslSession CipherSuite used "
-                            + sslSession.getCipherSuite());
-                }
+                session.setAttribute(
+                        SslFilter.SSL_SESSION, sslEngine.getSession());
                 handshakeComplete = true;
                 if (!initialHandshakeComplete
                         && 
session.containsAttribute(SslFilter.USE_NOTIFICATION)) {
@@ -489,17 +457,9 @@
                 }
                 break;
             } else if (handshakeStatus == 
SSLEngineResult.HandshakeStatus.NEED_TASK) {
-                if (logger.isDebugEnabled()) {
-                    logger.debug(
-                            "  handshakeStatus=NEED_TASK");
-                }
                 handshakeStatus = doTasks();
             } else if (handshakeStatus == 
SSLEngineResult.HandshakeStatus.NEED_UNWRAP) {
                 // we need more data read
-                if (logger.isDebugEnabled()) {
-                    logger.debug(
-                            "  handshakeStatus=NEED_UNWRAP");
-                }
                 SSLEngineResult.Status status = unwrapHandshake(nextFilter);
                 if (status == SSLEngineResult.Status.BUFFER_UNDERFLOW
                         || isInboundDone()) {
@@ -507,22 +467,22 @@
                     break;
                 }
             } else if (handshakeStatus == 
SSLEngineResult.HandshakeStatus.NEED_WRAP) {
-                if (logger.isDebugEnabled()) {
-                    logger.debug(
-                            "  handshakeStatus=NEED_WRAP");
-                }
                 // First make sure that the out buffer is completely empty. 
Since we
                 // cannot call wrap with data left on the buffer
-                if (outNetBuffer.hasRemaining()) {
-                    if (logger.isDebugEnabled()) {
-                        logger.debug("  Still data in out buffer!");
-                    }
+                if (outNetBuffer != null && outNetBuffer.hasRemaining()) {
                     break;
                 }
-                outNetBuffer.clear();
-                SSLEngineResult result = sslEngine.wrap(emptyBuffer, 
outNetBuffer);
-                if (logger.isDebugEnabled()) {
-                    logger.debug( " Wrap res:" + result);
+                
+                SSLEngineResult result;
+                createOutNetBuffer(0);
+                for (;;) {
+                    result = sslEngine.wrap(emptyBuffer.buf(), 
outNetBuffer.buf());
+                    if (result.getStatus() == 
SSLEngineResult.Status.BUFFER_OVERFLOW) {
+                        outNetBuffer.capacity(outNetBuffer.capacity() << 1);
+                        outNetBuffer.limit(outNetBuffer.capacity());
+                    } else {
+                        break;
+                    }
                 }
 
                 outNetBuffer.flip();
@@ -535,10 +495,24 @@
         }
     }
 
+    private void createOutNetBuffer(int expectedRemaining) {
+        // SSLEngine requires us to allocate unnecessarily big buffer
+        // even for small data.  *Shrug*
+        int capacity = Math.max(
+                expectedRemaining,
+                sslEngine.getSession().getPacketBufferSize());
+        
+        if (outNetBuffer != null) {
+            outNetBuffer.capacity(capacity);
+        } else {
+            outNetBuffer = IoBuffer.allocate(capacity).minimumCapacity(0);
+        }
+    }
+
     public WriteFuture writeNetBuffer(NextFilter nextFilter)
             throws SSLException {
         // Check if any net data needed to be writen
-        if (!getOutNetBuffer().hasRemaining()) {
+        if (outNetBuffer == null || !outNetBuffer.hasRemaining()) {
             // no; bail out
             return null;
         }
@@ -551,16 +525,7 @@
         WriteFuture writeFuture = null;
 
         try {
-            if (logger.isDebugEnabled()) {
-                logger.debug( " write outNetBuffer: "
-                        + getOutNetBuffer());
-            }
-            IoBuffer writeBuffer = copy(getOutNetBuffer());
-            if (logger.isDebugEnabled()) {
-                logger.debug( " session write: " + writeBuffer);
-            }
-            //debug("outNetBuffer (after copy): {0}", 
sslHandler.getOutNetBuffer());
-
+            IoBuffer writeBuffer = fetchOutNetBuffer();
             writeFuture = new DefaultWriteFuture(session);
             parent.filterWrite(nextFilter, session, new DefaultWriteRequest(
                     writeBuffer, writeFuture));
@@ -575,15 +540,12 @@
                     newSsle.initCause(ssle);
                     throw newSsle;
                 }
-                if (getOutNetBuffer().hasRemaining()) {
-                    if (logger.isDebugEnabled()) {
-                        logger.debug( " write outNetBuffer2: "
-                                + getOutNetBuffer());
-                    }
-                    IoBuffer writeBuffer2 = copy(getOutNetBuffer());
+                
+                IoBuffer outNetBuffer = fetchOutNetBuffer();
+                if (outNetBuffer != null && outNetBuffer.hasRemaining()) {
                     writeFuture = new DefaultWriteFuture(session);
                     parent.filterWrite(nextFilter, session,
-                            new DefaultWriteRequest(writeBuffer2, 
writeFuture));
+                            new DefaultWriteRequest(outNetBuffer, 
writeFuture));
                 }
             }
         } finally {
@@ -594,17 +556,23 @@
     }
 
     private void unwrap(NextFilter nextFilter) throws SSLException {
-        if (logger.isDebugEnabled()) {
-            logger.debug( " unwrap()");
+        // Prepare the net data for reading.
+        if (inNetBuffer != null) {
+            inNetBuffer.flip();
         }
 
-        // Prepare the net data for reading.
-        inNetBuffer.flip();
+        if (inNetBuffer == null || !inNetBuffer.hasRemaining()) {
+            return;
+        }
 
         SSLEngineResult res = unwrap0();
 
         // prepare to be written again
-        inNetBuffer.compact();
+        if (inNetBuffer.hasRemaining()) {
+            inNetBuffer.compact();
+        } else {
+            inNetBuffer = null;
+        }
 
         checkStatus(res);
 
@@ -612,12 +580,15 @@
     }
 
     private SSLEngineResult.Status unwrapHandshake(NextFilter nextFilter) 
throws SSLException {
-        if (logger.isDebugEnabled()) {
-            logger.debug( " unwrapHandshake()");
-        }
-
         // Prepare the net data for reading.
-        inNetBuffer.flip();
+        if (inNetBuffer != null) {
+            inNetBuffer.flip();
+        }
+        
+        if (inNetBuffer == null || !inNetBuffer.hasRemaining()) {
+            // Need more data.
+            return SSLEngineResult.Status.BUFFER_UNDERFLOW;
+        }
 
         SSLEngineResult res = unwrap0();
         handshakeStatus = res.getHandshakeStatus();
@@ -632,12 +603,20 @@
             res = unwrap0();
 
             // prepare to be written again
-            inNetBuffer.compact();
+            if (inNetBuffer.hasRemaining()) {
+                inNetBuffer.compact();
+            } else {
+                inNetBuffer = null;
+            }
 
             renegotiateIfNeeded(nextFilter, res);
         } else {
             // prepare to be written again
-            inNetBuffer.compact();
+            if (inNetBuffer.hasRemaining()) {
+                inNetBuffer.compact();
+            } else {
+                inNetBuffer = null;
+            }
         }
 
         return res.getStatus();
@@ -649,7 +628,6 @@
                 && res.getStatus() != SSLEngineResult.Status.BUFFER_UNDERFLOW
                 && res.getHandshakeStatus() != 
SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
             // Renegotiation required.
-            logger.debug( " Renegotiating...");
             handshakeComplete = false;
             handshakeStatus = res.getHandshakeStatus();
             handshake(nextFilter);
@@ -657,19 +635,23 @@
     }
 
     private SSLEngineResult unwrap0() throws SSLException {
+        if (appBuffer == null) {
+            appBuffer = IoBuffer.allocate(inNetBuffer.remaining());
+        } else {
+            appBuffer.expand(inNetBuffer.remaining());
+        }
+        
         SSLEngineResult res;
         do {
-            if (logger.isDebugEnabled()) {
-                logger.debug( "   inNetBuffer: " + inNetBuffer);
-                logger.debug( "   appBuffer: " + appBuffer);
-            }
-            res = sslEngine.unwrap(inNetBuffer, appBuffer);
-            if (logger.isDebugEnabled()) {
-                logger.debug( " Unwrap res:" + res);
-            }
-        } while (res.getStatus() == SSLEngineResult.Status.OK
-                && (handshakeComplete && res.getHandshakeStatus() == 
SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING
-                || res.getHandshakeStatus() == 
SSLEngineResult.HandshakeStatus.NEED_UNWRAP));
+            res = sslEngine.unwrap(inNetBuffer.buf(), appBuffer.buf());
+            if (res.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) {
+                appBuffer.capacity(appBuffer.capacity() << 1);
+                appBuffer.limit(appBuffer.capacity());
+                continue;
+            }
+        } while ((res.getStatus() == SSLEngineResult.Status.OK || 
res.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) &&
+                 (handshakeComplete && res.getHandshakeStatus() == 
SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING ||
+                  res.getHandshakeStatus() == 
SSLEngineResult.HandshakeStatus.NEED_UNWRAP));
 
         return res;
     }
@@ -678,24 +660,13 @@
      * Do all the outstanding handshake tasks in the current Thread.
      */
     private SSLEngineResult.HandshakeStatus doTasks() {
-        if (logger.isDebugEnabled()) {
-            logger.debug( "   doTasks()");
-        }
-
         /*
          * We could run this in a separate thread, but I don't see the need
          * for this when used from SSLFilter. Use thread filters in MINA 
instead?
          */
         Runnable runnable;
         while ((runnable = sslEngine.getDelegatedTask()) != null) {
-            if (logger.isDebugEnabled()) {
-                logger.debug( "    doTask: " + runnable);
-            }
             runnable.run();
-        }
-        if (logger.isDebugEnabled()) {
-            logger.debug( "   doTasks(): "
-                    + sslEngine.getHandshakeStatus());
         }
         return sslEngine.getHandshakeStatus();
     }


Reply via email to