use of net.i2p.router.util.RandomIterator in project i2p.i2p by i2p.
the class UDPTransport method pickTestPeer.
/**
* Pick a Bob (if we are Alice) or a Charlie (if we are Bob).
*
* For Bob (as called from PeerTestEvent below), returns an established IPv4/v6 peer.
* While the protocol allows Alice to select an unestablished Bob, we don't support that.
*
* For Charlie (as called from PeerTestManager), returns an established IPv4 or IPv6 peer.
* (doesn't matter how Bob and Charlie communicate)
*
* Any returned peer must advertise an IPv4 address to prove it is IPv4-capable.
* Ditto for v6.
*
* @param peerRole The role of the peer we are looking for, BOB or CHARLIE only (NOT our role)
* @param isIPv6 true to get a v6-capable peer back
* @param dontInclude may be null
* @return IPv4 peer or null
*/
PeerState pickTestPeer(PeerTestState.Role peerRole, boolean isIPv6, RemoteHostId dontInclude) {
if (peerRole == ALICE)
throw new IllegalArgumentException();
List<PeerState> peers = new ArrayList<PeerState>(_peersByIdent.values());
for (Iterator<PeerState> iter = new RandomIterator<PeerState>(peers); iter.hasNext(); ) {
PeerState peer = iter.next();
if ((dontInclude != null) && (dontInclude.equals(peer.getRemoteHostId())))
continue;
// enforce IPv4/v6 connection if we are ALICE looking for a BOB
byte[] ip = peer.getRemoteIP();
if (peerRole == BOB) {
if (isIPv6) {
if (ip.length != 16)
continue;
} else {
if (ip.length != 4)
continue;
}
}
// enforce IPv4/v6 advertised for all
RouterInfo peerInfo = _context.netDb().lookupRouterInfoLocally(peer.getRemotePeer());
if (peerInfo == null)
continue;
if (isIPv6) {
String v = peerInfo.getVersion();
if (VersionComparator.comp(v, MIN_V6_PEER_TEST_VERSION) < 0)
continue;
}
ip = null;
List<RouterAddress> addrs = getTargetAddresses(peerInfo);
for (RouterAddress addr : addrs) {
byte[] rip = addr.getIP();
if (rip != null) {
if (isIPv6) {
if (rip.length != 16)
continue;
} else {
if (rip.length != 4)
continue;
}
// as of 0.9.27, we trust the 'B' cap for IPv6
String caps = addr.getOption(UDPAddress.PROP_CAPACITY);
if (caps != null && caps.contains(CAP_TESTING)) {
ip = rip;
break;
}
}
}
if (ip == null)
continue;
if (isTooClose(ip))
continue;
return peer;
}
return null;
}
use of net.i2p.router.util.RandomIterator in project i2p.i2p by i2p.
the class ProfileOrganizer method locked_selectPeers.
/**
* @param randomKey used for deterministic random partitioning into subtiers
* @param subTierMode 2-7:
*<pre>
* 2: return only from group 0 or 1
* 3: return only from group 2 or 3
* 4: return only from group 0
* 5: return only from group 1
* 6: return only from group 2
* 7: return only from group 3
*</pre>
*/
private void locked_selectPeers(Map<Hash, PeerProfile> peers, int howMany, Set<Hash> toExclude, Set<Hash> matches, Hash randomKey, Slice subTierMode) {
List<Hash> all = new ArrayList<Hash>(peers.keySet());
// use RandomIterator to avoid shuffling the whole thing
for (Iterator<Hash> iter = new RandomIterator<Hash>(all); (matches.size() < howMany) && iter.hasNext(); ) {
Hash peer = iter.next();
if (toExclude != null && toExclude.contains(peer))
continue;
if (matches.contains(peer))
continue;
if (_us.equals(peer))
continue;
int subTier = getSubTier(peer, randomKey);
if ((subTier & subTierMode.mask) != subTierMode.val)
continue;
boolean ok = isSelectable(peer);
if (ok)
matches.add(peer);
else
matches.remove(peer);
}
}
use of net.i2p.router.util.RandomIterator in project i2p.i2p by i2p.
the class ProfileOrganizer method locked_selectPeers.
/**
* As of 0.9.24, checks for a netdb family match as well, unless mask == 0.
*
* @param mask 0-4 Number of bytes to match to determine if peers in the same IP range should
* not be in the same tunnel. 0 = disable check; 1 = /8; 2 = /16; 3 = /24; 4 = exact IP match
*/
private void locked_selectPeers(Map<Hash, PeerProfile> peers, int howMany, Set<Hash> toExclude, Set<Hash> matches, int mask) {
List<Hash> all = new ArrayList<Hash>(peers.keySet());
MaskedIPSet IPSet = new MaskedIPSet(16);
// use RandomIterator to avoid shuffling the whole thing
for (Iterator<Hash> iter = new RandomIterator<Hash>(all); (matches.size() < howMany) && iter.hasNext(); ) {
Hash peer = iter.next();
if (toExclude != null && toExclude.contains(peer))
continue;
if (matches.contains(peer))
continue;
if (_us.equals(peer))
continue;
boolean ok = isSelectable(peer);
if (ok) {
ok = mask <= 0 || notRestricted(peer, IPSet, mask);
if ((!ok) && _log.shouldLog(Log.WARN))
_log.warn("IP restriction prevents " + peer + " from joining " + matches);
}
if (ok)
matches.add(peer);
else
matches.remove(peer);
}
}
use of net.i2p.router.util.RandomIterator in project i2p.i2p by i2p.
the class ProfileOrganizer method selectAllNotFailingPeers.
/**
* @param mask ignored, should call locked_selectPeers, to be fixed
*/
private void selectAllNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, boolean onlyNotFailing, int mask) {
if (matches.size() < howMany) {
int orig = matches.size();
int needed = howMany - orig;
List<Hash> selected = new ArrayList<Hash>(needed);
getReadLock();
try {
// use RandomIterator to avoid shuffling the whole thing
for (Iterator<Hash> iter = new RandomIterator<Hash>(_notFailingPeersList); (selected.size() < needed) && iter.hasNext(); ) {
Hash cur = iter.next();
if (matches.contains(cur) || (exclude != null && exclude.contains(cur))) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("matched? " + matches.contains(cur) + " exclude: " + exclude + " cur=" + cur.toBase64());
continue;
} else if (onlyNotFailing && _highCapacityPeers.containsKey(cur)) {
// we dont want the good peers, just random ones
continue;
} else {
if (isSelectable(cur))
selected.add(cur);
else if (_log.shouldLog(Log.DEBUG))
_log.debug("Not selectable: " + cur.toBase64());
}
}
} finally {
releaseReadLock();
}
if (_log.shouldLog(Log.INFO))
_log.info("Selecting all not failing (strict? " + onlyNotFailing + ") found " + selected.size() + " new peers: " + selected + " all=" + _notFailingPeersList.size() + " strict=" + _strictCapacityOrder.size());
matches.addAll(selected);
}
if (matches.size() < howMany) {
if (_log.shouldLog(Log.INFO))
_log.info("selectAllNotFailing(" + howMany + "), not enough (" + matches.size() + ") going on to failing");
selectFailingPeers(howMany, exclude, matches);
} else {
if (_log.shouldLog(Log.INFO))
_log.info("selectAllNotFailing(" + howMany + "), enough (" + matches.size() + ")");
}
return;
}
use of net.i2p.router.util.RandomIterator in project i2p.i2p by i2p.
the class IterativeSearchJob method runJob.
@Override
public void runJob() {
if (_facade.isNegativeCached(_key)) {
if (_log.shouldLog(Log.WARN))
_log.warn("Negative cached, not searching: " + _key);
failed();
return;
}
// pick some floodfill peers and send out the searches
List<Hash> floodfillPeers;
KBucketSet<Hash> ks = _facade.getKBuckets();
if (ks != null) {
// Ideally we would add the key to an exclude list, so we don't try to query a ff peer for itself,
// but we're passing the rkey not the key, so we do it below instead in certain cases.
floodfillPeers = ((FloodfillPeerSelector) _facade.getPeerSelector()).selectFloodfillParticipants(_rkey, _totalSearchLimit + EXTRA_PEERS, ks);
} else {
floodfillPeers = new ArrayList<Hash>(_totalSearchLimit);
}
// For testing or local networks... we will
// pretend that the specified router is floodfill, and always closest-to-the-key.
// May be set after startup but can't be changed or unset later.
// Warning - experts only!
String alwaysQuery = getContext().getProperty("netDb.alwaysQuery");
if (alwaysQuery != null) {
if (_alwaysQueryHash == null) {
byte[] b = Base64.decode(alwaysQuery);
if (b != null && b.length == Hash.HASH_LENGTH)
_alwaysQueryHash = Hash.create(b);
}
}
if (floodfillPeers.isEmpty()) {
// so this situation should be temporary
if (_log.shouldLog(Log.WARN))
_log.warn("Running netDb searches against the floodfill peers, but we don't know any");
List<Hash> all = new ArrayList<Hash>(_facade.getAllRouters());
if (all.isEmpty()) {
if (_log.shouldLog(Log.ERROR))
_log.error("We don't know any peers at all");
failed();
return;
}
Iterator<Hash> iter = new RandomIterator<Hash>(all);
// so once we get some FFs we want to be sure to query them
for (int i = 0; iter.hasNext() && i < MAX_NON_FF; i++) {
floodfillPeers.add(iter.next());
}
}
final boolean empty;
// outside sync to avoid deadlock
final Hash us = getContext().routerHash();
synchronized (this) {
_toTry.addAll(floodfillPeers);
// don't ask ourselves or the target
_toTry.remove(us);
_toTry.remove(_key);
empty = _toTry.isEmpty();
}
if (empty) {
if (_log.shouldLog(Log.WARN))
_log.warn(getJobId() + ": ISJ for " + _key + " had no peers to send to");
// no floodfill peers, fail
failed();
return;
}
// This OutNetMessage is never used or sent (setMessage() is never called), it's only
// so we can register a reply selector.
MessageSelector replySelector = new IterativeLookupSelector(getContext(), this);
ReplyJob onReply = new FloodOnlyLookupMatchJob(getContext(), this);
Job onTimeout = new FloodOnlyLookupTimeoutJob(getContext(), this);
_out = getContext().messageRegistry().registerPending(replySelector, onReply, onTimeout);
if (_log.shouldLog(Log.INFO))
_log.info(getJobId() + ": New ISJ for " + (_isLease ? "LS " : "RI ") + _key + " (rkey " + _rkey + ") timeout " + DataHelper.formatDuration(_timeoutMs) + " toTry: " + DataHelper.toString(_toTry));
retry();
}
Aggregations