package lbms.plugins.mldht.kad;
import java.io.Serializable;
import java.net.InetSocketAddress;
import java.util.Comparator;
/**
* Entry in a KBucket, it basically contains an ip_address of a node,
* the udp port of the node and a node_id.
*
* @author Damokles
*/
public class KBucketEntry implements Serializable {
/**
* ascending order for last seen, i.e. the last value will be the least recently seen one
*/
public static final Comparator<KBucketEntry> LAST_SEEN_ORDER = new Comparator<KBucketEntry>() {
public int compare(KBucketEntry o1, KBucketEntry o2) {
return Long.signum(o1.lastSeen - o2.lastSeen);
}
};
/**
* ascending order for timeCreated, i.e. the first value will be the oldest
*/
public static final Comparator<KBucketEntry> AGE_ORDER = new Comparator<KBucketEntry>() {
public int compare(KBucketEntry o1, KBucketEntry o2) {
return Long.signum(o1.timeCreated - o2.timeCreated);
}
};
public static final class DistanceOrder implements Comparator<KBucketEntry> {
final Key target;
public DistanceOrder(Key target) {
this.target = target;
}
public int compare(KBucketEntry o1, KBucketEntry o2) {
return target.distance(o1.getID()).compareTo(target.distance(o2.getID()));
}
}
private static final long serialVersionUID = 3230342110307814047L;
private InetSocketAddress addr;
private Key nodeID;
private long lastSeen;
private int failedQueries = 0;
private long timeCreated;
private String version;
/**
* Constructor, sets everything to 0.
* @return
*/
public KBucketEntry () {
lastSeen = System.currentTimeMillis();
timeCreated = lastSeen;
}
/**
* Constructor, set the ip, port and key
* @param addr socket address
* @param id ID of node
*/
public KBucketEntry (InetSocketAddress addr, Key id) {
lastSeen = System.currentTimeMillis();
timeCreated = lastSeen;
this.addr = addr;
this.nodeID = id;
}
/**
* Constructor, set the ip, port and key
* @param addr socket address
* @param id ID of node
* @param timestamp the timestamp when this node last responded
*/
public KBucketEntry (InetSocketAddress addr, Key id, long timestamp) {
lastSeen = timestamp;
timeCreated = timestamp;
this.addr = addr;
this.nodeID = id;
}
/**
* Copy constructor.
* @param other KBucketEntry to copy
* @return
*/
public KBucketEntry (KBucketEntry other) {
addr = other.addr;
nodeID = other.nodeID;
lastSeen = other.lastSeen;
failedQueries = other.failedQueries;
timeCreated = other.timeCreated;
}
/**
* @return the address of the node
*/
public InetSocketAddress getAddress () {
return addr;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals (Object obj) {
if (obj instanceof KBucketEntry) {
KBucketEntry other = (KBucketEntry) obj;
return nodeID.equals(other.nodeID)
|| addr.getAddress().equals(other.addr.getAddress());
}
return super.equals(obj);
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode () {
return addr.hashCode() ^ nodeID.hashCode();
}
/**
* @return id
*/
public Key getID () {
return nodeID;
}
/**
* @param version the version to set
*/
public void setVersion (String version) {
this.version = version;
}
/**
* @return the version
*/
public String getVersion () {
return version;
}
/**
* @return the last_responded
*/
public long getLastSeen () {
return lastSeen;
}
public long getCreationTime() {
return timeCreated;
}
/**
* @return the failedQueries
*/
public int getFailedQueries () {
return failedQueries;
}
/**
* Checks if the node is Good.
*
* A node is considered Good if it has responded in the last 15 min
*
* @return true if the node as responded in the last 15 min.
*/
public boolean isGood () {
return !isQuestionable();
}
/**
* Checks if a node is Questionable.
*
* A node is considered Questionable if it hasn't responded in the last 15 min
*
* @return true if peer hasn't responded in the last 15 min.
*/
public boolean isQuestionable () {
return (System.currentTimeMillis() - lastSeen > DHTConstants.KBE_QUESTIONABLE_TIME || isBad());
}
/**
* Checks if a node is Bad.
*
* A node is bad if it isn't good and hasn't responded the last 3 queries, or
* failed 5 times. i
*
* @return true if bad
*/
public boolean isBad () {
if (failedQueries >= DHTConstants.KBE_BAD_IMMEDIATLY_ON_FAILED_QUERIES) {
return true;
}
if(System.currentTimeMillis() - lastSeen > DHTConstants.KBE_QUESTIONABLE_TIME &&
failedQueries > DHTConstants.KBE_BAD_IF_FAILED_QUERIES_LARGER_THAN) {
return true;
}
return false;
}
/**
* Should be called to signal that the peer has responded
*/
public void signalLastSeen () {
lastSeen = System.currentTimeMillis();
}
public void signalResponse() {
lastSeen = System.currentTimeMillis();
failedQueries = 0;
}
/**
* Should be called to signal that a request to this peer has timed out;
*/
public void signalRequestTimeout () {
failedQueries++;
}
}