You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by tr...@apache.org on 2005/10/26 16:04:31 UTC

svn commit: r328648 - in /directory/network/trunk/src: java/org/apache/mina/common/ java/org/apache/mina/common/support/ java/org/apache/mina/filter/ java/org/apache/mina/filter/support/ test/org/apache/mina/examples/echoserver/

Author: trustin
Date: Wed Oct 26 07:04:21 2005
New Revision: 328648

URL: http://svn.apache.org/viewcvs?rev=328648&view=rev
Log:
Resolving an issue: DIRMINA-106 - Add TLS closure to SSLFilter
* Modified ConntectorTest to test TLS closure
* Added SSLFilter.closeOutbound() to let user send close_notify
* Removed unused flags in SSLHandler
* Added WriteFuture.new(Not)WrittenFuture() method
* Added IoFilterChain.getNextFilter() method

I tested TLS closure work correctly.  It worked great.

Modified:
    directory/network/trunk/src/java/org/apache/mina/common/IoFilterChain.java
    directory/network/trunk/src/java/org/apache/mina/common/WriteFuture.java
    directory/network/trunk/src/java/org/apache/mina/common/support/AbstractIoFilterChain.java
    directory/network/trunk/src/java/org/apache/mina/filter/SSLFilter.java
    directory/network/trunk/src/java/org/apache/mina/filter/support/SSLHandler.java
    directory/network/trunk/src/test/org/apache/mina/examples/echoserver/ConnectorTest.java

Modified: directory/network/trunk/src/java/org/apache/mina/common/IoFilterChain.java
URL: http://svn.apache.org/viewcvs/directory/network/trunk/src/java/org/apache/mina/common/IoFilterChain.java?rev=328648&r1=328647&r2=328648&view=diff
==============================================================================
--- directory/network/trunk/src/java/org/apache/mina/common/IoFilterChain.java (original)
+++ directory/network/trunk/src/java/org/apache/mina/common/IoFilterChain.java Wed Oct 26 07:04:21 2005
@@ -46,9 +46,19 @@
      * Returns the name of the specified {@link IoFilter} in this chain.
      * @return <tt>null</tt> if there's no such filter in this chain.
      */
-    
     String getName( IoFilter filter );
     
+    /**
+     * Returns the {@link NextFilter} of the {@link IoFilter} with the specified
+     * <tt>name</tt> in this chain.
+     */
+    NextFilter getNextFilter( String name );
+
+    /**
+     * Returns the {@link NextFilter} of the specified <tt>filter</tt> in this chain.
+     */
+    NextFilter getNextFilter( IoFilter filter );
+
     /**
      * Returns the list of all filters this chain contains.
      */

Modified: directory/network/trunk/src/java/org/apache/mina/common/WriteFuture.java
URL: http://svn.apache.org/viewcvs/directory/network/trunk/src/java/org/apache/mina/common/WriteFuture.java?rev=328648&r1=328647&r2=328648&view=diff
==============================================================================
--- directory/network/trunk/src/java/org/apache/mina/common/WriteFuture.java (original)
+++ directory/network/trunk/src/java/org/apache/mina/common/WriteFuture.java Wed Oct 26 07:04:21 2005
@@ -27,6 +27,26 @@
 public class WriteFuture extends IoFuture
 {
     /**
+     * Returns a new {@link WriteFuture} which is already marked as 'written'.
+     */
+    public static WriteFuture newWrittenFuture()
+    {
+        WriteFuture unwrittenFuture = new WriteFuture();
+        unwrittenFuture.setWritten( true );
+        return unwrittenFuture;
+    }
+
+    /**
+     * Returns a new {@link WriteFuture} which is already marked as 'not written'.
+     */
+    public static WriteFuture newNotWrittenFuture()
+    {
+        WriteFuture unwrittenFuture = new WriteFuture();
+        unwrittenFuture.setWritten( false );
+        return unwrittenFuture;
+    }
+    
+    /**
      * Returns <tt>true</tt> if the write operation is finished successfully.
      */
     public boolean isWritten()

Modified: directory/network/trunk/src/java/org/apache/mina/common/support/AbstractIoFilterChain.java
URL: http://svn.apache.org/viewcvs/directory/network/trunk/src/java/org/apache/mina/common/support/AbstractIoFilterChain.java?rev=328648&r1=328647&r2=328648&view=diff
==============================================================================
--- directory/network/trunk/src/java/org/apache/mina/common/support/AbstractIoFilterChain.java (original)
+++ directory/network/trunk/src/java/org/apache/mina/common/support/AbstractIoFilterChain.java Wed Oct 26 07:04:21 2005
@@ -261,6 +261,27 @@
         return e.name;
     }
     
