package lbms.plugins.mldht.kad;
import lbms.plugins.mldht.kad.DHT.DHTtype;
import lbms.plugins.mldht.kad.messages.FindNodeRequest;
import lbms.plugins.mldht.kad.messages.FindNodeResponse;
import lbms.plugins.mldht.kad.messages.MessageBase;
import lbms.plugins.mldht.kad.messages.MessageBase.Method;
import lbms.plugins.mldht.kad.messages.MessageBase.Type;
/**
* @author Damokles
*
*/
public class KeyspaceCrawler extends Task {
KeyspaceCrawler (RPCServerBase rpc, Node node) {
super(Key.createRandomKey(),rpc, node);
setInfo("Exhaustive Keyspace Crawl");
}
@Override
synchronized void update () {
// go over the todo list and send find node calls
// until we have nothing left
synchronized (todo) {
while (todo.size() > 0 && canDoRequest()) {
KBucketEntry e = todo.first();
todo.remove(e);
// only send a findNode if we haven't allready visited the node
if (!visited.contains(e)) {
// send a findNode to the node
FindNodeRequest fnr;
fnr = new FindNodeRequest(node.getOurID(),Key.createRandomKey());
fnr.setWant4(rpc.getDHT().getType() == DHTtype.IPV4_DHT || DHT.getDHT(DHTtype.IPV4_DHT).getNode().getNumEntriesInRoutingTable() < DHTConstants.BOOTSTRAP_IF_LESS_THAN_X_PEERS);
fnr.setWant6(rpc.getDHT().getType() == DHTtype.IPV6_DHT || DHT.getDHT(DHTtype.IPV6_DHT).getNode().getNumEntriesInRoutingTable() < DHTConstants.BOOTSTRAP_IF_LESS_THAN_X_PEERS);
fnr.setDestination(e.getAddress());
rpcCall(fnr);
if(canDoRequest())
{
fnr = new FindNodeRequest(node.getOurID(),e.getID());
fnr.setWant4(rpc.getDHT().getType() == DHTtype.IPV4_DHT || DHT.getDHT(DHTtype.IPV4_DHT).getNode().getNumEntriesInRoutingTable() < DHTConstants.BOOTSTRAP_IF_LESS_THAN_X_PEERS);
fnr.setWant6(rpc.getDHT().getType() == DHTtype.IPV6_DHT || DHT.getDHT(DHTtype.IPV6_DHT).getNode().getNumEntriesInRoutingTable() < DHTConstants.BOOTSTRAP_IF_LESS_THAN_X_PEERS);
fnr.setDestination(e.getAddress());
rpcCall(fnr);
}
synchronized (visited) {
visited.add(e);
}
}
// remove the entry from the todo list
}
}
if (todo.size() == 0 && getNumOutstandingRequests() == 0
&& !isFinished()) {
done();
}
}
@Override
void callFinished (RPCCallBase c, MessageBase rsp) {
if (isFinished()) {
return;
}
// check the response and see if it is a good one
if (rsp.getMethod() == Method.FIND_NODE
&& rsp.getType() == Type.RSP_MSG) {
FindNodeResponse fnr = (FindNodeResponse) rsp;
for (DHTtype type : DHTtype.values())
{
byte[] nodes = fnr.getNodes(type);
if (nodes == null)
continue;
int nval = nodes.length / type.NODES_ENTRY_LENGTH;
if (type == rpc.getDHT().getType())
{
synchronized (todo)
{
for (int i = 0; i < nval; i++)
{
// add node to todo list
KBucketEntry e = PackUtil.UnpackBucketEntry(nodes, i * type.NODES_ENTRY_LENGTH, type);
if (!e.getID().equals(node.getOurID()) && !todo.contains(e) && !visited.contains(e))
{
todo.add(e);
}
}
}
} else
{
System.out.println("found nodes6");
for (int i = 0; i < nval; i++)
{
KBucketEntry e = PackUtil.UnpackBucketEntry(nodes, i * type.NODES_ENTRY_LENGTH, type);
DHT.getDHT(type).addDHTNode(e.getAddress().getAddress().getHostAddress(), e.getAddress().getPort());
}
}
}
}
}
@Override
boolean canDoRequest() {
return getNumOutstandingRequests() < DHTConstants.MAX_CONCURRENT_REQUESTS * 5;
}
@Override
void kill() {
// do nothing to evade safeties
}
@Override
void callTimeout (RPCCallBase c) {
}
/* (non-Javadoc)
* @see lbms.plugins.mldht.kad.Task#start()
*/
@Override
void start () {
int added = 0;
// delay the filling of the todo list until we actually start the task
KBucket[] buckets = node.getBuckets();
outer: for (int i = buckets.length -1; i >= 1; i--)
if (buckets[i] != null)
for (KBucketEntry e : buckets[i].getEntries())
if (!e.isBad())
{
todo.add(e);
added++;
}
super.start();
}
@Override
protected void done () {
super.done();
System.out.println("crawled "+visited.size()+" nodes");
}
}