use of net.i2p.data.Destination in project i2p.i2p-bote by i2p.
the class KademliaDHT method getDhtResults.
/**
* Returns all <code>DhtStorablePacket</code> packets that have been received as a response to a send batch,
* plus <code>localResult</code> if it is non-<code>null</code>.
* @param batch
* @param localResult
*/
private DhtResults getDhtResults(PacketBatch batch, DhtStorablePacket localResult) {
Map<Destination, DataPacket> responses = batch.getResponses();
DhtResults results = new DhtResults();
for (Entry<Destination, DataPacket> result : responses.entrySet()) {
DataPacket packet = result.getValue();
if (packet instanceof DhtStorablePacket)
results.put(result.getKey(), (DhtStorablePacket) packet);
}
int totalResponses = responses.size();
if (localResult != null) {
results.put(localDestination, localResult);
totalResponses++;
}
results.setTotalResponses(totalResponses);
return results;
}
use of net.i2p.data.Destination in project i2p.i2p-bote by i2p.
the class KademliaDHT method store.
@Override
public void store(DhtStorablePacket packet) throws DhtException, InterruptedException {
Hash key = packet.getDhtKey();
log.info("Looking up nodes to store a " + packet.getClass().getSimpleName() + " with key " + key);
List<Destination> closeNodes = getClosestNodes(key);
if (closeNodes.isEmpty())
throw new DhtException("Cannot store packet because no storage nodes found.");
// store on local node if appropriate
if (!closeNodes.contains(localDestination))
if (closeNodes.size() < KademliaConstants.K || isCloser(localDestination, closeNodes.get(0), key))
closeNodes.add(localDestination);
log.info("Storing a " + packet.getClass().getSimpleName() + " with key " + key + " on " + closeNodes.size() + " nodes");
PacketBatch batch = new PacketBatch();
for (Destination node : closeNodes) if (localDestination.equals(node))
storeLocally(packet, null);
else {
// use a separate packet id for each request
StoreRequest storeRequest = new StoreRequest(packet);
batch.putPacket(storeRequest, node);
}
sendQueue.send(batch);
batch.awaitSendCompletion();
// TODO awaitAllResponses, repeat if necessary
sendQueue.remove(batch);
}
use of net.i2p.data.Destination in project i2p.i2p-bote by i2p.
the class ReplicateThread method replicate.
private void replicate() throws InterruptedException {
log.debug("Replicating DHT data...");
replicationRunning = true;
// refresh peers close to the local destination
ClosestNodesLookupTask lookupTask = new ClosestNodesLookupTask(localDestination.calculateHash(), sendQueue, i2pReceiver, bucketManager);
List<Destination> closestNodes = lookupTask.call();
closestNodes.remove(localDestination);
int numReplicated = 0;
int numSkipped = 0;
// If a peer responds with a delete request, replicate the delete request instead.
for (DhtStorageHandler dhtStore : dhtStores) for (Iterator<? extends DhtStorablePacket> packetIterator = dhtStore.individualPackets(); packetIterator.hasNext(); ) {
DhtStorablePacket packet = packetIterator.next();
Hash dhtKey = packet.getDhtKey();
if (!keysToSkip.contains(dhtKey)) {
StoreRequest request = new StoreRequest(packet);
List<Destination> closestPeers = bucketManager.getClosestPeers(dhtKey, KademliaConstants.K);
for (Destination peer : closestPeers) {
// Send the store request and give the peer time to respond with a delete request
sendQueue.send(request, peer).await(SEND_TIMEOUT_MINUTES, TimeUnit.MINUTES);
TimeUnit.SECONDS.sleep(WAIT_TIME_SECONDS);
// If we received a delete request for the DHT item, notify the other close peers
DeleteRequest delRequest = receivedDeleteRequests.get(dhtKey);
if (delRequest != null) {
// KademliaDHT handles the delete request for local data, but we forward the
// request to the other nodes close to the DHT key.
// Note that the delete request contains only one entry, see packetReceived()
sendDeleteRequest(delRequest, closestPeers, peer);
break;
}
}
numReplicated++;
} else
numSkipped++;
}
keysToSkip.clear();
replicationRunning = false;
receivedDeleteRequests.clear();
log.debug("Replication finished. Replicated " + numReplicated + " packets, skipped: " + numSkipped);
}
use of net.i2p.data.Destination in project i2p.i2p-bote by i2p.
the class RelayPeerManager method run.
@Override
public void run() {
while (!Thread.interrupted()) {
try {
// ask all peers for their peer lists
Set<RelayPeer> peersToQuery = new HashSet<RelayPeer>(peers);
PacketBatch batch = new PacketBatch();
for (RelayPeer peer : peersToQuery) // don't reuse request packets because PacketBatch will not add the same one more than once
batch.putPacket(new PeerListRequest(), peer);
sendQueue.send(batch);
batch.awaitSendCompletion();
batch.awaitAllResponses(2, TimeUnit.MINUTES);
// build a Set of destinations
Set<Destination> responders = batch.getResponses().keySet();
// update reachability data
log.debug("Relay peer stats:");
for (RelayPeer peer : peersToQuery) {
// use peersToQuery (not peers) so new peers that have been added in the meantime are not wrongly considered unresponsive
boolean didRespond = responders.contains(peer);
peer.addReachabilitySample(didRespond);
if (log.shouldLog(Log.DEBUG)) {
StringBuilder logMessage = new StringBuilder(" ");
logMessage.append(Util.toBase32(peer));
logMessage.append(" ");
for (boolean responded : peer.getAllSamples()) logMessage.append(responded ? '*' : '.');
log.debug(logMessage.toString());
}
}
// make a Set with the new peers
Set<Destination> receivedPeers = new HashSet<Destination>();
BanList banList = BanList.getInstance();
for (DataPacket response : batch.getResponses().values()) {
if (!(response instanceof PeerList))
continue;
PeerList peerList = (PeerList) response;
for (Destination peer : peerList.getPeers()) if (!banList.isBanned(peer))
receivedPeers.add(peer);
}
log.debug("Received a total of " + receivedPeers.size() + " relay peers in " + batch.getResponses().size() + " packets.");
// replace low-reachability peers with new peers (a PeerList is supposed to contain only high-reachability peers)
synchronized (peers) {
// add all received peers, then remove low-reachability ones (all of which are existing peers)
for (Destination newPeer : receivedPeers) if (!localDestination.equals(newPeer))
peers.add(new RelayPeer(newPeer));
for (Iterator<RelayPeer> iterator = peers.iterator(); iterator.hasNext(); ) {
if (peers.size() <= MAX_PEERS)
break;
RelayPeer peer = iterator.next();
if (// don't remove the peer before it has had a chance to respond to a request
!peer.getAllSamples().isEmpty() && peer.getReachability() < MIN_REACHABILITY)
iterator.remove();
}
}
log.debug("Number of relay peers is now " + peers.size());
// if no good peers available, ask more often
if (getGoodPeers().isEmpty())
TimeUnit.MINUTES.sleep(UPDATE_INTERVAL_SHORT);
else
TimeUnit.MINUTES.sleep(UPDATE_INTERVAL_LONG);
} catch (InterruptedException e) {
break;
} catch (RuntimeException e) {
// catch unexpected exceptions to keep the thread running
log.error("Exception caught in RelayPeerManager loop", e);
}
}
writePeers(peerFile);
log.debug("RelayPeerManager thread exiting.");
}
use of net.i2p.data.Destination in project i2p.i2p-bote by i2p.
the class RelayRequest method create.
/**
* Creates a <code>RelayRequest</code> containing <code>numHops</code> nested
* <code>RelayRequest</code>s<br/>
* Returns <code>null</code> if <code>numHops</code> is <code>0</code>.
* @param payload
* @param peerManager For obtaining relay peers
* @param numHops
* @param minDelay The minimum delay in milliseconds
* @param maxDelay The maximum delay in milliseconds
*/
public static RelayRequest create(CommunicationPacket payload, RelayPeerManager peerManager, int numHops, long minDelay, long maxDelay) {
List<Destination> relayPeers = peerManager.getRandomPeers(numHops);
Log log = new Log(RelayRequest.class);
if (log.shouldLog(Log.DEBUG)) {
StringBuilder debugMsg = new StringBuilder("Creating relay chain: [");
for (int i = relayPeers.size() - 1; i >= 0; i--) {
debugMsg.append(Util.toShortenedBase32(relayPeers.get(i)));
if (i > 0)
debugMsg.append(" --> ");
}
debugMsg.append("]");
log.debug(debugMsg.toString());
}
// calculate the number of pad bytes necessary to pad the payload to the maximum size possible
int maxSize = I2PBotePacket.MAX_DATAGRAM_SIZE - getMaxOverhead(numHops);
int padBytes = maxSize - payload.getSize();
if (padBytes < 0)
padBytes = 0;
CommunicationPacket request = payload;
for (Destination relayPeer : relayPeers) {
// generate a random time between minDelay and maxDelay in the future
long delay;
if (minDelay == maxDelay)
delay = minDelay;
else
delay = minDelay + Math.abs(random.nextLong()) % Math.abs(maxDelay - minDelay);
request = new RelayRequest(request, relayPeer, delay, padBytes);
// only pad the innermost packet (the payload)
padBytes = 0;
}
return (RelayRequest) request;
}
Aggregations