/** * When a previously unknown peer contacts us, this method adds it to <code>initialPeers</code> * so it can be used as a bootstrap node. * @param packet * @param sender * @param receiveTime */ @Override public void packetReceived(CommunicationPacket packet, Destination sender, long receiveTime) { initialPeers.add(new KademliaPeer(sender, receiveTime)); } }
private void addPeerData(DhtPeerStatsRenderer renderer, AbstractBucket bucket, Hash localDestinationHash) { for (KademliaPeer peer: bucket) { BigInteger distance = KademliaUtil.getDistance(localDestinationHash, peer.calculateHash()); data.add(new KademliaPeerStatsRow( renderer, data.size() + 1, peer, getBucketPrefix(renderer, bucket), distance, peer.isLocked(), peer.getConsecTimeouts(), peer.getFirstSeen() )); } }
maxSiblingId = MIN_HASH_VALUE; for (KademliaPeer sibling: peers) { BigInteger id = new BigInteger(1, sibling.getDestinationHash().getData()); minSiblingId = minSiblingId.min(id); maxSiblingId = maxSiblingId.max(id);
@Override public int compare(KademliaPeer peer1, KademliaPeer peer2) { if (peer1.isLocked() || peer2.isLocked()) { int n1 = peer1.isLocked() ? 0 : 1; int n2 = peer2.isLocked() ? 0 : 1; return n2 - n1; } else return Long.valueOf(peer2.getFirstSeen()).compareTo(peer1.getFirstSeen()); } });
KademliaPeer(Destination destination, long lastReception) { // initialize the Destination part of the KademliaPeer setCertificate(destination.getCertificate()); setSigningPublicKey(destination.getSigningPublicKey()); setPublicKey(destination.getPublicKey()); // initialize KademliaPeer-specific fields destinationHash = destination.calculateHash(); if (destinationHash == null) log.error("calculateHash() returned null!"); firstSeen = lastReception; }
initialPeers.add(new KademliaPeer(destination)); bootstrapNode.setFirstSeen(System.currentTimeMillis()); // Set the "first seen" time to the current time before every bootstrap attempt bootstrapNode.responseReceived(); // unlock the peer so ClosestNodesLookupTask will give it a chance bucketManager.addOrUpdate(bootstrapNode); log.info("Trying " + Util.toBase32(bootstrapNode) + " for bootstrapping.");
BigInteger peer1Key = new BigInteger(1, peer1.calculateHash().getData()); for (KademliaPeer peer2: bucket2) { BigInteger peer2Key = new BigInteger(1, peer2.calculateHash().getData()); assertTrue(peer1Key.compareTo(peer2Key) == -1); BigInteger peerId = new BigInteger(1, peer.calculateHash().getData()); assertTrue(bucket.getStartId().compareTo(peerId) <= 0); assertTrue(bucket.getEndId().compareTo(peerId) >= 0); Boolean previousBit = null; for (KademliaPeer peer: bucket) { BigInteger peerId = new BigInteger(1, peer.getDestinationHash().getData()); boolean currentBit = peerId.testBit(bitIndex); if (previousBit == null)
private BigInteger maxId(KBucket bucket) { BigInteger maxId = null; for (KademliaPeer peer: bucket.getPeers()) { BigInteger id = new BigInteger(1, peer.calculateHash().getData()); if (maxId==null || id.compareTo(maxId)>0) maxId = id; } return maxId; }
peers.get(index).responseReceived(); return null; log.error("insertionPoint > size(), this shouldn't happen."); if (insertionPoint < size()) { // if destination is closer than an existing sibling, replace the furthest away sibling and return the removed sibling peers.add(insertionPoint, new KademliaPeer(peer)); KademliaPeer removedPeer = peers.remove(size() - 1); return removedPeer;
/** * Returns all peers that are not locked. * @return */ public synchronized List<Destination> getAllUnlockedPeers() { List<Destination> allPeers = new ArrayList<Destination>(); for (KBucket bucket: kBuckets) for (KademliaPeer peer: bucket.getPeers()) if (!peer.isLocked()) allPeers.add(peer); for (KademliaPeer peer: sBucket.getPeers()) if (!peer.isLocked()) allPeers.add(peer); return allPeers; }
/** * Notifies the <code>BucketManager</code> that a peer didn't respond to * a request. * @param destination */ public synchronized void noResponse(Destination destination) { KademliaPeer peer = getPeer(destination); if (peer != null) peer.noResponse(); else log.debug("Peer not found in buckets: " + Util.toBase32(destination)); // this happens when a peer that was not yet known is contacted and fails to respond }
/** * Updates a known peer, or adds the peer if it isn't known. If the bucket * is full and the replacement cache is not empty, the oldest peer is removed * before adding the new peer. * If the bucket is full and the replacement cache is empty, the peer is * added to the replacement cache. * @param peer */ void addOrUpdate(KademliaPeer peer) { // TODO log an error if peer outside bucket's range int index = getPeerIndex(peer); if (index >= 0) { KademliaPeer existingPeer = peers.remove(index); existingPeer.responseReceived(); add(existingPeer); } else { if (!isFull()) add(peer); else addOrUpdateReplacement(peer); } }
private BigInteger minId(KBucket bucket) { BigInteger minId = null; for (KademliaPeer peer: bucket.getPeers()) { BigInteger id = new BigInteger(1, peer.calculateHash().getData()); if (minId==null || id.compareTo(minId)<0) minId = id; } return minId; }
/** * Adds a peer to the tail of the bucket if it is locked, or to the * head of the bucket if it isn't locked. * The bucket cannot be full when calling this method. * @param peer */ private void add(KademliaPeer peer) { if (isFull()) log.error("Error: adding a node to a full k-bucket. Bucket needs to be split first. Size=" + size() + ", capacity=" + capacity); if (peer.isLocked()) peers.add(peer); else peers.add(0, peer); }
/** * Creates peer destinations from a <code>String</code> each, and adds them to <code>initialPeers</code>. * @param peerFileEntries A list of <code>String</code>s as they appear in the peer file */ private void addPeers(List<String> peerFileEntries) { for (String line: peerFileEntries) { if (!line.trim().isEmpty() && !line.startsWith("#")) try { Destination destination = new Destination(line); // don't add the local destination as a peer if (!destination.equals(localDestination)) { KademliaPeer peer = new KademliaPeer(destination, 0); initialPeers.add(peer); } } catch (DataFormatException e) { log.error("Invalid destination key in line " + line, e); } } }
/** * Splits the bucket in two by keeping all peers with a DHT key less than * <code>pivot</code> in the existing bucket, and moving the rest into a new bucket. * @param pivot * @return The new bucket (which contains the higher IDs) */ private KBucket split(BigInteger pivot) { depth++; KBucket newBucket = new KBucket(pivot, endId, depth); endId = pivot; for (int i=peers.size()-1; i>=0; i--) { KademliaPeer peer = peers.get(i); BigInteger nodeId = new BigInteger(1, peer.getDestinationHash().getData()); if (nodeId.compareTo(pivot) >= 0) { newBucket.add(peer); remove(peer); } } return newBucket; }
int bucketIndex = getBucketIndex(peer.calculateHash()); KBucket bucket = kBuckets.get(bucketIndex); bucket = getKBucket(peer.calculateHash());
@Override public void packetReceived(CommunicationPacket packet, Destination sender, long receiveTime) { BanList banList = BanList.getInstance(); banList.update(sender, packet); if (!banList.isBanned(sender)) // any type of incoming packet updates the peer's record in the bucket/sibling list, or adds the peer to the bucket/sibling list addOrUpdate(new KademliaPeer(sender)); else remove(sender); }
/** * Moves peers from the k-buckets to the s-bucket until the s-bucket is full * or all k-buckets are empty. */ private void refillSiblings() { // Sort all k-peers by distance to the local destination List<KademliaPeer> kPeers = new ArrayList<KademliaPeer>(); for (KBucket kBucket: kBuckets) kPeers.addAll(kBucket.getPeers()); Collections.sort(kPeers, new PeerDistanceComparator(localDestinationHash)); while (!sBucket.isFull() && !kPeers.isEmpty()) { // move the closest k-peer to the s-bucket KademliaPeer peerToMove = kPeers.remove(0); int bucketIndex = getBucketIndex(peerToMove.getDestinationHash()); kBuckets.get(bucketIndex).remove(peerToMove); sBucket.addOrUpdate(peerToMove); } }
@Test public void testIsFull() { for (KBucket bucket: buckets) { Destination[] destinations = destinationMap.get(bucket); for (int i=0; i<K-1; i++) { bucket.addOrUpdate(new KademliaPeer(destinations[i])); assertFalse(bucket.isFull()); } bucket.addOrUpdate(new KademliaPeer(destinations[K-1])); assertTrue(bucket.isFull()); } }