From dd3f48a7f785d08f9bf821ce2efb7566c376528b Mon Sep 17 00:00:00 2001
From: bontric <benjohnwie@gmail.com>
Date: Wed, 12 Sep 2018 18:37:31 +0200
Subject: [PATCH] Fix session termination on error

---
 .../mailbox/AbstractMailboxSession.java       | 21 ++++++++++++-------
 .../bramble/mailbox/MailboxOwnerSession.java  | 19 ++++++++++++-----
 .../mailbox/PrivateMailboxSession.java        | 10 ++++++++-
 .../mailbox/protocol/MailboxProtocol.java     | 10 +++++++--
 .../MailboxProtocolIntegrationTest.java       | 16 +++++++-------
 5 files changed, 54 insertions(+), 22 deletions(-)

diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/AbstractMailboxSession.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/AbstractMailboxSession.java
index 5f27522d8..ca7c10d7b 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/AbstractMailboxSession.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/AbstractMailboxSession.java
@@ -22,6 +22,7 @@ import java.io.ByteArrayOutputStream;
 import java.io.EOFException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.ProtocolException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Logger;
@@ -135,16 +136,20 @@ abstract class AbstractMailboxSession {
 		while (!terminated.get()) {
 			try {
 				MailboxRequest req = mailboxProtocol.getNextRequest();
-				if (req.getType() == END) {
-					synchronized (remoteSessionFinished) {
-						remoteSessionFinished.set(true);
-					}
+				if (req.getType() == END)
 					return;
-				}
 				ioExecutor.execute(() -> handleRequest(req));
 			} catch (InterruptedException e) {
-				logException(LOG, INFO, e);
-				return;
+				if (LOG.isLoggable(INFO))
+					LOG.info(e.toString());
+			} catch (ProtocolException e) {
+				if (LOG.isLoggable(INFO))
+					LOG.info(e.toString());
+				handleProtocolException();
+			} finally {
+				synchronized (remoteSessionFinished){
+					remoteSessionFinished.set(true);
+				}
 			}
 		}
 	}
