use of net.i2p.data.Hash in project i2p.i2p by i2p.
the class KRPC method getPeersAndAnnounce.
/**
* Get peers for a torrent, and announce to the closest annMax nodes we find.
* This is an iterative lookup in the DHT.
* Blocking!
* Caller should run in a thread.
*
* @param ih the Info Hash (torrent)
* @param max maximum number of peers to return
* @param maxWait the maximum time to wait (ms) must be > 0
* @param annMax the number of peers to announce to
* @param annMaxWait the maximum total time to wait for announces, may be 0 to return immediately without waiting for acks
* @param isSeed true if seed, false if leech
* @param noSeeds true if we do not want seeds in the result
* @return possibly empty (never null)
*/
@SuppressWarnings("unchecked")
public Collection<Hash> getPeersAndAnnounce(byte[] ih, int max, long maxWait, int annMax, long annMaxWait, boolean isSeed, boolean noSeeds) {
// check local tracker first
InfoHash iHash = new InfoHash(ih);
Collection<Hash> rv = _tracker.getPeers(iHash, max, noSeeds);
rv.remove(_myNodeInfo.getHash());
if (rv.size() >= max)
return rv;
rv = new HashSet<Hash>(rv);
long endTime = _context.clock().now() + maxWait;
// needs to be much higher than log(size) since many lookups will fail
// at first and we will give up too early
int maxNodes = 30;
// Initial set to try, will get added to as we go
List<NodeInfo> nodes = _knownNodes.findClosest(iHash, maxNodes);
NodeInfoComparator comp = new NodeInfoComparator(iHash);
SortedSet<NodeInfo> toTry = new TreeSet<NodeInfo>(comp);
SortedSet<NodeInfo> heardFrom = new TreeSet<NodeInfo>(comp);
toTry.addAll(nodes);
SortedSet<NodeInfo> tried = new TreeSet<NodeInfo>(comp);
if (_log.shouldLog(Log.INFO))
_log.info("Starting getPeers for " + iHash + " (b64: " + new NID(ih) + ") " + " with " + nodes.size() + " to try");
for (int i = 0; i < maxNodes; i++) {
if (!_isRunning)
break;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Now to try: " + toTry);
NodeInfo nInfo;
try {
nInfo = toTry.first();
} catch (NoSuchElementException nsee) {
break;
}
toTry.remove(nInfo);
tried.add(nInfo);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Try " + i + ": " + nInfo);
ReplyWaiter waiter = sendGetPeers(nInfo, iHash, noSeeds);
if (waiter == null)
continue;
synchronized (waiter) {
try {
waiter.wait(Math.max(30 * 1000, (Math.min(45 * 1000, endTime - _context.clock().now()))));
} catch (InterruptedException ie) {
}
}
int replyType = waiter.getReplyCode();
if (replyType == REPLY_NONE) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got no reply");
} else if (replyType == REPLY_PONG) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got pong");
} else if (replyType == REPLY_PEERS) {
heardFrom.add(waiter.getSentTo());
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got peers");
List<Hash> reply = (List<Hash>) waiter.getReplyObject();
// 0.9.8.1 it will
if (!reply.isEmpty()) {
for (int j = 0; j < reply.size() && rv.size() < max; j++) {
Hash h = reply.get(j);
if (!h.equals(_myNodeInfo.getHash()))
rv.add(h);
}
}
if (_log.shouldLog(Log.INFO))
_log.info("Finished get Peers, got " + reply.size() + " from DHT, returning " + rv.size());
break;
} else if (replyType == REPLY_NODES) {
heardFrom.add(waiter.getSentTo());
List<NodeInfo> reply = (List<NodeInfo>) waiter.getReplyObject();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got " + reply.size() + " nodes");
for (NodeInfo ni : reply) {
if (!(ni.equals(_myNodeInfo) || tried.contains(ni) || toTry.contains(ni)))
toTry.add(ni);
}
} else if (replyType == REPLY_NETWORK_FAIL) {
break;
} else {
if (_log.shouldLog(Log.INFO))
_log.info("Got unexpected reply " + replyType + ": " + waiter.getReplyObject());
}
if (_context.clock().now() > endTime)
break;
if (!toTry.isEmpty() && !heardFrom.isEmpty() && comp.compare(toTry.first(), heardFrom.first()) >= 0) {
if (_log.shouldLog(Log.INFO))
_log.info("Finished get Peers, nothing closer to try after " + (i + 1));
break;
}
}
// now announce
if (!heardFrom.isEmpty()) {
announce(ih, isSeed);
// announce to the closest we've heard from
int annCnt = 0;
long start = _context.clock().now();
for (Iterator<NodeInfo> iter = heardFrom.iterator(); iter.hasNext() && annCnt < annMax && _isRunning; ) {
NodeInfo annTo = iter.next();
if (_log.shouldLog(Log.INFO))
_log.info("Announcing to closest from get peers: " + annTo);
long toWait = annMaxWait > 0 ? Math.min(annMaxWait, 60 * 1000) : 0;
if (announce(ih, annTo, toWait, isSeed))
annCnt++;
if (annMaxWait > 0) {
annMaxWait -= _context.clock().now() - start;
if (annMaxWait < 1000)
break;
}
}
} else {
// so this is essentially just a retry
if (_log.shouldLog(Log.INFO))
_log.info("Announcing to closest in kbuckets after get peers failed");
announce(ih, annMax, annMaxWait, isSeed);
}
if (_log.shouldLog(Log.INFO)) {
_log.info("Finished get Peers, returning " + rv.size());
_log.info("Tried: " + tried);
_log.info("Heard from: " + heardFrom);
_log.info("Not tried: " + toTry);
}
return rv;
}
use of net.i2p.data.Hash in project i2p.i2p by i2p.
the class KRPC method announce.
/**
* Announce somebody else we know about to ourselves.
* Non-blocking.
*
* @param ih the Info Hash (torrent)
* @param peerHash the peer's Hash
*/
public void announce(byte[] ih, byte[] peerHash, boolean isSeed) {
InfoHash iHash = new InfoHash(ih);
_tracker.announce(iHash, new Hash(peerHash), isSeed);
// Do NOT do this, corrupts the Hash cache and the Peer ID
// _tracker.announce(iHash, Hash.create(peerHash));
}
use of net.i2p.data.Hash in project i2p.i2p by i2p.
the class KRPC method receiveGetPeers.
/**
* Handle and respond to the query
*/
private void receiveGetPeers(MsgID msgID, NodeInfo nInfo, InfoHash ih, boolean noSeeds) throws InvalidBEncodingException {
if (_log.shouldLog(Log.INFO))
_log.info("Rcvd get_peers from: " + nInfo + " for: " + ih + " noseeds? " + noSeeds);
// generate and save random token
Token token = new Token(_context);
_outgoingTokens.put(token, nInfo);
if (_log.shouldLog(Log.INFO))
_log.info("Stored new OB token: " + token + " for: " + nInfo);
List<Hash> peers = _tracker.getPeers(ih, MAX_WANT, noSeeds);
// Check this before removing him, so we don't needlessly send nodes
// if he's the only one on the torrent.
boolean noPeers = peers.isEmpty();
// him
peers.remove(nInfo.getHash());
if (noPeers) {
// similar to find node, but with token
// get closest from DHT
List<NodeInfo> nodes = _knownNodes.findClosest(ih, K);
// him
nodes.remove(nInfo);
// me
nodes.remove(_myNodeInfo);
byte[] nodeArray = new byte[nodes.size() * NodeInfo.LENGTH];
for (int i = 0; i < nodes.size(); i++) {
System.arraycopy(nodes.get(i).getData(), 0, nodeArray, i * NodeInfo.LENGTH, NodeInfo.LENGTH);
}
sendNodes(nInfo, msgID, token, nodeArray);
} else {
List<byte[]> hashes;
if (peers.isEmpty()) {
hashes = Collections.emptyList();
} else {
hashes = new ArrayList<byte[]>(peers.size());
for (Hash peer : peers) {
hashes.add(peer.getData());
}
}
sendPeers(nInfo, msgID, token, hashes);
}
}
use of net.i2p.data.Hash in project i2p.i2p by i2p.
the class KRPC method receivePeers.
/**
* rcv 32 byte Hashes, return as a List
* @throws NPE, IllegalArgumentException, and others too
*/
private List<Hash> receivePeers(NodeInfo nInfo, List<BEValue> peers) throws InvalidBEncodingException {
if (_log.shouldLog(Log.INFO))
_log.info("Rcvd peers from: " + nInfo);
int max = Math.min(MAX_WANT * 2, peers.size());
List<Hash> rv = new ArrayList<Hash>(max);
for (BEValue bev : peers) {
byte[] b = bev.getBytes();
if (b.length != Hash.HASH_LENGTH) {
if (_log.shouldWarn())
_log.info("Bad peers entry from: " + nInfo);
continue;
}
// Hash h = new Hash(b);
Hash h = Hash.create(b);
rv.add(h);
if (rv.size() >= max)
break;
}
if (_log.shouldLog(Log.INFO))
_log.info("Rcvd " + peers.size() + " peers from: " + nInfo + ": " + DataHelper.toString(rv));
return rv;
}
use of net.i2p.data.Hash in project i2p.i2p by i2p.
the class NewsFetcher method processBlocklistEntries.
/**
* Process blocklist entries
*
* @since 0.9.28
*/
private void processBlocklistEntries(BlocklistEntries ble) {
long oldTime = _context.getProperty(PROP_BLOCKLIST_TIME, 0L);
if (ble.updated <= oldTime) {
if (_log.shouldWarn())
_log.warn("Not processing blocklist " + new Date(ble.updated) + ", already have " + new Date(oldTime));
return;
}
Blocklist bl = _context.blocklist();
Banlist ban = _context.banlist();
DateFormat fmt = DateFormat.getDateInstance(DateFormat.SHORT);
fmt.setTimeZone(SystemVersion.getSystemTimeZone(_context));
String reason = "Blocklist feed " + new Date(ble.updated);
int banned = 0;
for (Iterator<String> iter = ble.entries.iterator(); iter.hasNext(); ) {
String s = iter.next();
if (s.length() == 44) {
byte[] b = Base64.decode(s);
if (b == null || b.length != Hash.HASH_LENGTH) {
iter.remove();
continue;
}
Hash h = Hash.create(b);
if (!ban.isBanlistedForever(h))
ban.banlistRouterForever(h, reason);
} else {
byte[] ip = Addresses.getIP(s);
if (ip == null) {
iter.remove();
continue;
}
if (!bl.isBlocklisted(ip))
bl.add(ip);
}
if (++banned >= BlocklistEntries.MAX_ENTRIES) {
// prevent somebody from destroying the whole network
break;
}
}
for (String s : ble.removes) {
if (s.length() == 44) {
byte[] b = Base64.decode(s);
if (b == null || b.length != Hash.HASH_LENGTH)
continue;
Hash h = Hash.create(b);
if (ban.isBanlistedForever(h))
ban.unbanlistRouter(h);
} else {
byte[] ip = Addresses.getIP(s);
if (ip == null)
continue;
if (bl.isBlocklisted(ip))
bl.remove(ip);
}
}
// Save the blocks. We do not save the unblocks.
File f = new SecureFile(_context.getConfigDir(), BLOCKLIST_DIR);
f.mkdirs();
f = new File(f, BLOCKLIST_FILE);
boolean fail = false;
BufferedWriter out = null;
try {
out = new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(f), "UTF-8"));
out.write("# ");
out.write(ble.supdated);
out.newLine();
banned = 0;
for (String s : ble.entries) {
// IPv6
s = s.replace(':', ';');
out.write(reason);
out.write(':');
out.write(s);
out.newLine();
if (++banned >= BlocklistEntries.MAX_ENTRIES)
break;
}
} catch (IOException ioe) {
_log.error("Error writing blocklist", ioe);
fail = true;
} finally {
if (out != null)
try {
out.close();
} catch (IOException ioe) {
}
}
if (!fail) {
f.setLastModified(ble.updated);
String upd = Long.toString(ble.updated);
_context.router().saveConfig(PROP_BLOCKLIST_TIME, upd);
_mgr.notifyVersionAvailable(this, _currentURI, BLOCKLIST, "", HTTP, null, upd, "");
}
if (_log.shouldWarn())
_log.warn("Processed " + ble.entries.size() + " blocks and " + ble.removes.size() + " unblocks from news feed");
}
Aggregations