geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bschucha...@apache.org
Subject [geode] 01/01: GEODE-7556: remove membership dependencies on geode-core exeptions
Date Wed, 18 Dec 2019 22:30:18 GMT
This is an automated email from the ASF dual-hosted git repository.

bschuchardt pushed a commit to branch feature/GEODE-7556b
in repository https://gitbox.apache.org/repos/asf/geode.git

commit cc2edc06d526a6a97c20d943f035b83b3ffaa160
Author: Bruce Schuchardt <bschuchardt@pivotal.io>
AuthorDate: Wed Dec 18 14:25:02 2019 -0800

    GEODE-7556: remove membership dependencies on geode-core exeptions
    
    Removed use of geode-core exceptions from membership. DistributionImpl now converts membership exceptions into geode-core exceptions where necessary.
    
    Except for MembershipClosedException the new membership exceptions are all checked exceptions. This let me isolate where the exceptions are used and ensure that they're changed into appropriate geode-core exceptions.
    
    MemberShunnedException is now in the membership module instead of the TcpConduit module. It, too, is a checked exception.
    
    CancelCriterion is also removed from use in the membership module. The Stopper in Services.java doesn't need to be a CancelCriterion to function properly.
    
    Several tests had to be modified to handle our stress-test environement.
---
 .../cache30/ReconnectWithCacheXMLDUnitTest.java    |  25 ++-
 .../apache/geode/distributed/LocatorDUnitTest.java |  28 +--
 .../ClusterDistributionManagerDUnitTest.java       |  31 +++-
 .../internal/RestartOfMemberDistributedTest.java   |   2 +
 .../internal/cache/ConcurrentMapOpsDUnitTest.java  |  49 +++++-
 .../MeterSubregistryReconnectDistributedTest.java  |   2 +
 .../LoggingWithReconnectDistributedTest.java       |   2 +
 .../internal/membership/MembershipJUnitTest.java   |   7 +-
 .../membership/gms/GMSMembershipJUnitTest.java     |   4 +-
 .../gms/fd/GMSHealthMonitorJUnitTest.java          |   3 +-
 .../gms/locator/GMSLocatorIntegrationTest.java     |   3 +-
 .../locator/GMSLocatorRecoveryIntegrationTest.java |   3 +-
 .../gms/membership/GMSJoinLeaveJUnitTest.java      |  27 +--
 .../gms/messenger/JGroupsMessengerJUnitTest.java   |  87 +++++----
 .../internal/ClusterDistributionManager.java       | 125 ++++++++++---
 .../geode/distributed/internal/Distribution.java   |   9 +-
 .../distributed/internal/DistributionImpl.java     | 138 +++++++++++----
 .../distributed/internal/DistributionManager.java  |  14 ++
 .../internal/LonerDistributionManager.java         |  10 ++
 .../gms/api => }/MembershipTestHook.java           |   2 +-
 .../distributed/internal/direct/DirectChannel.java |   4 +-
 .../membership/adapter/GMSLocatorAdapter.java      |  14 +-
 .../internal/membership/gms/GMSMembership.java     | 196 +++++----------------
 .../internal/membership/gms/GMSUtil.java           |  16 +-
 .../membership/gms/MembershipBuilderImpl.java      |  21 +--
 .../internal/membership/gms/Services.java          |  33 ++--
 ...tHook.java => MemberDisconnectedException.java} |  21 +--
 .../gms/api}/MemberShunnedException.java           |   6 +-
 ...ipTestHook.java => MemberStartupException.java} |  24 +--
 .../internal/membership/gms/api/Membership.java    |  23 +--
 .../membership/gms/api/MembershipBuilder.java      |   2 +-
 ...estHook.java => MembershipClosedException.java} |  23 ++-
 ....java => MembershipConfigurationException.java} |  26 +--
 .../membership/gms/api/MessageListener.java        |   2 +-
 .../membership/gms/fd/GMSHealthMonitor.java        |  39 ++--
 .../membership/gms/interfaces/JoinLeave.java       |   5 +-
 .../membership/gms/interfaces/Manager.java         |   3 +-
 .../membership/gms/interfaces/MessageHandler.java  |   4 +-
 .../membership/gms/interfaces/Messenger.java       |   3 +-
 .../membership/gms/interfaces/Service.java         |   6 +-
 .../membership/gms/locator/GMSLocator.java         |  15 +-
 .../membership/gms/membership/GMSJoinLeave.java    |  45 +++--
 .../membership/gms/messenger/GMSQuorumChecker.java |   4 +-
 .../membership/gms/messenger/JGroupsMessenger.java | 113 ++++++------
 .../apache/geode/internal/net/SocketCreator.java   |  70 ++++----
 .../org/apache/geode/internal/tcp/Connection.java  |   6 +-
 .../org/apache/geode/internal/tcp/TCPConduit.java  |   4 +-
 .../sanctioned-geode-core-serializables.txt        |   6 +-
 .../distributed/internal/DistributionTest.java     |   3 +-
 .../MembershipDependenciesJUnitTest.java           |  11 --
 .../internal/membership/gms/GMSUtilTest.java       |  18 +-
 .../membership/gms/MembershipManagerHelper.java    |   6 +-
 52 files changed, 750 insertions(+), 593 deletions(-)

diff --git a/geode-core/src/distributedTest/java/org/apache/geode/cache30/ReconnectWithCacheXMLDUnitTest.java b/geode-core/src/distributedTest/java/org/apache/geode/cache30/ReconnectWithCacheXMLDUnitTest.java
index 5502d9a..36a0a5b 100755
--- a/geode-core/src/distributedTest/java/org/apache/geode/cache30/ReconnectWithCacheXMLDUnitTest.java
+++ b/geode-core/src/distributedTest/java/org/apache/geode/cache30/ReconnectWithCacheXMLDUnitTest.java
@@ -14,11 +14,14 @@
  */
 package org.apache.geode.cache30;
 
+import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
+import static org.apache.geode.distributed.internal.membership.gms.membership.GMSJoinLeave.BYPASS_DISCOVERY_PROPERTY;
 import static org.apache.geode.internal.Assert.assertTrue;
 import static org.apache.geode.test.awaitility.GeodeAwaitility.await;
 import static org.apache.geode.test.util.ResourceUtils.createTempFileFromResource;
 import static org.junit.Assert.assertEquals;
 
+import java.io.File;
 import java.util.Properties;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -29,12 +32,15 @@ import org.junit.experimental.categories.Category;
 import org.apache.geode.cache.Cache;
 import org.apache.geode.cache.server.CacheServer;
 import org.apache.geode.distributed.ConfigurationProperties;
+import org.apache.geode.distributed.Locator;
 import org.apache.geode.distributed.ServerLauncherParameters;
 import org.apache.geode.distributed.internal.DistributionConfig;
 import org.apache.geode.distributed.internal.InternalDistributedSystem;
+import org.apache.geode.distributed.internal.MembershipTestHook;
 import org.apache.geode.distributed.internal.membership.gms.MembershipManagerHelper;
-import org.apache.geode.distributed.internal.membership.gms.api.MembershipTestHook;
 import org.apache.geode.internal.AvailablePortHelper;
+import org.apache.geode.test.dunit.Invoke;
+import org.apache.geode.test.dunit.VM;
 import org.apache.geode.test.dunit.cache.internal.JUnit4CacheTestCase;
 import org.apache.geode.test.dunit.rules.DistributedRestoreSystemProperties;
 import org.apache.geode.test.junit.categories.ClientServerTest;
@@ -55,10 +61,22 @@ public class ReconnectWithCacheXMLDUnitTest extends JUnit4CacheTestCase {
   @Rule
   public DistributedRestoreSystemProperties restoreSystemProperties =
       new DistributedRestoreSystemProperties();
+  private int locatorPort;
 
   @Override
   public final void postSetUp() {
     oldPropertySetting = System.setProperty(xmlProperty, "true");
+    // stress testing needs this so that join attempts don't give up too soon
+    Invoke.invokeInEveryVM(() -> System.setProperty("p2p.joinTimeout", "120000"));
+    // reconnect tests should create their own locator so as to not impact other tests
+    VM locatorVM = VM.getVM(0);
+    final int port = locatorVM.invoke(() -> {
+      System.setProperty(BYPASS_DISCOVERY_PROPERTY, "true");
+      System.setProperty(DistributionConfig.GEMFIRE_PREFIX + "member-weight", "100");
+      return Locator.startLocatorAndDS(0, new File(""), new Properties()).getPort();
+    });
+    locatorPort = port;
+
   }
 
   @Override
@@ -68,6 +86,7 @@ public class ReconnectWithCacheXMLDUnitTest extends JUnit4CacheTestCase {
     } else {
       System.setProperty(xmlProperty, oldPropertySetting);
     }
+    disconnectAllFromDS();
   }
 
   @Override
@@ -79,7 +98,9 @@ public class ReconnectWithCacheXMLDUnitTest extends JUnit4CacheTestCase {
     result.setProperty(ConfigurationProperties.CACHE_XML_FILE, fileName);
     result.setProperty(ConfigurationProperties.ENABLE_NETWORK_PARTITION_DETECTION, "true");
     result.setProperty(ConfigurationProperties.DISABLE_AUTO_RECONNECT, "false");
-    result.setProperty(ConfigurationProperties.MAX_WAIT_TIME_RECONNECT, "2000");
+    result.setProperty(ConfigurationProperties.MAX_WAIT_TIME_RECONNECT, "3000");
+    result.setProperty(ConfigurationProperties.MEMBER_TIMEOUT, "2000");
+    result.put(LOCATORS, "localhost[" + locatorPort + "]");
     return result;
   }
 
diff --git a/geode-core/src/distributedTest/java/org/apache/geode/distributed/LocatorDUnitTest.java b/geode-core/src/distributedTest/java/org/apache/geode/distributed/LocatorDUnitTest.java
index 0725cc1..94acffe 100644
--- a/geode-core/src/distributedTest/java/org/apache/geode/distributed/LocatorDUnitTest.java
+++ b/geode-core/src/distributedTest/java/org/apache/geode/distributed/LocatorDUnitTest.java
@@ -89,14 +89,17 @@ import org.apache.geode.distributed.internal.HighPriorityAckedMessage;
 import org.apache.geode.distributed.internal.InternalDistributedSystem;
 import org.apache.geode.distributed.internal.InternalLocator;
 import org.apache.geode.distributed.internal.MembershipListener;
+import org.apache.geode.distributed.internal.MembershipTestHook;
 import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
 import org.apache.geode.distributed.internal.membership.gms.MembershipManagerHelper;
-import org.apache.geode.distributed.internal.membership.gms.api.MembershipTestHook;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberDisconnectedException;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfigurationException;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipView;
 import org.apache.geode.internal.AvailablePort;
 import org.apache.geode.internal.AvailablePortHelper;
 import org.apache.geode.internal.tcp.Connection;
 import org.apache.geode.logging.internal.log4j.api.LogService;
+import org.apache.geode.test.awaitility.GeodeAwaitility;
 import org.apache.geode.test.dunit.AsyncInvocation;
 import org.apache.geode.test.dunit.DUnitBlackboard;
 import org.apache.geode.test.dunit.DistributedTestUtils;
@@ -163,6 +166,8 @@ public class LocatorDUnitTest implements Serializable {
     port3 = ports[2];
     port4 = ports[3];
     Invoke.invokeInEveryVM(() -> deleteLocatorStateFile(port1, port2, port3, port4));
+    addIgnoredException(MemberDisconnectedException.class); // ignore this suspect string
+    addIgnoredException(MembershipConfigurationException.class); // ignore this suspect string
   }
 
   @After
