This is an automated email from the ASF dual-hosted git repository.

johnnyv pushed a commit to branch bugfix/DIRMINA1132
in repository https://gitbox.apache.org/repos/asf/mina.git


The following commit(s) were added to refs/heads/bugfix/DIRMINA1132 by this 
push:
     new 4c11155  SSL improvements
4c11155 is described below

commit 4c1115590e183267d5536ded8d3eec316efb128f
Author: Jonathan Valliere <john...@apache.org>
AuthorDate: Fri Aug 6 14:09:41 2021 -0400

    SSL improvements
    
    - Adds linger support to ssl closure; you can now choose to close the
    ssl after pending writes are completed.
    - Adds WriteRejectedException to dispatch exceptions for unwritten
    messages once SSL is closed.
    - Changes SSL_SECURED to the SSLSession object; once SSL_SECURED it set
    the user has access to the session information.
---
 .../mina/core/write/WriteRejectedException.java    | 44 +++++++++++++++++
 .../org/apache/mina/filter/ssl2/SSL2Filter.java    | 38 ++++++++++-----
 .../org/apache/mina/filter/ssl2/SSL2Handler.java   |  8 +--
 .../org/apache/mina/filter/ssl2/SSL2HandlerG0.java | 57 +++++++++++++++++++---
 4 files changed, 124 insertions(+), 23 deletions(-)

diff --git 
a/mina-core/src/main/java/org/apache/mina/core/write/WriteRejectedException.java
 