+    public NextFilter getNextFilter( String name )
+    {
+        Entry e = ( Entry ) name2entry.get( name );
+        if ( e == null )
+        {
+            return null;
+        }
+        return e.nextFilter;
+    }
+
+    public NextFilter getNextFilter( IoFilter filter )
+    {
+        Entry e = ( Entry ) filter2entry.get( filter );
+        if( e == null )
+        {
+            return null;
+        }
+        
+        return e.nextFilter;
+    }
+
     public synchronized void addFirst( String name,
                                        IoFilter filter ) throws Exception
     {

Modified: directory/network/trunk/src/java/org/apache/mina/filter/SSLFilter.java
URL: http://svn.apache.org/viewcvs/directory/network/trunk/src/java/org/apache/mina/filter/SSLFilter.java?rev=328648&r1=328647&r2=328648&view=diff
==============================================================================
--- directory/network/trunk/src/java/org/apache/mina/filter/SSLFilter.java (original)
+++ directory/network/trunk/src/java/org/apache/mina/filter/SSLFilter.java Wed Oct 26 07:04:21 2005
@@ -94,6 +94,8 @@
 
     private static final Logger log = LoggerFactory.getLogger( SSLFilter.class );
 
+    private IoFilterChain parent;
+    
     // SSL Context
     private SSLContext sslContext;
 
@@ -125,6 +127,31 @@
     {
         return ( SSLSession ) session.getAttribute( SSL_SESSION );
     }
+    
+    /**
+     * Sends TLS <tt>close_notify</tt> message to initiate TLS closure.
+     * 
+     * @param session the {@link IoSession} to initiate TLS closure
+     * @throws SSLException if failed to initiate TLS closure
+     * @throws IllegalArgumentException if this filter is not managing the specified session
+     */
+    public WriteFuture closeOutbound( IoSession session ) throws SSLException
+    {
+        SSLHandler handler = getSSLSessionHandler( session );
+        if( handler == null )
+        {
+            // Return a dummy future to prevent NFE.
+            return WriteFuture.newNotWrittenFuture();
+        }
+        
+        if( handler.getParent() != this )
+        {
+            throw new IllegalArgumentException( "Not managed by this filter." );
+        }
+        
+        NextFilter nextFilter = parent.getNextFilter( this );
+        return initiateClosure( nextFilter, session );
+    }
 
     /**
      * Returns <tt>true</tt> if the engine is set to use client mode
@@ -226,12 +253,18 @@
     
     public void init( IoFilterChain parent, NextFilter nextFilter ) throws SSLException
     {
+        this.parent = parent;
         Object managerOrSession = parent.getParent();
         if( managerOrSession instanceof IoSession )
         {
             createSSLSessionHandler( nextFilter, ( IoSession ) managerOrSession );
         }
     }
+    
+    public void destroy( IoFilterChain parent, NextFilter nextFilter )
+    {
+        
+    }
 
     // IoFilter impl.
 
@@ -244,27 +277,20 @@
 
     public void sessionClosed( NextFilter nextFilter, IoSession session ) throws SSLException
     {
-        SSLHandler sslHandler = getSSLSessionHandler( session );
         if( log.isDebugEnabled() )
         {
-            log.debug( session + " Closed: " + sslHandler );
+            log.debug( session + " Closed: " + getSSLSessionHandler( session ) );
         }
-        if( sslHandler != null )
+        
+        // release resources
+        try
         {
-            synchronized( sslHandler )
-            {
-                // release resources
-                removeSSLSessionHandler( session );
-                try
-                {
-                    sslHandler.release();
-                }
-                finally
-                {
-                   // notify closed session
-                   nextFilter.sessionClosed( session );
-                }
-            }
+            removeSSLSessionHandler( session );
+        }
+        finally
+        {
+           // notify closed session
+           nextFilter.sessionClosed( session );
         }
     }
    
@@ -289,14 +315,22 @@
                     // Handle data to be forwarded to application or written to net
                     handleSSLData( nextFilter, session, sslHandler );
 
-                    if( sslHandler.isClosed() )
+                    if( sslHandler.isInboundDone() )
                     {
-                        if( log.isDebugEnabled() )
+                        if( sslHandler.isOutboundDone() )
                         {
-                            log.debug(
-                                     session + " SSL Session closed. Closing connection.." );
+                            if( log.isDebugEnabled() )
+                            {
+                                log.debug(
+                                         session + " SSL Session closed." );
+                            }
+
+                            removeSSLSessionHandler( session );
+                        }
+                        else
+                        {
+                            initiateClosure( nextFilter, session );
                         }
-                        session.close();
                     }
                 }
                 catch( SSLException ssle )
@@ -413,7 +447,7 @@
     {
         try
         {
-            initiateClosure( nextFilter, session );
+            initiateClosure( nextFilter, session ).join();
         }
         finally
         {
@@ -421,37 +455,26 @@
         }
     }
     
-    private void initiateClosure( NextFilter nextFilter, IoSession session ) throws SSLException
+    private WriteFuture initiateClosure( NextFilter nextFilter, IoSession session ) throws SSLException
     {
         SSLHandler handler = getSSLSessionHandler( session );
         if( handler == null )
         {
-            return;
+            return WriteFuture.newNotWrittenFuture();
         }
         
-        WriteFuture future;
-        try
+        synchronized( handler )
         {
-            synchronized( handler )
+            if( handler.isOutboundDone() )
             {
-                // shut down
-                handler.shutdown();
-                
-                // there might be data to write out here?
-                future = handler.writeNetBuffer( nextFilter, session );
-                
-                // release buffers
-                handler.release();
+                return WriteFuture.newNotWrittenFuture();
             }
+
+            // shut down
+            handler.closeOutbound();
             
-            if( future != null )
-            {
-                future.join();
-            }
-        }
-        finally
-        {
-            removeSSLSessionHandler( session );
+            // there might be data to write out here?
+            return handler.writeNetBuffer( nextFilter, session );
         }
     }
 
@@ -532,9 +555,18 @@
         return ( SSLHandler ) session.getAttribute( SSL_HANDLER );
     }
 
-    private SSLHandler removeSSLSessionHandler( IoSession session )
+    private void removeSSLSessionHandler( IoSession session )
     {
-        return ( SSLHandler ) session.removeAttribute( SSL_HANDLER );
+        SSLHandler sslHandler = getSSLSessionHandler( session );
+        if( sslHandler != null )
+        {
+            synchronized( sslHandler )
+            {
+                // release resources
+                session.removeAttribute( SSL_HANDLER );
+                sslHandler.release();
+            }
+        }
     }
 
     private static class EncryptedBuffer extends ByteBufferProxy

Modified: directory/network/trunk/src/java/org/apache/mina/filter/support/SSLHandler.java
URL: http://svn.apache.org/viewcvs/directory/network/trunk/src/java/org/apache/mina/filter/support/SSLHandler.java?rev=328648&r1=328647&r2=328648&view=diff
==============================================================================
--- directory/network/trunk/src/java/org/apache/mina/filter/support/SSLHandler.java (original)
+++ directory/network/trunk/src/java/org/apache/mina/filter/support/SSLHandler.java Wed Oct 26 07:04:21 2005
@@ -52,11 +52,8 @@
     private static final Logger log = LoggerFactory.getLogger( SSLFilter.class );
 
     private final SSLFilter parent;
-
     private final IoSession session;
-    
     private final Queue scheduledWrites = new Queue();
-
     private final SSLEngine sslEngine;
 
     /**
@@ -89,14 +86,6 @@
      */
     private boolean initialHandshakeComplete;
 
-    /**
-     * We have received the shutdown request by our caller, and have
-     * closed our outbound side.
-     */
-    private boolean shutdown = false;
-
-    private boolean closed = false;
-
     private boolean isWritingEncryptedData = false;
     
     /**
@@ -145,6 +134,11 @@
         outNetBuffer.position( 0 );
         outNetBuffer.limit( 0 );
     }
+    
+    public SSLFilter getParent()
+    {
+        return parent;
+    }
 
     /**
      * Indicate that we are writing encrypted data.
@@ -171,12 +165,14 @@
         return initialHandshakeComplete;
     }
 
-    /**
-     * Check if SSL sesssion closed
-     */
-    public boolean isClosed()
+    public boolean isInboundDone()
+    {
+        return sslEngine.isInboundDone();
+    }
+
+    public boolean isOutboundDone()
     {
-        return closed;
+        return sslEngine.isOutboundDone();
     }
 
     /**
@@ -184,7 +180,7 @@
      */
     public boolean needToCompleteInitialHandshake()
     {
-        return ( initialHandshakeStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP && !closed );
+        return ( initialHandshakeStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP && !isInboundDone() );
     }
     
     public synchronized void scheduleWrite( NextFilter nextFilter, WriteRequest writeRequest )
@@ -295,9 +291,9 @@
      *
      * @throws SSLException on errors
      */
-    public void shutdown() throws SSLException
+    public void closeOutbound() throws SSLException
     {
-        if( !shutdown )
+        if( !sslEngine.isOutboundDone() )
         {
             doShutdown();
         }
@@ -445,7 +441,7 @@
                 SSLEngineResult.Status status = unwrapHandshake();
                 if( ( initialHandshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED 
                 		&&  status == SSLEngineResult.Status.BUFFER_UNDERFLOW )
-                        || closed )
+                        || isInboundDone() )
                 {
                     // We need more data or the session is closed
                     return;
@@ -494,7 +490,7 @@
         if( !getOutNetBuffer().hasRemaining() )
         {
             // no; bail out
-            return null;
+            return WriteFuture.newNotWrittenFuture();
         }
         
         WriteFuture writeFuture = null;
@@ -558,7 +554,14 @@
             }
         }
         
