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) {