b/mina-core/src/main/java/org/apache/mina/core/write/WriteRejectedException.java
new file mode 100644
index 0000000..a0d4a01
--- /dev/null
+++ 
b/mina-core/src/main/java/org/apache/mina/core/write/WriteRejectedException.java
@@ -0,0 +1,44 @@
+package org.apache.mina.core.write;
+
+import java.util.Collection;
+
+public class WriteRejectedException extends WriteException {
+       private static final long serialVersionUID = 6272160412793858438L;
+
+       /**
+        * Create a new WriteRejectedException instance
+        * 
+        * @param requests The {@link WriteRequest} which has been rejected
+        * @param message  The error message
+        */
+       public WriteRejectedException(WriteRequest requests, String message) {
+               super(requests, message);
+       }
+
+       /**
+        * Create a new WriteRejectedException instance
+        * 
+        * @param requests The {@link WriteRequest} which has been rejected
+        */
+       public WriteRejectedException(WriteRequest requests) {
+               super(requests);
+       }
+
+       /**
+        * Create a new WriteRejectedException instance
+        * 
+        * @param requests The {@link WriteRequest} which has been rejected
+        */
+       public WriteRejectedException(Collection<WriteRequest> requests) {
+               super(requests);
+       }
+       
+       /**
+        * Create a new WriteRejectedException instance
+        * 
+        * @param requests The {@link WriteRequest} which has been rejected
+        */
+       public WriteRejectedException(Collection<WriteRequest> requests, String 
message) {
+               super(requests, message);
+       }
+}
diff --git 
a/mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2Filter.java 
b/mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2Filter.java
index 0b36259..00554db 100644
--- a/mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2Filter.java
+++ b/mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2Filter.java
@@ -49,12 +49,6 @@ import org.slf4j.LoggerFactory;
  * @author <a href="http://mina.apache.org";>Apache MINA Project</a>
  */
 public class SSL2Filter extends IoFilterAdapter {
-
-       /**
-        * Returns the SSL2Handler object
-        */
-       static public final AttributeKey SSL_HANDLER = new 
AttributeKey(SSL2Filter.class, "handler");
-
        /**
         * The presence of this attribute in a session indicates that the 
session is
         * secured.
@@ -62,6 +56,11 @@ public class SSL2Filter extends IoFilterAdapter {
        static public final AttributeKey SSL_SECURED = new 
AttributeKey(SSL2Filter.class, "status");
 
        /**
+        * Returns the SSL2Handler object
+        */
+       static protected final AttributeKey SSL_HANDLER = new 
AttributeKey(SSL2Filter.class, "handler");
+
+       /**
         * The logger
         */
        static protected final Logger LOGGER = 
LoggerFactory.getLogger(SSL2Filter.class);
@@ -194,11 +193,7 @@ public class SSL2Filter extends IoFilterAdapter {
        @Override
        public void onPreRemove(IoFilterChain parent, String name, NextFilter 
next) throws Exception {
                IoSession session = parent.getSession();
-               session.removeAttribute(SSL_SECURED);
-               SSL2Handler x = 
SSL2Handler.class.cast(session.removeAttribute(SSL_HANDLER));
-               if (x != null) {
-                       x.close(next);
-               }
+               onClose(next, session, false);
        }
 
        /**
@@ -209,7 +204,7 @@ public class SSL2Filter extends IoFilterAdapter {
         * @param session
         * @throws Exception
         */
-       protected void onConnected(NextFilter next, IoSession session) throws 
Exception {
+       synchronized protected void onConnected(NextFilter next, IoSession 
session) throws Exception {
                SSL2Handler x = 
SSL2Handler.class.cast(session.getAttribute(SSL_HANDLER));
 
                if (x == null) {
@@ -222,6 +217,14 @@ public class SSL2Filter extends IoFilterAdapter {
                x.open(next);
        }
 
+       synchronized protected void onClose(NextFilter next, IoSession session, 
boolean linger) throws Exception {
+               session.removeAttribute(SSL_SECURED);
+               SSL2Handler x = 
SSL2Handler.class.cast(session.removeAttribute(SSL_HANDLER));
+               if (x != null) {
+                       x.close(next, linger);
+               }
+       }
+       
        /**
         * Customization handler for creating the engine
         * 
@@ -260,6 +263,17 @@ public class SSL2Filter extends IoFilterAdapter {
         * {@inheritDoc}
         */
        @Override
+       public void sessionClosed(NextFilter next, IoSession session) throws 
Exception {
+               if (LOGGER.isDebugEnabled())
+                       LOGGER.debug("session {} closed", session);
+               this.onClose(next, session, false);
+               super.sessionClosed(next, session);
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
        public void messageReceived(NextFilter next, IoSession session, Object 
message) throws Exception {
                if (LOGGER.isDebugEnabled())
                        LOGGER.debug("session {} received {}", session, 
message);
diff --git 
a/mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2Handler.java 
b/mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2Handler.java
index 4206ba6..b5e522b 100644
--- a/mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2Handler.java
+++ b/mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2Handler.java
@@ -11,6 +11,7 @@ import javax.net.ssl.SSLSession;
 import org.apache.mina.core.buffer.IoBuffer;
 import org.apache.mina.core.filterchain.IoFilter.NextFilter;
 import org.apache.mina.core.session.IoSession;
+import org.apache.mina.core.write.WriteRejectedException;
 import org.apache.mina.core.write.WriteRequest;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -140,18 +141,19 @@ public abstract class SSL2Handler {
         * @param next
         * 
         * @throws SSLException
+        * @throws WriteRejectedException when the session is closing
         */
-       abstract public void write(NextFilter next, final WriteRequest request) 
throws SSLException;
+       abstract public void write(NextFilter next, final WriteRequest request) 
throws SSLException, WriteRejectedException;
 
        /**
         * Closes the encryption session and writes any required messages
         * 
-        * @param session
         * @param next
+        * @param linger if true, write any queued messages before closing
         * 
         * @throws SSLException
         */
-       abstract public void close(NextFilter next) throws SSLException;
+       abstract public void close(NextFilter next, final boolean linger) 
throws SSLException;
 
        /**
         * {@inheritDoc}
diff --git 
a/mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2HandlerG0.java 
b/mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2HandlerG0.java
index 1b308aa..fd2ecd1 100644
--- a/mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2HandlerG0.java
+++ b/mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2HandlerG0.java
@@ -1,6 +1,7 @@
 package org.apache.mina.filter.ssl2;
 
 import java.nio.BufferOverflowException;
+import java.util.ArrayList;
 import java.util.concurrent.Executor;
 
 import javax.net.ssl.SSLEngine;
@@ -10,6 +11,7 @@ import javax.net.ssl.SSLException;
 import org.apache.mina.core.buffer.IoBuffer;
 import org.apache.mina.core.filterchain.IoFilter.NextFilter;
 import org.apache.mina.core.session.IoSession;
+import org.apache.mina.core.write.WriteRejectedException;
 import org.apache.mina.core.write.WriteRequest;
 import org.apache.mina.filter.ssl.SslEvent;
 
@@ -46,7 +48,17 @@ public class SSL2HandlerG0 extends SSL2Handler {
        protected boolean mHandshakeStarted = false;
 
        /**
-        * Holds the decoder thread reference
+        * Indicates that the outbound is closing
+        */
+       protected boolean mOutboundClosing = false;
+
+       /**
+        * Indicates that previously queued messages should be written before 
closing
+        */
+       protected boolean mOutboundLinger = false;
+
+       /**
+        * Holds the decoder thread reference; used for recursion detection
         */
        protected Thread mDecodeThread = null;
 
@@ -207,11 +219,16 @@ public class SSL2HandlerG0 extends SSL2Handler {
        /**
         * {@inheritDoc}
         */
-       synchronized public void write(final NextFilter next, final 
WriteRequest request) throws SSLException {
+       synchronized public void write(final NextFilter next, final 
WriteRequest request)
+                       throws SSLException, WriteRejectedException {
                if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("{} write() - source {}", toString(), 
request);
                }
 
+               if (this.mOutboundClosing) {
+                       throw new WriteRejectedException(request, "closing");
+               }
+
                if (this.mEncodeQueue.isEmpty()) {
                        if (qwrite(next, request) == false) {
                                if (LOGGER.isDebugEnabled()) {
@@ -357,6 +374,10 @@ public class SSL2HandlerG0 extends SSL2Handler {
         */
        @SuppressWarnings("incomplete-switch")
        protected boolean lwrite(NextFilter next, IoBuffer source, IoBuffer 
dest) throws SSLException {
+               if (this.mOutboundClosing && this.mEngine.isOutboundDone()) {
+                       return false;
+               }
+
                final SSLEngineResult result = this.mEngine.wrap(source.buf(), 
dest.buf());
 
                if (LOGGER.isDebugEnabled()) {
@@ -441,7 +462,7 @@ public class SSL2HandlerG0 extends SSL2Handler {
        synchronized protected void lfinish(final NextFilter next) throws 
SSLException {
                if (this.mHandshakeComplete == false) {
                        this.mHandshakeComplete = true;
-                       this.mSession.setAttribute(SSL2Filter.SSL_SECURED, 
this);
+                       this.mSession.setAttribute(SSL2Filter.SSL_SECURED, 
this.mEngine.getSession());
                        next.event(this.mSession, SslEvent.SECURED);
                }
                /**
@@ -459,7 +480,11 @@ public class SSL2HandlerG0 extends SSL2Handler {
         * @throws SSLException
         */
        synchronized public void flush(final NextFilter next) throws 
SSLException {
-               if (this.mEncodeQueue.isEmpty()) {
+               if (this.mOutboundClosing && this.mOutboundLinger == false) {
+                       return;
+               }
+
+               if (this.mEncodeQueue.size() != 0) {
                        if (LOGGER.isDebugEnabled()) {
                                LOGGER.debug("{} flush() - no saved messages", 
toString());
                        }
@@ -476,21 +501,37 @@ public class SSL2HandlerG0 extends SSL2Handler {
                                break;
                        }
                }
+
+               if (this.mOutboundClosing && this.mEncodeQueue.size() == 0) {
+                       this.mEngine.closeOutbound();
+                       this.write(next);
+               }
        }
 
        /**
         * {@inheritDoc}
         */
-       synchronized public void close(final NextFilter next) throws 
SSLException {
-               if (this.mEngine.isOutboundDone())
+       synchronized public void close(final NextFilter next, final boolean 
linger) throws SSLException {
+               if (this.mOutboundClosing)
                        return;
 
                if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("{} close() - closing session", 
toString());
                }
 
-               this.mEngine.closeOutbound();
-               this.write(next);
+               this.mOutboundLinger = linger;
+               this.mOutboundClosing = true;
+               if (linger == false) {
+                       if (this.mEncodeQueue.size() != 0) {
+                               next.exceptionCaught(this.mSession,
+                                               new WriteRejectedException(new 
ArrayList<>(this.mEncodeQueue), "closing"));
+                               this.mEncodeQueue.clear();
+                       }
+                       this.mEngine.closeOutbound();
+                       this.write(next);
+               } else {
+                       this.flush(next);
+               }
        }
 
        protected void schedule_task(final NextFilter next) {

Reply via email to