-        return writeFuture;
+        if( writeFuture != null )
+        {
+            return writeFuture;
+        }
+        else
+        {
+            return WriteFuture.newNotWrittenFuture();
+        }
     }
     
     
@@ -590,12 +593,6 @@
         }
         while( res.getStatus() == SSLEngineResult.Status.OK );
 
-        // If we are CLOSED, set flag
-        if( res.getStatus() == SSLEngineResult.Status.CLOSED )
-        {
-            closed = true;
-        }
-
         // prepare to be written again
         inNetBuffer.compact();
         // prepare app data to be read
@@ -663,12 +660,6 @@
 			} while (res.getStatus() == SSLEngineResult.Status.OK);
 		}
 
-        // If we are CLOSED, set flag
-        if( res.getStatus() == SSLEngineResult.Status.CLOSED )
-        {
-            closed = true;
-        }
-        
         // prepare to be written again
         inNetBuffer.compact();
 
@@ -724,10 +715,9 @@
     void doShutdown() throws SSLException
     {
 
-        if( !shutdown )
+        if( !sslEngine.isOutboundDone() )
         {
             sslEngine.closeOutbound();
-            shutdown = true;
         }
 
         // By RFC 2616, we can "fire and forget" our close_notify

Modified: directory/network/trunk/src/test/org/apache/mina/examples/echoserver/ConnectorTest.java
URL: http://svn.apache.org/viewcvs/directory/network/trunk/src/test/org/apache/mina/examples/echoserver/ConnectorTest.java?rev=328648&r1=328647&r2=328648&view=diff
==============================================================================
--- directory/network/trunk/src/test/org/apache/mina/examples/echoserver/ConnectorTest.java (original)
+++ directory/network/trunk/src/test/org/apache/mina/examples/echoserver/ConnectorTest.java Wed Oct 26 07:04:21 2005
@@ -76,7 +76,7 @@
             new SSLFilter( BogusSSLContextFactory.getInstance( true ) );
         IoAcceptor acceptor = registry.getAcceptor( TransportType.SOCKET );
         acceptor.getFilterChain().addLast( "SSL", acceptorSSLFilter );
-
+        
         // Create a connector
         IoConnector connector = new SocketConnector();
         
@@ -170,6 +170,11 @@
         }
 
         writeFuture.join();
+        
+        // Send closeNotify to test TLS closure.
+        SSLFilter sslf = ( SSLFilter ) connector.getFilterChain().get("SSL");
+        sslf.closeOutbound( session ).join();
+        
         session.close();
         
         Assert.assertEquals( 160, readBuf.position() );