@@ -277,6 +282,8 @@ abstract class AbstractMailboxSession {
 
 	public abstract void run() throws IOException;
 
+	protected abstract void handleProtocolException();
+
 	protected class MailboxSessionHandleException extends Exception {
 		public MailboxSessionHandleException(String error) {
 			super(error);
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxOwnerSession.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxOwnerSession.java
index caed520d4..c794731a9 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxOwnerSession.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxOwnerSession.java
@@ -13,15 +13,13 @@ import java.io.IOException;
 import java.util.concurrent.Executor;
 import java.util.logging.Logger;
 
-import static java.util.logging.Level.INFO;
-
 class MailboxOwnerSession extends AbstractMailboxSession {
 
 	private static final Logger LOG =
 			Logger.getLogger(MailboxOwnerSession.class.getName());
 	private final Executor ioExecutor;
 	private final MailboxProtocol mailboxProtocol;
-	private SyncSession syncSession;
+	private SyncSession duplexOutgoingSession;
 
 	public MailboxOwnerSession(ContactId contactId, Executor ioExecutor,
 			KeyManager keyManager,
@@ -42,8 +40,19 @@ class MailboxOwnerSession extends AbstractMailboxSession {
 	@Override
 	public void run() throws IOException {
 		ioExecutor.execute(() -> readRequests());
-		syncSession = createDuplexOutgoingSession();
-		syncSession.run();
+		duplexOutgoingSession = createDuplexOutgoingSession();
+		duplexOutgoingSession.run();
+		try {
+			endSession();
+		} catch (InterruptedException e) {
+			throw new IOException("Interrupted while ending session");
+		}
+	}
+
+	@Override
+	protected void handleProtocolException() {
+		if (duplexOutgoingSession != null)
+			duplexOutgoingSession.interrupt();
 	}
 
 	@Override
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/PrivateMailboxSession.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/PrivateMailboxSession.java
index cef10a8b6..9085b834b 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/PrivateMailboxSession.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/PrivateMailboxSession.java
@@ -25,6 +25,7 @@ class PrivateMailboxSession extends AbstractMailboxSession {
 	private static final Logger LOG =
 			Logger.getLogger(PrivateMailboxSession.class.getName());
 	private MailboxProtocol mailboxProtocol;
+	private SyncSession duplexOutgoingSession;
 
 	public PrivateMailboxSession(ContactId contactId, Executor ioExecutor,
 			KeyManager keyManager,
@@ -71,7 +72,8 @@ class PrivateMailboxSession extends AbstractMailboxSession {
 	@Override
 	public void run() throws IOException {
 		ioExecutor.execute(() -> super.readRequests());
-		createDuplexOutgoingSession().run();
+		duplexOutgoingSession = createDuplexOutgoingSession();
+		duplexOutgoingSession.run();
 		try {
 			endSession();
 		} catch (InterruptedException e) {
@@ -79,6 +81,12 @@ class PrivateMailboxSession extends AbstractMailboxSession {
 		}
 	}
 
+	@Override
+	protected void handleProtocolException() {
+		if (duplexOutgoingSession != null)
+			duplexOutgoingSession.interrupt();
+	}
+
 	@Override
 	public void handleStore(MailboxRequestStore req)
 			throws MailboxSessionHandleException {
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocol.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocol.java
index 7df043a43..e5db5b2f1 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocol.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocol.java
@@ -53,6 +53,8 @@ public class MailboxProtocol implements Runnable {
 
 	public void sendKeepAlive() throws IOException {
 		// flush the writer without pending data to send a keepalive
+		if (stopped.get())
+			throw new ProtocolException("Mailbox protocol has stopped");
 		synchronized (mailboxBdfWriter) {
 			mailboxBdfWriter.flush();
 		}
@@ -93,8 +95,12 @@ public class MailboxProtocol implements Runnable {
 	}
 
 	public MailboxRequest getNextRequest()
-			throws InterruptedException {
-		return inQueue.take();
+			throws InterruptedException, ProtocolException {
+		MailboxRequest req =  inQueue.take();
+		if (stopped.get())
+			throw new ProtocolException("Protocol has stopped");
+
+		return req;
 	}
 
 	@Override
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocolIntegrationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocolIntegrationTest.java
index 7a5420289..d1e02bbbb 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocolIntegrationTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocolIntegrationTest.java
@@ -13,6 +13,7 @@ import org.junit.Test;
 import java.io.IOException;
 import java.io.PipedInputStream;
 import java.io.PipedOutputStream;
+import java.net.ProtocolException;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Executor;
 import java.util.concurrent.RejectedExecutionHandler;
@@ -73,7 +74,7 @@ public class MailboxProtocolIntegrationTest extends BrambleTestCase {
 		mailboxProtocol = new MailboxProtocol(ioExecutor, bdfWriter, bdfReader);
 	}
 
-	@Test
+	@Test(expected = ProtocolException.class)
 	public void testProtocolTerminationOnClosedConnection()
 			throws IOException, InterruptedException {
 		ioExecutor.execute(mailboxProtocol);
@@ -88,12 +89,13 @@ public class MailboxProtocolIntegrationTest extends BrambleTestCase {
 		pipedOS.close();
 
 		// And "End" request should be the next read request
-		MailboxRequest recvReq = mailboxProtocol.getNextRequest();
-		assertEquals(END, recvReq.getType());
-
-		// pending request should be marked as failed
-		assertEquals(false, req.awaitAndGetResponse());
-		assertEquals("Connection closed", req.getError());
+		try {
+			MailboxRequest recvReq = mailboxProtocol.getNextRequest();
+		}finally {
+			// pending request should be marked as failed
+			assertEquals(false, req.awaitAndGetResponse());
+			assertEquals("Connection closed", req.getError());
+		}
 	}
 
 
-- 
GitLab