You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by jo...@apache.org on 2021/08/06 18:09:53 UTC

[mina] branch bugfix/DIRMINA1132 updated: SSL improvements

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 <jo...@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) {