diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java index b1453f71d0..d54444ed6f 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java @@ -29,6 +29,7 @@ import net.i2p.router.OutNetMessage; import net.i2p.router.ReplyJob; import net.i2p.router.RouterContext; import net.i2p.router.TunnelInfo; +import net.i2p.router.tunnel.pool.ConnectChecker; import net.i2p.util.Log; import net.i2p.util.VersionComparator; @@ -46,6 +47,8 @@ class StoreJob extends JobImpl { private final long _timeoutMs; private final long _expiration; private final PeerSelector _peerSelector; + private final ConnectChecker _connectChecker; + private final int _connectMask; private final static int PARALLELIZATION = 4; // how many sent at a time private final static int REDUNDANCY = 4; // we want the data sent to 6 peers @@ -75,6 +78,17 @@ class StoreJob extends JobImpl { _timeoutMs = timeoutMs; _expiration = context.clock().now() + timeoutMs; _peerSelector = facade.getPeerSelector(); + if (data.getType() == DatabaseEntry.KEY_TYPE_LEASESET) { + _connectChecker = null; + _connectMask = 0; + } else { + _connectChecker = new ConnectChecker(context); + RouterInfo us = context.router().getRouterInfo(); + if (us != null) + _connectMask = _connectChecker.getOutboundMask(us); + else + _connectMask = ConnectChecker.ANY_V4; + } } public String getName() { return "Kademlia NetDb Store";} @@ -333,7 +347,11 @@ class StoreJob extends JobImpl { sendStoreThroughClient(msg, peer, expiration); } else { getContext().statManager().addRateData("netDb.storeRouterInfoSent", 1); - sendDirect(msg, peer, expiration); + // if we can't connect to peer directly, just send it out an exploratory tunnel + if (_connectChecker.canConnect(_connectMask, peer)) + sendDirect(msg, peer, expiration); + else + sendStoreThroughGarlic(msg, peer, expiration); } } @@ -347,9 +365,6 @@ class StoreJob extends JobImpl { msg.setReplyToken(token); msg.setReplyGateway(getContext().routerHash()); - if (_log.shouldLog(Log.DEBUG)) - _log.debug(getJobId() + ": send(dbStore) w/ token expected " + token); - _state.addPending(peer.getIdentity().getHash()); SendSuccessJob onReply = new SendSuccessJob(getContext(), peer); @@ -357,7 +372,7 @@ class StoreJob extends JobImpl { StoreMessageSelector selector = new StoreMessageSelector(getContext(), getJobId(), peer, token, expiration); if (_log.shouldLog(Log.DEBUG)) - _log.debug("sending store directly to " + peer.getIdentity().getHash()); + _log.debug(getJobId() + ": sending store directly to " + peer.getIdentity().getHash()); OutNetMessage m = new OutNetMessage(getContext(), msg, expiration, STORE_PRIORITY, peer); m.setOnFailedReplyJob(onFail); m.setOnFailedSendJob(onFail); @@ -388,7 +403,7 @@ class StoreJob extends JobImpl { msg.setReplyGateway(replyTunnel.getPeer(0)); if (_log.shouldLog(Log.DEBUG)) - _log.debug(getJobId() + ": send(dbStore) w/ token expected " + token); + _log.debug(getJobId() + ": send store thru expl. tunnel to " + peer.getIdentity().getHash() + " w/ token expected " + token); _state.addPending(to); @@ -618,8 +633,8 @@ class StoreJob extends JobImpl { getContext().statManager().addRateData("netDb.ackTime", howLong, howLong); if ( (_sendThrough != null) && (_msgSize > 0) ) { - if (_log.shouldLog(Log.INFO)) - _log.info("sent a " + _msgSize + " byte netDb message through tunnel " + _sendThrough + " after " + howLong); + if (_log.shouldDebug()) + _log.debug("sent a " + _msgSize + " byte netDb message through tunnel " + _sendThrough + " after " + howLong); for (int i = 0; i < _sendThrough.getLength(); i++) getContext().profileManager().tunnelDataPushed(_sendThrough.getPeer(i), howLong, _msgSize); _sendThrough.incrementVerifiedBytesTransferred(_msgSize); 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 8fcd7aa82b..e88ce2c646 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -1581,8 +1581,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private boolean locked_needsRebuild() { if (_needsRebuild) return true; // simple enough if (_context.router().isHidden()) return false; - RouterAddress addr = getCurrentAddress(false); - if (introducersRequired()) { + boolean v6Only = getIPv6Config() == IPV6_ONLY; + RouterAddress addr = getCurrentAddress(v6Only); + if (!v6Only && introducersRequired()) { UDPAddress ua = new UDPAddress(addr); long now = _context.clock().now(); int valid = 0; @@ -2139,7 +2140,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } } else { if (!introducersRequired()) { - RouterAddress cur = getCurrentExternalAddress(false); + boolean v6Only = getIPv6Config() == IPV6_ONLY; + RouterAddress cur = getCurrentExternalAddress(v6Only); if (cur != null) host = cur.getHost(); } diff --git a/router/java/src/net/i2p/router/tunnel/pool/ConnectChecker.java b/router/java/src/net/i2p/router/tunnel/pool/ConnectChecker.java new file mode 100644 index 0000000000..f9327100d4 --- /dev/null +++ b/router/java/src/net/i2p/router/tunnel/pool/ConnectChecker.java @@ -0,0 +1,328 @@ +package net.i2p.router.tunnel.pool; + +import java.util.Collection; + +import net.i2p.data.Hash; +import net.i2p.data.router.RouterAddress; +import net.i2p.data.router.RouterInfo; +import net.i2p.router.Router; +import net.i2p.router.CommSystemFacade.Status; +import net.i2p.router.RouterContext; +import net.i2p.router.transport.TransportManager; +import net.i2p.util.Log; + +/** + * Tools to check transport compatibility. + * + * @since 0.9.34 + */ +public class ConnectChecker { + protected final RouterContext ctx; + protected final Log log; + + private static final int NTCP_V4 = 0x01; + private static final int SSU_V4 = 0x02; + public static final int ANY_V4 = NTCP_V4 | SSU_V4; + private static final int NTCP_V6 = 0x04; + private static final int SSU_V6 = 0x08; + private static final int ANY_V6 = NTCP_V6 | SSU_V6; + + + public ConnectChecker(RouterContext context) { + ctx = context; + log = ctx.logManager().getLog(getClass()); + } + + /** + * Is NTCP disabled? + * @since 0.9.34 + */ + protected boolean isNTCPDisabled() { + return !TransportManager.isNTCPEnabled(ctx); + } + + /** + * Is SSU disabled? + * @since 0.9.34 + */ + protected boolean isSSUDisabled() { + return !ctx.getBooleanPropertyDefaultTrue(TransportManager.PROP_ENABLE_UDP); + } + + /** + * Can "from" connect to "to" based on published addresses? + * + * This is intended for tunnel candidates, where we already have + * the RI. Will not force RI lookups. + * Either from or to may be us. + * + * This is best effort, as we can't know for sure. + * Published addresses or introducers may have changed. + * Even if a can't connect to b, they may already be connected + * as b connected to a. + * + * @return true if we don't have either RI + * @since 0.9.34 + */ + public boolean canConnect(Hash from, Hash to) { + Hash us = ctx.routerHash(); + if (us == null) + return true; + boolean usf = from.equals(us); + if (usf && ctx.commSystem().isEstablished(to)) + return true; + boolean ust = to.equals(us); + if (ust && ctx.commSystem().isEstablished(from)) + return true; + RouterInfo rt = ctx.netDb().lookupRouterInfoLocally(to); + if (rt == null) + return true; + RouterInfo rf = ctx.netDb().lookupRouterInfoLocally(from); + if (rf == null) + return true; + int ct; + if (ust) { + // to us + ct = getInboundMask(rt); + } else { + Collection at = rt.getAddresses(); + // assume nothing if hidden + if (at.isEmpty()) + return false; + ct = getConnectMask(at); + } + + int cf; + if (usf) { + // from us + cf = getOutboundMask(rf); + } else { + Collection a = rf.getAddresses(); + if (a.isEmpty()) { + // assume IPv4 if hidden + cf = NTCP_V4 | SSU_V4; + } else { + cf = getConnectMask(a); + } + } + + boolean rv = (ct & cf) != 0; + if (!rv && log.shouldWarn()) { + log.warn("Cannot connect: " + + (usf ? "us" : from.toString()) + " with mask " + cf + "\nto " + + (ust ? "us" : to.toString()) + " with mask " + ct); + } + return rv; + } + + /** + * Can we connect to "to" based on published addresses? + * + * This is intended for tunnel candidates, where we already have + * the RI. Will not force RI lookups. + * + * This is best effort, as we can't know for sure. + * Does not check isEstablished(); do that first. + * + * @since 0.9.34 + */ + public boolean canConnect(int ourMask, RouterInfo to) { + Collection ra = to.getAddresses(); + // assume nothing if hidden + if (ra.isEmpty()) + return false; + int ct = getConnectMask(ra); + boolean rv = (ourMask & ct) != 0; + //if (!rv && log.shouldWarn()) + // log.warn("Cannot connect: us with mask " + ourMask + " to " + to + " with mask " + ct); + return rv; + } + + /** + * Can "from" connect to us based on published addresses? + * + * This is intended for tunnel candidates, where we already have + * the RI. Will not force RI lookups. + * + * This is best effort, as we can't know for sure. + * Does not check isEstablished(); do that first. + * + * @since 0.9.34 + */ + public boolean canConnect(RouterInfo from, int ourMask) { + if (ourMask == 0) + return false; + Collection ra = from.getAddresses(); + int cf; + // assume v4 if hidden + if (ra.isEmpty()) + cf = NTCP_V4 | SSU_V4; + else + cf = getConnectMask(ra); + boolean rv = (cf & ourMask) != 0; + //if (!rv && log.shouldWarn()) + // log.warn("Cannot connect: " + from + " with mask " + cf + " to us with mask " + ourMask); + return rv; + } + + /** + * Our inbound mask. + * For most cases, we use what we published, i.e. getConnectMask() + * + * @return bitmask for accepting connections + * @since 0.9.34 + */ + public int getInboundMask(RouterInfo us) { + // to us + int ct = 0; + Status status = ctx.commSystem().getStatus(); + switch (status) { + case OK: + case IPV4_UNKNOWN_IPV6_OK: + case IPV4_FIREWALLED_IPV6_OK: + case IPV4_SNAT_IPV6_OK: + case IPV4_SNAT_IPV6_UNKNOWN: + case IPV4_FIREWALLED_IPV6_UNKNOWN: + case IPV4_UNKNOWN_IPV6_FIREWALLED: + case IPV4_OK_IPV6_FIREWALLED: + case DIFFERENT: + case REJECT_UNSOLICITED: + // use what we published + Collection at = us.getAddresses(); + if (at.isEmpty()) + return 0; + ct = getConnectMask(at); + break; + + case IPV4_DISABLED_IPV6_OK: + case IPV4_DISABLED_IPV6_UNKNOWN: + // maybe should return zero for this one? + case IPV4_DISABLED_IPV6_FIREWALLED: + // TODO look at force-firewalled settings per-transport + if (!isNTCPDisabled()) + ct |= NTCP_V6; + if (!isSSUDisabled()) + ct |= SSU_V6; + break; + + case IPV4_OK_IPV6_UNKNOWN: + case DISCONNECTED: + case HOSED: + case UNKNOWN: + default: + if (!isNTCPDisabled()) + ct |= NTCP_V4; + if (!isSSUDisabled()) + ct |= SSU_V4; + break; + } + return ct; + } + + /** + * Our outbound mask. + * For most cases, we use our comm system status. + * + * @return bitmask for initiating connections + * @since 0.9.34 + */ + public int getOutboundMask(RouterInfo us) { + // from us + int cf = 0; + Status status = ctx.commSystem().getStatus(); + switch (status) { + case OK: + // use what we published, as the OK state doesn't tell us about IPv6 + // Addresses.isConnectedIPv6() is too slow + Collection a = us.getAddresses(); + if (a.isEmpty()) { + // we are hidden + // TODO ipv6 + if (!isNTCPDisabled()) + cf |= NTCP_V4; + if (!isSSUDisabled()) + cf |= SSU_V4; + } else { + cf = getConnectMask(a); + } + break; + + case IPV4_OK_IPV6_FIREWALLED: + case IPV4_UNKNOWN_IPV6_OK: + case IPV4_FIREWALLED_IPV6_OK: + case IPV4_SNAT_IPV6_OK: + case IPV4_UNKNOWN_IPV6_FIREWALLED: + if (!isNTCPDisabled()) + cf |= NTCP_V4 | NTCP_V6; + if (!isSSUDisabled()) + cf |= SSU_V4 | SSU_V6; + break; + + case IPV4_DISABLED_IPV6_OK: + case IPV4_DISABLED_IPV6_UNKNOWN: + case IPV4_DISABLED_IPV6_FIREWALLED: + if (!isNTCPDisabled()) + cf |= NTCP_V6; + if (!isSSUDisabled()) + cf |= SSU_V6; + break; + + case DIFFERENT: + case IPV4_SNAT_IPV6_UNKNOWN: + case IPV4_FIREWALLED_IPV6_UNKNOWN: + case REJECT_UNSOLICITED: + case IPV4_OK_IPV6_UNKNOWN: + case DISCONNECTED: + case HOSED: + case UNKNOWN: + default: + if (!isNTCPDisabled()) + cf |= NTCP_V4; + if (!isSSUDisabled()) + cf |= SSU_V4; + break; + } + return cf; + } + + /** prevent object churn */ + private static final String IHOST[] = { "ihost0", "ihost1", "ihost2" }; + + /** + * @param addrs non-empty, set your own default if empty + * @return bitmask of v4/v6 NTCP/SSU + * @since 0.9.34 + */ + private static int getConnectMask(Collection addrs) { + int rv = 0; + for (RouterAddress ra : addrs) { + String style = ra.getTransportStyle(); + String host = ra.getHost(); + if ("NTCP".equals(style)) { + if (host != null) { + if (host.contains(":")) + rv |= NTCP_V6; + else + rv |= NTCP_V4; + } + } else if ("SSU".equals(style)) { + if (host == null) { + for (int i = 0; i < 2; i++) { + String ihost = ra.getOption(IHOST[i]); + if (ihost == null) + break; + if (ihost.contains(":")) + rv |= SSU_V6; + else + rv |= SSU_V4; + } + } else if (host.contains(":")) { + rv |= SSU_V6; + } else { + rv |= SSU_V4; + } + } + } + return rv; + } +} diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java index ddab5de043..0be44f41ee 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java @@ -12,20 +12,16 @@ import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; -import net.i2p.I2PAppContext; import net.i2p.crypto.SHA256Generator; import net.i2p.crypto.SigType; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.Hash; -import net.i2p.data.router.RouterAddress; import net.i2p.data.router.RouterInfo; import net.i2p.router.Router; -import net.i2p.router.CommSystemFacade.Status; import net.i2p.router.RouterContext; import net.i2p.router.TunnelPoolSettings; import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade; -import net.i2p.router.transport.TransportManager; import net.i2p.router.transport.TransportUtil; import net.i2p.router.util.HashDistance; import net.i2p.util.Log; @@ -35,23 +31,11 @@ import net.i2p.util.VersionComparator; * Coordinate the selection of peers to go into a tunnel for one particular * pool. * - * Todo: there's nothing non-static in here */ -public abstract class TunnelPeerSelector { - protected final RouterContext ctx; - protected final Log log; - - private static final int NTCP_V4 = 0x01; - private static final int SSU_V4 = 0x02; - private static final int ANY_V4 = NTCP_V4 | SSU_V4; - private static final int NTCP_V6 = 0x04; - private static final int SSU_V6 = 0x08; - private static final int ANY_V6 = NTCP_V6 | SSU_V6; - +public abstract class TunnelPeerSelector extends ConnectChecker { protected TunnelPeerSelector(RouterContext context) { - ctx = context; - log = ctx.logManager().getLog(getClass()); + super(context); } /** @@ -120,7 +104,7 @@ public abstract class TunnelPeerSelector { if (opts != null) { String peers = opts.getProperty("explicitPeers"); if (peers == null) - peers = I2PAppContext.getGlobalContext().getProperty("explicitPeers"); + peers = ctx.getProperty("explicitPeers"); if (peers != null) return true; } @@ -139,7 +123,7 @@ public abstract class TunnelPeerSelector { peers = opts.getProperty("explicitPeers"); if (peers == null) - peers = I2PAppContext.getGlobalContext().getProperty("explicitPeers"); + peers = ctx.getProperty("explicitPeers"); List rv = new ArrayList(); StringTokenizer tok = new StringTokenizer(peers, ","); @@ -350,22 +334,6 @@ public abstract class TunnelPeerSelector { return TransportUtil.getIPv6Config(ctx, "SSU") == TransportUtil.IPv6Config.IPV6_ONLY; } - /** - * Is NTCP disabled? - * @since 0.9.34 - */ - protected boolean isNTCPDisabled() { - return !TransportManager.isNTCPEnabled(ctx); - } - - /** - * Is SSU disabled? - * @since 0.9.34 - */ - protected boolean isSSUDisabled() { - return !ctx.getBooleanPropertyDefaultTrue(TransportManager.PROP_ENABLE_UDP); - } - /** * Should we allow as OBEP? * This just checks for IPv4 support. @@ -759,281 +727,4 @@ public abstract class TunnelPeerSelector { } return rv; } - - /** - * Can "from" connect to "to" based on published addresses? - * - * This is intended for tunnel candidates, where we already have - * the RI. Will not force RI lookups. - * Either from or to may be us. - * - * This is best effort, as we can't know for sure. - * Published addresses or introducers may have changed. - * Even if a can't connect to b, they may already be connected - * as b connected to a. - * - * @return true if we don't have either RI - * @since 0.9.34 - */ - private boolean canConnect(Hash from, Hash to) { - Hash us = ctx.routerHash(); - if (us == null) - return true; - boolean usf = from.equals(us); - if (usf && ctx.commSystem().isEstablished(to)) - return true; - boolean ust = to.equals(us); - if (ust && ctx.commSystem().isEstablished(from)) - return true; - RouterInfo rt = ctx.netDb().lookupRouterInfoLocally(to); - if (rt == null) - return true; - RouterInfo rf = ctx.netDb().lookupRouterInfoLocally(from); - if (rf == null) - return true; - int ct; - if (ust) { - // to us - ct = getInboundMask(rt); - } else { - Collection at = rt.getAddresses(); - // assume nothing if hidden - if (at.isEmpty()) - return false; - ct = getConnectMask(at); - } - - int cf; - if (usf) { - // from us - cf = getOutboundMask(rf); - } else { - Collection a = rf.getAddresses(); - if (a.isEmpty()) { - // assume IPv4 if hidden - cf = NTCP_V4 | SSU_V4; - } else { - cf = getConnectMask(a); - } - } - - boolean rv = (ct & cf) != 0; - if (!rv && log.shouldWarn()) { - log.warn("Cannot connect: " + - (usf ? "us" : from.toString()) + " with mask " + cf + "\nto " + - (ust ? "us" : to.toString()) + " with mask " + ct); - } - return rv; - } - - /** - * Can we connect to "to" based on published addresses? - * - * This is intended for tunnel candidates, where we already have - * the RI. Will not force RI lookups. - * - * This is best effort, as we can't know for sure. - * Does not check isEstablished(); do that first. - * - * @since 0.9.34 - */ - private boolean canConnect(int ourMask, RouterInfo to) { - Collection ra = to.getAddresses(); - // assume nothing if hidden - if (ra.isEmpty()) - return false; - int ct = getConnectMask(ra); - boolean rv = (ourMask & ct) != 0; - //if (!rv && log.shouldWarn()) - // log.warn("Cannot connect: us with mask " + ourMask + " to " + to + " with mask " + ct); - return rv; - } - - /** - * Can "from" connect to us based on published addresses? - * - * This is intended for tunnel candidates, where we already have - * the RI. Will not force RI lookups. - * - * This is best effort, as we can't know for sure. - * Does not check isEstablished(); do that first. - * - * @since 0.9.34 - */ - private boolean canConnect(RouterInfo from, int ourMask) { - if (ourMask == 0) - return false; - Collection ra = from.getAddresses(); - int cf; - // assume v4 if hidden - if (ra.isEmpty()) - cf = NTCP_V4 | SSU_V4; - else - cf = getConnectMask(ra); - boolean rv = (cf & ourMask) != 0; - //if (!rv && log.shouldWarn()) - // log.warn("Cannot connect: " + from + " with mask " + cf + " to us with mask " + ourMask); - return rv; - } - - /** - * Our inbound mask. - * For most cases, we use what we published, i.e. getConnectMask() - * - * @return bitmask for accepting connections - * @since 0.9.34 - */ - private int getInboundMask(RouterInfo us) { - // to us - int ct = 0; - Status status = ctx.commSystem().getStatus(); - switch (status) { - case OK: - case IPV4_UNKNOWN_IPV6_OK: - case IPV4_FIREWALLED_IPV6_OK: - case IPV4_SNAT_IPV6_OK: - case IPV4_SNAT_IPV6_UNKNOWN: - case IPV4_FIREWALLED_IPV6_UNKNOWN: - case IPV4_UNKNOWN_IPV6_FIREWALLED: - case IPV4_OK_IPV6_FIREWALLED: - case DIFFERENT: - case REJECT_UNSOLICITED: - // use what we published - Collection at = us.getAddresses(); - if (at.isEmpty()) - return 0; - ct = getConnectMask(at); - break; - - case IPV4_DISABLED_IPV6_OK: - case IPV4_DISABLED_IPV6_UNKNOWN: - // maybe should return zero for this one? - case IPV4_DISABLED_IPV6_FIREWALLED: - // TODO look at force-firewalled settings per-transport - if (!isNTCPDisabled()) - ct |= NTCP_V6; - if (!isSSUDisabled()) - ct |= SSU_V6; - break; - - case IPV4_OK_IPV6_UNKNOWN: - case DISCONNECTED: - case HOSED: - case UNKNOWN: - default: - if (!isNTCPDisabled()) - ct |= NTCP_V4; - if (!isSSUDisabled()) - ct |= SSU_V4; - break; - } - return ct; - } - - /** - * Our outbound mask. - * For most cases, we use our comm system status. - * - * @return bitmask for initiating connections - * @since 0.9.34 - */ - private int getOutboundMask(RouterInfo us) { - // from us - int cf = 0; - Status status = ctx.commSystem().getStatus(); - switch (status) { - case OK: - // use what we published, as the OK state doesn't tell us about IPv6 - // Addresses.isConnectedIPv6() is too slow - Collection a = us.getAddresses(); - if (a.isEmpty()) { - // we are hidden - // TODO ipv6 - if (!isNTCPDisabled()) - cf |= NTCP_V4; - if (!isSSUDisabled()) - cf |= SSU_V4; - } else { - cf = getConnectMask(a); - } - break; - - case IPV4_OK_IPV6_FIREWALLED: - case IPV4_UNKNOWN_IPV6_OK: - case IPV4_FIREWALLED_IPV6_OK: - case IPV4_SNAT_IPV6_OK: - case IPV4_UNKNOWN_IPV6_FIREWALLED: - if (!isNTCPDisabled()) - cf |= NTCP_V4 | NTCP_V6; - if (!isSSUDisabled()) - cf |= SSU_V4 | SSU_V6; - break; - - case IPV4_DISABLED_IPV6_OK: - case IPV4_DISABLED_IPV6_UNKNOWN: - case IPV4_DISABLED_IPV6_FIREWALLED: - if (!isNTCPDisabled()) - cf |= NTCP_V6; - if (!isSSUDisabled()) - cf |= SSU_V6; - break; - - case DIFFERENT: - case IPV4_SNAT_IPV6_UNKNOWN: - case IPV4_FIREWALLED_IPV6_UNKNOWN: - case REJECT_UNSOLICITED: - case IPV4_OK_IPV6_UNKNOWN: - case DISCONNECTED: - case HOSED: - case UNKNOWN: - default: - if (!isNTCPDisabled()) - cf |= NTCP_V4; - if (!isSSUDisabled()) - cf |= SSU_V4; - break; - } - return cf; - } - - /** prevent object churn */ - private static final String IHOST[] = { "ihost0", "ihost1", "ihost2" }; - - /** - * @param addrs non-empty, set your own default if empty - * @return bitmask of v4/v6 NTCP/SSU - * @since 0.9.34 - */ - private static int getConnectMask(Collection addrs) { - int rv = 0; - for (RouterAddress ra : addrs) { - String style = ra.getTransportStyle(); - String host = ra.getHost(); - if ("NTCP".equals(style)) { - if (host != null) { - if (host.contains(":")) - rv |= NTCP_V6; - else - rv |= NTCP_V4; - } - } else if ("SSU".equals(style)) { - if (host == null) { - for (int i = 0; i < 2; i++) { - String ihost = ra.getOption(IHOST[i]); - if (ihost == null) - break; - if (ihost.contains(":")) - rv |= SSU_V6; - else - rv |= SSU_V4; - } - } else if (host.contains(":")) { - rv |= SSU_V6; - } else { - rv |= SSU_V4; - } - } - } - return rv; - } }