package net.i2p.router;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk.
*
*/
import java.io.IOException;
import java.io.Writer;
import java.util.Collections;
import java.util.List;
import net.i2p.data.Hash;
import net.i2p.data.router.RouterAddress;
import net.i2p.data.router.RouterInfo;
import net.i2p.router.transport.Transport;
import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
/**
* Manages the communication subsystem between peers, including connections,
* listeners, transports, connection keys, etc.
*
*/
public abstract class CommSystemFacade implements Service {
public abstract void processMessage(OutNetMessage msg);
public void renderStatusHTML(Writer out, String urlBase, int sortFlags) throws IOException { }
public void renderStatusHTML(Writer out) throws IOException { renderStatusHTML(out, null, 0); }
/** Create the list of RouterAddress structures based on the router's config */
public List<RouterAddress> createAddresses() { return Collections.emptyList(); }
/**
* How many peers are we currently connected to, that we have
* sent a message to or received a message from in the last five minutes.
*/
public int countActivePeers() { return 0; }
/**
* How many peers are we currently connected to, that we have
* sent a message to in the last minute.
* Unused for anything, to be removed.
*/
public int countActiveSendPeers() { return 0; }
public boolean haveInboundCapacity(int pct) { return true; }
public boolean haveOutboundCapacity(int pct) { return true; }
public boolean haveHighOutboundCapacity() { return true; }
public List<String> getMostRecentErrorMessages() { return Collections.emptyList(); }
/**
* Median clock skew of connected peers in seconds, or null if we cannot answer.
* CommSystemFacadeImpl overrides this.
*/
public Long getMedianPeerClockSkew() { return null; }
/**
* Return framed average clock skew of connected peers in seconds, or null if we cannot answer.
* CommSystemFacadeImpl overrides this.
*/
public long getFramedAveragePeerClockSkew(int percentToInclude) { return 0; }
/**
* 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.
*
* @deprecated use getStatus()
*/
@Deprecated
public short getReachabilityStatus() { return (short) getStatus().getCode(); }
/**
* Determine under what conditions we are remotely reachable.
* @since 0.9.20
*/
public Status getStatus() { return Status.OK; }
/**
* @deprecated unused
*/
@Deprecated
public void recheckReachability() {}
public boolean isBacklogged(Hash peer) { return false; }
public boolean wasUnreachable(Hash peer) { return false; }
public boolean isEstablished(Hash peer) { return false; }
public byte[] getIP(Hash dest) { return null; }
public void queueLookup(byte[] ip) {}
/**
* Tell the comm system that we may disconnect from this peer.
* This is advisory only.
*
* @since 0.9.24
*/
public void mayDisconnect(Hash peer) {}
/** @since 0.8.11 */
public String getOurCountry() { return null; }
/** @since 0.8.13 */
public boolean isInBadCountry() { return false; }
/** @since 0.9.16 */
public boolean isInBadCountry(Hash peer) { return false; }
/** @since 0.9.16 */
public boolean isInBadCountry(RouterInfo ri) { return false; }
public String getCountry(Hash peer) { return null; }
public String getCountryName(String code) { return code; }
public String renderPeerHTML(Hash peer) {
return peer.toBase64().substring(0, 4);
}
/** @since 0.8.13 */
public boolean isDummy() { return true; }
/**
* Tell other transports our address changed
*/
public void notifyReplaceAddress(RouterAddress address) {}
/**
* Tell other transports our address changed
* @since 0.9.20
*/
public void notifyRemoveAddress(RouterAddress address) {}
/**
* Tell other transports our address changed
* @since 0.9.20
*/
public void notifyRemoveAddress(boolean ipv6) {}
/**
* Pluggable transport
* @since 0.9.16
*/
public void registerTransport(Transport t) {}
/**
* Pluggable transport
* @since 0.9.16
*/
public void unregisterTransport(Transport t) {}
/**
* Hook for pluggable transport creation.
* @since 0.9.16
*/
public DHSessionKeyBuilder.Factory getDHFactory() { return null; }
/*
* Reachability status codes
*
* IPv4 IPv6 Status
* ---- ---- ------
* ok ok OK 0
* ok x OK 0
* ok unk OK/UNKNOWN 1
* ok fw OK/FIREWALLED 2
*
* x ok DISABLED/OK 5
* x x HOSED 12
* x unk DISABLED/UNKNOWN 10
* x fw DISABLED/FIREWALLED 11
*
* unk ok UNKNOWN/OK 3
* unk x UNKNOWN 14
* unk unk UNKNOWN 14
* unk fw UNKNOWN/FIREWALLED 9
*
* fw ok FIREWALLED/OK 4
* fw x FIREWALLED 8
* fw unk FIREWALLED/UNKNOWN 7
* fw fw FIREWALLED 8
*
* sym any DIFFERENT 6 (TODO add IPv6 states or not worth it?)
* disconnected DISCONNECTED 12
* hosed HOSED 13
*/
/**
* These must be increasing in "badness" (see TransportManager.java),
* but UNKNOWN must be last.
*
* We are able to receive unsolicited connections
* on all enabled transports
*/
public static final short STATUS_OK = 0;
/**
* We have an IPv6 transport enabled and a public IPv6 address.
* We can receive unsolicited connections on IPv4.
* We might be able to receive unsolicited connections on IPv6.
* @since 0.9.20
*/
public static final short STATUS_IPV4_OK_IPV6_UNKNOWN = 2;
/**
* We have an IPv6 transport enabled and a public IPv6 address.
* We can receive unsolicited connections on IPv4.
* We cannot receive unsolicited connections on IPv6.
* @since 0.9.20
*/
public static final short STATUS_IPV4_OK_IPV6_FIREWALLED = 1;
/**
* We have an IPv6 transport enabled and a public IPv6 address.
* We may be able to receive unsolicited connections on IPv4.
* We can receive unsolicited connections on IPv6.
* @since 0.9.20
*/
public static final short STATUS_IPV4_UNKNOWN_IPV6_OK = 4;
/**
* We have an IPv6 transport enabled and a public IPv6 address.
* We cannot receive unsolicited connections on IPv4.
* We can receive unsolicited connections on IPv6.
* @since 0.9.20
*/
public static final short STATUS_IPV4_FIREWALLED_IPV6_OK = 3;
/**
* We have an IPv6 transport enabled and a public IPv6 address.
* IPv4 is disabled.
* We can receive unsolicited connections on IPv6.
* @since 0.9.20
*/
public static final short STATUS_IPV4_DISABLED_IPV6_OK = 5;
/**
* We are behind a symmetric NAT which will make our 'from' address look
* differently when we talk to multiple people
* We can receive unsolicited connections on IPv6.
* @since 0.9.20
*/
public static final short STATUS_IPV4_SNAT_IPV6_OK = 6;
/**
* We are behind a symmetric NAT which will make our 'from' address look
* differently when we talk to multiple people
*
*/
public static final short STATUS_DIFFERENT = 7;
/**
* We are behind a symmetric NAT which will make our 'from' address look
* differently when we talk to multiple people
* We might be able to receive unsolicited connections on IPv6.
* @since 0.9.20
*/
public static final short STATUS_IPV4_SNAT_IPV6_UNKNOWN = 8;
/**
* We have an IPv6 transport enabled and a public IPv6 address.
* We cannot receive unsolicited connections on IPv4.
* We might be able to receive unsolicited connections on IPv6.
* @since 0.9.20
*/
public static final short STATUS_IPV4_FIREWALLED_IPV6_UNKNOWN = 10;
/**
* We are able to talk to peers that we initiate communication with, but
* cannot receive unsolicited connections, i.e. Firewalled,
* on all enabled transports.
*/
public static final short STATUS_REJECT_UNSOLICITED = 9;
/**
* We have an IPv6 transport enabled and a public IPv6 address.
* We may be able to receive unsolicited connections on IPv4.
* We cannot receive unsolicited connections on IPv6.
* @since 0.9.20
*/
public static final short STATUS_IPV4_UNKNOWN_IPV6_FIREWALLED = 11;
/**
* We have an IPv6 transport enabled and a public IPv6 address.
* IPv4 is disabled.
* We might be able to receive unsolicited connections on IPv6.
* @since 0.9.20
*/
public static final short STATUS_IPV4_DISABLED_IPV6_UNKNOWN = 13;
/**
* We have an IPv6 transport enabled and a public IPv6 address.
* IPv4 is disabled.
* We can receive unsolicited connections on IPv6.
* @since 0.9.20
*/
public static final short STATUS_IPV4_DISABLED_IPV6_FIREWALLED = 12;
/**
* We have no network interface at all enabled transports
* @since 0.9.4
*/
public static final short STATUS_DISCONNECTED = 14;
/**
* Our detection system is broken (SSU bind port failed)
*/
public static final short STATUS_HOSED = 15;
/**
* Our reachability is unknown on all
*/
public static final short STATUS_UNKNOWN = 16;
/**
* Since the codes may change.
* @since 0.9.20
*/
public enum Status {
/** IPv4 OK, IPv6 OK or disabled or no address */
OK(STATUS_OK, _x("OK")),
IPV4_OK_IPV6_UNKNOWN(STATUS_IPV4_OK_IPV6_UNKNOWN, _x("IPv4: OK; IPv6: Testing")),
IPV4_OK_IPV6_FIREWALLED(STATUS_IPV4_OK_IPV6_FIREWALLED, _x("IPv4: OK; IPv6: Firewalled")),
IPV4_UNKNOWN_IPV6_OK(STATUS_IPV4_UNKNOWN_IPV6_OK, _x("IPv4: Testing; IPv6: OK")),
IPV4_FIREWALLED_IPV6_OK(STATUS_IPV4_FIREWALLED_IPV6_OK, _x("IPv4: Firewalled; IPv6: OK")),
IPV4_DISABLED_IPV6_OK(STATUS_IPV4_DISABLED_IPV6_OK, _x("IPv4: Disabled; IPv6: OK")),
IPV4_SNAT_IPV6_OK(STATUS_IPV4_SNAT_IPV6_OK, _x("IPv4: Symmetric NAT; IPv6: OK")),
/** IPv4 symmetric NAT, IPv6 firewalled or disabled or no address */
DIFFERENT(STATUS_DIFFERENT, _x("Symmetric NAT")),
IPV4_SNAT_IPV6_UNKNOWN(STATUS_IPV4_SNAT_IPV6_UNKNOWN, _x("IPv4: Symmetric NAT; IPv6: Testing")),
IPV4_FIREWALLED_IPV6_UNKNOWN(STATUS_IPV4_FIREWALLED_IPV6_UNKNOWN, _x("IPv4: Firewalled; IPv6: Testing")),
/** IPv4 firewalled, IPv6 firewalled or disabled or no address */
REJECT_UNSOLICITED(STATUS_REJECT_UNSOLICITED, _x("Firewalled")),
IPV4_UNKNOWN_IPV6_FIREWALLED(STATUS_IPV4_UNKNOWN_IPV6_FIREWALLED, _x("IPv4: Testing; IPv6: Firewalled")),
IPV4_DISABLED_IPV6_UNKNOWN(STATUS_IPV4_DISABLED_IPV6_UNKNOWN, _x("IPv4: Disabled; IPv6: Testing")),
IPV4_DISABLED_IPV6_FIREWALLED(STATUS_IPV4_DISABLED_IPV6_FIREWALLED, _x("IPv4: Disabled; IPv6: Firewalled")),
DISCONNECTED(STATUS_DISCONNECTED, _x("Disconnected")),
HOSED(STATUS_HOSED, _x("Port Conflict")),
UNKNOWN(STATUS_UNKNOWN, _x("Testing"));
private final int code;
private final String status;
Status(int code, String status) {
this.code = code;
this.status = status;
}
public int getCode() {
return code;
}
/**
* merge the new Status with the old Status
*/
public static Status merge(Status oldStatus, Status newStatus) {
// shortcut newStatus
if (oldStatus == newStatus || newStatus == UNKNOWN)
return oldStatus;
// shortcut oldStatus
if (oldStatus == UNKNOWN || oldStatus == DISCONNECTED || oldStatus == HOSED)
return newStatus;
switch (newStatus) {
case IPV4_OK_IPV6_UNKNOWN:
switch (oldStatus) {
// cases where we already knew both states
case OK:
case IPV4_FIREWALLED_IPV6_OK:
case IPV4_DISABLED_IPV6_OK:
case IPV4_SNAT_IPV6_OK:
return OK;
case IPV4_OK_IPV6_FIREWALLED:
return oldStatus;
case DIFFERENT:
case REJECT_UNSOLICITED:
return newStatus;
case IPV4_DISABLED_IPV6_FIREWALLED:
return IPV4_OK_IPV6_FIREWALLED;
// cases where we already knew the IPv6 state only
case IPV4_UNKNOWN_IPV6_OK:
return OK;
case IPV4_UNKNOWN_IPV6_FIREWALLED:
return IPV4_OK_IPV6_FIREWALLED;
// cases where we already knew the IPv4 state only
case IPV4_OK_IPV6_UNKNOWN:
case IPV4_FIREWALLED_IPV6_UNKNOWN:
case IPV4_DISABLED_IPV6_UNKNOWN:
case IPV4_SNAT_IPV6_UNKNOWN:
return newStatus;
default:
return newStatus;
}
case IPV4_UNKNOWN_IPV6_OK:
switch (oldStatus) {
// cases where we already knew both states
case OK:
case IPV4_OK_IPV6_FIREWALLED:
return OK;
case IPV4_FIREWALLED_IPV6_OK:
case IPV4_DISABLED_IPV6_OK:
case DIFFERENT:
case IPV4_SNAT_IPV6_OK:
return oldStatus;
case REJECT_UNSOLICITED:
return IPV4_FIREWALLED_IPV6_OK;
case IPV4_DISABLED_IPV6_FIREWALLED:
return IPV4_DISABLED_IPV6_OK;
// cases where we already knew the IPv6 state only
case IPV4_UNKNOWN_IPV6_OK:
case IPV4_UNKNOWN_IPV6_FIREWALLED:
return newStatus;
// cases where we already knew the IPv4 state only
case IPV4_OK_IPV6_UNKNOWN:
return OK;
case IPV4_FIREWALLED_IPV6_UNKNOWN:
return IPV4_FIREWALLED_IPV6_OK;
case IPV4_DISABLED_IPV6_UNKNOWN:
return IPV4_DISABLED_IPV6_OK;
case IPV4_SNAT_IPV6_UNKNOWN:
return IPV4_SNAT_IPV6_OK;
default:
return newStatus;
}
case IPV4_FIREWALLED_IPV6_UNKNOWN:
switch (oldStatus) {
// cases where we already knew both states
case OK:
case IPV4_DISABLED_IPV6_OK:
case IPV4_FIREWALLED_IPV6_OK:
case IPV4_SNAT_IPV6_OK:
return IPV4_FIREWALLED_IPV6_OK;
case IPV4_OK_IPV6_FIREWALLED:
case IPV4_DISABLED_IPV6_FIREWALLED:
return REJECT_UNSOLICITED;
case DIFFERENT:
case REJECT_UNSOLICITED:
return newStatus;
// cases where we already knew the IPv6 state only
case IPV4_UNKNOWN_IPV6_OK:
return IPV4_FIREWALLED_IPV6_OK;
case IPV4_UNKNOWN_IPV6_FIREWALLED:
return REJECT_UNSOLICITED;
// cases where we already knew the IPv4 state only
case IPV4_OK_IPV6_UNKNOWN:
case IPV4_FIREWALLED_IPV6_UNKNOWN:
case IPV4_DISABLED_IPV6_UNKNOWN:
case IPV4_SNAT_IPV6_UNKNOWN:
return newStatus;
default:
return newStatus;
}
case IPV4_UNKNOWN_IPV6_FIREWALLED:
switch (oldStatus) {
// cases where we already knew both states
case OK:
return IPV4_OK_IPV6_FIREWALLED;
case IPV4_OK_IPV6_FIREWALLED:
return oldStatus;
case REJECT_UNSOLICITED:
case IPV4_FIREWALLED_IPV6_OK:
case IPV4_DISABLED_IPV6_FIREWALLED:
return REJECT_UNSOLICITED;
case IPV4_DISABLED_IPV6_OK:
return IPV4_DISABLED_IPV6_FIREWALLED;
case DIFFERENT:
case IPV4_SNAT_IPV6_OK:
return oldStatus;
// cases where we already knew the IPv6 state only
case IPV4_UNKNOWN_IPV6_OK:
case IPV4_UNKNOWN_IPV6_FIREWALLED:
return newStatus;
// cases where we already knew the IPv4 state only
case IPV4_OK_IPV6_UNKNOWN:
return IPV4_OK_IPV6_FIREWALLED;
case IPV4_FIREWALLED_IPV6_UNKNOWN:
return REJECT_UNSOLICITED;
case IPV4_DISABLED_IPV6_UNKNOWN:
return IPV4_DISABLED_IPV6_FIREWALLED;
case IPV4_SNAT_IPV6_UNKNOWN:
return DIFFERENT;
default:
return newStatus;
}
case IPV4_DISABLED_IPV6_UNKNOWN:
switch (oldStatus) {
// cases where we already knew both states
case OK:
case IPV4_DISABLED_IPV6_OK:
case IPV4_FIREWALLED_IPV6_OK:
case IPV4_SNAT_IPV6_OK:
return IPV4_DISABLED_IPV6_OK;
case IPV4_OK_IPV6_FIREWALLED:
case IPV4_DISABLED_IPV6_FIREWALLED:
case REJECT_UNSOLICITED:
return IPV4_DISABLED_IPV6_FIREWALLED;
case DIFFERENT:
return newStatus;
// cases where we already knew the IPv6 state only
case IPV4_UNKNOWN_IPV6_OK:
return IPV4_DISABLED_IPV6_OK;
case IPV4_UNKNOWN_IPV6_FIREWALLED:
return IPV4_DISABLED_IPV6_FIREWALLED;
// cases where we already knew the IPv4 state only
case IPV4_OK_IPV6_UNKNOWN:
case IPV4_FIREWALLED_IPV6_UNKNOWN:
case IPV4_DISABLED_IPV6_UNKNOWN:
case IPV4_SNAT_IPV6_UNKNOWN:
return newStatus;
default:
return newStatus;
}
case IPV4_SNAT_IPV6_UNKNOWN:
switch (oldStatus) {
// cases where we already knew both states
case OK:
case IPV4_DISABLED_IPV6_OK:
case IPV4_FIREWALLED_IPV6_OK:
case IPV4_SNAT_IPV6_OK:
return IPV4_SNAT_IPV6_OK;
case IPV4_OK_IPV6_FIREWALLED:
case IPV4_DISABLED_IPV6_FIREWALLED:
case REJECT_UNSOLICITED:
return DIFFERENT;
case DIFFERENT:
return newStatus;
// cases where we already knew the IPv6 state only
case IPV4_UNKNOWN_IPV6_OK:
return IPV4_SNAT_IPV6_OK;
case IPV4_UNKNOWN_IPV6_FIREWALLED:
return DIFFERENT;
// cases where we already knew the IPv4 state only
case IPV4_OK_IPV6_UNKNOWN:
case IPV4_FIREWALLED_IPV6_UNKNOWN:
case IPV4_DISABLED_IPV6_UNKNOWN:
case IPV4_SNAT_IPV6_UNKNOWN:
return newStatus;
default:
return newStatus;
}
case UNKNOWN:
return oldStatus;
default:
return newStatus;
}
}
/**
* Readable status, not translated
*/
public String toStatusString() {
return status;
}
@Override
public String toString() {
return super.toString() + " (" + code + "; " + status + ')';
}
/**
* Tag for translation.
*/
private static String _x(String s) { return s; }
}
}
/** unused
class DummyCommSystemFacade extends CommSystemFacade {
public void shutdown() {}
public void startup() {}
public void restart() {}
public void processMessage(OutNetMessage msg) { }
}
**/