Changeset 69aadaa for router


Ignore:
Timestamp:
Mar 8, 2018 2:30:26 PM (2 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
fac4f6c
Parents:
1412dbd
Message:

Router: Improve tunnel peer selection of closest hop
for routers that are hidden, IPv6-only, or have disabled transports.
Don't try to build tunnel if adjacent peers don't have compatible transports.
Don't select IPv6-only routers for IBGW or OBEP.
Remove old version check in peer selectors
Peer selector cleanups
Extend peer selection startup time for Android

Location:
router/java/src/net/i2p/router
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • router/java/src/net/i2p/router/RouterVersion.java

    r1412dbd r69aadaa  
    1919    public final static String ID = "Monotone";
    2020    public final static String VERSION = CoreVersion.VERSION;
    21     public final static long BUILD = 12;
     21    public final static long BUILD = 13;
    2222
    2323    /** for example "-test" */
  • router/java/src/net/i2p/router/tunnel/pool/ClientPeerSelector.java

    r1412dbd r69aadaa  
    66import java.util.Set;
    77
     8import net.i2p.data.DataHelper;
    89import net.i2p.data.Hash;
    910import net.i2p.router.RouterContext;
     
    2223    }
    2324
     25    /**
     26     * Returns ENDPOINT FIRST, GATEWAY LAST!!!!
     27     * In: us .. closest .. middle .. IBGW
     28     * Out: OBGW .. middle .. closest .. us
     29     *
     30     * @return ordered list of Hash objects (one per peer) specifying what order
     31     *         they should appear in a tunnel (ENDPOINT FIRST).  This includes
     32     *         the local router in the list.  If there are no tunnels or peers
     33     *         to build through, and the settings reject 0 hop tunnels, this will
     34     *         return null.
     35     */
    2436    public List<Hash> selectPeers(TunnelPoolSettings settings) {
    2537        int length = getLength(settings);
     
    3042
    3143        List<Hash> rv;
     44        boolean isInbound = settings.isInbound();
    3245   
    3346        if (length > 0) {
     47            // special cases
     48            boolean v6Only = isIPv6Only();
     49            boolean ntcpDisabled = isNTCPDisabled();
     50            boolean ssuDisabled = isSSUDisabled();
     51            boolean checkClosestHop = v6Only || ntcpDisabled || ssuDisabled;
     52            boolean hidden = ctx.router().isHidden() ||
     53                             ctx.router().getRouterInfo().getAddressCount() <= 0;
     54            boolean hiddenInbound = hidden && isInbound;
     55
    3456            if (shouldSelectExplicit(settings))
    3557                return selectExplicit(settings, length);
    3658       
    37             Set<Hash> exclude = getExclude(settings.isInbound(), false);
     59            Set<Hash> exclude = getExclude(isInbound, false);
    3860            Set<Hash> matches = new HashSet<Hash>(length);
    3961            if (length == 1) {
    4062                // closest-hop restrictions
    41                 Set<Hash> moreExclude = getClosestHopExclude(settings.isInbound());
    42                 if (moreExclude != null)
    43                     exclude.addAll(moreExclude);
    44                 ctx.profileOrganizer().selectFastPeers(length, exclude, matches, 0);
     63                if (checkClosestHop) {
     64                    Set<Hash> moreExclude = getClosestHopExclude(isInbound);
     65                    if (moreExclude != null)
     66                        exclude.addAll(moreExclude);
     67                }
     68                if (hiddenInbound)
     69                    ctx.profileOrganizer().selectActiveNotFailingPeers(1, exclude, matches);
     70                if (matches.isEmpty()) {
     71                    // ANFP does not fall back to non-connected
     72                    ctx.profileOrganizer().selectFastPeers(length, exclude, matches, 0);
     73                }
    4574                matches.remove(ctx.routerHash());
    4675                rv = new ArrayList<Hash>(matches);
     
    5382                // group 0 or 1 if two hops, otherwise group 0
    5483                Set<Hash> firstHopExclude;
    55                 if (!settings.isInbound()) {
     84                if (isInbound) {
    5685                    // exclude existing OBEPs to get some diversity ?
    57 
    5886                    // closest-hop restrictions
    59                     Set<Hash> moreExclude = getClosestHopExclude(false);
    60                     if (moreExclude != null) {
    61                         moreExclude.addAll(exclude);
    62                         firstHopExclude = moreExclude;
     87                    if (checkClosestHop) {
     88                        Set<Hash> moreExclude = getClosestHopExclude(false);
     89                        if (moreExclude != null) {
     90                            moreExclude.addAll(exclude);
     91                            firstHopExclude = moreExclude;
     92                        } else {
     93                            firstHopExclude = exclude;
     94                        }
    6395                    } else {
    64                         firstHopExclude = exclude;
     96                         firstHopExclude = exclude;
    6597                    }
    6698                } else {
    6799                    firstHopExclude = exclude;
    68100                }
    69                 ctx.profileOrganizer().selectFastPeers(1, firstHopExclude, matches, settings.getRandomKey(), length == 2 ? SLICE_0_1 : SLICE_0);
     101                if (hiddenInbound) {
     102                    ctx.profileOrganizer().selectActiveNotFailingPeers(1, exclude, matches);
     103                    if (matches.isEmpty()) {
     104                        // ANFP does not fall back to non-connected
     105                        ctx.profileOrganizer().selectFastPeers(1, firstHopExclude, matches, settings.getRandomKey(), length == 2 ? SLICE_0_1 : SLICE_0);
     106                    }
     107                } else {
     108                    // TODO exclude IPv6-only at OBEP? Caught in checkTunnel() below
     109                    ctx.profileOrganizer().selectFastPeers(1, firstHopExclude, matches, settings.getRandomKey(), length == 2 ? SLICE_0_1 : SLICE_0);
     110                }
    70111                matches.remove(ctx.routerHash());
    71112                exclude.addAll(matches);
     
    90131                // IBGW or OB first hop
    91132                // group 2 or 3 if two hops, otherwise group 1
    92                 if (settings.isInbound()) {
     133                if (!isInbound) {
    93134                    // exclude existing IBGWs to get some diversity ?
    94 
    95135                    // closest-hop restrictions
    96                     Set<Hash> moreExclude = getClosestHopExclude(true);
    97                     if (moreExclude != null)
    98                         exclude.addAll(moreExclude);
     136                    if (checkClosestHop) {
     137                        Set<Hash> moreExclude = getClosestHopExclude(true);
     138                        if (moreExclude != null)
     139                            exclude.addAll(moreExclude);
     140                    }
    99141                }
     142                // TODO exclude IPv6-only at IBGW? Caught in checkTunnel() below
    100143                ctx.profileOrganizer().selectFastPeers(1, exclude, matches, settings.getRandomKey(), length == 2 ? SLICE_2_3 : SLICE_1);
    101144                matches.remove(ctx.routerHash());
     
    106149        }
    107150       
    108         if (settings.isInbound())
     151        //if (length != rv.size() && log.shouldWarn())
     152        //    log.warn("CPS requested " + length + " got " + rv.size() + ": " + DataHelper.toString(rv));
     153        //else if (log.shouldDebug())
     154        //    log.debug("EPS result: " + DataHelper.toString(rv));
     155        if (isInbound)
    109156            rv.add(0, ctx.routerHash());
    110157        else
    111158            rv.add(ctx.routerHash());
     159        if (rv.size() > 1) {
     160            if (!checkTunnel(isInbound, rv))
     161                rv = null;
     162        }
    112163        return rv;
    113164    }
  • router/java/src/net/i2p/router/tunnel/pool/ExploratoryPeerSelector.java

    r1412dbd r69aadaa  
    1313import net.i2p.stat.RateStat;
    1414import net.i2p.util.Log;
     15import net.i2p.util.SystemVersion;
    1516
    1617/**
     
    2526    }
    2627
     28    /**
     29     * Returns ENDPOINT FIRST, GATEWAY LAST!!!!
     30     * In: us .. closest .. middle .. IBGW
     31     * Out: OBGW .. middle .. closest .. us
     32     *
     33     * @return ordered list of Hash objects (one per peer) specifying what order
     34     *         they should appear in a tunnel (ENDPOINT FIRST).  This includes
     35     *         the local router in the list.  If there are no tunnels or peers
     36     *         to build through, and the settings reject 0 hop tunnels, this will
     37     *         return null.
     38     */
    2739    public List<Hash> selectPeers(TunnelPoolSettings settings) {
    28         Log l = ctx.logManager().getLog(getClass());
    2940        int length = getLength(settings);
    3041        if (length < 0) {
    31             if (l.shouldLog(Log.DEBUG))
    32                 l.debug("Length requested is zero: " + settings);
     42            if (log.shouldLog(Log.DEBUG))
     43                log.debug("Length requested is zero: " + settings);
    3344            return null;
    3445        }
     
    4152        //}
    4253       
    43         Set<Hash> exclude = getExclude(settings.isInbound(), true);
     54        boolean isInbound = settings.isInbound();
     55        Set<Hash> exclude = getExclude(isInbound, true);
    4456        exclude.add(ctx.routerHash());
     57
     58        // special cases
     59        boolean nonzero = length > 0;
     60        boolean exploreHighCap = nonzero && shouldPickHighCap();
     61        boolean v6Only = nonzero && isIPv6Only();
     62        boolean ntcpDisabled = nonzero && isNTCPDisabled();
     63        boolean ssuDisabled = nonzero && isSSUDisabled();
     64        boolean checkClosestHop = v6Only || ntcpDisabled || ssuDisabled;
     65        boolean hidden = nonzero && (ctx.router().isHidden() ||
     66                                     ctx.router().getRouterInfo().getAddressCount() <= 0);
     67        boolean hiddenInbound = hidden && isInbound;
     68        boolean lowOutbound = nonzero && !isInbound && !ctx.commSystem().haveHighOutboundCapacity();
     69
     70
    4571        // closest-hop restrictions
    4672        // Since we're applying orderPeers() later, we don't know
    47         // which will be the closest hop, so just appply to all peers for now.
    48         Set<Hash> moreExclude = getClosestHopExclude(settings.isInbound());
    49         if (moreExclude != null)
    50             exclude.addAll(moreExclude);
     73        // which will be the closest hop, so select the closest one here if necessary.
     74
     75        Hash closestHop = null;
     76        if (v6Only || hiddenInbound || lowOutbound) {
     77            Set<Hash> closestExclude;
     78            if (checkClosestHop) {
     79                closestExclude = getClosestHopExclude(isInbound);
     80                if (closestExclude != null)
     81                    closestExclude.addAll(exclude);
     82                else
     83                    closestExclude = exclude;
     84            } else {
     85                closestExclude = exclude;
     86            }
     87
     88            Set<Hash> closest = new HashSet<Hash>(1);
     89            if (hiddenInbound || lowOutbound) {
     90                // If hidden and inbound, use fast peers - that we probably have recently
     91                // connected to and so they have our real RI - to maximize the chance
     92                // that the adjacent hop can connect to us.
     93                // use only connected peers so we don't make more connections
     94                if (log.shouldLog(Log.INFO))
     95                    log.info("EPS SANFP closest " + (isInbound ? "IB" : "OB") + " exclude " + closestExclude.size());
     96                ctx.profileOrganizer().selectActiveNotFailingPeers(1, closestExclude, closest);
     97                if (closest.isEmpty()) {
     98                    // ANFP does not fall back to non-connected
     99                    if (log.shouldLog(Log.INFO))
     100                        log.info("EPS SFP closest " + (isInbound ? "IB" : "OB") + " exclude " + closestExclude.size());
     101                    ctx.profileOrganizer().selectFastPeers(1, closestExclude, closest);
     102                }
     103            } else if (exploreHighCap) {
     104                if (log.shouldLog(Log.INFO))
     105                    log.info("EPS SHCP closest " + (isInbound ? "IB" : "OB") + " exclude " + closestExclude.size());
     106                ctx.profileOrganizer().selectHighCapacityPeers(1, closestExclude, closest);
     107            } else {
     108                if (log.shouldLog(Log.INFO))
     109                    log.info("EPS SNFP closest " + (isInbound ? "IB" : "OB") + " exclude " + closestExclude.size());
     110                ctx.profileOrganizer().selectNotFailingPeers(1, closestExclude, closest, false);
     111            }
     112            if (!closest.isEmpty()) {
     113                closestHop = closest.iterator().next();
     114                exclude.add(closestHop);
     115                length--;
     116            }
     117        }
    51118
    52119        // Don't use ff peers for exploratory tunnels to lessen exposure to netDb searches and stores
     
    58125
    59126        if (length > 0) {
    60             boolean exploreHighCap = shouldPickHighCap();
    61 
    62127            //
    63128            // We don't honor IP Restriction here, to be fixed
    64129            //
    65 
    66             // If hidden and inbound, use fast peers - that we probably have recently
    67             // connected to and so they have our real RI - to maximize the chance
    68             // that the adjacent hop can connect to us.
    69             if (settings.isInbound() &&
    70                 (ctx.router().isHidden() ||
    71                  ctx.router().getRouterInfo().getAddressCount() <= 0)) {
    72                 if (l.shouldLog(Log.INFO))
    73                     l.info("EPS SFP " + length + (settings.isInbound() ? " IB" : " OB") + " exclude " + exclude.size());
    74                 ctx.profileOrganizer().selectFastPeers(length, exclude, matches);
    75             } else if (exploreHighCap) {
    76                 if (l.shouldLog(Log.INFO))
    77                     l.info("EPS SHCP " + length + (settings.isInbound() ? " IB" : " OB") + " exclude " + exclude.size());
     130            if (exploreHighCap) {
     131                if (log.shouldLog(Log.INFO))
     132                    log.info("EPS SHCP " + length + (isInbound ? " IB" : " OB") + " exclude " + exclude.size());
    78133                ctx.profileOrganizer().selectHighCapacityPeers(length, exclude, matches);
    79             } else if (ctx.commSystem().haveHighOutboundCapacity()) {
    80                 if (l.shouldLog(Log.INFO))
    81                     l.info("EPS SNFP " + length + (settings.isInbound() ? " IB" : " OB") + " exclude " + exclude.size());
     134            } else {
    82135                // As of 0.9.23, we include a max of 2 not failing peers,
    83136                // to improve build success on 3-hop tunnels.
     
    85138                if (length > 2)
    86139                    ctx.profileOrganizer().selectHighCapacityPeers(length - 2, exclude, matches);
     140                if (log.shouldLog(Log.INFO))
     141                    log.info("EPS SNFP " + length + (isInbound ? " IB" : " OB") + " exclude " + exclude.size());
    87142                ctx.profileOrganizer().selectNotFailingPeers(length, exclude, matches, false);
    88             } else { // use only connected peers so we don't make more connections
    89                 if (l.shouldLog(Log.INFO))
    90                     l.info("EPS SANFP " + length + (settings.isInbound() ? " IB" : " OB") + " exclude " + exclude.size());
    91                 ctx.profileOrganizer().selectActiveNotFailingPeers(length, exclude, matches);
    92             }
    93            
     143            }
    94144            matches.remove(ctx.routerHash());
    95145        }
     
    98148        if (rv.size() > 1)
    99149            orderPeers(rv, settings.getRandomKey());
    100         if (l.shouldLog(Log.DEBUG))
    101             l.debug("EPS got " + rv.size() + ": " + DataHelper.toString(rv));
    102         if (settings.isInbound())
     150        if (closestHop != null) {
     151            if (isInbound)
     152                rv.add(0, closestHop);
     153            else
     154                rv.add(closestHop);
     155            length++;
     156        }
     157        //if (length != rv.size() && log.shouldWarn())
     158        //    log.warn("EPS requested " + length + " got " + rv.size() + ": " + DataHelper.toString(rv));
     159        //else if (log.shouldDebug())
     160        //    log.debug("EPS result: " + DataHelper.toString(rv));
     161        if (isInbound)
    103162            rv.add(0, ctx.routerHash());
    104163        else
    105164            rv.add(ctx.routerHash());
     165        if (rv.size() > 1) {
     166            if (!checkTunnel(isInbound, rv))
     167                rv = null;
     168        }
    106169        return rv;
    107170    }
     
    132195
    133196        // no need to explore too wildly at first (if we have enough connected peers)
    134         if (ctx.router().getUptime() <= 5*60*1000)
     197        if (ctx.router().getUptime() <= (SystemVersion.isAndroid() ? 15*60*1000 : 5*60*1000))
    135198            return true;
    136199        // or at the end
  • router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java

    r1412dbd r69aadaa  
    1717import net.i2p.crypto.SigType;
    1818import net.i2p.data.DataFormatException;
     19import net.i2p.data.DataHelper;
    1920import net.i2p.data.Hash;
     21import net.i2p.data.router.RouterAddress;
    2022import net.i2p.data.router.RouterInfo;
    2123import net.i2p.router.Router;
     24import net.i2p.router.CommSystemFacade.Status;
    2225import net.i2p.router.RouterContext;
    2326import net.i2p.router.TunnelPoolSettings;
    2427import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
     28import net.i2p.router.transport.TransportManager;
     29import net.i2p.router.transport.TransportUtil;
    2530import net.i2p.router.util.HashDistance;
    2631import net.i2p.util.Log;
     
    3540public abstract class TunnelPeerSelector {
    3641    protected final RouterContext ctx;
     42    protected final Log log;
     43
     44    private static final int NTCP_V4 = 0x01;
     45    private static final int SSU_V4 = 0x02;
     46    private static final int ANY_V4 = NTCP_V4 | SSU_V4;
     47    private static final int NTCP_V6 = 0x04;
     48    private static final int SSU_V6 = 0x08;
     49    private static final int ANY_V6 = NTCP_V6 | SSU_V6;
     50
    3751
    3852    protected TunnelPeerSelector(RouterContext context) {
    3953        ctx = context;
     54        log = ctx.logManager().getLog(getClass());
    4055    }
    4156
     
    127142            peers = I2PAppContext.getGlobalContext().getProperty("explicitPeers");
    128143       
    129         Log log = ctx.logManager().getLog(ClientPeerSelector.class);
    130144        List<Hash> rv = new ArrayList<Hash>();
    131145        StringTokenizer tok = new StringTokenizer(peers, ",");
     
    201215        // Defaults changed to true for inbound only in filterUnreachable below.
    202216
    203         Set<Hash> peers = new HashSet<Hash>(1);
     217        Set<Hash> peers = new HashSet<Hash>(8);
    204218        peers.addAll(ctx.profileOrganizer().selectPeersRecentlyRejecting());
    205219        peers.addAll(ctx.tunnelManager().selectPeersInTooManyTunnels());
     
    217231        if (filterSlow(isInbound, isExploratory)) {
    218232            // NOTE: filterSlow always returns true
    219             Log log = ctx.logManager().getLog(TunnelPeerSelector.class);
    220233            char excl[] = getExcludeCaps(ctx);
    221234            if (excl != null) {
     
    225238                    for (int i = 0; i < known.size(); i++) {
    226239                        RouterInfo peer = known.get(i);
    227                         boolean shouldExclude = shouldExclude(ctx, log, peer, excl);
     240                        boolean shouldExclude = shouldExclude(peer, excl);
    228241                        if (shouldExclude) {
    229242                            peers.add(peer.getIdentity().calculateHash());
     
    328341        return peers;
    329342    }
     343
     344    /**
     345     *  Are we IPv6 only?
     346     *  @since 0.9.34
     347     */
     348    protected boolean isIPv6Only() {
     349        // The setting is the same for both SSU and NTCP, so just take the SSU one
     350        return TransportUtil.getIPv6Config(ctx, "SSU") == TransportUtil.IPv6Config.IPV6_ONLY;
     351    }
     352
     353    /**
     354     *  Is NTCP disabled?
     355     *  @since 0.9.34
     356     */
     357    protected boolean isNTCPDisabled() {
     358        return !TransportManager.isNTCPEnabled(ctx);
     359    }
     360
     361    /**
     362     *  Is SSU disabled?
     363     *  @since 0.9.34
     364     */
     365    protected boolean isSSUDisabled() {
     366        return !ctx.getBooleanPropertyDefaultTrue(TransportManager.PROP_ENABLE_UDP);
     367    }
     368
     369    /**
     370     *  Should we allow as OBEP?
     371     *  This just checks for IPv4 support.
     372     *  Will return false for IPv6-only.
     373     *  This is intended for tunnel candidates, where we already have
     374     *  the RI. Will not force RI lookups.
     375     *  Default true.
     376     *
     377     *  @since 0.9.34
     378     */
     379    private boolean allowAsOBEP(Hash h) {
     380        RouterInfo ri = ctx.netDb().lookupRouterInfoLocally(h);
     381        if (ri == null)
     382            return true;
     383        return canConnect(ri, ANY_V4);
     384    }
     385
     386    /**
     387     *  Should we allow as IBGW?
     388     *  This just checks for IPv4 support.
     389     *  Will return false for hidden or IPv6-only.
     390     *  This is intended for tunnel candidates, where we already have
     391     *  the RI. Will not force RI lookups.
     392     *  Default true.
     393     *
     394     *  @since 0.9.34
     395     */
     396    private boolean allowAsIBGW(Hash h) {
     397        RouterInfo ri = ctx.netDb().lookupRouterInfoLocally(h);
     398        if (ri == null)
     399            return true;
     400        return canConnect(ANY_V4, ri);
     401    }
    330402   
    331403    /**
    332404     *  Pick peers that we want to avoid for the first OB hop or last IB hop.
    333      *  This is only filled in if our router sig type is not DSA.
    334      *
    335      *  @param isInbound unused
     405     *  There's several cases of importance:
     406     *  <ol><li>Inbound and we are hidden -
     407     *      Exclude all unless connected.
     408     *      This is taken care of in ClientPeerSelector and TunnelPeerSelector selectPeers(), not here.
     409     *
     410     *  <li>We are IPv6-only.
     411     *      Exclude all v4-only peers, unless connected
     412     *      This is taken care of here.
     413     *
     414     *  <li>We have NTCP or SSU disabled.
     415     *      Exclude all incompatible peers, unless connected
     416     *      This is taken care of here.
     417     *
     418     *  <li>Minimum version check, if we are some brand-new sig type,
     419     *      or are using some new tunnel build method.
     420     *      Not currently used, but this is where to implement the checks if needed.
     421     *      Make sure that ClientPeerSelector and TunnelPeerSelector selectPeers() call this when needed.
     422     *  </ol>
     423     *
     424     *  Don't call this unless you need to.
     425     *  See ClientPeerSelector and TunnelPeerSelector selectPeers().
     426     *
     427     *  @param isInbound
    336428     *  @return null if none
    337429     *  @since 0.9.17
     
    341433        if (ri == null)
    342434            return null;
    343         SigType type = ri.getIdentity().getSigType();
    344         if (type == SigType.DSA_SHA1)
    345             return null;
    346         Set<Hash> rv = new HashSet<Hash>(1024);
     435
     436        // we can skip this check now, uncomment if we have some new sigtype
     437        //SigType type = ri.getIdentity().getSigType();
     438        //if (type == SigType.DSA_SHA1)
     439        //    return null;
     440
     441        int ourMask = isInbound ? getInboundMask(ri) : getOutboundMask(ri);
     442        Set<Hash> connected = ctx.commSystem().getEstablished();
     443        Set<Hash> rv = new HashSet<Hash>(256);
    347444        FloodfillNetworkDatabaseFacade fac = (FloodfillNetworkDatabaseFacade)ctx.netDb();
    348445        List<RouterInfo> known = fac.getKnownRouterData();
     
    350447            for (int i = 0; i < known.size(); i++) {
    351448                RouterInfo peer = known.get(i);
    352                 String v = peer.getVersion();
     449                // we can skip this check now, uncomment if we have some breaking change
     450                //String v = peer.getVersion();
    353451                // RI sigtypes added in 0.9.16
    354452                // SSU inbound connection bug fixed in 0.9.17, but it won't bid, so NTCP only,
    355453                // no need to check
    356                 if (VersionComparator.comp(v, "0.9.16") < 0)
    357                     rv.add(peer.getIdentity().calculateHash());
     454                //if (VersionComparator.comp(v, "0.9.16") < 0)
     455                //    rv.add(peer.getIdentity().calculateHash());
     456
     457                Hash h = peer.getIdentity().calculateHash();
     458                if (connected.contains(h))
     459                    continue;
     460                boolean canConnect = isInbound ? canConnect(peer, ourMask) : canConnect(ourMask, peer);
     461                if (!canConnect)
     462                    rv.add(h);
    358463            }
    359464        }
     
    363468    /** warning, this is also called by ProfileOrganizer.isSelectable() */
    364469    public static boolean shouldExclude(RouterContext ctx, RouterInfo peer) {
    365         Log log = ctx.logManager().getLog(TunnelPeerSelector.class);
    366         return shouldExclude(ctx, log, peer, getExcludeCaps(ctx));
     470        return shouldExclude(peer, getExcludeCaps(ctx));
    367471    }
    368472   
     
    379483   
    380484    /** 0.7.8 and earlier had major message corruption bugs */
    381     private static final String MIN_VERSION = "0.7.9";
    382 
    383     private static boolean shouldExclude(RouterContext ctx, Log log, RouterInfo peer, char excl[]) {
     485    //private static final String MIN_VERSION = "0.7.9";
     486
     487    private static boolean shouldExclude(RouterInfo peer, char excl[]) {
    384488        String cap = peer.getCapabilities();
    385489        for (int j = 0; j < excl.length; j++) {
     
    401505
    402506        // minimum version check
    403         String v = peer.getVersion();
    404         if (VersionComparator.comp(v, MIN_VERSION) < 0)
    405             return true;
     507        // we can skip this check now
     508        //String v = peer.getVersion();
     509        //if (VersionComparator.comp(v, MIN_VERSION) < 0)
     510        //    return true;
    406511
    407512        // uptime is always spoofed to 90m, so just remove all this
     
    584689        }
    585690    }
     691
     692    /**
     693     *  Connectivity check.
     694     *  Check that each hop can connect to the next, including us.
     695     *  Check that the OBEP is not IPv6-only, and the IBGW is
     696     *  not hidden or IPv6-only.
     697     *  Tells the profile manager to blame the hop, and returns false on failure.
     698     *
     699     *  @param tunnel ENDPOINT FIRST, GATEWAY LAST!!!!, length 2 or greater
     700     *  @return ok
     701     *  @since 0.9.34
     702     */
     703    protected boolean checkTunnel(boolean isInbound, List<Hash> tunnel) {
     704        if (!checkTunnel(tunnel))
     705            return false;
     706        if (isInbound) {
     707            Hash h = tunnel.get(tunnel.size() - 1);
     708            if (!allowAsIBGW(h)) {
     709                if (log.shouldWarn())
     710                    log.warn("Picked IPv6-only or hidden peer for IBGW: " + h);
     711                // treat as a timeout in the profile
     712                // tunnelRejected() would set the last heard from time
     713                ctx.profileManager().tunnelTimedOut(h);
     714                return false;
     715            }
     716        } else {
     717            Hash h = tunnel.get(0);
     718            if (!allowAsOBEP(h)) {
     719                if (log.shouldWarn())
     720                    log.warn("Picked IPv6-only peer for OBEP: " + h);
     721                // treat as a timeout in the profile
     722                // tunnelRejected() would set the last heard from time
     723                ctx.profileManager().tunnelTimedOut(h);
     724                return false;
     725            }
     726        }
     727        return true;
     728    }
     729
     730    /**
     731     *  Connectivity check.
     732     *  Check that each hop can connect to the next, including us.
     733     *
     734     *  @param tunnel ENDPOINT FIRST, GATEWAY LAST!!!!
     735     *  @return ok
     736     *  @since 0.9.34
     737     */
     738    private boolean checkTunnel(List<Hash> tunnel) {
     739        boolean rv = true;
     740        for (int i = 0; i < tunnel.size() - 1; i++) {
     741            // order is backwards!
     742            Hash hf = tunnel.get(i+1);
     743            Hash ht = tunnel.get(i);
     744            if (!canConnect(hf, ht)) {
     745                if (log.shouldWarn())
     746                    log.warn("Connect check fail hop " + (i+1) + " to " + i +
     747                             " in tunnel (EP<-GW): " + DataHelper.toString(tunnel));
     748                // Blame them both
     749                // treat as a timeout in the profile
     750                // tunnelRejected() would set the last heard from time
     751                Hash us = ctx.routerHash();
     752                if (!hf.equals(us))
     753                    ctx.profileManager().tunnelTimedOut(hf);
     754                if (!ht.equals(us))
     755                    ctx.profileManager().tunnelTimedOut(ht);
     756                rv = false;
     757                break;
     758            }
     759        }
     760        return rv;
     761    }
     762
     763    /**
     764     *  Can "from" connect to "to" based on published addresses?
     765     *
     766     *  This is intended for tunnel candidates, where we already have
     767     *  the RI. Will not force RI lookups.
     768     *  Either from or to may be us.
     769     *
     770     *  This is best effort, as we can't know for sure.
     771     *  Published addresses or introducers may have changed.
     772     *  Even if a can't connect to b, they may already be connected
     773     *  as b connected to a.
     774     *
     775     *  @return true if we don't have either RI
     776     *  @since 0.9.34
     777     */
     778    private boolean canConnect(Hash from, Hash to) {
     779        Hash us = ctx.routerHash();
     780        if (us == null)
     781            return true;
     782        boolean usf = from.equals(us);
     783        if (usf && ctx.commSystem().isEstablished(to))
     784            return true;
     785        boolean ust = to.equals(us);
     786        if (ust && ctx.commSystem().isEstablished(from))
     787            return true;
     788        RouterInfo rt = ctx.netDb().lookupRouterInfoLocally(to);
     789        if (rt == null)
     790            return true;
     791        RouterInfo rf = ctx.netDb().lookupRouterInfoLocally(from);
     792        if (rf == null)
     793            return true;
     794        int ct;
     795        if (ust) {
     796            // to us
     797            ct = getInboundMask(rt);
     798        } else {
     799            Collection<RouterAddress> at = rt.getAddresses();
     800            // assume nothing if hidden
     801            if (at.isEmpty())
     802                return false;
     803            ct = getConnectMask(at);
     804        }
     805
     806        int cf;
     807        if (usf) {
     808            // from us
     809            cf = getOutboundMask(rf);
     810        } else {
     811            Collection<RouterAddress> a = rf.getAddresses();
     812            if (a.isEmpty()) {
     813                // assume IPv4 if hidden
     814                cf = NTCP_V4 | SSU_V4;
     815            } else {
     816                cf = getConnectMask(a);
     817            }
     818        }
     819
     820        boolean rv = (ct & cf) != 0;
     821        if (!rv && log.shouldWarn()) {
     822            log.warn("Cannot connect: " +
     823                     (usf ? "us" : from.toString()) + " with mask " + cf + "\nto " +
     824                     (ust ? "us" : to.toString()) + " with mask " + ct);
     825        }
     826        return rv;
     827    }
     828
     829    /**
     830     *  Can we connect to "to" based on published addresses?
     831     *
     832     *  This is intended for tunnel candidates, where we already have
     833     *  the RI. Will not force RI lookups.
     834     *
     835     *  This is best effort, as we can't know for sure.
     836     *  Does not check isEstablished(); do that first.
     837     *
     838     *  @since 0.9.34
     839     */
     840    private boolean canConnect(int ourMask, RouterInfo to) {
     841        Collection<RouterAddress> ra = to.getAddresses();
     842        // assume nothing if hidden
     843        if (ra.isEmpty())
     844            return false;
     845        int ct = getConnectMask(ra);
     846        boolean rv = (ourMask & ct) != 0;
     847        //if (!rv && log.shouldWarn())
     848        //    log.warn("Cannot connect: us with mask " + ourMask + " to " + to + " with mask " + ct);
     849        return rv;
     850    }
     851
     852    /**
     853     *  Can "from" connect to us based on published addresses?
     854     *
     855     *  This is intended for tunnel candidates, where we already have
     856     *  the RI. Will not force RI lookups.
     857     *
     858     *  This is best effort, as we can't know for sure.
     859     *  Does not check isEstablished(); do that first.
     860     *
     861     *  @since 0.9.34
     862     */
     863    private boolean canConnect(RouterInfo from, int ourMask) {
     864        if (ourMask == 0)
     865            return false;
     866        Collection<RouterAddress> ra = from.getAddresses();
     867        int cf;
     868        // assume v4 if hidden
     869        if (ra.isEmpty())
     870            cf = NTCP_V4 | SSU_V4;
     871        else
     872            cf = getConnectMask(ra);
     873        boolean rv = (cf & ourMask) != 0;
     874        //if (!rv && log.shouldWarn())
     875        //    log.warn("Cannot connect: " + from + " with mask " + cf + " to us with mask " + ourMask);
     876        return rv;
     877    }
     878
     879    /**
     880     *  Our inbound mask.
     881     *  For most cases, we use what we published, i.e. getConnectMask()
     882     *
     883     *  @return bitmask for accepting connections
     884     *  @since 0.9.34
     885     */
     886    private int getInboundMask(RouterInfo us) {
     887        // to us
     888        int ct = 0;
     889        Status status = ctx.commSystem().getStatus();
     890        switch (status) {
     891            case OK:
     892            case IPV4_UNKNOWN_IPV6_OK:
     893            case IPV4_FIREWALLED_IPV6_OK:
     894            case IPV4_SNAT_IPV6_OK:
     895            case IPV4_SNAT_IPV6_UNKNOWN:
     896            case IPV4_FIREWALLED_IPV6_UNKNOWN:
     897            case IPV4_UNKNOWN_IPV6_FIREWALLED:
     898            case IPV4_OK_IPV6_FIREWALLED:
     899            case DIFFERENT:
     900            case REJECT_UNSOLICITED:
     901                // use what we published
     902                Collection<RouterAddress> at = us.getAddresses();
     903                if (at.isEmpty())
     904                    return 0;
     905                ct = getConnectMask(at);
     906                break;
     907
     908            case IPV4_DISABLED_IPV6_OK:
     909            case IPV4_DISABLED_IPV6_UNKNOWN:
     910            // maybe should return zero for this one?
     911            case IPV4_DISABLED_IPV6_FIREWALLED:
     912                // TODO look at force-firewalled settings per-transport
     913                if (!isNTCPDisabled())
     914                    ct |= NTCP_V6;
     915                if (!isSSUDisabled())
     916                    ct |= SSU_V6;
     917                break;
     918
     919            case IPV4_OK_IPV6_UNKNOWN:
     920            case DISCONNECTED:
     921            case HOSED:
     922            case UNKNOWN:
     923            default:
     924                if (!isNTCPDisabled())
     925                    ct |= NTCP_V4;
     926                if (!isSSUDisabled())
     927                    ct |= SSU_V4;
     928                break;
     929        }
     930        return ct;
     931    }
     932
     933    /**
     934     *  Our outbound mask.
     935     *  For most cases, we use our comm system status.
     936     *
     937     *  @return bitmask for initiating connections
     938     *  @since 0.9.34
     939     */
     940    private int getOutboundMask(RouterInfo us) {
     941        // from us
     942        int cf = 0;
     943        Status status = ctx.commSystem().getStatus();
     944        switch (status) {
     945            case OK:
     946                // use what we published, as the OK state doesn't tell us about IPv6
     947                // Addresses.isConnectedIPv6() is too slow
     948                Collection<RouterAddress> a = us.getAddresses();
     949                if (a.isEmpty()) {
     950                    // we are hidden
     951                    // TODO ipv6
     952                    if (!isNTCPDisabled())
     953                        cf |= NTCP_V4;
     954                    if (!isSSUDisabled())
     955                        cf |= SSU_V4;
     956                } else {
     957                    cf = getConnectMask(a);
     958                }
     959                break;
     960
     961            case IPV4_OK_IPV6_FIREWALLED:
     962            case IPV4_UNKNOWN_IPV6_OK:
     963            case IPV4_FIREWALLED_IPV6_OK:
     964            case IPV4_SNAT_IPV6_OK:
     965            case IPV4_UNKNOWN_IPV6_FIREWALLED:
     966                if (!isNTCPDisabled())
     967                    cf |= NTCP_V4 | NTCP_V6;
     968                if (!isSSUDisabled())
     969                    cf |= SSU_V4 | SSU_V6;
     970                break;
     971
     972            case IPV4_DISABLED_IPV6_OK:
     973            case IPV4_DISABLED_IPV6_UNKNOWN:
     974            case IPV4_DISABLED_IPV6_FIREWALLED:
     975                if (!isNTCPDisabled())
     976                    cf |= NTCP_V6;
     977                if (!isSSUDisabled())
     978                    cf |= SSU_V6;
     979                break;
     980
     981            case DIFFERENT:
     982            case IPV4_SNAT_IPV6_UNKNOWN:
     983            case IPV4_FIREWALLED_IPV6_UNKNOWN:
     984            case REJECT_UNSOLICITED:
     985            case IPV4_OK_IPV6_UNKNOWN:
     986            case DISCONNECTED:
     987            case HOSED:
     988            case UNKNOWN:
     989            default:
     990                if (!isNTCPDisabled())
     991                    cf |= NTCP_V4;
     992                if (!isSSUDisabled())
     993                    cf |= SSU_V4;
     994                break;
     995        }
     996        return cf;
     997    }
     998
     999    /** prevent object churn */
     1000    private static final String IHOST[] = { "ihost0", "ihost1", "ihost2" };
     1001
     1002    /**
     1003     *  @param addrs non-empty, set your own default if empty
     1004     *  @return bitmask of v4/v6 NTCP/SSU
     1005     *  @since 0.9.34
     1006     */
     1007    private static int getConnectMask(Collection<RouterAddress> addrs) {
     1008        int rv = 0;
     1009        for (RouterAddress ra : addrs) {
     1010            String style = ra.getTransportStyle();
     1011            String host = ra.getHost();
     1012            if ("NTCP".equals(style)) {
     1013                if (host != null) {
     1014                    if (host.contains(":"))
     1015                        rv |= NTCP_V6;
     1016                    else
     1017                        rv |= NTCP_V4;
     1018                }
     1019            } else if ("SSU".equals(style)) {
     1020                if (host == null) {
     1021                    for (int i = 0; i < 2; i++) {
     1022                        String ihost = ra.getOption(IHOST[i]);
     1023                        if (ihost == null)
     1024                            break;
     1025                        if (ihost.contains(":"))
     1026                            rv |= SSU_V6;
     1027                        else
     1028                            rv |= SSU_V4;
     1029                    }
     1030                } else if (host.contains(":")) {
     1031                    rv |= SSU_V6;
     1032                } else {
     1033                    rv |= SSU_V4;
     1034                }
     1035            }
     1036        }
     1037        return rv;
     1038    }
    5861039}
Note: See TracChangeset for help on using the changeset viewer.