@@ -765,7 +770,7 @@ public class LocatorDUnitTest implements Serializable {
         addIgnoredException(ForcedDisconnectException.class);
 
         hook = new TestHook();
-        MembershipManagerHelper.getDistribution(system).registerTestHook(hook);
+        MembershipManagerHelper.addTestHook(system, hook);
         try {
           MembershipManagerHelper.crashDistributedSystem(system);
         } finally {
@@ -793,8 +798,6 @@ public class LocatorDUnitTest implements Serializable {
 
     vm2.invokeAsync(crashSystem);
 
-    Wait.pause(1000); // 4 x the member-timeout
-
     // request member removal for first peer from second peer.
     vm2.invoke(new SerializableRunnable("Request Member Removal") {
 
@@ -805,11 +808,12 @@ public class LocatorDUnitTest implements Serializable {
         // check for shutdown cause in Distribution. Following call should
         // throw DistributedSystemDisconnectedException which should have cause as
         // ForceDisconnectException.
+        await().until(() -> !mmgr.getMembership().isConnected());
         try (IgnoredException i = addIgnoredException("Membership: requesting removal of")) {
           mmgr.requestMemberRemoval((InternalDistributedMember) mem1, "test reasons");
           fail("It should have thrown exception in requestMemberRemoval");
         } catch (DistributedSystemDisconnectedException e) {
-          assertThat(e).hasRootCauseInstanceOf(ForcedDisconnectException.class);
+          // expected
         } finally {
           hook.reset();
         }
@@ -1306,13 +1310,15 @@ public class LocatorDUnitTest implements Serializable {
     vm2.invoke("waitUntilLocatorBecomesCoordinator", this::waitUntilLocatorBecomesCoordinator);
 
     if (vm1.invoke(() -> system.getDistributedMember().equals(getView().getCreator()))) {
-      assertFalse(
-          vm2.invoke("Checking ViewCreator",
-              () -> system.getDistributedMember().equals(getView().getCreator())));
+      vm2.invoke(() -> {
+        GeodeAwaitility.await()
+            .until(() -> !system.getDistributedMember().equals(getView().getCreator()));
+      });
     } else {
-      assertTrue(
-          vm2.invoke("Checking ViewCreator",
-              () -> system.getDistributedMember().equals(getView().getCreator())));
+      vm2.invoke(() -> {
+        GeodeAwaitility.await()
+            .until(() -> system.getDistributedMember().equals(getView().getCreator()));
+      });
     }
   }
 
diff --git a/geode-core/src/distributedTest/java/org/apache/geode/distributed/internal/ClusterDistributionManagerDUnitTest.java b/geode-core/src/distributedTest/java/org/apache/geode/distributed/internal/ClusterDistributionManagerDUnitTest.java
index 5009f55..ea78eab 100644
--- a/geode-core/src/distributedTest/java/org/apache/geode/distributed/internal/ClusterDistributionManagerDUnitTest.java
+++ b/geode-core/src/distributedTest/java/org/apache/geode/distributed/internal/ClusterDistributionManagerDUnitTest.java
@@ -20,6 +20,7 @@ import static org.apache.geode.distributed.ConfigurationProperties.BIND_ADDRESS;
 import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
 import static org.apache.geode.distributed.ConfigurationProperties.NAME;
 import static org.apache.geode.distributed.internal.DistributionConfig.GEMFIRE_PREFIX;
+import static org.apache.geode.distributed.internal.membership.gms.membership.GMSJoinLeave.BYPASS_DISCOVERY_PROPERTY;
 import static org.apache.geode.test.awaitility.GeodeAwaitility.await;
 import static org.apache.geode.test.dunit.IgnoredException.addIgnoredException;
 import static org.apache.geode.test.dunit.Invoke.invokeInEveryVM;
@@ -29,6 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatCode;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
+import java.io.File;
 import java.net.InetAddress;
 import java.util.Properties;
 import java.util.concurrent.ExecutorService;
@@ -56,10 +58,14 @@ import org.apache.geode.cache.RegionEvent;
 import org.apache.geode.cache.RegionFactory;
 import org.apache.geode.cache.Scope;
 import org.apache.geode.cache.util.CacheListenerAdapter;
+import org.apache.geode.distributed.ConfigurationProperties;
+import org.apache.geode.distributed.Locator;
 import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
 import org.apache.geode.distributed.internal.membership.gms.MembershipManagerHelper;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberDisconnectedException;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipView;
 import org.apache.geode.logging.internal.log4j.api.LogService;
+import org.apache.geode.test.dunit.Invoke;
 import org.apache.geode.test.dunit.SerializableRunnable;
 import org.apache.geode.test.dunit.VM;
 import org.apache.geode.test.dunit.cache.CacheTestCase;
@@ -80,6 +86,7 @@ public class ClusterDistributionManagerDUnitTest extends CacheTestCase {
 
   private transient ExecutorService executorService;
 
+  private VM locatorvm;
   private VM vm1;
 
   @Rule
@@ -88,11 +95,28 @@ public class ClusterDistributionManagerDUnitTest extends CacheTestCase {
 
   @Rule
   public SharedErrorCollector errorCollector = new SharedErrorCollector();
+  private int locatorPort;
 
   @Before
   public void setUp() {
     executorService = Executors.newSingleThreadExecutor();
+
+    locatorvm = VM.getVM(0);
     vm1 = VM.getVM(1);
+    Invoke.invokeInEveryVM(() -> System.setProperty("p2p.joinTimeout", "120000"));
+    final int port = locatorvm.invoke(() -> {
+      System.setProperty(BYPASS_DISCOVERY_PROPERTY, "true");
+      return Locator.startLocatorAndDS(0, new File(""), new Properties()).getPort();
+    });
+    vm1.invoke(() -> locatorPort = port);
+    locatorPort = port;
+  }
+
+  @Override
+  public Properties getDistributedSystemProperties() {
+    Properties result = super.getDistributedSystemProperties();
+    result.put(ConfigurationProperties.LOCATORS, "localhost[" + locatorPort + "]");
+    return result;
   }
 
   @After
@@ -237,6 +261,7 @@ public class ClusterDistributionManagerDUnitTest extends CacheTestCase {
   @Test
   public void testKickOutSickMember() {
     addIgnoredException("10 seconds have elapsed while waiting");
+    addIgnoredException(MemberDisconnectedException.class);
 
     // in order to set a small ack-wait-threshold, we have to remove the
     // system property established by the dunit harness
@@ -321,7 +346,7 @@ public class ClusterDistributionManagerDUnitTest extends CacheTestCase {
    */
   @Test
   public void testWaitForViewInstallation() {
-    InternalDistributedSystem system = getSystem(new Properties());
+    InternalDistributedSystem system = getSystem();
     ClusterDistributionManager dm = (ClusterDistributionManager) system.getDM();
     MembershipView<InternalDistributedMember> view = dm.getDistribution().getView();
 
@@ -337,8 +362,8 @@ public class ClusterDistributionManagerDUnitTest extends CacheTestCase {
 
     pause(2000);
 
-    VM.getVM(1).invoke("create another member to initiate a new view", () -> {
-      getSystem(new Properties());
+    vm1.invoke("create another member to initiate a new view", () -> {
+      getSystem();
     });
 
     await()
diff --git a/geode-core/src/distributedTest/java/org/apache/geode/distributed/internal/RestartOfMemberDistributedTest.java b/geode-core/src/distributedTest/java/org/apache/geode/distributed/internal/RestartOfMemberDistributedTest.java
index e3339af..a080a7c 100644
--- a/geode-core/src/distributedTest/java/org/apache/geode/distributed/internal/RestartOfMemberDistributedTest.java
+++ b/geode-core/src/distributedTest/java/org/apache/geode/distributed/internal/RestartOfMemberDistributedTest.java
@@ -27,6 +27,7 @@ import org.junit.Rule;
 import org.junit.Test;
 
 import org.apache.geode.ForcedDisconnectException;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberDisconnectedException;
 import org.apache.geode.test.dunit.rules.ClusterStartupRule;
 
 public class RestartOfMemberDistributedTest {
@@ -54,6 +55,7 @@ public class RestartOfMemberDistributedTest {
     clusterStartupRule.startServerVM(server2, properties, locatorPort1);
 
     addIgnoredException(ForcedDisconnectException.class.getName());
+    addIgnoredException(MemberDisconnectedException.class.getName());
     addIgnoredException("Possible loss of quorum due to the loss");
     addIgnoredException("Received invalid result from");
   }
diff --git a/geode-core/src/distributedTest/java/org/apache/geode/internal/cache/ConcurrentMapOpsDUnitTest.java b/geode-core/src/distributedTest/java/org/apache/geode/internal/cache/ConcurrentMapOpsDUnitTest.java
index d38ffcd..5751095 100644
--- a/geode-core/src/distributedTest/java/org/apache/geode/internal/cache/ConcurrentMapOpsDUnitTest.java
+++ b/geode-core/src/distributedTest/java/org/apache/geode/internal/cache/ConcurrentMapOpsDUnitTest.java
@@ -15,7 +15,9 @@
 package org.apache.geode.internal.cache;
 
 import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_NETWORK_PARTITION_DETECTION;
+import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
 import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
+import static org.apache.geode.distributed.internal.membership.gms.membership.GMSJoinLeave.BYPASS_DISCOVERY_PROPERTY;
 import static org.apache.geode.test.dunit.Assert.assertEquals;
 import static org.apache.geode.test.dunit.Assert.assertFalse;
 import static org.apache.geode.test.dunit.Assert.assertNotNull;
@@ -25,17 +27,22 @@ import static org.apache.geode.test.dunit.Assert.fail;
 
 import java.io.DataInput;
 import java.io.DataOutput;
+import java.io.File;
 import java.io.IOException;
 import java.util.HashSet;
 import java.util.Properties;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Ignore;
+import org.junit.Rule;
 import org.junit.Test;
 
 import org.apache.geode.DataSerializable;
 import org.apache.geode.Delta;
+import org.apache.geode.ForcedDisconnectException;
 import org.apache.geode.InvalidDeltaException;
 import org.apache.geode.cache.CacheListener;
 import org.apache.geode.cache.EntryEvent;
@@ -50,19 +57,24 @@ import org.apache.geode.cache.client.ClientRegionShortcut;
 import org.apache.geode.cache.client.internal.DestroyOp;
 import org.apache.geode.cache.server.CacheServer;
 import org.apache.geode.cache.util.CacheListenerAdapter;
+import org.apache.geode.distributed.Locator;
 import org.apache.geode.distributed.internal.Distribution;
+import org.apache.geode.distributed.internal.DistributionConfig;
 import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
 import org.apache.geode.distributed.internal.membership.gms.MembershipManagerHelper;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberDisconnectedException;
 import org.apache.geode.internal.AvailablePort;
 import org.apache.geode.test.awaitility.GeodeAwaitility;
 import org.apache.geode.test.dunit.Host;
 import org.apache.geode.test.dunit.IgnoredException;
+import org.apache.geode.test.dunit.Invoke;
 import org.apache.geode.test.dunit.LogWriterUtils;
 import org.apache.geode.test.dunit.SerializableCallable;
 import org.apache.geode.test.dunit.SerializableRunnable;
 import org.apache.geode.test.dunit.VM;
 import org.apache.geode.test.dunit.WaitCriterion;
 import org.apache.geode.test.dunit.cache.internal.JUnit4CacheTestCase;
+import org.apache.geode.test.dunit.rules.DistributedRestoreSystemProperties;
 
 /**
  * tests for the concurrentMapOperations. there are more tests in ClientServerMiscDUnitTest
@@ -73,15 +85,42 @@ public class ConcurrentMapOpsDUnitTest extends JUnit4CacheTestCase {
   private static final String REP_REG_NAME = "repRegion";
   private static final String PR_REG_NAME = "prRegion";
   private static final int MAX_ENTRIES = 113;
+  private int locatorPort;
 
   enum OP {
     PUTIFABSENT, REPLACE, REMOVE
   }
 
+  @Rule
+  public DistributedRestoreSystemProperties restoreProperties =
+      new DistributedRestoreSystemProperties();
+
+  @Before
+  public void setup() {
+    // stress testing needs this so that join attempts don't give up too soon
+    Invoke.invokeInEveryVM(() -> System.setProperty("p2p.joinTimeout", "120000"));
+    VM locatorVM = VM.getVM(4);
+    final int port = locatorVM.invoke(() -> {
+      System.setProperty(BYPASS_DISCOVERY_PROPERTY, "true");
+      // set a big weight on the locator to prevent total shutdown when one server decides
+      // to kill the other server
+      System.setProperty(DistributionConfig.GEMFIRE_PREFIX + "member-weight", "100");
+      return Locator.startLocatorAndDS(0, new File(""), new Properties()).getPort();
+    });
+    Invoke.invokeInEveryVM(() -> locatorPort = port);
+    locatorPort = port;
+  }
+
+  @After
+  public void teardown() {
+    VM.getVM(4).invoke(() -> disconnectFromDS());
+  }
+
   @Override
   public Properties getDistributedSystemProperties() {
     Properties result = super.getDistributedSystemProperties();
     result.put(ENABLE_NETWORK_PARTITION_DETECTION, "false");
+    result.put(LOCATORS, "localhost[" + locatorPort + "]");
     return result;
   }
 
@@ -1209,8 +1248,14 @@ public class ConcurrentMapOpsDUnitTest extends JUnit4CacheTestCase {
     Set<IgnoredException> exceptions = new HashSet<IgnoredException>();
     exceptions.add(IgnoredException.addIgnoredException("Membership: requesting removal", server1));
     exceptions.add(IgnoredException.addIgnoredException("Membership: requesting removal", server2));
-    exceptions.add(IgnoredException.addIgnoredException("ForcedDisconnect", server1));
-    exceptions.add(IgnoredException.addIgnoredException("ForcedDisconnect", server2));
+    exceptions.add(IgnoredException
+        .addIgnoredException(ForcedDisconnectException.class.getSimpleName(), server1));
+    exceptions.add(IgnoredException
+        .addIgnoredException(ForcedDisconnectException.class.getSimpleName(), server2));
+    exceptions.add(IgnoredException
+        .addIgnoredException(MemberDisconnectedException.class.getSimpleName(), server1));
+    exceptions.add(IgnoredException
+        .addIgnoredException(MemberDisconnectedException.class.getSimpleName(), server2));
 
     try {
 
diff --git a/geode-core/src/distributedTest/java/org/apache/geode/internal/metrics/MeterSubregistryReconnectDistributedTest.java b/geode-core/src/distributedTest/java/org/apache/geode/internal/metrics/MeterSubregistryReconnectDistributedTest.java
index 704dc01..8b616fd 100644
--- a/geode-core/src/distributedTest/java/org/apache/geode/internal/metrics/MeterSubregistryReconnectDistributedTest.java
+++ b/geode-core/src/distributedTest/java/org/apache/geode/internal/metrics/MeterSubregistryReconnectDistributedTest.java
@@ -48,6 +48,7 @@ import org.apache.geode.cache.CacheFactory;
 import org.apache.geode.distributed.LocatorLauncher;
 import org.apache.geode.distributed.internal.Distribution;
 import org.apache.geode.distributed.internal.InternalDistributedSystem;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberDisconnectedException;
 import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.test.dunit.VM;
 import org.apache.geode.test.dunit.rules.DistributedRule;
@@ -87,6 +88,7 @@ public class MeterSubregistryReconnectDistributedTest implements Serializable {
     otherServer.invoke(() -> createServer(OTHER_SERVER_NAME));
 
     addIgnoredException(ForcedDisconnectException.class);
+    addIgnoredException(MemberDisconnectedException.class);
     addIgnoredException("Possible loss of quorum");
   }
 
diff --git a/geode-core/src/distributedTest/java/org/apache/geode/logging/internal/LoggingWithReconnectDistributedTest.java b/geode-core/src/distributedTest/java/org/apache/geode/logging/internal/LoggingWithReconnectDistributedTest.java
index 67f5638..36b00a5 100644
--- a/geode-core/src/distributedTest/java/org/apache/geode/logging/internal/LoggingWithReconnectDistributedTest.java
+++ b/geode-core/src/distributedTest/java/org/apache/geode/logging/internal/LoggingWithReconnectDistributedTest.java
@@ -48,6 +48,7 @@ import org.apache.geode.distributed.LocatorLauncher;
 import org.apache.geode.distributed.ServerLauncher;
 import org.apache.geode.distributed.internal.Distribution;
 import org.apache.geode.distributed.internal.InternalDistributedSystem;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberDisconnectedException;
 import org.apache.geode.test.assertj.LogFileAssert;
 import org.apache.geode.test.dunit.VM;
 import org.apache.geode.test.dunit.rules.DistributedRule;
@@ -109,6 +110,7 @@ public class LoggingWithReconnectDistributedTest implements Serializable {
     server2VM.invoke(() -> createServer(server2Name, server2Dir, locatorPort));
 
     addIgnoredException(ForcedDisconnectException.class);
+    addIgnoredException(MemberDisconnectedException.class);
     addIgnoredException("Possible loss of quorum");
   }
 
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/MembershipJUnitTest.java b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/MembershipJUnitTest.java
index 5027b51..5c87f6d 100755
--- a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/MembershipJUnitTest.java
+++ b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/MembershipJUnitTest.java
@@ -44,7 +44,6 @@ import org.junit.rules.TemporaryFolder;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
-import org.apache.geode.GemFireConfigException;
 import org.apache.geode.distributed.ConfigurationProperties;
 import org.apache.geode.distributed.Locator;
 import org.apache.geode.distributed.internal.ClusterDistributionManager;
@@ -65,9 +64,11 @@ import org.apache.geode.distributed.internal.membership.gms.Services;
 import org.apache.geode.distributed.internal.membership.gms.api.LifecycleListener;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifierFactory;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberStartupException;
 import org.apache.geode.distributed.internal.membership.gms.api.Membership;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipBuilder;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfig;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfigurationException;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipListener;
 import org.apache.geode.distributed.internal.membership.gms.api.MessageListener;
 import org.apache.geode.distributed.internal.membership.gms.interfaces.JoinLeave;
@@ -256,7 +257,7 @@ public class MembershipJUnitTest {
 
   private Pair<Membership, MessageListener> createMembershipManager(
       final DistributionConfigImpl config,
-      final RemoteTransportConfig transport) {
+      final RemoteTransportConfig transport) throws MemberStartupException {
     final MembershipListener listener = mock(MembershipListener.class);
     final MessageListener messageListener = mock(MessageListener.class);
     final DMStats stats1 = mock(DMStats.class);
@@ -490,7 +491,7 @@ public class MembershipJUnitTest {
       joinLeave.init(services);
       throw new Error(
           "expected a GemFireConfigException to be thrown because no locators are configured");
-    } catch (GemFireConfigException e) {
+    } catch (MembershipConfigurationException e) {
       // expected
     }
   }
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/GMSMembershipJUnitTest.java b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/GMSMembershipJUnitTest.java
index ed330c1..44ff1f0 100644
--- a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/GMSMembershipJUnitTest.java
+++ b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/GMSMembershipJUnitTest.java
@@ -63,6 +63,8 @@ import org.apache.geode.distributed.internal.membership.gms.Services.Stopper;
 import org.apache.geode.distributed.internal.membership.gms.api.Authenticator;
 import org.apache.geode.distributed.internal.membership.gms.api.LifecycleListener;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberShunnedException;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberStartupException;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfig;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipListener;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipView;
@@ -314,7 +316,7 @@ public class GMSMembershipJUnitTest {
   }
 
   @Test
-  public void noDispatchWhenSick() {
+  public void noDispatchWhenSick() throws MemberShunnedException, MemberStartupException {
     final DistributionMessage msg = mock(DistributionMessage.class);
     when(msg.dropMessageWhenMembershipIsPlayingDead()).thenReturn(true);
 
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/fd/GMSHealthMonitorJUnitTest.java b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/fd/GMSHealthMonitorJUnitTest.java
index b376ae0..f19de75 100644
--- a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/fd/GMSHealthMonitorJUnitTest.java
+++ b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/fd/GMSHealthMonitorJUnitTest.java
@@ -83,6 +83,7 @@ import org.apache.geode.distributed.internal.membership.gms.Services.Stopper;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberData;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberDataBuilder;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberStartupException;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfig;
 import org.apache.geode.distributed.internal.membership.gms.fd.GMSHealthMonitor.ClientSocketHandler;
 import org.apache.geode.distributed.internal.membership.gms.interfaces.JoinLeave;
@@ -119,7 +120,7 @@ public class GMSHealthMonitorJUnitTest {
   private final int myAddressIndex = 3;
 
   @Before
-  public void initMocks() throws UnknownHostException {
+  public void initMocks() throws UnknownHostException, MemberStartupException {
     // ensure that Geode's serialization and version are initialized
     Version currentVersion = Version.CURRENT;
     InternalDataSerializer.getDSFIDSerializer();
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/locator/GMSLocatorIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/locator/GMSLocatorIntegrationTest.java
index aa16704..4eefd71 100644
--- a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/locator/GMSLocatorIntegrationTest.java
+++ b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/locator/GMSLocatorIntegrationTest.java
@@ -35,6 +35,7 @@ import org.apache.geode.distributed.internal.membership.InternalDistributedMembe
 import org.apache.geode.distributed.internal.membership.gms.GMSMembership;
 import org.apache.geode.distributed.internal.membership.gms.GMSMembershipView;
 import org.apache.geode.distributed.internal.membership.gms.Services;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfigurationException;
 import org.apache.geode.distributed.internal.membership.gms.interfaces.JoinLeave;
 import org.apache.geode.distributed.internal.membership.gms.interfaces.Messenger;
 import org.apache.geode.distributed.internal.tcpserver.TcpClient;
@@ -59,7 +60,7 @@ public class GMSLocatorIntegrationTest {
   private Messenger messenger;
 
   @Before
-  public void setUp() {
+  public void setUp() throws MembershipConfigurationException {
 
     SocketCreatorFactory.setDistributionConfig(new DistributionConfigImpl(new Properties()));
 
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/locator/GMSLocatorRecoveryIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/locator/GMSLocatorRecoveryIntegrationTest.java
index 091fca6..5bb3539 100644
--- a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/locator/GMSLocatorRecoveryIntegrationTest.java
+++ b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/locator/GMSLocatorRecoveryIntegrationTest.java
@@ -42,7 +42,6 @@ import org.junit.rules.TemporaryFolder;
 import org.junit.rules.TestName;
 
 import org.apache.geode.DataSerializer;
-import org.apache.geode.InternalGemFireException;
 import org.apache.geode.distributed.Locator;
 import org.apache.geode.distributed.internal.ClusterDistributionManager;
 import org.apache.geode.distributed.internal.DMStats;
@@ -154,7 +153,7 @@ public class GMSLocatorRecoveryIntegrationTest {
     Throwable thrown = catchThrowable(() -> gmsLocator.recoverFromFile(stateFile));
 
     assertThat(thrown)
-        .isInstanceOf(InternalGemFireException.class)
+        .isInstanceOf(IllegalStateException.class)
         .hasMessageStartingWith("Unable to recover previous membership view from");
   }
 
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeaveJUnitTest.java b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeaveJUnitTest.java
index 9c24ec6..85b77ea 100644
--- a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeaveJUnitTest.java
+++ b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeaveJUnitTest.java
@@ -54,7 +54,6 @@ import org.junit.experimental.categories.Category;
 import org.mockito.internal.verification.Times;
 import org.mockito.verification.Timeout;
 
-import org.apache.geode.SystemConnectException;
 import org.apache.geode.distributed.internal.ClusterDistributionManager;
 import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
 import org.apache.geode.distributed.internal.membership.adapter.ServiceConfig;
@@ -66,6 +65,7 @@ import org.apache.geode.distributed.internal.membership.gms.Services.Stopper;
 import org.apache.geode.distributed.internal.membership.gms.api.Authenticator;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberDataBuilder;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberStartupException;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfig;
 import org.apache.geode.distributed.internal.membership.gms.interfaces.HealthMonitor;
 import org.apache.geode.distributed.internal.membership.gms.interfaces.Locator;
@@ -107,15 +107,16 @@ public class GMSJoinLeaveJUnitTest {
   private MemberIdentifier leaveMember = null;
   private TcpClient locatorClient;
 
-  public void initMocks() {
+  public void initMocks() throws Exception {
     initMocks(false);
   }
 
-  public void initMocks(boolean enableNetworkPartition) {
+  public void initMocks(boolean enableNetworkPartition) throws Exception {
     initMocks(enableNetworkPartition, false);
   }
 
-  public void initMocks(boolean enableNetworkPartition, boolean useTestGMSJoinLeave) {
+  public void initMocks(boolean enableNetworkPartition, boolean useTestGMSJoinLeave)
+      throws Exception {
     mockConfig = mock(ServiceConfig.class);
     when(mockConfig.getEnableNetworkPartitionDetection()).thenReturn(enableNetworkPartition);
     when(mockConfig.getSecurityUDPDHAlgo()).thenReturn("");
@@ -219,7 +220,7 @@ public class GMSJoinLeaveJUnitTest {
     // and will throw an exception when going to pause
     Thread.currentThread().interrupt();
     assertThatThrownBy(() -> gmsJoinLeave.findCoordinator())
-        .isInstanceOf(SystemConnectException.class)
+        .isInstanceOf(MemberStartupException.class)
         .hasMessageContaining("Interrupted while trying to contact locators");
     assertThat(Thread.currentThread().interrupted()).isTrue();
     verify(locatorClient, times(1)).requestToServer(isA(InetSocketAddress.class),
@@ -270,7 +271,7 @@ public class GMSJoinLeaveJUnitTest {
   }
 
   @Test
-  public void testProcessJoinMessageRejectOldMemberVersion() throws IOException {
+  public void testProcessJoinMessageRejectOldMemberVersion() throws Exception {
     initMocks();
 
     gmsJoinLeave.processMessage(new JoinRequestMessage(mockOldMember, mockOldMember, null, -1, 0));
@@ -292,7 +293,7 @@ public class GMSJoinLeaveJUnitTest {
 
 
   @Test
-  public void testProcessJoinMessageWithBadAuthentication() throws IOException {
+  public void testProcessJoinMessageWithBadAuthentication() throws Exception {
     initMocks();
     when(authenticator.authenticate(mockMembers[0], credentials))
         .thenThrow(new AuthenticationFailedException("we want to fail auth here"));
@@ -305,7 +306,7 @@ public class GMSJoinLeaveJUnitTest {
   }
 
   @Test
-  public void testProcessJoinMessageWithAuthenticationButNullCredentials() throws IOException {
+  public void testProcessJoinMessageWithAuthenticationButNullCredentials() throws Exception {
     initMocks();
     when(authenticator.authenticate(mockMembers[0], null))
         .thenThrow(new AuthenticationFailedException("we want to fail auth here"));
@@ -319,7 +320,7 @@ public class GMSJoinLeaveJUnitTest {
 
   // This test does not test the actual join process but rather that the join response gets logged
   @Test
-  public void testProcessJoinResponseIsRecorded() throws IOException {
+  public void testProcessJoinResponseIsRecorded() throws Exception {
     initMocks();
     when(authenticator.authenticate(mockMembers[0], null))
         .thenThrow(new AuthenticationFailedException("we want to fail auth here"));
@@ -436,7 +437,7 @@ public class GMSJoinLeaveJUnitTest {
 
 
   @Test
-  public void testRejectOlderView() throws IOException {
+  public void testRejectOlderView() throws Exception {
     initMocks();
     prepareAndInstallView(mockMembers[0], createMemberList(mockMembers[0], gmsJoinLeaveMemberId));
 
@@ -452,7 +453,7 @@ public class GMSJoinLeaveJUnitTest {
   }
 
   @Test
-  public void testForceDisconnectedFromNewView() throws IOException {
+  public void testForceDisconnectedFromNewView() throws Exception {
     initMocks(true);// enabledNetworkPartition;
     Manager mockManager = mock(Manager.class);
     when(services.getManager()).thenReturn(mockManager);
@@ -839,7 +840,7 @@ public class GMSJoinLeaveJUnitTest {
   }
 
   @Test
-  public void testNetworkPartitionDetected() throws IOException {
+  public void testNetworkPartitionDetected() throws Exception {
     initMocks(true);
     prepareAndInstallView(mockMembers[0], createMemberList(mockMembers[0], gmsJoinLeaveMemberId));
 
@@ -887,7 +888,7 @@ public class GMSJoinLeaveJUnitTest {
 
 
   @Test
-  public void testQuorumLossNotificationWithNetworkPartitionDetectionDisabled() throws IOException {
+  public void testQuorumLossNotificationWithNetworkPartitionDetectionDisabled() throws Exception {
     initMocks(false);
     prepareAndInstallView(mockMembers[0], createMemberList(mockMembers[0], gmsJoinLeaveMemberId));
 
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/messenger/JGroupsMessengerJUnitTest.java b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/messenger/JGroupsMessengerJUnitTest.java
index 36aad0c..9d66194 100755
--- a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/messenger/JGroupsMessengerJUnitTest.java
+++ b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/messenger/JGroupsMessengerJUnitTest.java
@@ -21,6 +21,7 @@ import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
 import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
 import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
 import static org.apache.geode.distributed.ConfigurationProperties.MCAST_TTL;
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -52,7 +53,9 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
+import java.util.Set;
 import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.TimeoutException;
 
 import org.jgroups.Address;
 import org.jgroups.Event;
@@ -66,11 +69,8 @@ import org.junit.After;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
-import org.apache.geode.ForcedDisconnectException;
-import org.apache.geode.GemFireIOException;
 import org.apache.geode.SerializationException;
 import org.apache.geode.distributed.ConfigurationProperties;
-import org.apache.geode.distributed.DistributedSystemDisconnectedException;
 import org.apache.geode.distributed.internal.DistributionConfigImpl;
 import org.apache.geode.distributed.internal.DistributionStats;
 import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
@@ -79,7 +79,9 @@ import org.apache.geode.distributed.internal.membership.gms.GMSMembershipView;
 import org.apache.geode.distributed.internal.membership.gms.MemberIdentifierFactoryImpl;
 import org.apache.geode.distributed.internal.membership.gms.Services;
 import org.apache.geode.distributed.internal.membership.gms.Services.Stopper;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberDisconnectedException;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipClosedException;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfig;
 import org.apache.geode.distributed.internal.membership.gms.api.Message;
 import org.apache.geode.distributed.internal.membership.gms.interfaces.HealthMonitor;
@@ -289,27 +291,21 @@ public class JGroupsMessengerJUnitTest {
       when(msg.getDSFID()).thenReturn((int) DataSerializableFixedID.HEARTBEAT_RESPONSE);
 
       // for code coverage we need to test with both a SerializationException and
-      // an IOException. The former is wrapped in a GemfireIOException while the
+      // an IOException. The former is wrapped in a MembershipIOException while the
       // latter is not
       doThrow(new SerializationException("")).when(msg).toData(any(DataOutput.class),
           any(SerializationContext.class));
-      try {
-        messenger.send(msg);
-        fail("expected a failure");
-      } catch (GemFireIOException e) {
-        // success
-      }
+      Set<?> failures = messenger.send(msg);
+      assertThat(failures).isNotNull();
+      assertThat(failures).isNotEmpty();
       if (enableMcast) {
         verify(msg, atLeastOnce()).registerProcessor();
       }
       doThrow(new IOException()).when(msg).toData(any(DataOutput.class),
           any(SerializationContext.class));
-      try {
-        messenger.send(msg);
-        fail("expected a failure");
-      } catch (GemFireIOException e) {
-        // success
-      }
+      failures = messenger.send(msg);
+      assertThat(failures).isNotNull();
+      assertThat(failures).isNotEmpty();
     }
   }
 
@@ -332,7 +328,7 @@ public class JGroupsMessengerJUnitTest {
         try {
           messenger.send(msg);
           fail("expected a failure");
-        } catch (DistributedSystemDisconnectedException e) {
+        } catch (MembershipClosedException e) {
           // success
         }
         verify(mockChannel).send(isA(org.jgroups.Message.class));
@@ -355,7 +351,7 @@ public class JGroupsMessengerJUnitTest {
         ex = new RuntimeException("");
         shutdownCause = new RuntimeException("shutdownCause");
       } else {
-        shutdownCause = new ForcedDisconnectException("");
+        shutdownCause = new MemberDisconnectedException("");
         ex = new RuntimeException("", shutdownCause);
       }
       doThrow(ex).when(mockChannel).send(any(org.jgroups.Message.class));
@@ -373,7 +369,7 @@ public class JGroupsMessengerJUnitTest {
         try {
           messenger.send(msg);
           fail("expected a failure");
-        } catch (DistributedSystemDisconnectedException e) {
+        } catch (MembershipClosedException e) {
           // the ultimate cause should be the shutdownCause returned
           // by Services.getShutdownCause()
           Throwable cause = e;
@@ -408,7 +404,7 @@ public class JGroupsMessengerJUnitTest {
         try {
           messenger.send(msg);
           fail("expected a failure");
-        } catch (DistributedSystemDisconnectedException e) {
+        } catch (MembershipClosedException e) {
           // success
         }
         verify(mockChannel, never()).send(isA(org.jgroups.Message.class));
@@ -430,11 +426,8 @@ public class JGroupsMessengerJUnitTest {
       when(msg.getMulticast()).thenReturn(enableMcast);
       when(msg.getDSFID()).thenReturn((int) DataSerializableFixedID.HEARTBEAT_RESPONSE);
       interceptor.collectMessages = true;
-      try {
-        messenger.sendUnreliably(msg);
-      } catch (GemFireIOException e) {
-        fail("expected success");
-      }
+      Set<?> failures = messenger.sendUnreliably(msg);
+      assertTrue(failures == null || failures.isEmpty());
       if (enableMcast) {
         verify(msg, atLeastOnce()).registerProcessor();
       }
@@ -594,12 +587,12 @@ public class JGroupsMessengerJUnitTest {
   public void testChannelStillConnectedAfterEmergencyCloseAfterForcedDisconnectWithAutoReconnect()
       throws Exception {
     initMocks(false);
-    doCallRealMethod().when(services).setShutdownCause(any(ForcedDisconnectException.class));
+    doCallRealMethod().when(services).setShutdownCause(any(MemberDisconnectedException.class));
     doCallRealMethod().when(services).getShutdownCause();
     doCallRealMethod().when(services).emergencyClose();
     doCallRealMethod().when(services).isShutdownDueToForcedDisconnect();
     doCallRealMethod().when(services).isAutoReconnectEnabled();
-    services.setShutdownCause(new ForcedDisconnectException("Test Forced Disconnect"));
+    services.setShutdownCause(new MemberDisconnectedException("Test Forced Disconnect"));
     assertTrue(messenger.myChannel.isConnected());
     messenger.emergencyClose();
     assertTrue(messenger.myChannel.isConnected());
@@ -609,12 +602,12 @@ public class JGroupsMessengerJUnitTest {
   public void testChannelStillConnectedAfterStopAfterForcedDisconnectWithAutoReconnect()
       throws Exception {
     initMocks(false);
-    doCallRealMethod().when(services).setShutdownCause(any(ForcedDisconnectException.class));
+    doCallRealMethod().when(services).setShutdownCause(any(MemberDisconnectedException.class));
     doCallRealMethod().when(services).getShutdownCause();
     doCallRealMethod().when(services).emergencyClose();
     doCallRealMethod().when(services).isShutdownDueToForcedDisconnect();
     doCallRealMethod().when(services).isAutoReconnectEnabled();
-    services.setShutdownCause(new ForcedDisconnectException("Test Forced Disconnect"));
+    services.setShutdownCause(new MemberDisconnectedException("Test Forced Disconnect"));
     assertTrue(messenger.myChannel.isConnected());
     messenger.stop();
     assertTrue(messenger.myChannel.isConnected());
@@ -623,13 +616,13 @@ public class JGroupsMessengerJUnitTest {
   @Test
   public void testChannelStillConnectedAfteremergencyWhileReconnectingDS() throws Exception {
     initMocks(false);
-    doCallRealMethod().when(services).setShutdownCause(any(ForcedDisconnectException.class));
+    doCallRealMethod().when(services).setShutdownCause(any(MemberDisconnectedException.class));
     doCallRealMethod().when(services).getShutdownCause();
     doCallRealMethod().when(services).emergencyClose();
     doReturn(false).when(services).isShutdownDueToForcedDisconnect();
     doReturn(false).when(services).isAutoReconnectEnabled();
     doReturn(true).when(manager).isReconnectingDS();
-    services.setShutdownCause(new ForcedDisconnectException("Test Forced Disconnect"));
+    services.setShutdownCause(new MemberDisconnectedException("Test Forced Disconnect"));
     assertTrue(messenger.myChannel.isConnected());
     messenger.emergencyClose();
     assertTrue(messenger.myChannel.isConnected());
@@ -639,13 +632,13 @@ public class JGroupsMessengerJUnitTest {
   @Test
   public void testChannelStillConnectedAfterStopWhileReconnectingDS() throws Exception {
     initMocks(false);
-    doCallRealMethod().when(services).setShutdownCause(any(ForcedDisconnectException.class));
+    doCallRealMethod().when(services).setShutdownCause(any(MemberDisconnectedException.class));
     doCallRealMethod().when(services).getShutdownCause();
     doCallRealMethod().when(services).emergencyClose();
     doReturn(false).when(services).isShutdownDueToForcedDisconnect();
     doReturn(false).when(services).isAutoReconnectEnabled();
     doReturn(true).when(manager).isReconnectingDS();
-    services.setShutdownCause(new ForcedDisconnectException("Test Forced Disconnect"));
+    services.setShutdownCause(new MemberDisconnectedException("Test Forced Disconnect"));
     assertTrue(messenger.myChannel.isConnected());
     messenger.stop();
     assertTrue(messenger.myChannel.isConnected());
@@ -654,13 +647,13 @@ public class JGroupsMessengerJUnitTest {
   @Test
   public void testChannelClosedOnEmergencyClose() throws Exception {
     initMocks(false);
-    doCallRealMethod().when(services).setShutdownCause(any(ForcedDisconnectException.class));
+    doCallRealMethod().when(services).setShutdownCause(any(MemberDisconnectedException.class));
     doCallRealMethod().when(services).getShutdownCause();
     doCallRealMethod().when(services).emergencyClose();
     doReturn(false).when(services).isShutdownDueToForcedDisconnect();
     doReturn(false).when(services).isAutoReconnectEnabled();
     doReturn(false).when(manager).isReconnectingDS();
-    services.setShutdownCause(new ForcedDisconnectException("Test Forced Disconnect"));
+    services.setShutdownCause(new MemberDisconnectedException("Test Forced Disconnect"));
     assertTrue(messenger.myChannel.isConnected());
     messenger.emergencyClose();
     assertFalse(messenger.myChannel.isConnected());
@@ -669,13 +662,13 @@ public class JGroupsMessengerJUnitTest {
   @Test
   public void testChannelClosedOnStop() throws Exception {
     initMocks(false);
-    doCallRealMethod().when(services).setShutdownCause(any(ForcedDisconnectException.class));
+    doCallRealMethod().when(services).setShutdownCause(any(MemberDisconnectedException.class));
     doCallRealMethod().when(services).getShutdownCause();
     doCallRealMethod().when(services).emergencyClose();
     doReturn(false).when(services).isShutdownDueToForcedDisconnect();
     doReturn(false).when(services).isAutoReconnectEnabled();
     doReturn(false).when(manager).isReconnectingDS();
-    services.setShutdownCause(new ForcedDisconnectException("Test Forced Disconnect"));
+    services.setShutdownCause(new MemberDisconnectedException("Test Forced Disconnect"));
     assertTrue(messenger.myChannel.isConnected());
     messenger.stop();
     assertFalse(messenger.myChannel.isConnected());
@@ -685,13 +678,13 @@ public class JGroupsMessengerJUnitTest {
   public void testChannelClosedAfterEmergencyCloseForcedDisconnectWithoutAutoReconnect()
       throws Exception {
     initMocks(false);
-    doCallRealMethod().when(services).setShutdownCause(any(ForcedDisconnectException.class));
+    doCallRealMethod().when(services).setShutdownCause(any(MemberDisconnectedException.class));
     doCallRealMethod().when(services).getShutdownCause();
     doCallRealMethod().when(services).emergencyClose();
     doReturn(true).when(services).isShutdownDueToForcedDisconnect();
     doReturn(false).when(services).isAutoReconnectEnabled();
     doReturn(false).when(manager).isReconnectingDS();
-    services.setShutdownCause(new ForcedDisconnectException("Test Forced Disconnect"));
+    services.setShutdownCause(new MemberDisconnectedException("Test Forced Disconnect"));
     assertTrue(messenger.myChannel.isConnected());
     messenger.emergencyClose();
     assertFalse(messenger.myChannel.isConnected());
@@ -701,13 +694,13 @@ public class JGroupsMessengerJUnitTest {
   public void testChannelStillConnectedStopAfterForcedDisconnectWithoutAutoReconnect()
       throws Exception {
     initMocks(false);
-    doCallRealMethod().when(services).setShutdownCause(any(ForcedDisconnectException.class));
+    doCallRealMethod().when(services).setShutdownCause(any(MemberDisconnectedException.class));
     doCallRealMethod().when(services).getShutdownCause();
     doCallRealMethod().when(services).emergencyClose();
     doReturn(true).when(services).isShutdownDueToForcedDisconnect();
     doReturn(false).when(services).isAutoReconnectEnabled();
     doReturn(false).when(manager).isReconnectingDS();
-    services.setShutdownCause(new ForcedDisconnectException("Test Forced Disconnect"));
+    services.setShutdownCause(new MemberDisconnectedException("Test Forced Disconnect"));
     assertTrue(messenger.myChannel.isConnected());
     messenger.stop();
     assertFalse(messenger.myChannel.isConnected());
@@ -717,13 +710,13 @@ public class JGroupsMessengerJUnitTest {
   public void testChannelClosedAfterEmergencyCloseNotForcedDisconnectWithAutoReconnect()
       throws Exception {
     initMocks(false);
-    doCallRealMethod().when(services).setShutdownCause(any(ForcedDisconnectException.class));
+    doCallRealMethod().when(services).setShutdownCause(any(MemberDisconnectedException.class));
     doCallRealMethod().when(services).getShutdownCause();
     doCallRealMethod().when(services).emergencyClose();
     doReturn(false).when(services).isShutdownDueToForcedDisconnect();
     doReturn(true).when(services).isAutoReconnectEnabled();
     doReturn(false).when(manager).isReconnectingDS();
-    services.setShutdownCause(new ForcedDisconnectException("Test Forced Disconnect"));
+    services.setShutdownCause(new MemberDisconnectedException("Test Forced Disconnect"));
     assertTrue(messenger.myChannel.isConnected());
     messenger.emergencyClose();
     assertFalse(messenger.myChannel.isConnected());
@@ -732,13 +725,13 @@ public class JGroupsMessengerJUnitTest {
   @Test
   public void testChannelStillConnectedStopNotForcedDisconnectWithAutoReconnect() throws Exception {
     initMocks(false);
-    doCallRealMethod().when(services).setShutdownCause(any(ForcedDisconnectException.class));
+    doCallRealMethod().when(services).setShutdownCause(any(MemberDisconnectedException.class));
     doCallRealMethod().when(services).getShutdownCause();
     doCallRealMethod().when(services).emergencyClose();
     doReturn(false).when(services).isShutdownDueToForcedDisconnect();
     doReturn(true).when(services).isAutoReconnectEnabled();
     doReturn(false).when(manager).isReconnectingDS();
-    services.setShutdownCause(new ForcedDisconnectException("Test Forced Disconnect"));
+    services.setShutdownCause(new MemberDisconnectedException("Test Forced Disconnect"));
     assertTrue(messenger.myChannel.isConnected());
     messenger.stop();
     assertFalse(messenger.myChannel.isConnected());
@@ -943,8 +936,8 @@ public class JGroupsMessengerJUnitTest {
       MemberIdentifier mbr = createAddress(1234);
       messenger.scheduledMcastSeqnos.put(mbr, new JGroupsMessenger.MessageTracker(30));
       messenger.waitForMessageState(mbr, state);
-      fail("expected a GemFireIOException to be thrown");
-    } catch (GemFireIOException e) {
+      fail("expected a MembershipIOException to be thrown");
+    } catch (TimeoutException e) {
       // pass
     }
   }
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/ClusterDistributionManager.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/ClusterDistributionManager.java
index d823398..f8c1b1b 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/ClusterDistributionManager.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/ClusterDistributionManager.java
@@ -19,6 +19,7 @@ package org.apache.geode.distributed.internal;
 import java.io.NotSerializableException;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -163,6 +164,12 @@ public class ClusterDistributionManager implements DistributionManager {
   private ClusterOperationExecutors executors;
 
   /**
+   * Membership failure listeners - for testing
+   */
+  private List<MembershipTestHook> membershipTestHooks;
+
+
+  /**
    * The <code>MembershipListener</code>s that are registered on this manager for ALL members.
    *
    * @since GemFire 5.7
@@ -2288,7 +2295,29 @@ public class ClusterDistributionManager implements DistributionManager {
     public void membershipFailure(String reason, Throwable t) {
       exceptionInThreads = true;
       rootCause = t;
-      getSystem().disconnect(reason, true);
+      if (rootCause != null && !(rootCause instanceof ForcedDisconnectException)) {
+        logger.info("cluster membership failed due to ", rootCause);
+        rootCause = new ForcedDisconnectException(rootCause.getMessage());
+      }
+      try {
+        if (membershipTestHooks != null) {
+          List<MembershipTestHook> l = membershipTestHooks;
+          for (final MembershipTestHook aL : l) {
+            MembershipTestHook dml = aL;
+            dml.beforeMembershipFailure(reason, rootCause);
+          }
+        }
+        getSystem().disconnect(reason, true);
+        if (membershipTestHooks != null) {
+          List<MembershipTestHook> l = membershipTestHooks;
+          for (final MembershipTestHook aL : l) {
+            MembershipTestHook dml = aL;
+            dml.afterMembershipFailure(reason, rootCause);
+          }
+        }
+      } catch (RuntimeException re) {
+        logger.warn("Exception caught while shutting down", re);
+      }
     }
 
     @Override
@@ -2297,39 +2326,63 @@ public class ClusterDistributionManager implements DistributionManager {
       // without holding the view lock. That can cause a race condition and
       // subsequent deadlock (#45566). Elder selection is now done when a view
       // is installed.
-      dm.addNewMember(member);
+      try {
+        dm.addNewMember(member);
+      } catch (VirtualMachineError err) {
+        // If this ever returns, rethrow the error. We're poisoned
+        // now, so don't let this thread continue.
+        throw err;
+      } catch (DistributedSystemDisconnectedException e) {
+        // don't log shutdown exceptions
+      } catch (Throwable t) {
+        logger.info(String.format("Membership: Fault while processing view addition of %s",
+            member),
+            t);
+      }
     }
 
     @Override
     public void memberDeparted(InternalDistributedMember theId, boolean crashed, String reason) {
-      boolean wasAdmin = getAdminMemberSet().contains(theId);
-      if (wasAdmin) {
-        // Pretend we received an AdminConsoleDisconnectMessage from the console that
-        // is no longer in the JavaGroup view.
-        // It must have died without sending a ShutdownMessage.
-        // This fixes bug 28454.
-        AdminConsoleDisconnectMessage message = new AdminConsoleDisconnectMessage();
-        message.setSender(theId);
-        message.setCrashed(crashed);
-        message.setAlertListenerExpected(true);
-        message.setIgnoreAlertListenerRemovalFailure(true); // we don't know if it was a listener so
-                                                            // don't issue a warning
-        message.setRecipient(localAddress);
-        message.setReason(reason); // added for #37950
-        handleIncomingDMsg(message);
-      }
-      dm.handleManagerDeparture(theId, crashed, reason);
+      try {
+        boolean wasAdmin = getAdminMemberSet().contains(theId);
+        if (wasAdmin) {
+          // Pretend we received an AdminConsoleDisconnectMessage from the console that
+          // is no longer in the JavaGroup view.
+          // It must have died without sending a ShutdownMessage.
+          // This fixes bug 28454.
+          AdminConsoleDisconnectMessage message = new AdminConsoleDisconnectMessage();
+          message.setSender(theId);
+          message.setCrashed(crashed);
+          message.setAlertListenerExpected(true);
+          message.setIgnoreAlertListenerRemovalFailure(true); // we don't know if it was a listener
+                                                              // so
+          // don't issue a warning
+          message.setRecipient(localAddress);
+          message.setReason(reason); // added for #37950
+          handleIncomingDMsg(message);
+        }
+        dm.handleManagerDeparture(theId, crashed, reason);
+      } catch (DistributedSystemDisconnectedException se) {
+        // let's not get huffy about it
+      }
     }
 
     @Override
     public void memberSuspect(InternalDistributedMember suspect,
         InternalDistributedMember whoSuspected, String reason) {
-      dm.handleManagerSuspect(suspect, whoSuspected, reason);
+      try {
+        dm.handleManagerSuspect(suspect, whoSuspected, reason);
+      } catch (DistributedSystemDisconnectedException se) {
+        // let's not get huffy about it
+      }
     }
 
     @Override
     public void viewInstalled(MembershipView view) {
-      dm.handleViewInstalled(view);
+      try {
+        dm.handleViewInstalled(view);
+      } catch (DistributedSystemDisconnectedException se) {
+      }
     }
 
     @Override
@@ -2656,6 +2709,36 @@ public class ClusterDistributionManager implements DistributionManager {
     return distributedSystemId;
   }
 
+  @Override
+  public void registerTestHook(MembershipTestHook mth) {
+    this.getDistribution().doWithViewLocked(() -> {
+      if (this.membershipTestHooks == null) {
+        this.membershipTestHooks = Collections.singletonList(mth);
+      } else {
+        List<MembershipTestHook> l = new ArrayList<>(this.membershipTestHooks);
+        l.add(mth);
+        this.membershipTestHooks = l;
+      }
+      return null;
+    });
+  }
+
+  @Override
+  public void unregisterTestHook(MembershipTestHook mth) {
+    this.getDistribution().doWithViewLocked(() -> {
+      if (this.membershipTestHooks != null) {
+        if (this.membershipTestHooks.size() == 1) {
+          this.membershipTestHooks = null;
+        } else {
+          List<MembershipTestHook> l = new ArrayList<>(this.membershipTestHooks);
+          l.remove(mth);
+          this.membershipTestHooks = l;
+        }
+      }
+      return null;
+    });
+  }
+
   /**
    * this causes the given InternalDistributedMembers to log thread dumps. If useNative is true we
    * attempt to use OSProcess native code for the dumps. This goes to stdout instead of the
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/Distribution.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/Distribution.java
index 03ba64c..830135a 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/Distribution.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/Distribution.java
@@ -25,7 +25,6 @@ import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
 import org.apache.geode.distributed.internal.membership.gms.GMSMembershipView;
 import org.apache.geode.distributed.internal.membership.gms.api.Membership;
-import org.apache.geode.distributed.internal.membership.gms.api.MembershipTestHook;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipView;
 import org.apache.geode.distributed.internal.membership.gms.api.QuorumChecker;
 
@@ -48,7 +47,7 @@ public interface Distribution {
       DistributedMember member, boolean includeMulticast);
 
   void waitForMessageState(InternalDistributedMember member,
-      Map<String, Long> state) throws InterruptedException;
+      Map<String, Long> state) throws InterruptedException, java.util.concurrent.TimeoutException;
 
   boolean requestMemberRemoval(InternalDistributedMember member,
       String reason);
@@ -100,12 +99,6 @@ public interface Distribution {
 
   Throwable getShutdownCause();
 
-  void registerTestHook(
-      MembershipTestHook mth);
-
-  void unregisterTestHook(
-      MembershipTestHook mth);
-
   boolean addSurpriseMember(InternalDistributedMember mbr);
 
   void startupMessageFailed(InternalDistributedMember mbr,
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionImpl.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionImpl.java
index 09fd867..42ae4ef 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionImpl.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionImpl.java
@@ -34,6 +34,9 @@ import java.util.function.Supplier;
 import org.apache.logging.log4j.Logger;
 
 import org.apache.geode.CancelException;
+import org.apache.geode.ForcedDisconnectException;
+import org.apache.geode.GemFireConfigException;
+import org.apache.geode.SystemConnectException;
 import org.apache.geode.SystemFailure;
 import org.apache.geode.ToDataException;
 import org.apache.geode.annotations.Immutable;
@@ -51,12 +54,16 @@ import org.apache.geode.distributed.internal.membership.gms.GMSMembership;
 import org.apache.geode.distributed.internal.membership.gms.GMSMembershipView;
 import org.apache.geode.distributed.internal.membership.gms.Services;
 import org.apache.geode.distributed.internal.membership.gms.api.LifecycleListener;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberDisconnectedException;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberShunnedException;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberStartupException;
 import org.apache.geode.distributed.internal.membership.gms.api.Membership;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipBuilder;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipClosedException;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfigurationException;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipListener;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipStatistics;
-import org.apache.geode.distributed.internal.membership.gms.api.MembershipTestHook;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipView;
 import org.apache.geode.distributed.internal.membership.gms.api.Message;
 import org.apache.geode.distributed.internal.membership.gms.api.MessageListener;
@@ -72,8 +79,11 @@ import org.apache.geode.internal.serialization.DeserializationContext;
 import org.apache.geode.internal.serialization.SerializationContext;
 import org.apache.geode.internal.serialization.Version;
 import org.apache.geode.internal.tcp.ConnectExceptions;
+import org.apache.geode.internal.tcp.ConnectionException;
 import org.apache.geode.internal.util.Breadcrumbs;
 import org.apache.geode.logging.internal.executors.LoggingThread;
+import org.apache.geode.security.AuthenticationRequiredException;
+import org.apache.geode.security.GemFireSecurityException;
 
 public class DistributionImpl implements Distribution {
   private static final Logger logger = Services.getLogger();
@@ -127,24 +137,33 @@ public class DistributionImpl implements Distribution {
     }
 
     memberTimeout = system.getConfig().getMemberTimeout();
-    membership = MembershipBuilder.<InternalDistributedMember>newMembershipBuilder()
-        .setAuthenticator(
-            new GMSAuthenticator(system.getSecurityProperties(), system.getSecurityService(),
-                system.getSecurityLogWriter(), system.getInternalLogWriter()))
-        .setStatistics(clusterDistributionManager.stats)
-        .setMessageListener(messageListener)
-        .setMembershipListener(listener)
-        .setConfig(new ServiceConfig(transport, system.getConfig()))
-        .setSerializer(InternalDataSerializer.getDSFIDSerializer())
-        .setLifecycleListener(new LifecycleListenerImpl(this))
-        .setMemberIDFactory(new ClusterDistributionManager.ClusterDistributionManagerIDFactory())
-        .setLocatorClient(new TcpClient(
-            asTcpSocketCreator(
-                SocketCreatorFactory
-                    .getSocketCreatorForComponent(SecurableCommunicationChannel.LOCATOR)),
-            InternalDataSerializer.getDSFIDSerializer().getObjectSerializer(),
-            InternalDataSerializer.getDSFIDSerializer().getObjectDeserializer()))
-        .create();
+    try {
+      membership = MembershipBuilder.<InternalDistributedMember>newMembershipBuilder()
+          .setAuthenticator(
+              new GMSAuthenticator(system.getSecurityProperties(), system.getSecurityService(),
+                  system.getSecurityLogWriter(), system.getInternalLogWriter()))
+          .setStatistics(clusterDistributionManager.stats)
+          .setMessageListener(messageListener)
+          .setMembershipListener(listener)
+          .setConfig(new ServiceConfig(transport, system.getConfig()))
+          .setSerializer(InternalDataSerializer.getDSFIDSerializer())
+          .setLifecycleListener(new LifecycleListenerImpl(this))
+          .setMemberIDFactory(new ClusterDistributionManager.ClusterDistributionManagerIDFactory())
+          .setLocatorClient(new TcpClient(
+              asTcpSocketCreator(
+                  SocketCreatorFactory
+                      .getSocketCreatorForComponent(SecurableCommunicationChannel.LOCATOR)),
+              InternalDataSerializer.getDSFIDSerializer().getObjectSerializer(),
+              InternalDataSerializer.getDSFIDSerializer().getObjectDeserializer()))
+          .create();
+    } catch (MembershipConfigurationException e) {
+      throw new GemFireConfigException(e.getMessage(), e.getCause());
+    } catch (GemFireSecurityException e) {
+      throw e;
+    } catch (RuntimeException e) {
+      Services.getLogger().error("Unexpected problem starting up membership services", e);
+      throw new SystemConnectException("Problem starting up membership services", e);
+    }
   }
 
   /**
@@ -176,7 +195,28 @@ public class DistributionImpl implements Distribution {
 
   @Override
   public void start() {
-    membership.start();
+    try {
+      membership.start();
+    } catch (ConnectionException e) {
+      throw new DistributionException(
+          "Unable to create membership manager",
+          e);
+    } catch (SecurityException e) {
+      String failReason = e.getMessage();
+      if (failReason.contains("Failed to find credentials")) {
+        throw new AuthenticationRequiredException(failReason);
+      }
+      throw new GemFireSecurityException(e.getMessage(),
+          e);
+    } catch (MembershipConfigurationException e) {
+      throw new GemFireConfigException(e.getMessage());
+    } catch (MemberStartupException e) {
+      throw new SystemConnectException(e.getMessage());
+    } catch (RuntimeException e) {
+      logger.error("Unexpected problem starting up membership services", e);
+      throw new SystemConnectException("Problem starting up membership services: " + e.getMessage()
+          + ".  Consult log file for more details");
+    }
   }
 
   @VisibleForTesting
@@ -227,7 +267,7 @@ public class DistributionImpl implements Distribution {
     Set<InternalDistributedMember> result;
     boolean allDestinations = msg.forAll();
 
-    membership.checkCancelled();
+    checkCancelled();
 
     membership.waitIfPlayingDead();
 
@@ -289,6 +329,19 @@ public class DistributionImpl implements Distribution {
   }
 
   /**
+   * This method catches membership exceptions that need to be translated into
+   * exceptions implementing CancelException in order to satisfy geode-core
+   * error handling.
+   */
+  private void checkCancelled() {
+    try {
+      membership.checkCancelled();
+    } catch (MembershipClosedException e) {
+      throw new DistributedSystemDisconnectedException(e.getMessage());
+    }
+  }
+
+  /**
    * Perform the grossness associated with sending a message over a DirectChannel
    *
    * @param destinations the list of destinations
@@ -325,9 +378,10 @@ public class DistributionImpl implements Distribution {
       if (sentBytes == 0) {
         membership.checkCancelled();
       }
+    } catch (MembershipClosedException e) {
+      throw new DistributedSystemDisconnectedException(e.getMessage(), e.getCause());
     } catch (DistributedSystemDisconnectedException ex) {
-      membership.checkCancelled();
-      throw ex; // see bug 41416
+      throw ex;
     } catch (ConnectExceptions ex) {
       // Check if the connect exception is due to system shutting down.
       if (membership.shutdownInProgress()) {
@@ -391,7 +445,7 @@ public class DistributionImpl implements Distribution {
 
   @Override
   public void waitForMessageState(InternalDistributedMember member,
-      Map<String, Long> state) throws InterruptedException {
+      Map<String, Long> state) throws InterruptedException, TimeoutException {
     if (Thread.interrupted())
       throw new InterruptedException();
     DirectChannel dc = directChannel;
@@ -409,7 +463,16 @@ public class DistributionImpl implements Distribution {
 
   @Override
   public boolean requestMemberRemoval(InternalDistributedMember member, String reason) {
-    return membership.requestMemberRemoval(member, reason);
+    try {
+      return membership.requestMemberRemoval(member, reason);
+    } catch (MemberDisconnectedException | MembershipClosedException e) {
+      throw new DistributedSystemDisconnectedException("Distribution is closed");
+    } catch (RuntimeException e) {
+      if (!membership.isConnected()) {
+        throw new DistributedSystemDisconnectedException("Distribution is closed", e);
+      }
+      throw e;
+    }
   }
 
   @Override
@@ -525,18 +588,6 @@ public class DistributionImpl implements Distribution {
   }
 
   @Override
-  public void registerTestHook(
-      MembershipTestHook mth) {
-    membership.registerTestHook(mth);
-  }
-
-  @Override
-  public void unregisterTestHook(
-      MembershipTestHook mth) {
-    membership.unregisterTestHook(mth);
-  }
-
-  @Override
   public boolean addSurpriseMember(InternalDistributedMember mbr) {
     return membership.addSurpriseMember(mbr);
   }
@@ -831,7 +882,8 @@ public class DistributionImpl implements Distribution {
     }
 
     @Override
-    public void messageReceived(Message<InternalDistributedMember> msg) {
+    public void messageReceived(Message<InternalDistributedMember> msg)
+        throws MemberShunnedException {
       membership.processMessage(msg);
 
     }
@@ -899,7 +951,15 @@ public class DistributionImpl implements Distribution {
     }
 
     @Override
-    public boolean disconnect(Exception exception) {
+    public boolean disconnect(Exception cause) {
+      Exception exception = cause;
+      // translate into a ForcedDisconnectException if necessary
+      if (cause instanceof MemberDisconnectedException) {
+        exception = new ForcedDisconnectException(cause.getMessage());
+        if (cause.getCause() != null) {
+          exception.initCause(cause.getCause());
+        }
+      }
       return distribution.disconnectDirectChannel(exception);
     }
 
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionManager.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionManager.java
index dbb3c72..1db7aad 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionManager.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/DistributionManager.java
@@ -452,4 +452,18 @@ public interface DistributionManager extends ReplySender {
    * Returns the {@link AlertingService}.
    */
   AlertingService getAlertingService();
+
+  /**
+   * register a test hook for membership events
+   *
+   * @see MembershipTestHook
+   */
+  void registerTestHook(MembershipTestHook mth);
+
+  /**
+   * remove a test hook previously registered with the manager
+   */
+  void unregisterTestHook(MembershipTestHook mth);
+
+
 }
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/LonerDistributionManager.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/LonerDistributionManager.java
index 69077a4..d9d181c 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/LonerDistributionManager.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/LonerDistributionManager.java
@@ -1478,4 +1478,14 @@ public class LonerDistributionManager implements DistributionManager {
   public AlertingService getAlertingService() {
     return NullAlertingService.get();
   }
+
+  @Override
+  public void registerTestHook(MembershipTestHook mth) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public void unregisterTestHook(MembershipTestHook mth) {
+    throw new UnsupportedOperationException();
+  }
 }
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipTestHook.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/MembershipTestHook.java
similarity index 94%
copy from geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipTestHook.java
copy to geode-core/src/main/java/org/apache/geode/distributed/internal/MembershipTestHook.java
index b76facc..0d5d32c 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipTestHook.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/MembershipTestHook.java
@@ -12,7 +12,7 @@
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
-package org.apache.geode.distributed.internal.membership.gms.api;
+package org.apache.geode.distributed.internal;
 
 /**
  * Test hook for membership test development
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/direct/DirectChannel.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/direct/DirectChannel.java
index ffe7c30..ed92af6 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/direct/DirectChannel.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/direct/DirectChannel.java
@@ -45,6 +45,7 @@ import org.apache.geode.distributed.internal.DistributionManager;
 import org.apache.geode.distributed.internal.DistributionMessage;
 import org.apache.geode.distributed.internal.ReplyProcessor21;
 import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberShunnedException;
 import org.apache.geode.distributed.internal.membership.gms.api.Membership;
 import org.apache.geode.distributed.internal.membership.gms.api.MessageListener;
 import org.apache.geode.internal.cache.DirectReplyMessage;
@@ -54,7 +55,6 @@ import org.apache.geode.internal.tcp.BaseMsgStreamer;
 import org.apache.geode.internal.tcp.ConnectExceptions;
 import org.apache.geode.internal.tcp.Connection;
 import org.apache.geode.internal.tcp.ConnectionException;
-import org.apache.geode.internal.tcp.MemberShunnedException;
 import org.apache.geode.internal.tcp.MsgStreamer;
 import org.apache.geode.internal.tcp.TCPConduit;
 import org.apache.geode.internal.util.Breadcrumbs;
@@ -699,7 +699,7 @@ public class DirectChannel {
     }
   }
 
-  public void receive(DistributionMessage msg, int bytesRead) {
+  public void receive(DistributionMessage msg, int bytesRead) throws MemberShunnedException {
     if (disconnected) {
       return;
     }
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/adapter/GMSLocatorAdapter.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/adapter/GMSLocatorAdapter.java
index 31f1b2e..c079ad3 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/adapter/GMSLocatorAdapter.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/adapter/GMSLocatorAdapter.java
@@ -20,6 +20,7 @@ import java.io.IOException;
 import java.net.InetAddress;
 import java.nio.file.Path;
 
+import org.apache.geode.GemFireConfigException;
 import org.apache.geode.cache.GemFireCache;
 import org.apache.geode.distributed.DistributedSystem;
 import org.apache.geode.distributed.internal.Distribution;
@@ -30,6 +31,7 @@ import org.apache.geode.distributed.internal.RestartableTcpHandler;
 import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
 import org.apache.geode.distributed.internal.membership.NetLocator;
 import org.apache.geode.distributed.internal.membership.gms.api.Membership;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfigurationException;
 import org.apache.geode.distributed.internal.membership.gms.interfaces.Locator;
 import org.apache.geode.distributed.internal.membership.gms.locator.GMSLocator;
 import org.apache.geode.distributed.internal.tcpserver.TcpClient;
@@ -61,10 +63,14 @@ public class GMSLocatorAdapter implements RestartableTcpHandler, NetLocator {
                 .getSocketCreatorForComponent(SecurableCommunicationChannel.LOCATOR)),
         InternalDataSerializer.getDSFIDSerializer().getObjectSerializer(),
         InternalDataSerializer.getDSFIDSerializer().getObjectDeserializer());
-    gmsLocator =
-        new GMSLocator<>(bindAddress, locatorString, usePreferredCoordinators,
-            networkPartitionDetectionEnabled,
-            locatorStats, securityUDPDHAlgo, workingDirectory, locatorClient);
+    try {
+      gmsLocator =
+          new GMSLocator<>(bindAddress, locatorString, usePreferredCoordinators,
+              networkPartitionDetectionEnabled,
+              locatorStats, securityUDPDHAlgo, workingDirectory, locatorClient);
+    } catch (MembershipConfigurationException e) {
+      throw new GemFireConfigException(e.getMessage());
+    }
   }
 
   @Override
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/GMSMembership.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/GMSMembership.java
index 44865ce..fc39073 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/GMSMembership.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/GMSMembership.java
@@ -32,6 +32,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -40,36 +41,31 @@ import java.util.stream.Collectors;
 
 import org.apache.logging.log4j.Logger;
 
-import org.apache.geode.CancelException;
-import org.apache.geode.ForcedDisconnectException;
 import org.apache.geode.GemFireConfigException;
-import org.apache.geode.InternalGemFireError;
-import org.apache.geode.SystemConnectException;
 import org.apache.geode.SystemFailure;
 import org.apache.geode.annotations.internal.MakeNotStatic;
-import org.apache.geode.distributed.DistributedSystemDisconnectedException;
 import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.distributed.internal.DistributionException;
 import org.apache.geode.distributed.internal.StartupMessage;
 import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
 import org.apache.geode.distributed.internal.membership.adapter.LocalViewMessage;
 import org.apache.geode.distributed.internal.membership.gms.api.LifecycleListener;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberDisconnectedException;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberShunnedException;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberStartupException;
 import org.apache.geode.distributed.internal.membership.gms.api.Membership;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipClosedException;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfig;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfigurationException;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipListener;
-import org.apache.geode.distributed.internal.membership.gms.api.MembershipTestHook;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipView;
 import org.apache.geode.distributed.internal.membership.gms.api.Message;
 import org.apache.geode.distributed.internal.membership.gms.api.MessageListener;
 import org.apache.geode.distributed.internal.membership.gms.api.QuorumChecker;
 import org.apache.geode.distributed.internal.membership.gms.interfaces.Manager;
 import org.apache.geode.internal.serialization.Version;
-import org.apache.geode.internal.tcp.ConnectionException;
-import org.apache.geode.internal.tcp.MemberShunnedException;
 import org.apache.geode.logging.internal.executors.LoggingExecutors;
 import org.apache.geode.logging.internal.executors.LoggingThread;
-import org.apache.geode.security.GemFireSecurityException;
 
 public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID> {
   private static final Logger logger = Services.getLogger();
@@ -247,11 +243,6 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
   private final MessageListener<ID> messageListener;
 
   /**
-   * Membership failure listeners - for testing
-   */
-  private List<MembershipTestHook> membershipTestHooks;
-
-  /**
    * This is a representation of the local member (ourself)
    */
   private ID address = null; // new ID(-1);
@@ -467,19 +458,7 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
 
         logger.info("Membership: Processing addition <{}>", m);
 
-        try {
-          listener.newMemberConnected(m);
-        } catch (VirtualMachineError err) {
-          // If this ever returns, rethrow the error. We're poisoned
-          // now, so don't let this thread continue.
-          throw err;
-        } catch (DistributedSystemDisconnectedException e) {
-          // don't log shutdown exceptions
-        } catch (Throwable t) {
-          logger.info(String.format("Membership: Fault while processing view addition of %s",
-              m),
-              t);
-        }
+        listener.newMemberConnected(m);
       } // additions
 
       // look for departures
@@ -542,10 +521,7 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
       // the view is complete - let's install it
       newlatestView.makeUnmodifiable();
       latestView = newlatestView;
-      try {
-        listener.viewInstalled(latestView);
-      } catch (DistributedSystemDisconnectedException se) {
-      }
+      listener.viewInstalled(latestView);
     } finally {
       latestViewWriteLock.unlock();
     }
@@ -580,9 +556,8 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
    * Joins the distributed system
    *
    * @throws GemFireConfigException - configuration error
-   * @throws SystemConnectException - problem joining
    */
-  private void join() {
+  private void join() throws MemberStartupException {
     services.setShutdownCause(null);
     services.getCancelCriterion().cancel(null);
 
@@ -595,7 +570,7 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
         boolean ok = services.getJoinLeave().join();
 
         if (!ok) {
-          throw new GemFireConfigException("Unable to join the distributed system.  "
+          throw new MembershipConfigurationException("Unable to join the distributed system.  "
               + "Operation either timed out, was stopped or Locator does not exist.");
         }
 
@@ -603,16 +578,6 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
         latestView = new MembershipView<>(initialView, initialView.getViewId());
         latestView.makeUnmodifiable();
         listener.viewInstalled(latestView);
-
-      } catch (RuntimeException ex) {
-        throw ex;
-      } catch (Exception ex) {
-        if (ex.getCause() != null && ex.getCause().getCause() instanceof SystemConnectException) {
-          throw (SystemConnectException) (ex.getCause().getCause());
-        }
-        throw new DistributionException(
-            "An Exception was thrown while attempting to join the distributed system.",
-            ex);
       } finally {
         this.isJoining = false;
       }
@@ -718,11 +683,7 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
       return; // Explicit deletion, no upcall.
     }
 
-    try {
-      listener.memberDeparted(dm, crashed, reason);
-    } catch (DistributedSystemDisconnectedException se) {
-      // let's not get huffy about it
-    }
+    listener.memberDeparted(dm, crashed, reason);
   }
 
   /**
@@ -746,13 +707,8 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
   public void startupMessageFailed(ID mbr, String failureMessage) {
     // fix for bug #40666
     addShunnedMember(mbr);
-    // fix for bug #41329, hang waiting for replies
-    try {
-      listener.memberDeparted(mbr, true,
-          "failed to pass startup checks");
-    } catch (DistributedSystemDisconnectedException se) {
-      // let's not get huffy about it
-    }
+    listener.memberDeparted(mbr, true,
+        "failed to pass startup checks");
   }
 
 
@@ -796,7 +752,7 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
           try {
             requestMemberRemoval(member,
                 "this member is no longer in the view but is initiating connections");
-          } catch (CancelException e) {
+          } catch (MembershipClosedException | MemberDisconnectedException e) {
             // okay to ignore
           }
         }).start();
@@ -887,7 +843,7 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
    *
    * @param msg the message to process
    */
-  protected void handleOrDeferMessage(Message<ID> msg) {
+  protected void handleOrDeferMessage(Message<ID> msg) throws MemberShunnedException {
     if (msg.dropMessageWhenMembershipIsPlayingDead() && (beingSick || playingDead)) {
       return;
     }
@@ -929,7 +885,7 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
    *
    * @param msg the message
    */
-  protected void dispatchMessage(Message<ID> msg) {
+  protected void dispatchMessage(Message<ID> msg) throws MemberShunnedException {
     ID m = msg.getSender();
     boolean shunned = false;
 
@@ -1028,7 +984,11 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
           (MembershipView<InternalDistributedMember>) viewArg,
           (GMSMembership<InternalDistributedMember>) GMSMembership.this);
 
-      messageListener.messageReceived((Message<ID>) v);
+      try {
+        messageListener.messageReceived((Message<ID>) v);
+      } catch (MemberShunnedException e) {
+        logger.error("View installation was blocked by a MemberShunnedException", e);
+      }
     } finally {
       latestViewWriteLock.unlock();
     }
@@ -1052,11 +1012,7 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
       ID suspect = gmsMemberToDMember(suspectInfo.suspectedMember);
       ID who = gmsMemberToDMember(suspectInfo.whoSuspected);
       this.suspectedMembers.put(suspect, Long.valueOf(System.currentTimeMillis()));
-      try {
-        listener.memberSuspect(suspect, who, suspectInfo.reason);
-      } catch (DistributedSystemDisconnectedException se) {
-        // let's not get huffy about it
-      }
+      listener.memberSuspect(suspect, who, suspectInfo.reason);
     } finally {
       latestViewWriteLock.unlock();
     }
@@ -1093,11 +1049,9 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
       processView(o.gmsView.getViewId(), o.gmsView);
     } else if (o.isSurpriseConnect()) { // connect
       processSurpriseConnect(o.member);
+    } else {
+      throw new IllegalArgumentException("unknown startup event: " + o);
     }
-
-    else // sanity
-      throw new InternalGemFireError(
-          String.format("unknown startup event: %s", o));
   }
 
   /**
@@ -1249,7 +1203,7 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
   }
 
   @Override
-  public void processMessage(final Message<ID> msg) {
+  public void processMessage(final Message<ID> msg) throws MemberShunnedException {
     // notify failure detection that we've had contact from a member
     services.getHealthMonitor().contactedBy(msg.getSender());
     handleOrDeferMessage(msg);
@@ -1332,21 +1286,7 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
 
     if (e != null) {
       try {
-        if (membershipTestHooks != null) {
-          List<MembershipTestHook> l = membershipTestHooks;
-          for (final MembershipTestHook aL : l) {
-            MembershipTestHook dml = aL;
-            dml.beforeMembershipFailure(reason, e);
-          }
-        }
         listener.membershipFailure(reason, e);
-        if (membershipTestHooks != null) {
-          List<MembershipTestHook> l = membershipTestHooks;
-          for (final MembershipTestHook aL : l) {
-            MembershipTestHook dml = aL;
-            dml.afterMembershipFailure(reason, e);
-          }
-        }
       } catch (RuntimeException re) {
         logger.warn("Exception caught while shutting down", re);
       }
@@ -1356,7 +1296,7 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
 
 
   @Override
-  public boolean requestMemberRemoval(ID mbr, String reason) {
+  public boolean requestMemberRemoval(ID mbr, String reason) throws MemberDisconnectedException {
     if (mbr.equals(this.address)) {
       return false;
     }
@@ -1365,13 +1305,13 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
     try {
       services.getJoinLeave().remove(mbr, reason);
     } catch (RuntimeException e) {
-      Throwable problem = e;
+      RuntimeException problem = e;
       if (services.getShutdownCause() != null) {
         Throwable cause = services.getShutdownCause();
         // If ForcedDisconnectException occurred then report it as actual
         // problem.
-        if (cause instanceof ForcedDisconnectException) {
-          problem = cause;
+        if ((cause instanceof MemberDisconnectedException)) {
+          throw (MemberDisconnectedException) cause;
         } else {
           Throwable ne = problem;
           while (ne.getCause() != null) {
@@ -1387,7 +1327,7 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
       listener.saveConfig();
 
       listener.membershipFailure("Channel closed", problem);
-      throw new DistributedSystemDisconnectedException("Channel closed", problem);
+      throw new MembershipClosedException("Channel closed", problem);
     }
     return true;
   }
@@ -1464,11 +1404,11 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
   /**
    * Check to see if the membership system is being shutdown
    *
-   * @throws DistributedSystemDisconnectedException if the system is shutting down
+   * @throws MembershipClosedException if the system is shutting down
    */
-  public void checkCancelled() {
+  public void checkCancelled() throws MembershipClosedException {
     if (services.getCancelCriterion().isCancelInProgress()) {
-      throw new DistributedSystemDisconnectedException("Distributed System is shutting down",
+      throw new MembershipClosedException("Distributed System is shutting down",
           services.getCancelCriterion().generateCancelledException(services.getShutdownCause()));
     }
   }
@@ -1744,7 +1684,7 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
 
   @Override
   public void waitForMessageState(ID otherMember, Map<String, Long> state)
-      throws InterruptedException {
+      throws InterruptedException, TimeoutException {
     services.getMessenger().waitForMessageState(otherMember, state);
   }
 
@@ -1802,41 +1742,6 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
     return services.getShutdownCause();
   }
 
-  @Override
-  public void registerTestHook(MembershipTestHook mth) {
-    // lock for additions to avoid races during startup
-    latestViewWriteLock.lock();
-    try {
-      if (this.membershipTestHooks == null) {
-        this.membershipTestHooks = Collections.singletonList(mth);
-      } else {
-        List<MembershipTestHook> l = new ArrayList<>(this.membershipTestHooks);
-        l.add(mth);
-        this.membershipTestHooks = l;
-      }
-    } finally {
-      latestViewWriteLock.unlock();
-    }
-  }
-
-  @Override
-  public void unregisterTestHook(MembershipTestHook mth) {
-    latestViewWriteLock.lock();
-    try {
-      if (this.membershipTestHooks != null) {
-        if (this.membershipTestHooks.size() == 1) {
-          this.membershipTestHooks = null;
-        } else {
-          List<MembershipTestHook> l = new ArrayList<>(this.membershipTestHooks);
-          l.remove(mth);
-          this.membershipTestHooks = l;
-        }
-      }
-    } finally {
-      latestViewWriteLock.unlock();
-    }
-  }
-
   private volatile boolean beingSick;
   private volatile boolean playingDead;
 
@@ -1939,19 +1844,8 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
   }
 
   @Override
-  public void start() {
-    try {
-      services.start();
-    } catch (ConnectionException e) {
-      throw new DistributionException(
-          "Unable to create membership manager",
-          e);
-    } catch (GemFireConfigException | SystemConnectException | GemFireSecurityException e) {
-      throw e;
-    } catch (RuntimeException e) {
-      Services.getLogger().error("Unexpected problem starting up membership services", e);
-      throw new SystemConnectException("Problem starting up membership services", e);
-    }
+  public void start() throws MemberStartupException {
+    services.start();
   }
 
   @Override
@@ -1969,7 +1863,7 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
 
     @Override
     /* Service interface */
-    public void init(Services<ID> services) {
+    public void init(Services<ID> services) throws MembershipConfigurationException {
       GMSMembership.this.services = services;
 
       MembershipConfig config = services.getConfig();
@@ -1988,7 +1882,7 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
 
     /* Service interface */
     @Override
-    public void start() {
+    public void start() throws MemberStartupException {
       lifecycleListener.start(services.getMessenger().getMemberID());
 
     }
@@ -2069,12 +1963,12 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
 
 
     @Override
-    public void joinDistributedSystem() {
+    public void joinDistributedSystem() throws MemberStartupException {
       long startTime = System.currentTimeMillis();
 
       try {
         join();
-      } catch (RuntimeException e) {
+      } catch (MemberStartupException | RuntimeException e) {
         lifecycleListener.disconnect(e);
         throw e;
       }
@@ -2108,7 +2002,7 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
 
       setShutdown();
 
-      final Exception shutdownCause = new ForcedDisconnectException(reason);
+      final Exception shutdownCause = new MemberDisconnectedException(reason);
 
       // cache the exception so it can be appended to ShutdownExceptions
       services.setShutdownCause(shutdownCause);
@@ -2123,7 +2017,7 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
       if (this.isReconnectingDS()) {
         logger.info("Reconnecting system failed to connect");
         uncleanShutdown(reason,
-            new ForcedDisconnectException("reconnecting system failed to connect"));
+            new MemberDisconnectedException("reconnecting system failed to connect"));
         return;
       }
 
@@ -2173,14 +2067,14 @@ public class GMSMembership<ID extends MemberIdentifier> implements Membership<ID
           listener.quorumLost(
               gmsMemberCollectionToIDSet(failures),
               remaining);
-        } catch (CancelException e) {
-          // safe to ignore - a forced disconnect probably occurred
+        } catch (Exception e) {
+          logger.info("Quorum-loss listener threw an exception", e);
         }
       }
     }
 
     @Override
-    public void processMessage(Message<ID> msg) {
+    public void processMessage(Message<ID> msg) throws MemberShunnedException {
       // UDP messages received from surprise members will have partial IDs.
       // Attempt to replace these with full IDs from the Membership's view.
       if (msg.getSender().isPartial()) {
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/GMSUtil.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/GMSUtil.java
index 0d8ded8..0708de3 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/GMSUtil.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/GMSUtil.java
@@ -28,8 +28,8 @@ import java.util.StringTokenizer;
 
 import org.apache.logging.log4j.Logger;
 
-import org.apache.geode.GemFireConfigException;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfigurationException;
 import org.apache.geode.distributed.internal.membership.gms.membership.HostAddress;
 import org.apache.geode.internal.net.SocketCreator;
 import org.apache.geode.internal.serialization.DeserializationContext;
@@ -47,7 +47,8 @@ public class GMSUtil {
    * @param bindAddress optional address to check for loopback compatibility
    * @return addresses of locators
    */
-  public static List<HostAddress> parseLocators(String locatorsString, String bindAddress) {
+  public static List<HostAddress> parseLocators(String locatorsString, String bindAddress)
+      throws MembershipConfigurationException {
     InetAddress addr = null;
 
     try {
@@ -85,7 +86,8 @@ public class GMSUtil {
    *
    * @see org.apache.geode.distributed.ConfigurationProperties#LOCATORS for format
    */
-  public static List<HostAddress> parseLocators(String locatorsString, InetAddress bindAddress) {
+  public static List<HostAddress> parseLocators(String locatorsString, InetAddress bindAddress)
+      throws MembershipConfigurationException {
     List<HostAddress> result = new ArrayList<>(2);
     Set<InetSocketAddress> inetAddresses = new HashSet<>();
     String host;
@@ -136,12 +138,12 @@ public class GMSUtil {
       final InetAddress locatorAddress = isa.getAddress();
 
       if (locatorAddress == null) {
-        throw new GemFireConfigException("This process is attempting to use a locator" +
+        throw new MembershipConfigurationException("This process is attempting to use a locator" +
             " at an unknown address or FQDN: " + host);
       }
 
       if (checkLoopback && isLoopback && !locatorAddress.isLoopbackAddress()) {
-        throw new GemFireConfigException(
+        throw new MembershipConfigurationException(
             "This process is attempting to join with a loopback address (" + bindAddress
                 + ") using a locator that does not have a local address (" + isa
                 + ").  On Unix this usually means that /etc/hosts is misconfigured.");
@@ -157,8 +159,8 @@ public class GMSUtil {
     return result;
   }
 
-  private static GemFireConfigException createBadPortException(final String str) {
-    return new GemFireConfigException("This process is attempting to use a locator" +
+  private static MembershipConfigurationException createBadPortException(final String str) {
+    return new MembershipConfigurationException("This process is attempting to use a locator" +
         " with a malformed port specification: " + str);
   }
 
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/MembershipBuilderImpl.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/MembershipBuilderImpl.java
index 061cb9f..81626b4 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/MembershipBuilderImpl.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/MembershipBuilderImpl.java
@@ -15,9 +15,6 @@
 package org.apache.geode.distributed.internal.membership.gms;
 
 
-import org.apache.geode.GemFireConfigException;
-import org.apache.geode.SystemConnectException;
-import org.apache.geode.distributed.internal.DistributionException;
 import org.apache.geode.distributed.internal.membership.gms.api.Authenticator;
 import org.apache.geode.distributed.internal.membership.gms.api.LifecycleListener;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
@@ -25,13 +22,12 @@ import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier
 import org.apache.geode.distributed.internal.membership.gms.api.Membership;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipBuilder;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfig;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfigurationException;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipListener;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipStatistics;
 import org.apache.geode.distributed.internal.membership.gms.api.MessageListener;
 import org.apache.geode.distributed.internal.tcpserver.TcpClient;
 import org.apache.geode.internal.serialization.DSFIDSerializer;
-import org.apache.geode.internal.tcp.ConnectionException;
-import org.apache.geode.security.GemFireSecurityException;
 
 public class MembershipBuilderImpl<ID extends MemberIdentifier> implements MembershipBuilder<ID> {
   private TcpClient locatorClient;
@@ -102,24 +98,13 @@ public class MembershipBuilderImpl<ID extends MemberIdentifier> implements Membe
   }
 
   @Override
-  public Membership<ID> create() {
+  public Membership<ID> create() throws MembershipConfigurationException {
     GMSMembership<ID> gmsMembership =
         new GMSMembership<>(membershipListener, messageListener, lifecycleListener);
     Services<ID> services =
         new Services<>(gmsMembership.getGMSManager(), statistics, authenticator,
             membershipConfig, serializer, memberFactory, locatorClient);
-    try {
-      services.init();
-    } catch (ConnectionException e) {
-      throw new DistributionException(
-          "Unable to create membership manager",
-          e);
-    } catch (GemFireConfigException | SystemConnectException | GemFireSecurityException e) {
-      throw e;
-    } catch (RuntimeException e) {
-      Services.getLogger().error("Unexpected problem starting up membership services", e);
-      throw new SystemConnectException("Problem starting up membership services", e);
-    }
+    services.init();
     return gmsMembership;
   }
 
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/Services.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/Services.java
index 0926746..9da4c98 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/Services.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/Services.java
@@ -36,15 +36,16 @@ import java.util.Timer;
 
 import org.apache.logging.log4j.Logger;
 
-import org.apache.geode.CancelCriterion;
-import org.apache.geode.ForcedDisconnectException;
 import org.apache.geode.annotations.VisibleForTesting;
-import org.apache.geode.distributed.DistributedSystemDisconnectedException;
 import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
 import org.apache.geode.distributed.internal.membership.gms.api.Authenticator;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberDisconnectedException;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifierFactory;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberStartupException;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipClosedException;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfig;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfigurationException;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipStatistics;
 import org.apache.geode.distributed.internal.membership.gms.fd.GMSHealthMonitor;
 import org.apache.geode.distributed.internal.membership.gms.interfaces.HealthMonitor;
@@ -174,7 +175,7 @@ public class Services<ID extends MemberIdentifier> {
   /**
    * Initialize services - do this before invoking start()
    */
-  public void init() {
+  public void init() throws MembershipConfigurationException {
     this.messenger.init(this);
     this.manager.init(this);
     this.joinLeave.init(this);
@@ -185,7 +186,7 @@ public class Services<ID extends MemberIdentifier> {
    * Start services - this will start everything up and join the cluster.
    * Invoke init() before this method.
    */
-  public void start() {
+  public void start() throws MemberStartupException {
     boolean started = false;
     try {
       logger.info("Starting membership services");
@@ -366,7 +367,7 @@ public class Services<ID extends MemberIdentifier> {
   }
 
   public boolean isShutdownDueToForcedDisconnect() {
-    return this.shutdownCause instanceof ForcedDisconnectException;
+    return this.shutdownCause instanceof MemberDisconnectedException;
   }
 
   public boolean isAutoReconnectEnabled() {
@@ -377,34 +378,44 @@ public class Services<ID extends MemberIdentifier> {
     return this.serializer;
   }
 
-  public class Stopper extends CancelCriterion {
+  public class Stopper {
     volatile String reasonForStopping = null;
 
     public void cancel(String reason) {
       this.reasonForStopping = reason;
     }
 
-    @Override
     public String cancelInProgress() {
       if (Services.this.shutdownCause != null)
         return Services.this.shutdownCause.toString();
       return this.reasonForStopping;
     }
 
-    @Override
     public RuntimeException generateCancelledException(Throwable e) {
       String reason = cancelInProgress();
       if (reason == null) {
         return null;
       } else {
         if (e == null) {
-          return new DistributedSystemDisconnectedException(reason);
+          return new MembershipClosedException(reason);
         } else {
-          return new DistributedSystemDisconnectedException(reason, e);
+          return new MembershipClosedException(reason, e);
         }
       }
     }
 
+    public boolean isCancelInProgress() {
+      return cancelInProgress() != null;
+    }
+
+    public void checkCancelInProgress(Throwable e) {
+      String reason = cancelInProgress();
+      if (reason == null) {
+        return;
+      }
+      throw generateCancelledException(e);
+    }
+
   }
 
 }
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipTestHook.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MemberDisconnectedException.java
similarity index 66%
copy from geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipTestHook.java
copy to geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MemberDisconnectedException.java
index b76facc..9e25f74 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipTestHook.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MemberDisconnectedException.java
@@ -15,21 +15,16 @@
 package org.apache.geode.distributed.internal.membership.gms.api;
 
 /**
- * Test hook for membership test development
+ * MemberDisconnectedException indicates that we've been kicked out of the cluster.
+ * Geode-core generally translates this into a ForcedDisconnectException, which is
+ * part of its public API.
  */
-public interface MembershipTestHook {
+public class MemberDisconnectedException extends Exception {
+  private static final long serialVersionUID = -3649273301807236514L;
 
-  /**
-   * test hook invoked prior to shutting down distributed system
-   */
-  default void beforeMembershipFailure(String reason, Throwable cause) {
-    // nothing
-  }
+  public MemberDisconnectedException() {}
 
-  /**
-   * test hook invoked after shutting down distributed system
-   */
-  default void afterMembershipFailure(String reason, Throwable cause) {
-    // nothing
+  public MemberDisconnectedException(String reason) {
+    super(reason);
   }
 }
diff --git a/geode-core/src/main/java/org/apache/geode/internal/tcp/MemberShunnedException.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MemberShunnedException.java
similarity index 88%
rename from geode-core/src/main/java/org/apache/geode/internal/tcp/MemberShunnedException.java
rename to geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MemberShunnedException.java
index 6b4e9bd..9bd010d 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/tcp/MemberShunnedException.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MemberShunnedException.java
@@ -13,16 +13,14 @@
  * the License.
  */
 
-package org.apache.geode.internal.tcp;
-
-import org.apache.geode.GemFireException;
+package org.apache.geode.distributed.internal.membership.gms.api;
 
 /**
  * MemberShunnedException may be thrown to prevent ack-ing a message received from a member that has
  * been removed from membership. It is currently only thrown by
  * JGroupMembershipManager.processMessage()
  */
-public class MemberShunnedException extends GemFireException {
+public class MemberShunnedException extends Exception {
   private static final long serialVersionUID = -8453126202477831557L;
 
   /**
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipTestHook.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MemberStartupException.java
similarity index 59%
copy from geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipTestHook.java
copy to geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MemberStartupException.java
index b76facc..f9b30e2 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipTestHook.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MemberStartupException.java
@@ -15,21 +15,21 @@
 package org.apache.geode.distributed.internal.membership.gms.api;
 
 /**
- * Test hook for membership test development
+ * MemberStartupException is thrown if there is a problem starting up membership
+ * services or joining the cluster. A subclass of MemberStartupException,
+ * MembershipConfigurationException, may also be thrown during startup and indicates a
+ * problem with configuration parameters.
  */
-public interface MembershipTestHook {
+public class MemberStartupException extends Exception {
+  private static final long serialVersionUID = 6610743861046044144L;
 
-  /**
-   * test hook invoked prior to shutting down distributed system
-   */
-  default void beforeMembershipFailure(String reason, Throwable cause) {
-    // nothing
+  public MemberStartupException() {}
+
+  public MemberStartupException(String reason) {
+    super(reason);
   }
 
-  /**
-   * test hook invoked after shutting down distributed system
-   */
-  default void afterMembershipFailure(String reason, Throwable cause) {
-    // nothing
+  public MemberStartupException(String reason, Throwable cause) {
+    super(reason, cause);
   }
 }
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/Membership.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/Membership.java
index a2474a7..6d65289 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/Membership.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/Membership.java
@@ -17,6 +17,7 @@ package org.apache.geode.distributed.internal.membership.gms.api;
 import java.io.NotSerializableException;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.TimeoutException;
 import java.util.function.Supplier;
 
 import org.apache.geode.SystemFailure;
@@ -71,12 +72,12 @@ public interface Membership<ID extends MemberIdentifier> {
    * @since GemFire 5.1
    */
   void waitForMessageState(ID member, Map<String, Long> state)
-      throws InterruptedException;
+      throws InterruptedException, TimeoutException;
 
   /**
    * Request the current membership coordinator to remove the given member
    */
-  boolean requestMemberRemoval(ID member, String reason);
+  boolean requestMemberRemoval(ID member, String reason) throws MemberDisconnectedException;
 
   /**
    * like memberExists() this checks to see if the given ID is in the current membership view. If it
@@ -235,18 +236,6 @@ public interface Membership<ID extends MemberIdentifier> {
   Throwable getShutdownCause();
 
   /**
-   * register a test hook for membership events
-   *
-   * @see MembershipTestHook
-   */
-  void registerTestHook(MembershipTestHook mth);
-
-  /**
-   * remove a test hook previously registered with the manager
-   */
-  void unregisterTestHook(MembershipTestHook mth);
-
-  /**
    * If this member is shunned, ensure that a warning is generated at least once.
    *
    * @param mbr the member that may be shunned
@@ -301,9 +290,9 @@ public interface Membership<ID extends MemberIdentifier> {
    * takes care of queueing up the message during startup and filtering out messages
    * from shunned members, before calling the message listener.
    */
-  void processMessage(Message<ID> msg);
+  void processMessage(Message<ID> msg) throws MemberShunnedException;
 
-  void checkCancelled();
+  void checkCancelled() throws MembershipClosedException;
 
   void waitIfPlayingDead();
 
@@ -318,7 +307,7 @@ public interface Membership<ID extends MemberIdentifier> {
    */
   boolean hasMember(ID member);
 
-  void start();
+  void start() throws MemberStartupException;
 
   void setCloseInProgress();
 }
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipBuilder.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipBuilder.java
index 3637979..3158644 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipBuilder.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipBuilder.java
@@ -43,7 +43,7 @@ public interface MembershipBuilder<ID extends MemberIdentifier> {
   MembershipBuilder<ID> setLocatorClient(final TcpClient tcpClient);
 
 
-  Membership<ID> create();
+  Membership<ID> create() throws MembershipConfigurationException;
 
   static <ID extends MemberIdentifier> MembershipBuilder<ID> newMembershipBuilder() {
     return new MembershipBuilderImpl<>();
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipTestHook.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipClosedException.java
similarity index 62%
copy from geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipTestHook.java
copy to geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipClosedException.java
index b76facc..2d46e95 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipTestHook.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipClosedException.java
@@ -15,21 +15,20 @@
 package org.apache.geode.distributed.internal.membership.gms.api;
 
 /**
- * Test hook for membership test development
+ * MembershipClosedException is thrown if membership services are no longer
+ * available. This exception may be thrown by any membership API and does
+ * not appear in API interfaces.
  */
-public interface MembershipTestHook {
+public class MembershipClosedException extends RuntimeException {
+  private static final long serialVersionUID = 6112938405434046127L;
 
-  /**
-   * test hook invoked prior to shutting down distributed system
-   */
-  default void beforeMembershipFailure(String reason, Throwable cause) {
-    // nothing
+  public MembershipClosedException() {}
+
+  public MembershipClosedException(String reason) {
+    super(reason);
   }
 
-  /**
-   * test hook invoked after shutting down distributed system
-   */
-  default void afterMembershipFailure(String reason, Throwable cause) {
-    // nothing
+  public MembershipClosedException(String reason, Throwable cause) {
+    super(reason, cause);
   }
 }
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipTestHook.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipConfigurationException.java
similarity index 55%
rename from geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipTestHook.java
rename to geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipConfigurationException.java
index b76facc..2310da8 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipTestHook.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MembershipConfigurationException.java
@@ -14,22 +14,24 @@
  */
 package org.apache.geode.distributed.internal.membership.gms.api;
 
+
 /**
- * Test hook for membership test development
+ * MembershipConfigurationException may be thrown during startup and indicates a
+ * problem with configuration parameters. MembershipConfigurationException is a
+ * subclass of MemberStartupException, which may also be thrown during startup but
+ * indicates a problem connecting to the cluster after membership configuration has
+ * completed.
  */
-public interface MembershipTestHook {
+public class MembershipConfigurationException extends MemberStartupException {
+  private static final long serialVersionUID = 5633602142465129621L;
+
+  public MembershipConfigurationException() {}
 
-  /**
-   * test hook invoked prior to shutting down distributed system
-   */
-  default void beforeMembershipFailure(String reason, Throwable cause) {
-    // nothing
+  public MembershipConfigurationException(String reason) {
+    super(reason);
   }
 
-  /**
-   * test hook invoked after shutting down distributed system
-   */
-  default void afterMembershipFailure(String reason, Throwable cause) {
-    // nothing
+  public MembershipConfigurationException(String reason, Throwable cause) {
+    super(reason, cause);
   }
 }
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MessageListener.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MessageListener.java
index 8f8ee37..9c250f9 100755
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MessageListener.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/api/MessageListener.java
@@ -21,7 +21,7 @@ public interface MessageListener<ID extends MemberIdentifier> {
    *
    * @param o the message that should be processed.
    */
-  void messageReceived(Message<ID> o);
+  void messageReceived(Message<ID> o) throws MemberShunnedException;
 
 
 }
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/fd/GMSHealthMonitor.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/fd/GMSHealthMonitor.java
index 1f6fbd7..782515a 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/fd/GMSHealthMonitor.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/fd/GMSHealthMonitor.java
@@ -51,14 +51,15 @@ import java.util.stream.Collectors;
 import org.apache.logging.log4j.Logger;
 import org.jgroups.util.UUID;
 
-import org.apache.geode.CancelException;
 import org.apache.geode.GemFireConfigException;
-import org.apache.geode.SystemConnectException;
 import org.apache.geode.distributed.internal.DistributionConfig;
 import org.apache.geode.distributed.internal.membership.gms.GMSMembershipView;
 import org.apache.geode.distributed.internal.membership.gms.Services;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberStartupException;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipClosedException;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfig;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfigurationException;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipStatistics;
 import org.apache.geode.distributed.internal.membership.gms.interfaces.HealthMonitor;
 import org.apache.geode.distributed.internal.membership.gms.messages.AbstractGMSMessage;
@@ -454,7 +455,7 @@ public class GMSHealthMonitor<ID extends MemberIdentifier> implements HealthMoni
       boolean pinged;
       try {
         pinged = GMSHealthMonitor.this.doCheckMember(mbr, true);
-      } catch (CancelException e) {
+      } catch (MembershipClosedException e) {
         return;
       }
 
@@ -669,7 +670,7 @@ public class GMSHealthMonitor<ID extends MemberIdentifier> implements HealthMoni
   }
 
   @Override
-  public void start() {
+  public void start() throws MemberStartupException {
     scheduler = LoggingExecutors.newScheduledThreadPool("Geode Failure Detection Scheduler", 1);
     checkExecutor = LoggingExecutors.newCachedThreadPool("Geode Failure Detection thread ", true);
     Monitor m = this.new Monitor(memberTimeout);
@@ -681,18 +682,12 @@ public class GMSHealthMonitor<ID extends MemberIdentifier> implements HealthMoni
   }
 
   ServerSocket createServerSocket(InetAddress socketAddress, int[] portRange) {
-    ServerSocket serverSocket;
-    try {
-      serverSocket = SocketCreatorFactory
-          .getSocketCreatorForComponent(SecurableCommunicationChannel.CLUSTER)
-          .createServerSocketUsingPortRange(socketAddress, 50/* backlog */, true/* isBindAddress */,
-              false/* useNIO */, 65536/* tcpBufferSize */, portRange, false);
-      socketPort = serverSocket.getLocalPort();
-    } catch (IOException | SystemConnectException e) {
-      throw new GemFireConfigException(
-          "Unable to allocate a failure detection port in the membership-port range", e);
-    }
-    return serverSocket;
+    ServerSocket newSocket = SocketCreatorFactory
+        .getSocketCreatorForComponent(SecurableCommunicationChannel.CLUSTER)
+        .createServerSocketUsingPortRange(socketAddress, 50/* backlog */, true/* isBindAddress */,
+            false/* useNIO */, 65536/* tcpBufferSize */, portRange, false);
+    socketPort = newSocket.getLocalPort();
+    return newSocket;
   }
 
   /**
@@ -789,7 +784,7 @@ public class GMSHealthMonitor<ID extends MemberIdentifier> implements HealthMoni
             }
             services.getMessenger().sendUnreliably(message);
             GMSHealthMonitor.this.stats.incHeartbeatsSent();
-          } catch (CancelException e) {
+          } catch (MembershipClosedException e) {
             return;
           }
         }
@@ -820,7 +815,7 @@ public class GMSHealthMonitor<ID extends MemberIdentifier> implements HealthMoni
             if (numSent >= NUM_HEARTBEATS) {
               break;
             }
-          } catch (CancelException e) {
+          } catch (MembershipClosedException e) {
             return;
           }
         }
@@ -925,7 +920,7 @@ public class GMSHealthMonitor<ID extends MemberIdentifier> implements HealthMoni
   }
 
   @Override
-  public void init(Services<ID> s) {
+  public void init(Services<ID> s) throws MembershipConfigurationException {
     isStopping = false;
     services = s;
     memberTimeout = s.getConfig().getMemberTimeout();
@@ -1189,7 +1184,7 @@ public class GMSHealthMonitor<ID extends MemberIdentifier> implements HealthMoni
           services.getMessenger().send(message);
           this.stats.incHeartbeatsSent();
           it.remove();
-        } catch (CancelException e) {
+        } catch (MembershipClosedException e) {
           return;
         }
       }
@@ -1300,7 +1295,7 @@ public class GMSHealthMonitor<ID extends MemberIdentifier> implements HealthMoni
       checkExecutor.execute(() -> {
         try {
           inlineCheckIfAvailable(initiator, cv, true, mbr, reason);
-        } catch (CancelException e) {
+        } catch (MembershipClosedException e) {
           // shutting down
         } catch (Exception e) {
           logger.info("Unexpected exception while verifying member", e);
@@ -1473,7 +1468,7 @@ public class GMSHealthMonitor<ID extends MemberIdentifier> implements HealthMoni
     try {
       failedRecipients = services.getMessenger().send(smm);
       this.stats.incSuspectsSent();
-    } catch (CancelException e) {
+    } catch (MembershipClosedException e) {
       return;
     }
 
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/JoinLeave.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/JoinLeave.java
index 7450fc4..1e77151 100755
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/JoinLeave.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/JoinLeave.java
@@ -16,14 +16,15 @@ package org.apache.geode.distributed.internal.membership.gms.interfaces;
 
 import org.apache.geode.distributed.internal.membership.gms.GMSMembershipView;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberStartupException;
 
 public interface JoinLeave<ID extends MemberIdentifier> extends Service<ID> {
 
   /**
    * joins the distributed system and returns true if successful, false if not. Throws
-   * SystemConnectException and GemFireConfigException
+   * MemberStartupException and MemberConfigurationException
    */
-  boolean join();
+  boolean join() throws MemberStartupException;
 
   /**
    * leaves the distributed system. Should be invoked before stop()
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/Manager.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/Manager.java
index 3ca5fd1..ba4fe81 100755
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/Manager.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/Manager.java
@@ -19,6 +19,7 @@ import java.util.Collection;
 import org.apache.geode.distributed.internal.membership.gms.GMSMembershipView;
 import org.apache.geode.distributed.internal.membership.gms.Services;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberStartupException;
 import org.apache.geode.distributed.internal.membership.gms.api.Message;
 
 /**
@@ -31,7 +32,7 @@ public interface Manager<ID extends MemberIdentifier>
   /**
    * After all services have been started this is used to join the distributed system
    */
-  void joinDistributedSystem();
+  void joinDistributedSystem() throws MemberStartupException;
 
   /**
    * initiates a Forced Disconnect, shutting down the distributed system and closing the cache
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/MessageHandler.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/MessageHandler.java
index 747dad1..dcbf6c2 100755
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/MessageHandler.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/MessageHandler.java
@@ -15,12 +15,14 @@
 package org.apache.geode.distributed.internal.membership.gms.interfaces;
 
 
+import org.apache.geode.distributed.internal.membership.gms.api.MemberShunnedException;
+
 /**
  * MessageHandler processes a message received by Messenger. Handlers are registered with Messenger
  * to consume specific classes of message.
  */
 public interface MessageHandler<T> {
 
-  void processMessage(T m);
+  void processMessage(T m) throws MemberShunnedException;
 
 }
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/Messenger.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/Messenger.java
index d6585a9..4bc64bc 100755
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/Messenger.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/Messenger.java
@@ -16,6 +16,7 @@ package org.apache.geode.distributed.internal.membership.gms.interfaces;
 
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.TimeoutException;
 
 import org.apache.geode.distributed.internal.membership.gms.GMSMembershipView;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
@@ -83,7 +84,7 @@ public interface Messenger<ID extends MemberIdentifier> extends Service<ID> {
    * @param state the state of that member's outgoing messaging to this member
    */
   void waitForMessageState(ID member, Map<String, Long> state)
-      throws InterruptedException;
+      throws InterruptedException, TimeoutException;
 
   /**
    * Get the public key of member.
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/Service.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/Service.java
index 1f53f4a8..9f55b1e 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/Service.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/interfaces/Service.java
@@ -17,19 +17,21 @@ package org.apache.geode.distributed.internal.membership.gms.interfaces;
 import org.apache.geode.distributed.internal.membership.gms.GMSMembershipView;
 import org.apache.geode.distributed.internal.membership.gms.Services;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberStartupException;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfigurationException;
 
 /**
  * Services in GMS all implement this interface
  *
  */
 public interface Service<ID extends MemberIdentifier> {
-  void init(Services<ID> s);
+  void init(Services<ID> s) throws MembershipConfigurationException;
 
   /**
    * called after all services have been initialized with init() and all services are available via
    * Services
    */
-  void start();
+  void start() throws MemberStartupException;
 
   /**
    * called after all servers have been started
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/locator/GMSLocator.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/locator/GMSLocator.java
index 75bd001..8abcc8c 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/locator/GMSLocator.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/locator/GMSLocator.java
@@ -37,7 +37,6 @@ import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.logging.log4j.Logger;
 
-import org.apache.geode.InternalGemFireException;
 import org.apache.geode.annotations.VisibleForTesting;
 import org.apache.geode.distributed.internal.LocatorStats;
 import org.apache.geode.distributed.internal.membership.gms.GMSMembership;
@@ -46,6 +45,7 @@ import org.apache.geode.distributed.internal.membership.gms.GMSUtil;
 import org.apache.geode.distributed.internal.membership.gms.Services;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
 import org.apache.geode.distributed.internal.membership.gms.api.Membership;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfigurationException;
 import org.apache.geode.distributed.internal.membership.gms.interfaces.Locator;
 import org.apache.geode.distributed.internal.membership.gms.membership.HostAddress;
 import org.apache.geode.distributed.internal.membership.gms.messenger.GMSMemberWrapper;
@@ -98,7 +98,8 @@ public class GMSLocator<ID extends MemberIdentifier> implements Locator<ID> {
    */
   public GMSLocator(InetAddress bindAddress, String locatorString, boolean usePreferredCoordinators,
       boolean networkPartitionDetectionEnabled, LocatorStats locatorStats,
-      String securityUDPDHAlgo, Path workingDirectory, final TcpClient locatorClient) {
+      String securityUDPDHAlgo, Path workingDirectory, final TcpClient locatorClient)
+      throws MembershipConfigurationException {
     this.usePreferredCoordinators = usePreferredCoordinators;
     this.networkPartitionDetectionEnabled = networkPartitionDetectionEnabled;
     this.securityUDPDHAlgo = securityUDPDHAlgo;
@@ -160,7 +161,7 @@ public class GMSLocator<ID extends MemberIdentifier> implements Locator<ID> {
     return viewFile;
   }
 
-  public void init(String persistentFileIdentifier) throws InternalGemFireException {
+  public void init(String persistentFileIdentifier) {
     if (viewFile == null) {
       viewFile =
           workingDirectory.resolve("locator" + persistentFileIdentifier + "view.dat").toFile();
@@ -219,7 +220,7 @@ public class GMSLocator<ID extends MemberIdentifier> implements Locator<ID> {
     if (!findRequest.getDHAlgo().equals(securityUDPDHAlgo)) {
       return new FindCoordinatorResponse<>(
           "Rejecting findCoordinatorRequest, as member not configured same udp security("
-              + findRequest.getDHAlgo() + " )as locator (" + securityUDPDHAlgo + ")");
+              + findRequest.getDHAlgo() + ") as locator (" + securityUDPDHAlgo + ")");
     }
 
     if (services == null) {
@@ -382,7 +383,7 @@ public class GMSLocator<ID extends MemberIdentifier> implements Locator<ID> {
     }
   }
 
-  private void recover() throws InternalGemFireException {
+  private void recover() {
     if (!recoverFromOtherLocators()) {
       recoverFromFile(viewFile);
     }
@@ -416,7 +417,7 @@ public class GMSLocator<ID extends MemberIdentifier> implements Locator<ID> {
     return false;
   }
 
-  boolean recoverFromFile(File file) throws InternalGemFireException {
+  boolean recoverFromFile(File file) {
     if (!file.exists()) {
       logger.info("recovery file not found: {}", file.getAbsolutePath());
       return false;
@@ -469,7 +470,7 @@ public class GMSLocator<ID extends MemberIdentifier> implements Locator<ID> {
         logger.warn("Peer locator was unable to recover from or delete {}", file);
         viewFile = null;
       }
-      throw new InternalGemFireException(message, e);
+      throw new IllegalStateException(message, e);
     }
   }
 }
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeave.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeave.java
index c1dd5df..0d73e4e 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeave.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeave.java
@@ -43,10 +43,7 @@ import java.util.concurrent.Future;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.Logger;
 
-import org.apache.geode.GemFireConfigException;
-import org.apache.geode.SystemConnectException;
 import org.apache.geode.annotations.VisibleForTesting;
-import org.apache.geode.distributed.DistributedSystemDisconnectedException;
 import org.apache.geode.distributed.Locator;
 import org.apache.geode.distributed.internal.ClusterDistributionManager;
 import org.apache.geode.distributed.internal.DistributionConfig;
@@ -54,7 +51,10 @@ import org.apache.geode.distributed.internal.membership.gms.GMSMembershipView;
 import org.apache.geode.distributed.internal.membership.gms.GMSUtil;
 import org.apache.geode.distributed.internal.membership.gms.Services;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberStartupException;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipClosedException;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfig;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfigurationException;
 import org.apache.geode.distributed.internal.membership.gms.interfaces.JoinLeave;
 import org.apache.geode.distributed.internal.membership.gms.locator.FindCoordinatorRequest;
 import org.apache.geode.distributed.internal.membership.gms.locator.FindCoordinatorResponse;
@@ -71,8 +71,6 @@ import org.apache.geode.distributed.internal.tcpserver.TcpClient;
 import org.apache.geode.internal.serialization.Version;
 import org.apache.geode.logging.internal.executors.LoggingExecutors;
 import org.apache.geode.logging.internal.executors.LoggingThread;
-import org.apache.geode.security.AuthenticationRequiredException;
-import org.apache.geode.security.GemFireSecurityException;
 
 /**
  * GMSJoinLeave handles membership communication with other processes in the distributed system. It
@@ -304,7 +302,7 @@ public class GMSJoinLeave<ID extends MemberIdentifier> implements JoinLeave<ID>
    * @return true if successful, false if not
    */
   @Override
-  public boolean join() {
+  public boolean join() throws MemberStartupException {
 
     try {
       if (Boolean.getBoolean(BYPASS_DISCOVERY_PROPERTY)) {
@@ -397,10 +395,10 @@ public class GMSJoinLeave<ID extends MemberIdentifier> implements JoinLeave<ID>
             + (System.currentTimeMillis() - startTime) + "ms");
       }
 
-      // to preserve old behavior we need to throw a SystemConnectException if
+      // to preserve old behavior we need to throw a MemberStartupException if
       // unable to contact any of the locators
       if (!this.isJoined && state.hasContactedAJoinedLocator) {
-        throw new SystemConnectException("Unable to join the distributed system in "
+        throw new MemberStartupException("Unable to join the distributed system in "
             + (System.currentTimeMillis() - startTime) + "ms");
       }
 
@@ -418,12 +416,12 @@ public class GMSJoinLeave<ID extends MemberIdentifier> implements JoinLeave<ID>
 
   /**
    * send a join request and wait for a reply. Process the reply. This may throw a
-   * SystemConnectException or an AuthenticationFailedException
+   * MemberStartupException or an exception from the authenticator, if present.
    *
    * @return true if the attempt succeeded, false if it timed out
    */
   @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "WA_NOT_IN_LOOP")
-  boolean attemptToJoin() {
+  boolean attemptToJoin() throws MemberStartupException {
     SearchState<ID> state = searchState;
 
     // send a join request to the coordinator and wait for a response
@@ -462,11 +460,9 @@ public class GMSJoinLeave<ID extends MemberIdentifier> implements JoinLeave<ID>
       if (failReason.contains("Rejecting the attempt of a member using an older version")
           || failReason.contains("15806")
           || failReason.contains("ForcedDisconnectException")) {
-        throw new SystemConnectException(failReason);
-      } else if (failReason.contains("Failed to find credentials")) {
-        throw new AuthenticationRequiredException(failReason);
+        throw new MemberStartupException(failReason);
       }
-      throw new GemFireSecurityException(failReason);
+      throw new SecurityException(failReason);
     }
 
     throw new RuntimeException("Join Request Failed with response " + response);
@@ -1110,7 +1106,7 @@ public class GMSJoinLeave<ID extends MemberIdentifier> implements JoinLeave<ID>
    * This contacts the locators to find out who the current coordinator is. All locators are
    * contacted. If they don't agree then we choose the oldest coordinator and return it.
    */
-  boolean findCoordinator() {
+  boolean findCoordinator() throws MemberStartupException {
     SearchState<ID> state = searchState;
 
     assert this.localAddress != null;
@@ -1149,7 +1145,7 @@ public class GMSJoinLeave<ID extends MemberIdentifier> implements JoinLeave<ID>
               (o instanceof FindCoordinatorResponse) ? (FindCoordinatorResponse<ID>) o : null;
           if (response != null) {
             if (response.getRejectionMessage() != null) {
-              throw new GemFireConfigException(response.getRejectionMessage());
+              throw new MembershipConfigurationException(response.getRejectionMessage());
             }
             setCoordinatorPublicKey(response);
             state.locatorsContacted++;
@@ -1195,7 +1191,7 @@ public class GMSJoinLeave<ID extends MemberIdentifier> implements JoinLeave<ID>
             } catch (InterruptedException e) {
               Thread.currentThread().interrupt();
               services.getCancelCriterion().checkCancelInProgress(e);
-              throw new SystemConnectException("Interrupted while trying to contact locators");
+              throw new MemberStartupException("Interrupted while trying to contact locators");
             }
           }
         }
@@ -1680,7 +1676,7 @@ public class GMSJoinLeave<ID extends MemberIdentifier> implements JoinLeave<ID>
   }
 
   @Override
-  public void start() {}
+  public void start() throws MemberStartupException {}
 
   @Override
   public void started() {}
@@ -1823,15 +1819,16 @@ public class GMSJoinLeave<ID extends MemberIdentifier> implements JoinLeave<ID>
   }
 
   @Override
-  public void init(Services<ID> s) {
+  public void init(Services<ID> s) throws MembershipConfigurationException {
     this.services = s;
 
     MembershipConfig config = services.getConfig();
     if (config.getMcastPort() != 0 && StringUtils.isBlank(config.getLocators())
         && StringUtils.isBlank(config.getStartLocator())) {
-      throw new GemFireConfigException("Multicast cannot be configured for a non-distributed cache."
-          + "  Please configure the locator services for this cache using " + LOCATORS + " or "
-          + START_LOCATOR + ".");
+      throw new MembershipConfigurationException(
+          "Multicast cannot be configured for a non-distributed cache."
+              + "  Please configure the locator services for this cache using " + LOCATORS + " or "
+              + START_LOCATOR + ".");
     }
 
     services.getMessenger().addHandler(JoinRequestMessage.class, this::processMessage);
@@ -2187,7 +2184,7 @@ public class GMSJoinLeave<ID extends MemberIdentifier> implements JoinLeave<ID>
           }
         } catch (InterruptedException e) {
           setShutdownFlag();
-        } catch (DistributedSystemDisconnectedException e) {
+        } catch (MembershipClosedException e) {
           setShutdownFlag();
         }
       } while (retry);
@@ -2322,7 +2319,7 @@ public class GMSJoinLeave<ID extends MemberIdentifier> implements JoinLeave<ID>
               } catch (InterruptedException e2) {
                 setShutdownFlag();
               }
-            } catch (DistributedSystemDisconnectedException e) {
+            } catch (MembershipClosedException e) {
               setShutdownFlag();
             } catch (InterruptedException e) {
               logger.info("View Creator thread interrupted");
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/messenger/GMSQuorumChecker.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/messenger/GMSQuorumChecker.java
index a74ca65..e34dea7 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/messenger/GMSQuorumChecker.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/messenger/GMSQuorumChecker.java
@@ -81,6 +81,7 @@ public class GMSQuorumChecker<ID extends MemberIdentifier> implements QuorumChec
   }
 
 
+  @Override
   public synchronized boolean checkForQuorum(long timeout) throws InterruptedException {
     if (quorumAchieved) {
       return true;
@@ -98,6 +99,7 @@ public class GMSQuorumChecker<ID extends MemberIdentifier> implements QuorumChec
     return quorumAchieved;
   }
 
+  @Override
   public void close() {
     if (channel != null && !channel.isClosed()) {
       channel.close();
@@ -109,7 +111,7 @@ public class GMSQuorumChecker<ID extends MemberIdentifier> implements QuorumChec
     JGroupsMessenger.setChannelReceiver(channel, new QuorumCheckerReceiver());
   }
 
-
+  @Override
   public MembershipInformation getMembershipInfo() {
     return new MembershipInformationImpl(channel, messageQueue);
   }
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/messenger/JGroupsMessenger.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/messenger/JGroupsMessenger.java
index 7ae80bf..4254b80 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/messenger/JGroupsMessenger.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/membership/gms/messenger/JGroupsMessenger.java
@@ -42,6 +42,7 @@ import java.util.Queue;
 import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.stream.Collectors;
@@ -66,23 +67,21 @@ import org.jgroups.stack.IpAddress;
 import org.jgroups.util.Digest;
 import org.jgroups.util.UUID;
 
-import org.apache.geode.ForcedDisconnectException;
-import org.apache.geode.GemFireConfigException;
-import org.apache.geode.GemFireIOException;
-import org.apache.geode.InternalGemFireError;
-import org.apache.geode.InternalGemFireException;
-import org.apache.geode.SystemConnectException;
 import org.apache.geode.alerting.internal.spi.AlertingAction;
 import org.apache.geode.annotations.internal.MutableForTesting;
-import org.apache.geode.distributed.DistributedSystemDisconnectedException;
 import org.apache.geode.distributed.internal.DistributionConfig;
 import org.apache.geode.distributed.internal.membership.gms.GMSMemberData;
 import org.apache.geode.distributed.internal.membership.gms.GMSMembershipView;
 import org.apache.geode.distributed.internal.membership.gms.GMSUtil;
 import org.apache.geode.distributed.internal.membership.gms.Services;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberData;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberDisconnectedException;
 import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberShunnedException;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberStartupException;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipClosedException;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfig;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfigurationException;
 import org.apache.geode.distributed.internal.membership.gms.api.MembershipStatistics;
 import org.apache.geode.distributed.internal.membership.gms.api.Message;
 import org.apache.geode.distributed.internal.membership.gms.interfaces.HealthMonitor;
@@ -100,7 +99,7 @@ import org.apache.geode.internal.serialization.BufferDataOutputStream;
 import org.apache.geode.internal.serialization.StaticSerialization;
 import org.apache.geode.internal.serialization.Version;
 import org.apache.geode.internal.serialization.VersionedDataInputStream;
-import org.apache.geode.internal.tcp.MemberShunnedException;
+
 
 @SuppressWarnings("StatementWithEmptyBody")
 public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<ID> {
@@ -186,14 +185,14 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
       receiver.setAccessible(true);
       receiver.set(channel, r);
     } catch (NoSuchFieldException | IllegalAccessException e) {
-      throw new InternalGemFireException("unable to establish a JGroups receiver", e);
+      throw new IllegalStateException("unable to establish a JGroups receiver", e);
     }
   }
 
   @Override
   @edu.umd.cs.findbugs.annotations.SuppressWarnings(
       value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD")
-  public void init(Services<ID> s) {
+  public void init(Services<ID> s) throws MembershipConfigurationException {
     this.services = s;
 
     MembershipConfig config = services.getConfig();
@@ -212,7 +211,7 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
     }
     is = ClassPathLoader.getLatest().getResourceAsStream(getClass(), r);
     if (is == null) {
-      throw new GemFireConfigException(
+      throw new MembershipConfigurationException(
           String.format("Cannot find %s", r));
     }
 
@@ -228,7 +227,7 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
       br.close();
       properties = sb.toString();
     } catch (Exception ex) {
-      throw new GemFireConfigException(
+      throw new MembershipConfigurationException(
           "An Exception was thrown while reading JGroups config.",
           ex);
     }
@@ -272,7 +271,7 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
       try {
         str = SocketCreator.getLocalHost().getHostAddress();
       } catch (UnknownHostException e) {
-        throw new GemFireConfigException(e.getMessage(), e);
+        throw new MembershipConfigurationException(e.getMessage(), e);
       }
     }
     properties = replaceStrings(properties, "BIND_ADDR_SETTING", "bind_addr=\"" + str + "\"");
@@ -303,7 +302,7 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
         this.encrypt = new GMSEncrypt<>(services, config.getSecurityUDPDHAlgo());
         logger.info("Initializing GMSEncrypt ");
       } catch (Exception e) {
-        throw new GemFireConfigException("problem initializing encryption protocol", e);
+        throw new MembershipConfigurationException("problem initializing encryption protocol", e);
       }
     }
   }
@@ -311,7 +310,7 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
   @Override
   @edu.umd.cs.findbugs.annotations.SuppressWarnings(
       value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD")
-  public void start() {
+  public void start() throws MemberStartupException {
     // create the configuration XML string for JGroups
     String properties = this.jgStackConfig;
 
@@ -353,7 +352,7 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
         myChannel = new JChannel(is);
       }
     } catch (Exception e) {
-      throw new GemFireConfigException("unable to create jgroups channel", e);
+      throw new MembershipConfigurationException("unable to create jgroups channel", e);
     }
 
     // give the stats to the jchannel statistics recorder
@@ -370,18 +369,22 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
 
     try {
       jgroupsReceiver = new JGroupsReceiver();
-      setChannelReceiver(myChannel, jgroupsReceiver);
+      try {
+        setChannelReceiver(myChannel, jgroupsReceiver);
+      } catch (IllegalStateException e) {
+        throw new MemberStartupException("problem initializing JGroups", e);
+      }
       if (!reconnecting) {
         myChannel.connect("AG"); // Apache Geode
       }
     } catch (Exception e) {
       myChannel.close();
-      throw new SystemConnectException("unable to create jgroups channel", e);
+      throw new MemberStartupException("unable to create jgroups channel", e);
     }
 
     if (JGroupsMessenger.THROW_EXCEPTION_ON_START_HOOK) {
       JGroupsMessenger.THROW_EXCEPTION_ON_START_HOOK = false;
-      throw new SystemConnectException("failing for test");
+      throw new MemberStartupException("failing for test");
     }
 
     establishLocalAddress();
@@ -506,7 +509,7 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
     }
   }
 
-  private void establishLocalAddress() {
+  private void establishLocalAddress() throws MemberStartupException {
     UUID logicalAddress = (UUID) myChannel.getAddress();
     logicalAddress = logicalAddress.copy();
 
@@ -523,7 +526,7 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
         ipaddr = (IpAddress) getAddress.invoke(udp, new Object[0]);
         this.jgAddress = new JGAddress(logicalAddress, ipaddr);
       } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
-        throw new InternalGemFireError(
+        throw new MemberStartupException(
             "Unable to configure JGroups channel for membership communications", e);
       }
     }
@@ -602,7 +605,7 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
 
   @Override
   public void waitForMessageState(ID sender, Map<String, Long> state)
-      throws InterruptedException {
+      throws InterruptedException, TimeoutException {
     Long seqno = state.get("JGroups.mcastState");
     if (seqno == null) {
       return;
@@ -641,7 +644,7 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
             Long.toString((warnTime - startTime) / 1000L), sender, received, seqno);
       }
       if (now >= quitTime) {
-        throw new GemFireIOException("Multicast operations from " + sender
+        throw new TimeoutException("Multicast operations from " + sender
             + " did not distribute within " + (now - startTime) + " milliseconds");
       }
       Thread.sleep(50);
@@ -671,7 +674,7 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
 
     if (!myChannel.isConnected()) {
       logger.info("JGroupsMessenger channel is closed - messaging is not possible");
-      throw new DistributedSystemDisconnectedException("Distributed System is shutting down");
+      throw new MembershipClosedException("Distributed System is shutting down");
     }
 
     filterOutgoingMessage(msg);
@@ -693,12 +696,18 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
 
     JGAddress local = this.jgAddress;
 
+    Set<ID> failedRecipients = new HashSet<>();
     if (useMcast) {
-
       long startSer = theStats.startMsgSerialization();
-      org.jgroups.Message jmsg =
-          createJGMessage(msg, local, null, Version.getCurrentVersion().ordinal());
-      theStats.endMsgSerialization(startSer);
+      org.jgroups.Message jmsg;
+      try {
+        jmsg =
+            createJGMessage(msg, local, null, Version.getCurrentVersion().ordinal());
+      } catch (IOException e) {
+        return new HashSet<>(msg.getRecipients());
+      } finally {
+        theStats.endMsgSerialization(startSer);
+      }
 
       Exception problem;
       try {
@@ -712,7 +721,7 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
       } catch (Exception e) {
         logger.debug("caught unexpected exception", e);
         Throwable cause = e.getCause();
-        if (cause instanceof ForcedDisconnectException) {
+        if (cause instanceof MemberDisconnectedException) {
           problem = (Exception) cause;
         } else {
           problem = e;
@@ -721,7 +730,7 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
           Throwable shutdownCause = services.getShutdownCause();
           // If ForcedDisconnectException occurred then report it as actual
           // problem.
-          if (shutdownCause instanceof ForcedDisconnectException) {
+          if (shutdownCause instanceof MemberDisconnectedException) {
             problem = (Exception) shutdownCause;
           } else {
             Throwable ne = problem;
@@ -733,7 +742,7 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
         }
         final String channelClosed =
             "Channel closed";
-        throw new DistributedSystemDisconnectedException(channelClosed, problem);
+        throw new MembershipClosedException(channelClosed, problem);
       }
     } // useMcast
     else { // ! useMcast
@@ -765,8 +774,14 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
       for (ID mbr : calculatedMembers) {
         short version = mbr.getVersionOrdinal();
         if (!messages.containsKey(version)) {
-          org.jgroups.Message jmsg = createJGMessage(msg, local, mbr, version);
-          messages.put(version, jmsg);
+          org.jgroups.Message jmsg;
+          try {
+            jmsg = createJGMessage(msg, local, mbr, version);
+            messages.put(version, jmsg);
+          } catch (IOException e) {
+            failedRecipients.add(mbr);
+            continue;
+          }
           if (firstMessage) {
             theStats.incSentBytes(jmsg.getLength());
             firstMessage = false;
@@ -780,6 +795,9 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
         JGAddress to = new JGAddress(mbr);
         short version = mbr.getVersionOrdinal();
         org.jgroups.Message jmsg = messages.get(version);
+        if (jmsg == null) {
+          continue; // failed for all recipients
+        }
         Exception problem = null;
         try {
           org.jgroups.Message tmp = (i < (calculatedLen - 1)) ? jmsg.copy(true) : jmsg;
@@ -798,7 +816,7 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
           if (cause != null) {
             // If ForcedDisconnectException occurred then report it as actual
             // problem.
-            if (cause instanceof ForcedDisconnectException) {
+            if (cause instanceof MemberDisconnectedException) {
               problem = (Exception) cause;
             } else {
               Throwable ne = problem;
@@ -810,7 +828,7 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
           }
           final String channelClosed =
               "Channel closed";
-          throw new DistributedSystemDisconnectedException(channelClosed, problem);
+          throw new MembershipClosedException(channelClosed, problem);
         }
       } // send individually
     } // !useMcast
@@ -818,20 +836,19 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
     // The contract is that every destination enumerated in the
     // message should have received the message. If one left
     // (i.e., left the view), we signal it here.
-    if (msg.forAll()) {
+    if (failedRecipients.isEmpty() && msg.forAll()) {
       return Collections.emptySet();
     }
-    Set<ID> result = new HashSet<>();
     GMSMembershipView<ID> newView = this.view;
     if (newView != null && newView != oldView) {
       for (ID d : destinations) {
         if (!newView.contains(d)) {
           logger.debug("messenger: member has left the view: {}  view is now {}", d, newView);
-          result.add(d);
+          failedRecipients.add(d);
         }
       }
     }
-    return result;
+    return failedRecipients;
   }
 
   /**
@@ -845,7 +862,7 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
    * @return the new message
    */
   org.jgroups.Message createJGMessage(Message<ID> gfmsg, JGAddress src, ID dst,
-      short version) {
+      short version) throws IOException {
     gfmsg.registerProcessor();
     org.jgroups.Message msg = new org.jgroups.Message();
     msg.setDest(null);
@@ -867,19 +884,13 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
 
       msg.setBuffer(out_stream.toByteArray());
       services.getStatistics().endMsgSerialization(start);
-    } catch (IOException | GemFireIOException ex) {
+    } catch (IOException ex) {
       logger.warn("Error serializing message", ex);
-      if (ex instanceof GemFireIOException) {
-        throw (GemFireIOException) ex;
-      } else {
-        GemFireIOException ioe = new GemFireIOException("Error serializing message");
-        ioe.initCause(ex);
-        throw ioe;
-      }
+      throw ex;
     } catch (Exception ex) {
       logger.warn("Error serializing message", ex);
-      GemFireIOException ioe = new GemFireIOException("Error serializing message");
-      ioe.initCause(ex.getCause());
+      IOException ioe =
+          new IOException("Error serializing message", ex.getCause());
       throw ioe;
     }
     return msg;
@@ -1019,7 +1030,7 @@ public class JGroupsMessenger<ID extends MemberIdentifier> implements Messenger<
       boolean isEncrypted = dis.readBoolean();
 
       if (isEncrypted && encrypt == null) {
-        throw new GemFireConfigException("Got remote message as encrypted");
+        throw new MembershipConfigurationException("Got remote message as encrypted");
       }
 
       if (isEncrypted) {
diff --git a/geode-core/src/main/java/org/apache/geode/internal/net/SocketCreator.java b/geode-core/src/main/java/org/apache/geode/internal/net/SocketCreator.java
index bfb1b38..1983d8e 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/net/SocketCreator.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/net/SocketCreator.java
@@ -754,44 +754,48 @@ public class SocketCreator {
    */
   public ServerSocket createServerSocketUsingPortRange(InetAddress ba, int backlog,
       boolean isBindAddress, boolean useNIO, int tcpBufferSize, int[] tcpPortRange,
-      boolean sslConnection) throws IOException {
+      boolean sslConnection) {
 
-    // Get a random port from range.
-    int startingPort = tcpPortRange[0]
-        + ThreadLocalRandom.current().nextInt(tcpPortRange[1] - tcpPortRange[0] + 1);
-    int localPort = startingPort;
-    int portLimit = tcpPortRange[1];
-
-    while (true) {
-      if (localPort > portLimit) {
-        if (startingPort != 0) {
-          localPort = tcpPortRange[0];
-          portLimit = startingPort - 1;
-          startingPort = 0;
-        } else {
-          throw new SystemConnectException(
-              "Unable to find a free port in the membership-port-range");
+    try {
+      // Get a random port from range.
+      int startingPort = tcpPortRange[0]
+          + ThreadLocalRandom.current().nextInt(tcpPortRange[1] - tcpPortRange[0] + 1);
+      int localPort = startingPort;
+      int portLimit = tcpPortRange[1];
+
+      while (true) {
+        if (localPort > portLimit) {
+          if (startingPort != 0) {
+            localPort = tcpPortRange[0];
+            portLimit = startingPort - 1;
+            startingPort = 0;
+          } else {
+            throw new SystemConnectException(
+                "Unable to find a free port in the membership-port-range");
+          }
         }
-      }
-      ServerSocket socket = null;
-      try {
-        if (useNIO) {
-          ServerSocketChannel channel = ServerSocketChannel.open();
-          socket = channel.socket();
+        ServerSocket socket = null;
+        try {
+          if (useNIO) {
+            ServerSocketChannel channel = ServerSocketChannel.open();
+            socket = channel.socket();
 
-          InetSocketAddress address = new InetSocketAddress(isBindAddress ? ba : null, localPort);
-          socket.bind(address, backlog);
-        } else {
-          socket = this.createServerSocket(localPort, backlog, isBindAddress ? ba : null,
-              tcpBufferSize, sslConnection);
-        }
-        return socket;
-      } catch (java.net.SocketException ex) {
-        if (socket != null && !socket.isClosed()) {
-          socket.close();
+            InetSocketAddress address = new InetSocketAddress(isBindAddress ? ba : null, localPort);
+            socket.bind(address, backlog);
+          } else {
+            socket = this.createServerSocket(localPort, backlog, isBindAddress ? ba : null,
+                tcpBufferSize, sslConnection);
+          }
+          return socket;
+        } catch (java.net.SocketException ex) {
+          if (socket != null && !socket.isClosed()) {
+            socket.close();
+          }
+          localPort++;
         }
-        localPort++;
       }
+    } catch (IOException e) {
+      throw new GemFireConfigException("unable to create a socket in the membership-port range", e);
     }
   }
 
diff --git a/geode-core/src/main/java/org/apache/geode/internal/tcp/Connection.java b/geode-core/src/main/java/org/apache/geode/internal/tcp/Connection.java
index 2554723..927e46a 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/tcp/Connection.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/tcp/Connection.java
@@ -72,6 +72,7 @@ import org.apache.geode.distributed.internal.ReplyProcessor21;
 import org.apache.geode.distributed.internal.ReplySender;
 import org.apache.geode.distributed.internal.direct.DirectChannel;
 import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberShunnedException;
 import org.apache.geode.distributed.internal.membership.gms.api.Membership;
 import org.apache.geode.internal.Assert;
 import org.apache.geode.internal.DSFIDFactory;
@@ -2654,8 +2655,6 @@ public class Connection implements Runnable {
       stats.incMessageChannelTime(msg.resetTimestamp());
       msg.process(dm, processor);
       // dispatchMessage(msg, len, false);
-    } catch (MemberShunnedException e) {
-      // do nothing
     } catch (SocketTimeoutException timeout) {
       throw timeout;
     } catch (IOException e) {
@@ -3171,7 +3170,8 @@ public class Connection implements Runnable {
     }
   }
 
-  private boolean dispatchMessage(DistributionMessage msg, int bytesRead, boolean directAck) {
+  private boolean dispatchMessage(DistributionMessage msg, int bytesRead, boolean directAck)
+      throws MemberShunnedException {
     try {
       msg.setDoDecMessagesBeingReceived(true);
       if (directAck) {
diff --git a/geode-core/src/main/java/org/apache/geode/internal/tcp/TCPConduit.java b/geode-core/src/main/java/org/apache/geode/internal/tcp/TCPConduit.java
index e553c54..a5a53fd 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/tcp/TCPConduit.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/tcp/TCPConduit.java
@@ -48,6 +48,7 @@ import org.apache.geode.distributed.internal.DistributionMessage;
 import org.apache.geode.distributed.internal.LonerDistributionManager;
 import org.apache.geode.distributed.internal.direct.DirectChannel;
 import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
+import org.apache.geode.distributed.internal.membership.gms.api.MemberShunnedException;
 import org.apache.geode.distributed.internal.membership.gms.api.Membership;
 import org.apache.geode.internal.logging.log4j.LogMarker;
 import org.apache.geode.internal.net.BufferPool;
@@ -655,7 +656,8 @@ public class TCPConduit implements Runnable {
    *
    * @param bytesRead number of bytes read off of network to get this message
    */
-  void messageReceived(Connection receiver, DistributionMessage message, int bytesRead) {
+  void messageReceived(Connection receiver, DistributionMessage message, int bytesRead)
+      throws MemberShunnedException {
     if (logger.isTraceEnabled()) {
       logger.trace("{} received {} from {}", id, message, receiver);
     }
diff --git a/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt b/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
index ca18ac8..5fefafa 100644
--- a/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
+++ b/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
@@ -259,6 +259,11 @@ org/apache/geode/distributed/internal/deadlock/MessageDependencyMonitor$MessageK
 org/apache/geode/distributed/internal/direct/ShunnedMemberException,true,-6455664684151074915
 org/apache/geode/distributed/internal/locks/DistributedMemberLock$LockReentryPolicy,false
 org/apache/geode/distributed/internal/locks/LockGrantorDestroyedException,true,-3540124531032570817
+org/apache/geode/distributed/internal/membership/gms/api/MemberDisconnectedException,true,-3649273301807236514
+org/apache/geode/distributed/internal/membership/gms/api/MemberShunnedException,true,-8453126202477831557
+org/apache/geode/distributed/internal/membership/gms/api/MemberStartupException,true,6610743861046044144
+org/apache/geode/distributed/internal/membership/gms/api/MembershipClosedException,true,6112938405434046127
+org/apache/geode/distributed/internal/membership/gms/api/MembershipConfigurationException,true,5633602142465129621
 org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeave$ViewAbandonedException,false
 org/apache/geode/distributed/internal/membership/gms/messages/InstallViewMessage$messageType,false
 org/apache/geode/internal/ConfigSource,true,-4097017272431018553,description:java/lang/String,type:org/apache/geode/internal/ConfigSource$Type
@@ -411,7 +416,6 @@ org/apache/geode/internal/tcp/ByteBufferInputStream,false,buffer:org/apache/geod
 org/apache/geode/internal/tcp/ConnectExceptions,true,-4173688946448867706,causes:java/util/List,members:java/util/List
 org/apache/geode/internal/tcp/ConnectionException,true,-1977443644277412122
 org/apache/geode/internal/tcp/ImmutableByteBufferInputStream,false
-org/apache/geode/internal/tcp/MemberShunnedException,true,-8453126202477831557
 org/apache/geode/internal/tcp/ReenteredConnectException,true,2878977454669428469
 org/apache/geode/internal/util/Breadcrumbs$CrumbType,false
 org/apache/geode/internal/util/SunAPINotFoundException,true,75895915344106684
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/internal/DistributionTest.java b/geode-core/src/test/java/org/apache/geode/distributed/internal/DistributionTest.java
index 629f16a..73ce133 100644
--- a/geode-core/src/test/java/org/apache/geode/distributed/internal/DistributionTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/internal/DistributionTest.java
@@ -45,6 +45,7 @@ import org.apache.geode.distributed.internal.membership.InternalDistributedMembe
 import org.apache.geode.distributed.internal.membership.gms.GMSMemberData;
 import org.apache.geode.distributed.internal.membership.gms.GMSMembership;
 import org.apache.geode.distributed.internal.membership.gms.api.Membership;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipClosedException;
 import org.apache.geode.internal.admin.remote.AlertListenerMessage;
 import org.apache.geode.internal.admin.remote.RemoteTransportConfig;
 import org.apache.geode.internal.tcp.ConnectExceptions;
@@ -138,7 +139,7 @@ public class DistributionTest {
         .directChannelSend(recipients, m);
     when(dc.send(any(), any(mockMembers.getClass()),
         any(DistributionMessage.class), anyInt(), anyInt())).thenReturn(0);
-    doThrow(DistributedSystemDisconnectedException.class).when(membership).checkCancelled();
+    doThrow(MembershipClosedException.class).when(membership).checkCancelled();
 
     try {
       distribution.directChannelSend(recipients, m);
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/internal/membership/MembershipDependenciesJUnitTest.java b/geode-core/src/test/java/org/apache/geode/distributed/internal/membership/MembershipDependenciesJUnitTest.java
index e1b8b0d..b5cd52d 100644
--- a/geode-core/src/test/java/org/apache/geode/distributed/internal/membership/MembershipDependenciesJUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/internal/membership/MembershipDependenciesJUnitTest.java
@@ -15,7 +15,6 @@
 package org.apache.geode.distributed.internal.membership;
 
 import static com.tngtech.archunit.base.DescribedPredicate.not;
-import static com.tngtech.archunit.core.domain.JavaClass.Predicates.assignableTo;
 import static com.tngtech.archunit.core.domain.JavaClass.Predicates.resideInAPackage;
 import static com.tngtech.archunit.core.domain.JavaClass.Predicates.type;
 import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
@@ -29,9 +28,6 @@ import com.tngtech.archunit.junit.CacheMode;
 import com.tngtech.archunit.lang.ArchRule;
 import org.junit.runner.RunWith;
 
-import org.apache.geode.CancelCriterion;
-import org.apache.geode.GemFireException;
-import org.apache.geode.InternalGemFireError;
 import org.apache.geode.alerting.internal.spi.AlertingAction;
 import org.apache.geode.distributed.Locator;
 import org.apache.geode.distributed.internal.LocatorStats;
@@ -111,16 +107,9 @@ public class MembershipDependenciesJUnitTest {
               // TODO: Create a new stats interface for membership
               .or(type(LocatorStats.class))
 
-              // TODO: Figure out what to do with exceptions
-              .or(assignableTo(GemFireException.class))
-              .or(type(InternalGemFireError.class))
-
               // TODO: Serialization needs to become its own module
               .or(type(InternalDataSerializer.class)) // still used by GMSLocator
 
-              // TODO
-              .or(assignableTo(CancelCriterion.class))
-
               // TODO:
               .or(type(SocketCreator.class))
               .or(type(SocketCreatorFactory.class))
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/internal/membership/gms/GMSUtilTest.java b/geode-core/src/test/java/org/apache/geode/distributed/internal/membership/gms/GMSUtilTest.java
index bc04765..6c6c3dd 100644
--- a/geode-core/src/test/java/org/apache/geode/distributed/internal/membership/gms/GMSUtilTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/internal/membership/gms/GMSUtilTest.java
@@ -27,7 +27,7 @@ import junitparams.Parameters;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import org.apache.geode.GemFireConfigException;
+import org.apache.geode.distributed.internal.membership.gms.api.MembershipConfigurationException;
 import org.apache.geode.distributed.internal.membership.gms.membership.HostAddress;
 
 @RunWith(JUnitParamsRunner.class)
@@ -43,7 +43,7 @@ public class GMSUtilTest {
 
 
   @Test
-  public void resolveableLoopBackAddress() {
+  public void resolveableLoopBackAddress() throws MembershipConfigurationException {
     assertThat(
         parseLocators(RESOLVEABLE_LOOPBACK_HOST + "[" + PORT + "]",
             InetAddress.getLoopbackAddress()))
@@ -57,7 +57,7 @@ public class GMSUtilTest {
     assertThatThrownBy(
         () -> parseLocators(RESOLVEABLE_NON_LOOPBACK_HOST + "[" + PORT + "]",
             InetAddress.getLoopbackAddress()))
-                .isInstanceOf(GemFireConfigException.class)
+                .isInstanceOf(MembershipConfigurationException.class)
                 .hasMessageContaining("does not have a local address");
   }
 
@@ -66,13 +66,13 @@ public class GMSUtilTest {
     assertThatThrownBy(
         () -> parseLocators(UNRESOLVEABLE_HOST + "[" + PORT + "]",
             InetAddress.getLoopbackAddress()))
-                .isInstanceOf(GemFireConfigException.class)
+                .isInstanceOf(MembershipConfigurationException.class)
                 .hasMessageContaining("unknown address or FQDN: " + UNRESOLVEABLE_HOST);
   }
 
   @Test
   @Parameters({"1234", "0"})
-  public void validPortSpecified(final int validPort) {
+  public void validPortSpecified(final int validPort) throws MembershipConfigurationException {
     final String locatorsString = RESOLVEABLE_LOOPBACK_HOST + "[" + validPort + "]";
     assertThat(parseLocators(locatorsString, InetAddress.getLoopbackAddress()))
         .contains(
@@ -86,13 +86,14 @@ public class GMSUtilTest {
     final String locatorsString = RESOLVEABLE_LOOPBACK_HOST + portSpecification;
     assertThatThrownBy(
         () -> parseLocators(locatorsString, InetAddress.getLoopbackAddress()))
-            .isInstanceOf(GemFireConfigException.class)
+            .isInstanceOf(MembershipConfigurationException.class)
             .hasMessageContaining("malformed port specification: " + locatorsString);
   }
 
   @Test
   @Parameters({"host@127.0.0.1[1234]", "host:127.0.0.1[1234]"})
-  public void validHostSpecified(final String locatorsString) {
+  public void validHostSpecified(final String locatorsString)
+      throws MembershipConfigurationException {
     assertThat(parseLocators(locatorsString, (InetAddress) null))
         .contains(
             new HostAddress(new InetSocketAddress("127.0.0.1", 1234), "127.0.0.1"));
@@ -100,7 +101,8 @@ public class GMSUtilTest {
 
   @Test
   @Parameters({"server1@fdf0:76cf:a0ed:9449::5[12233]", "fdf0:76cf:a0ed:9449::5[12233]"})
-  public void validIPV6AddySpecified(final String locatorsString) {
+  public void validIPV6AddySpecified(final String locatorsString)
+      throws MembershipConfigurationException {
     assertThat(parseLocators(locatorsString, (InetAddress) null))
         .contains(
             new HostAddress(new InetSocketAddress("fdf0:76cf:a0ed:9449::5", 12233),
diff --git a/geode-dunit/src/main/java/org/apache/geode/distributed/internal/membership/gms/MembershipManagerHelper.java b/geode-dunit/src/main/java/org/apache/geode/distributed/internal/membership/gms/MembershipManagerHelper.java
index f246530..df306ca 100644
--- a/geode-dunit/src/main/java/org/apache/geode/distributed/internal/membership/gms/MembershipManagerHelper.java
+++ b/geode-dunit/src/main/java/org/apache/geode/distributed/internal/membership/gms/MembershipManagerHelper.java
@@ -24,8 +24,8 @@ import org.apache.geode.distributed.DistributedSystem;
 import org.apache.geode.distributed.internal.ClusterDistributionManager;
 import org.apache.geode.distributed.internal.Distribution;
 import org.apache.geode.distributed.internal.InternalDistributedSystem;
+import org.apache.geode.distributed.internal.MembershipTestHook;
 import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
-import org.apache.geode.distributed.internal.membership.gms.api.MembershipTestHook;
 import org.apache.geode.test.awaitility.GeodeAwaitility;
 import org.apache.geode.test.dunit.WaitCriterion;
 
@@ -78,12 +78,12 @@ public class MembershipManagerHelper {
 
   /** register a test hook with the manager */
   public static void addTestHook(DistributedSystem sys, MembershipTestHook hook) {
-    getDistribution(sys).registerTestHook(hook);
+    ((InternalDistributedSystem) sys).getDistributionManager().registerTestHook(hook);
   }
 
   /** remove a registered test hook */
   public static void removeTestHook(DistributedSystem sys, MembershipTestHook hook) {
-    getDistribution(sys).unregisterTestHook(hook);
+    ((InternalDistributedSystem) sys).getDistributionManager().unregisterTestHook(hook);
   }
 
   /**


Mime
View raw message