diff --git a/router/java/src/net/i2p/router/CommSystemFacade.java b/router/java/src/net/i2p/router/CommSystemFacade.java
index 878a3e14b9d014e6adee3247d5692196d5306774..ae5817409db7b36d57c8896900b4a463ab24a29b 100644
--- a/router/java/src/net/i2p/router/CommSystemFacade.java
+++ b/router/java/src/net/i2p/router/CommSystemFacade.java
@@ -64,9 +64,17 @@ public abstract class CommSystemFacade implements Service {
     
     /**
      * Determine under what conditions we are remotely reachable.
-     *
+     * For internal use only.
+     * Not recommended for plugins or embedded applications, as
+     * the integer codes may change. Use getStatus() instead.
+     */
+    public short getReachabilityStatus() { return (short) getStatus().getCode(); }
+    
+    /**
+     * Determine under what conditions we are remotely reachable.
+     * @since 0.9.20
      */
-    public short getReachabilityStatus() { return STATUS_OK; }
+    public Status getStatus() { return Status.OK; }
 
     /**
      * @deprecated unused
diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java
index 3a244d715acf8a1d16677a1b45567657dc26f19b..8b56baba08b4b1373f5db9bd86ccaaf7d1e9e8b4 100644
--- a/router/java/src/net/i2p/router/Router.java
+++ b/router/java/src/net/i2p/router/Router.java
@@ -32,6 +32,7 @@ import net.i2p.data.SigningPrivateKey;
 import net.i2p.data.SigningPublicKey;
 import net.i2p.data.i2np.GarlicMessage;
 import net.i2p.data.router.RouterInfo;
+import net.i2p.router.CommSystemFacade.Status;
 import net.i2p.router.message.GarlicMessageHandler;
 import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
 import net.i2p.router.startup.CreateRouterInfoJob;
@@ -919,17 +920,20 @@ public class Router implements RouterClock.ClockShiftListener {
             ri.addCapability(CAPABILITY_UNREACHABLE);
             return;
         }
-        switch (_context.commSystem().getReachabilityStatus()) {
-            case CommSystemFacade.STATUS_OK:
+        switch (_context.commSystem().getStatus()) {
+            case OK:
                 ri.addCapability(CAPABILITY_REACHABLE);
                 break;
-            case CommSystemFacade.STATUS_DIFFERENT:
-            case CommSystemFacade.STATUS_REJECT_UNSOLICITED:
+
+            case DIFFERENT:
+            case REJECT_UNSOLICITED:
                 ri.addCapability(CAPABILITY_UNREACHABLE);
                 break;
-            case CommSystemFacade.STATUS_DISCONNECTED:
-            case CommSystemFacade.STATUS_HOSED:
-            case CommSystemFacade.STATUS_UNKNOWN:
+
+            case DISCONNECTED:
+            case HOSED:
+            case UNKNOWN:
+            default:
                 // no explicit capability
                 break;
         }
diff --git a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
index 59091a6d8aecef50ed1f5402bb5235f671663145..55a93349c4520aff5aad8dd351f17904b8f73730 100644
--- a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
+++ b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
@@ -176,13 +176,16 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
         return _manager.getMostRecentErrorMessages(); 
     }
 
+    /**
+     *  @since 0.9.20
+     */
     @Override
-    public short getReachabilityStatus() { 
+    public Status getStatus() { 
         if (!_netMonitorStatus)
-            return STATUS_DISCONNECTED;
-        short rv = _manager.getReachabilityStatus(); 
-        if (rv != STATUS_HOSED && _context.router().isHidden())
-            return STATUS_OK;
+            return Status.DISCONNECTED;
+        Status rv = _manager.getReachabilityStatus(); 
+        if (rv != Status.HOSED && _context.router().isHidden())
+            return Status.OK;
         return rv; 
     }
 
diff --git a/router/java/src/net/i2p/router/transport/Transport.java b/router/java/src/net/i2p/router/transport/Transport.java
index 459c846806a0f188bfb4649f0bd40127fc0aeaba..0789d7e75ffc5125a77066dc7c075c3c99eb4bd0 100644
--- a/router/java/src/net/i2p/router/transport/Transport.java
+++ b/router/java/src/net/i2p/router/transport/Transport.java
@@ -16,6 +16,7 @@ import java.util.Vector;
 import net.i2p.data.Hash;
 import net.i2p.data.router.RouterAddress;
 import net.i2p.data.router.RouterInfo;
+import net.i2p.router.CommSystemFacade.Status;
 import net.i2p.router.OutNetMessage;
 
 /**
@@ -131,7 +132,11 @@ public interface Transport {
     public List<String> getMostRecentErrorMessages();
     
     public void renderStatusHTML(Writer out, String urlBase, int sortFlags) throws IOException;
-    public short getReachabilityStatus();
+
+    /**
+     *  Previously returned short, now enum as of 0.9.20
+     */
+    public Status getReachabilityStatus();
 
     /**
      * @deprecated unused
diff --git a/router/java/src/net/i2p/router/transport/TransportImpl.java b/router/java/src/net/i2p/router/transport/TransportImpl.java
index 2aebf712823f1e488453173a9e980d19e89f1f96..6056089dd038c414dfc322db1891d758ac97269f 100644
--- a/router/java/src/net/i2p/router/transport/TransportImpl.java
+++ b/router/java/src/net/i2p/router/transport/TransportImpl.java
@@ -34,7 +34,7 @@ import net.i2p.data.router.RouterAddress;
 import net.i2p.data.router.RouterIdentity;
 import net.i2p.data.router.RouterInfo;
 import net.i2p.data.i2np.I2NPMessage;
-import net.i2p.router.CommSystemFacade;
+import net.i2p.router.CommSystemFacade.Status;
 import net.i2p.router.Job;
 import net.i2p.router.MessageSelector;
 import net.i2p.router.OutNetMessage;
@@ -726,7 +726,10 @@ public abstract class TransportImpl implements Transport {
     public void renderStatusHTML(Writer out) throws IOException {}
     public void renderStatusHTML(Writer out, String urlBase, int sortFlags) throws IOException { renderStatusHTML(out); }
 
-    public short getReachabilityStatus() { return CommSystemFacade.STATUS_UNKNOWN; }
+    /**
+     *  Previously returned short, now enum as of 0.9.20
+     */
+    public abstract Status getReachabilityStatus();
 
     /**
      * @deprecated unused
@@ -752,9 +755,9 @@ public abstract class TransportImpl implements Transport {
 
     /** called when we can't reach a peer */
     public void markUnreachable(Hash peer) {
-        short status = _context.commSystem().getReachabilityStatus();
-        if (status == CommSystemFacade.STATUS_DISCONNECTED ||
-            status == CommSystemFacade.STATUS_HOSED)
+        Status status = _context.commSystem().getStatus();
+        if (status == Status.DISCONNECTED ||
+            status == Status.HOSED)
             return;
         Long now = Long.valueOf(_context.clock().now());
         synchronized (_unreachableEntries) {
diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java
index 609bd7dc80728f6a3abca41df732d40b405b1185..1afb025619c3e4c8e7384b848651f4db7187425d 100644
--- a/router/java/src/net/i2p/router/transport/TransportManager.java
+++ b/router/java/src/net/i2p/router/transport/TransportManager.java
@@ -28,7 +28,7 @@ import net.i2p.data.router.RouterAddress;
 import net.i2p.data.router.RouterIdentity;
 import net.i2p.data.router.RouterInfo;
 import net.i2p.data.i2np.I2NPMessage;
-import net.i2p.router.CommSystemFacade;
+import net.i2p.router.CommSystemFacade.Status;
 import net.i2p.router.OutNetMessage;
 import net.i2p.router.RouterContext;
 import static net.i2p.router.transport.Transport.AddressSource.*;
@@ -371,12 +371,15 @@ public class TransportManager implements TransportEventListener {
         return skews;
     }
     
-    /** @return the best status of any transport */
-    public short getReachabilityStatus() { 
-        short rv = CommSystemFacade.STATUS_UNKNOWN;
+    /**
+     *  Previously returned short, now enum as of 0.9.20
+     *  @return the best status of any transport
+     */
+    public Status getReachabilityStatus() { 
+        Status rv = Status.UNKNOWN;
         for (Transport t : _transports.values()) {
-            short s = t.getReachabilityStatus();
-            if (s < rv)
+            Status s = t.getReachabilityStatus();
+            if (s.getCode() < rv.getCode())
                 rv = s;
         }
         return rv;
diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
index c25c4497a2137a1937b6c70e0e70b544471660ad..a085eb23566cc8f49afc5df390096b3b5985f931 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
@@ -31,7 +31,7 @@ import net.i2p.data.router.RouterIdentity;
 import net.i2p.data.router.RouterInfo;
 import net.i2p.data.i2np.DatabaseStoreMessage;
 import net.i2p.data.i2np.I2NPMessage;
-import net.i2p.router.CommSystemFacade;
+import net.i2p.router.CommSystemFacade.Status;
 import net.i2p.router.OutNetMessage;
 import net.i2p.router.RouterContext;
 import net.i2p.router.transport.Transport;
@@ -1162,17 +1162,18 @@ public class NTCPTransport extends TransportImpl {
      *
      * We have to be careful here because much of the router console code assumes
      * that the reachability status is really just the UDP status.
+     *
+     * Previously returned short, now enum as of 0.9.20
      */
-    @Override
-    public short getReachabilityStatus() { 
+    public Status getReachabilityStatus() { 
         // If we have an IPv4 address
         if (isAlive() && getCurrentAddress(false) != null) {
                 for (NTCPConnection con : _conByIdent.values()) {
                     if (con.isInbound())
-                        return CommSystemFacade.STATUS_OK;
+                        return Status.OK;
                 }
         }
-        return CommSystemFacade.STATUS_UNKNOWN;
+        return Status.UNKNOWN;
     }
 
     /**
diff --git a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java
index c1078f4e6ac7f61e7c8f774489d87f141125b0d9..87a7a3f824f66860e1e6296252080a3029ae9cfc 100644
--- a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java
+++ b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java
@@ -12,7 +12,7 @@ import net.i2p.data.DataHelper;
 import net.i2p.data.router.RouterAddress;
 import net.i2p.data.router.RouterInfo;
 import net.i2p.data.SessionKey;
-import net.i2p.router.CommSystemFacade;
+import net.i2p.router.CommSystemFacade.Status;
 import net.i2p.router.RouterContext;
 import static net.i2p.router.transport.udp.PeerTestState.Role.*;
 import net.i2p.router.transport.TransportUtil;
@@ -364,7 +364,7 @@ class PeerTestManager {
                 // why are we doing this instead of calling testComplete() ?
                 _currentTestComplete = true;
                 _context.statManager().addRateData("udp.statusKnownCharlie", 1);
-                honorStatus(CommSystemFacade.STATUS_UNKNOWN);
+                honorStatus(Status.UNKNOWN);
                 _currentTest = null;
                 return;
             }
@@ -433,7 +433,6 @@ class PeerTestManager {
      */
     private void testComplete(boolean forgetTest) {
         _currentTestComplete = true;
-        short status = -1;
         PeerTestState test = _currentTest;
 
         // Don't do this or we won't call honorStatus()
@@ -443,25 +442,26 @@ class PeerTestManager {
         //    return;
         // }
 
+        Status status;
         if (test.getAlicePortFromCharlie() > 0) {
             // we received a second message from charlie
             if ( (test.getAlicePort() == test.getAlicePortFromCharlie()) &&
                  (test.getAliceIP() != null) && (test.getAliceIPFromCharlie() != null) &&
                  (test.getAliceIP().equals(test.getAliceIPFromCharlie())) ) {
-                status = CommSystemFacade.STATUS_OK;
+                status = Status.OK;
             } else {
-                status = CommSystemFacade.STATUS_DIFFERENT;
+                status = Status.DIFFERENT;
             }
         } else if (test.getReceiveCharlieTime() > 0) {
             // we received only one message from charlie
-            status = CommSystemFacade.STATUS_UNKNOWN;
+            status = Status.UNKNOWN;
         } else if (test.getReceiveBobTime() > 0) {
             // we received a message from bob but no messages from charlie
-            status = CommSystemFacade.STATUS_REJECT_UNSOLICITED;
+            status = Status.REJECT_UNSOLICITED;
         } else {
             // we never received anything from bob - he is either down, 
             // ignoring us, or unable to get a Charlie to respond
-            status = CommSystemFacade.STATUS_UNKNOWN;
+            status = Status.UNKNOWN;
         }
         
         if (_log.shouldLog(Log.INFO))
@@ -477,7 +477,7 @@ class PeerTestManager {
      * necessary).
      *
      */
-    private void honorStatus(short status) {
+    private void honorStatus(Status status) {
         if (_log.shouldLog(Log.INFO))
             _log.info("Test results: status = " + status);
         _transport.setReachabilityStatus(status);
diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
index 644de36bdfd7354b3319a25774f7bb98b58bd41c..cc53894cd53a3eb3f86415ad90878d4d0c980c9b 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
@@ -30,6 +30,7 @@ import net.i2p.data.SessionKey;
 import net.i2p.data.i2np.DatabaseStoreMessage;
 import net.i2p.data.i2np.I2NPMessage;
 import net.i2p.router.CommSystemFacade;
+import net.i2p.router.CommSystemFacade.Status;
 import net.i2p.router.OutNetMessage;
 import net.i2p.router.Router;
 import net.i2p.router.RouterContext;
@@ -77,7 +78,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
     private final ExpirePeerEvent _expireEvent;
     private final PeerTestEvent _testEvent;
     private final PacketBuilder _destroyBuilder;
-    private short _reachabilityStatus;
+    private Status _reachabilityStatus;
     private long _reachabilityStatusLastUpdated;
     private int _reachabilityStatusUnchanged;
     private long _introducersSelectedOn;
@@ -245,7 +246,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
         _expireTimeout = EXPIRE_TIMEOUT;
         _expireEvent = new ExpirePeerEvent();
         _testEvent = new PeerTestEvent();
-        _reachabilityStatus = CommSystemFacade.STATUS_UNKNOWN;
+        _reachabilityStatus = Status.UNKNOWN;
         _introManager = new IntroductionManager(_context, this);
         _introducersSelectedOn = -1;
         _lastInboundReceivedOn = -1;
@@ -430,7 +431,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
         }
         if (_endpoints.isEmpty()) {
             _log.log(Log.CRIT, "Unable to open UDP port");
-            setReachabilityStatus(CommSystemFacade.STATUS_HOSED);
+            setReachabilityStatus(Status.HOSED);
             return;
         }
         if (newPort > 0 &&
@@ -508,7 +509,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
             _log.log(Log.CRIT, "UDP port failure: " + endpoint);
             if (_endpoints.isEmpty()) {
                 _log.log(Log.CRIT, "No more UDP sockets open");
-                setReachabilityStatus(CommSystemFacade.STATUS_HOSED);
+                setReachabilityStatus(Status.HOSED);
                 // TODO restart?
             }
             rebuildExternalAddress();
@@ -725,7 +726,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
         // Assume if we have an interface with a public IP that we aren't firewalled.
         // If this is wrong, the peer test will figure it out and change the status.
         if (changed && ip.length == 4 && source == SOURCE_INTERFACE)
-            setReachabilityStatus(CommSystemFacade.STATUS_OK);
+            setReachabilityStatus(Status.OK);
     }
 
     /**
@@ -743,7 +744,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
                 _log.warn("UPnP has failed to open the SSU port: " + port + " reason: " + reason);
         }
         if (success && ip != null && getExternalIP() != null)
-            setReachabilityStatus(CommSystemFacade.STATUS_OK);
+            setReachabilityStatus(Status.OK);
     }
 
     /**
@@ -980,8 +981,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
         String prop = _context.getProperty(PROP_FIXED_PORT);
         if (prop != null)
             return Boolean.parseBoolean(prop);
-        int status = getReachabilityStatus();
-        return status != CommSystemFacade.STATUS_REJECT_UNSOLICITED;
+        Status status = getReachabilityStatus();
+        return status != Status.REJECT_UNSOLICITED;
     }
 
     /** 
@@ -1187,7 +1188,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
         
         synchronized(_rebuildLock) {
             rebuildIfNecessary();
-            if (getReachabilityStatus() != CommSystemFacade.STATUS_OK &&
+            if (getReachabilityStatus() != Status.OK &&
                 _reachabilityStatusUnchanged < 7) {
                 _testEvent.forceRunSoon();
             }
@@ -1560,7 +1561,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
                 return _cachedBid[FAST_BID];
         } else {
             // If we don't have a port, all is lost
-            if ( _reachabilityStatus == CommSystemFacade.STATUS_HOSED) {
+            if ( _reachabilityStatus == Status.HOSED) {
                 markUnreachable(to);
                 return null;
             }
@@ -2087,10 +2088,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
             return true;
         }
         *******************/
-        short status = getReachabilityStatus();
+        Status status = getReachabilityStatus();
         switch (status) {
-            case CommSystemFacade.STATUS_REJECT_UNSOLICITED:
-            case CommSystemFacade.STATUS_DIFFERENT:
+            case REJECT_UNSOLICITED:
+            case DIFFERENT:
                 if (_log.shouldLog(Log.DEBUG))
                     _log.debug("Require introducers, because our status is " + status);
                 return true;
@@ -2695,7 +2696,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
             long longInactivityCutoff = now - EXPIRE_TIMEOUT;
             long pingCutoff = now - (2 * 60*60*1000);
             long pingFirewallCutoff = now - PING_FIREWALL_CUTOFF;
-            boolean shouldPingFirewall = _reachabilityStatus != CommSystemFacade.STATUS_OK;
+            boolean shouldPingFirewall = _reachabilityStatus != Status.OK;
             int currentListenPort = getListenPort(false);
             boolean pingOneOnly = shouldPingFirewall && getExternalPort(false) == currentListenPort;
             boolean shortLoop = shouldPingFirewall;
@@ -2772,17 +2773,17 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
         }
     }
     
-    void setReachabilityStatus(short status) { 
+    void setReachabilityStatus(Status status) { 
         synchronized (_rebuildLock) {
             locked_setReachabilityStatus(status);
         }
     }
 
-    private void locked_setReachabilityStatus(short status) { 
-        short old = _reachabilityStatus;
+    private void locked_setReachabilityStatus(Status status) { 
+        Status old = _reachabilityStatus;
         long now = _context.clock().now();
         switch (status) {
-            case CommSystemFacade.STATUS_OK:
+            case OK:
                 // TODO if OK but internal port != external port, should we have
                 // a different status state? ...as we don't know if the TCP
                 // port will be mapped the same way or not...
@@ -2791,22 +2792,22 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
                 _reachabilityStatus = status; 
                 _reachabilityStatusLastUpdated = now;
                 break;
-            case CommSystemFacade.STATUS_DIFFERENT:
+            case DIFFERENT:
                 _context.statManager().addRateData("udp.statusDifferent", 1);
                 _reachabilityStatus = status; 
                 _reachabilityStatusLastUpdated = now;
                 break;
-            case CommSystemFacade.STATUS_REJECT_UNSOLICITED:
+            case REJECT_UNSOLICITED:
                 _context.statManager().addRateData("udp.statusReject", 1);
 // if old != unsolicited && now - lastUpdated > STATUS_GRACE_PERIOD)
 //
                 // fall through...
-            case CommSystemFacade.STATUS_DISCONNECTED:
-            case CommSystemFacade.STATUS_HOSED:
+            case DISCONNECTED:
+            case HOSED:
                 _reachabilityStatus = status; 
                 _reachabilityStatusLastUpdated = now;
                 break;
-            case CommSystemFacade.STATUS_UNKNOWN:
+            case UNKNOWN:
             default:
                 _context.statManager().addRateData("udp.statusUnknown", 1);
                 //if (now - _reachabilityStatusLastUpdated < STATUS_GRACE_PERIOD) {
@@ -2819,17 +2820,17 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
                 break;
         }
         _testEvent.setLastTested();
-        if (status != CommSystemFacade.STATUS_UNKNOWN) {
+        if (status != Status.UNKNOWN) {
             if (status != old)
                 _reachabilityStatusUnchanged = 0;
             else
                 _reachabilityStatusUnchanged++;
         }
-        if ( (status != old) && (status != CommSystemFacade.STATUS_UNKNOWN) ) {
+        if ( (status != old) && (status != Status.UNKNOWN) ) {
             if (_log.shouldLog(Log.WARN))
                 _log.warn("Old status: " + old + " New status: " + status + " from: ", new Exception("traceback"));
-            if (old != CommSystemFacade.STATUS_UNKNOWN)
-                _context.router().eventLog().addEvent(EventLog.REACHABILITY, Integer.toString(status));
+            if (old != Status.UNKNOWN)
+                _context.router().eventLog().addEvent(EventLog.REACHABILITY, status.toStatusString());
             // Always rebuild when the status changes, even if our address hasn't changed,
             // as rebuildExternalAddress() calls replaceAddress() which calls CSFI.notifyReplaceAddress()
             // which will start up NTCP inbound when we transition to OK.
@@ -2844,18 +2845,20 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
 
     private static final String PROP_REACHABILITY_STATUS_OVERRIDE = "i2np.udp.status";
 
-    @Override
-    public short getReachabilityStatus() { 
+    /**
+     * Previously returned short, now enum as of 0.9.20
+     */
+    public Status getReachabilityStatus() { 
         String override = _context.getProperty(PROP_REACHABILITY_STATUS_OVERRIDE);
         if (override == null)
             return _reachabilityStatus;
             
         if ("ok".equals(override))
-            return CommSystemFacade.STATUS_OK;
+            return Status.OK;
         else if ("err-reject".equals(override))
-            return CommSystemFacade.STATUS_REJECT_UNSOLICITED;
+            return Status.REJECT_UNSOLICITED;
         else if ("err-different".equals(override))
-            return CommSystemFacade.STATUS_DIFFERENT;
+            return Status.DIFFERENT;
         
         return _reachabilityStatus; 
     }