Finished NodeLookupOperation functionality! Finally found the bug

This commit is contained in:
Joshua Kissoon 2014-02-22 19:37:04 +05:30
parent 9eca0614f2
commit 3344511603
10 changed files with 153 additions and 57 deletions

View File

@ -16,7 +16,7 @@ public class Configuration
* If no reply received from a node in this period (in milliseconds) * If no reply received from a node in this period (in milliseconds)
* consider the node unresponsive. * consider the node unresponsive.
* */ * */
public static long RESPONSE_TIMEOUT = 3000; public static long RESPONSE_TIMEOUT = 1500;
/** /**
* Maximum number of milliseconds for performing an operation. * Maximum number of milliseconds for performing an operation.
@ -36,7 +36,7 @@ public class Configuration
/** /**
* Bucket size. * Bucket size.
* */ * */
public static int K = 3; public static int K = 5;
/** /**
* Size of replacement cache. * Size of replacement cache.

View File

@ -35,6 +35,8 @@ public class KadServer
private final HashMap<Integer, Receiver> receivers; private final HashMap<Integer, Receiver> receivers;
private final Timer timer; // Schedule future tasks private final Timer timer; // Schedule future tasks
private final HashMap<Integer, TimerTask> tasks; // Keep track of scheduled tasks private final HashMap<Integer, TimerTask> tasks; // Keep track of scheduled tasks
private final Node localNode;
/* Factories */ /* Factories */
private final MessageFactory messageFactory; private final MessageFactory messageFactory;
@ -47,10 +49,12 @@ public class KadServer
this.timer = new Timer(true); this.timer = new Timer(true);
} }
public KadServer(int udpPort, MessageFactory mFactory) throws SocketException public KadServer(int udpPort, MessageFactory mFactory, Node localNode) throws SocketException
{ {
this.udpPort = udpPort; this.udpPort = udpPort;
this.socket = new DatagramSocket(udpPort); this.socket = new DatagramSocket(udpPort);
this.localNode = localNode;
this.messageFactory = mFactory; this.messageFactory = mFactory;
@ -128,7 +132,7 @@ public class KadServer
if (data.length > DATAGRAM_BUFFER_SIZE) if (data.length > DATAGRAM_BUFFER_SIZE)
{ {
throw new IOException("MEssage is too big"); throw new IOException("Message is too big");
} }
/* Everything is good, now create the packet and send it */ /* Everything is good, now create the packet and send it */
@ -163,9 +167,7 @@ public class KadServer
Message msg = messageFactory.createMessage(messCode, din); Message msg = messageFactory.createMessage(messCode, din);
din.close(); din.close();
System.out.println("Message Received: " + msg); System.out.println(this.localNode.getNodeId() + " Message Received: " + msg);
System.out.println("Receivers: " + receivers);
/* Get a receiver for this message */ /* Get a receiver for this message */
Receiver receiver; Receiver receiver;

View File

@ -49,7 +49,7 @@ public class Kademlia
this.name = name; this.name = name;
this.localNode = new Node(defaultId, InetAddress.getLocalHost(), udpPort); this.localNode = new Node(defaultId, InetAddress.getLocalHost(), udpPort);
this.messageFactory = new MessageFactory(localNode); this.messageFactory = new MessageFactory(localNode);
this.server = new KadServer(udpPort, this.messageFactory); this.server = new KadServer(udpPort, this.messageFactory, this.localNode);
this.timer = new Timer(true); this.timer = new Timer(true);
/* Schedule Recurring RestoreOperation */ /* Schedule Recurring RestoreOperation */

View File

@ -39,7 +39,7 @@ public class NodeLookupReceiver implements Receiver
Node origin = msg.getOrigin(); Node origin = msg.getOrigin();
System.out.println(this.localNode.getNodeId() + ": Received incoming NodeLookupMessage, sending NodeReplyMessage to: " + origin.getNodeId()); System.out.println(this.localNode.getNodeId() + ": Received NodeLookupMessage, sending NodeReplyMessage to: " + origin.getNodeId());
/* Update the local space by inserting the origin node. */ /* Update the local space by inserting the origin node. */
this.localNode.getRoutingTable().insert(origin); this.localNode.getRoutingTable().insert(origin);

View File

@ -117,6 +117,28 @@ public class Node implements Streamable
return this.routingTable; return this.routingTable;
} }
@Override
public boolean equals(Object o)
{
if (o instanceof Node)
{
return this.getNodeId().equals(((Node) o).getNodeId());
}
return false;
}
@Override
public int hashCode()
{
return this.getNodeId().hashCode();
}
@Override
public String toString()
{
return this.getNodeId().toString();
}
/** /**
* A DistanceComparator is used to compare Node objects based on their closeness * A DistanceComparator is used to compare Node objects based on their closeness
* */ * */
@ -145,23 +167,36 @@ public class Node implements Streamable
{ {
Node n1 = (Node) o1; Node n1 = (Node) o1;
Node n2 = (Node) o2; Node n2 = (Node) o2;
if(n1.getNodeId().equals(n2.getNodeId()))
int index1 = nodeId.xor(n1.getNodeId()).getFirstSetBitIndex();
int index2 = nodeId.xor(n2.getNodeId()).getFirstSetBitIndex();
/* If the first node is closer to the given node, return 1 */
if (index1 < index2)
{
return 1;
}
else if (index1 > index2)
{
return -1;
}
else
{ {
return 0; return 0;
} }
//System.out.println("\n **************** Compare Starting **************** ");
//System.out.println("Comparing to: " + this.nodeId);
int index1 = nodeId.xor(n1.getNodeId()).getFirstSetBitIndex();
//System.out.println("Node " + n1.getNodeId() + " distance: " + index1);
int index2 = nodeId.xor(n2.getNodeId()).getFirstSetBitIndex();
//System.out.println("Node " + n2.getNodeId() + " distance: " + index2);
/* If the first node is closer to the given node, return 1 */
int retval;
if (index1 < index2)
{
retval = 1;
}
else if (index1 > index2)
{
retval = -1;
}
else
{
retval = -1;
}
//System.out.println("Returned: " + retval);
//System.out.println("**************** Compare Ended ***************** \n");
return retval;
} }
} }
} }

View File

@ -8,13 +8,14 @@ package kademlia.node;
import java.io.DataInput; import java.io.DataInput;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import java.math.BigInteger;
import java.util.Arrays; import java.util.Arrays;
import java.util.Random; import java.util.Random;
import kademlia.message.Streamable; import kademlia.message.Streamable;
public class NodeId implements Streamable public class NodeId implements Streamable
{ {
public final static int ID_LENGTH = 160; public final static int ID_LENGTH = 160;
private byte[] keyBytes; private byte[] keyBytes;
@ -38,7 +39,7 @@ public class NodeId implements Streamable
keyBytes = new byte[ID_LENGTH / 8]; keyBytes = new byte[ID_LENGTH / 8];
new Random().nextBytes(keyBytes); new Random().nextBytes(keyBytes);
} }
public NodeId(byte[] bytes) public NodeId(byte[] bytes)
{ {
this.keyBytes = bytes; this.keyBytes = bytes;
@ -55,7 +56,7 @@ public class NodeId implements Streamable
{ {
this.fromStream(in); this.fromStream(in);
} }
public byte[] getBytes() public byte[] getBytes()
{ {
return this.keyBytes; return this.keyBytes;
@ -71,7 +72,7 @@ public class NodeId implements Streamable
@Override @Override
public boolean equals(Object o) public boolean equals(Object o)
{ {
if (o instanceof NodeId) if (o instanceof NodeId)
{ {
NodeId nid = (NodeId) o; NodeId nid = (NodeId) o;
@ -79,11 +80,13 @@ public class NodeId implements Streamable
} }
return false; return false;
} }
@Override @Override
public int hashCode() public int hashCode()
{ {
return Arrays.hashCode(this.getBytes()); int hash = 7;
hash = 83 * hash + Arrays.hashCode(this.keyBytes);
return hash;
} }
/** /**
@ -119,12 +122,17 @@ public class NodeId implements Streamable
{ {
byte[] result = new byte[ID_LENGTH / 8]; byte[] result = new byte[ID_LENGTH / 8];
byte[] nidBytes = nid.getBytes(); byte[] nidBytes = nid.getBytes();
for (int i = 0; i < ID_LENGTH / 8; i++) for (int i = 0; i < ID_LENGTH / 8; i++)
{ {
result[i] = (byte) (this.keyBytes[i] ^ nidBytes[i]); result[i] = (byte) (this.keyBytes[i] ^ nidBytes[i]);
//System.out.println("XOR Result: " + result[i]);
} }
return new NodeId(result); NodeId resNid = new NodeId(result);
//System.out.println("Resulting Nid: " + resNid + " First set bit: " + resNid.getFirstSetBitIndex());
return resNid;
} }
/** /**
@ -135,7 +143,7 @@ public class NodeId implements Streamable
public int getFirstSetBitIndex() public int getFirstSetBitIndex()
{ {
int prefixLength = 0; int prefixLength = 0;
for (byte b : this.keyBytes) for (byte b : this.keyBytes)
{ {
if (b == 0) if (b == 0)
@ -168,14 +176,14 @@ public class NodeId implements Streamable
} }
return ID_LENGTH - prefixLength; return ID_LENGTH - prefixLength;
} }
@Override @Override
public void toStream(DataOutput out) throws IOException public void toStream(DataOutput out) throws IOException
{ {
/* Add the NodeId to the stream */ /* Add the NodeId to the stream */
out.write(this.getBytes()); out.write(this.getBytes());
} }
@Override @Override
public void fromStream(DataInput in) throws IOException public void fromStream(DataInput in) throws IOException
{ {
@ -183,14 +191,16 @@ public class NodeId implements Streamable
in.readFully(input); in.readFully(input);
this.keyBytes = input; this.keyBytes = input;
} }
@Override @Override
public String toString() public String toString()
{ {
StringBuilder sb = new StringBuilder("NodeId: "); // StringBuilder sb = new StringBuilder("NodeId: ");
sb.append(new String(this.keyBytes)); BigInteger bi = new BigInteger(1, this.keyBytes);
return String.format("%0" + (this.keyBytes.length << 1) + "X", bi);
return sb.toString(); //sb.append(Hex.encodeBase64URLSafeString(this.keyBytes));
//return sb.toString();
} }
} }

View File

@ -125,11 +125,20 @@ public class NodeLookupOperation implements Operation, Receiver
for (Node o : list) for (Node o : list)
{ {
/* If this node is not in the list, add the node */ /* If this node is not in the list, add the node */
System.out.println("Trying to add node " + o.getNodeId() + " hash: " + o.hashCode());
System.out.println("Contains Key for this node: " + nodes.containsKey(o));
if (!nodes.containsKey(o)) if (!nodes.containsKey(o))
{ {
System.out.println("Adding unasked node " + o.getNodeId());
nodes.put(o, UNASKED); nodes.put(o, UNASKED);
} }
} }
System.out.println(this.localNode.getNodeId() + " Nodes List: ");
for (Node o : this.nodes.keySet())
{
System.out.println(o.getNodeId() + " hash: " + o.hashCode());
}
} }
/** /**
@ -153,6 +162,11 @@ public class NodeLookupOperation implements Operation, Receiver
/* Get unqueried nodes among the K closest seen that have not FAILED */ /* Get unqueried nodes among the K closest seen that have not FAILED */
ArrayList<Node> unasked = this.closestNodesNotFailed(UNASKED); ArrayList<Node> unasked = this.closestNodesNotFailed(UNASKED);
System.out.println("Unasked nodes found: ");
for (Node nn : unasked)
{
System.out.println(nn.getNodeId());
}
if (unasked.isEmpty() && this.messagesTransiting.isEmpty()) if (unasked.isEmpty() && this.messagesTransiting.isEmpty())
{ {
@ -256,6 +270,7 @@ public class NodeLookupOperation implements Operation, Receiver
/* Add the origin node to our routing table */ /* Add the origin node to our routing table */
Node origin = msg.getOrigin(); Node origin = msg.getOrigin();
System.out.println(this.localNode.getNodeId() + " Lookup Operation Response From: " + origin.getNodeId());
this.localNode.getRoutingTable().insert(origin); this.localNode.getRoutingTable().insert(origin);
/* Set that we've completed ASKing the origin node */ /* Set that we've completed ASKing the origin node */

View File

@ -7,7 +7,6 @@ package kademlia.routing;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
import kademlia.node.Node; import kademlia.node.Node;
import kademlia.node.NodeId; import kademlia.node.NodeId;
@ -42,7 +41,9 @@ public class KadBucket implements Bucket
} }
else else
{ {
//System.out.println("Adding new node - " + n.getNodeId() + " to bucket depth: " + this.depth);
nodes.put(n.getNodeId(), n); nodes.put(n.getNodeId(), n);
//System.out.println(this);
} }
} }
@ -92,7 +93,7 @@ public class KadBucket implements Bucket
@Override @Override
public String toString() public String toString()
{ {
StringBuilder sb = new StringBuilder("Printing bucket at depth: "); StringBuilder sb = new StringBuilder("Bucket at depth: ");
sb.append(this.depth); sb.append(this.depth);
sb.append("\n Nodes: \n"); sb.append("\n Nodes: \n");
for (Node n : this.nodes.values()) for (Node n : this.nodes.values())

View File

@ -12,7 +12,7 @@ import kademlia.node.NodeId;
public class RoutingTable public class RoutingTable
{ {
private final Node node; // The current node private final Node localNode; // The current node
private final KadBucket[] buckets; private final KadBucket[] buckets;
@ -20,9 +20,9 @@ public class RoutingTable
buckets = new KadBucket[NodeId.ID_LENGTH]; // 160 buckets; 1 for each level in the tree buckets = new KadBucket[NodeId.ID_LENGTH]; // 160 buckets; 1 for each level in the tree
} }
public RoutingTable(Node node) public RoutingTable(Node localNode)
{ {
this.node = node; this.localNode = localNode;
/* Initialize all of the buckets to a specific depth */ /* Initialize all of the buckets to a specific depth */
for (int i = 0; i < NodeId.ID_LENGTH; i++) for (int i = 0; i < NodeId.ID_LENGTH; i++)
@ -39,7 +39,11 @@ public class RoutingTable
public void insert(Node n) public void insert(Node n)
{ {
/* Find the first set bit: how far this node is away from the contact node */ /* Find the first set bit: how far this node is away from the contact node */
int bucketId = this.node.getNodeId().xor(n.getNodeId()).getFirstSetBitIndex(); NodeId id = this.localNode.getNodeId().xor(n.getNodeId());
//System.out.println(" First Bit Set: " + id.getFirstSetBitIndex());
int bucketId = id.getFirstSetBitIndex();
System.out.println(this.localNode.getNodeId() + " Adding Node " + n.getNodeId() + " to bucket at depth: " + bucketId);
/* Put this contact to the bucket that stores contacts prefixLength distance away */ /* Put this contact to the bucket that stores contacts prefixLength distance away */
this.buckets[bucketId].insert(n); this.buckets[bucketId].insert(n);
@ -53,7 +57,7 @@ public class RoutingTable
public void remove(Node n) public void remove(Node n)
{ {
/* Find the first set bit: how far this node is away from the contact node */ /* Find the first set bit: how far this node is away from the contact node */
int bucketId = this.node.getNodeId().xor(n.getNodeId()).getFirstSetBitIndex(); int bucketId = this.localNode.getNodeId().xor(n.getNodeId()).getFirstSetBitIndex();
/* If the bucket has the contact, remove it */ /* If the bucket has the contact, remove it */
if (this.buckets[bucketId].containNode(n)) if (this.buckets[bucketId].containNode(n))
@ -75,7 +79,7 @@ public class RoutingTable
ArrayList<Node> closest = new ArrayList<>(num); ArrayList<Node> closest = new ArrayList<>(num);
/* Get the bucket number to search for closest from */ /* Get the bucket number to search for closest from */
int bucketNumber = this.node.getNodeId().xor(target).getFirstSetBitIndex(); int bucketNumber = this.localNode.getNodeId().xor(target).getFirstSetBitIndex();
/* Add the contacts from this bucket to the return contacts */ /* Add the contacts from this bucket to the return contacts */
for (Node c : this.buckets[bucketNumber].getNodes()) for (Node c : this.buckets[bucketNumber].getNodes())
@ -158,12 +162,14 @@ public class RoutingTable
StringBuilder sb = new StringBuilder("\nPrinting Routing Table Started ***************** \n"); StringBuilder sb = new StringBuilder("\nPrinting Routing Table Started ***************** \n");
for (KadBucket b : this.buckets) for (KadBucket b : this.buckets)
{ {
// System.out.println("Bucket: " + b);
if (b.numNodes() > 0) if (b.numNodes() > 0)
{ {
sb.append("# nodes in Bucket with depth "); sb.append("# nodes in Bucket with depth ");
sb.append(b.getDepth()); sb.append(b.getDepth());
sb.append(": "); sb.append(": ");
sb.append(b.numNodes()); sb.append(b.numNodes());
sb.append("\n");
sb.append(b.toString()); sb.append(b.toString());
sb.append("\n"); sb.append("\n");
} }

View File

@ -17,22 +17,49 @@ public class NodeConnectionTest
try try
{ {
/* Setting up 2 Kad networks */ /* Setting up 2 Kad networks */
Kademlia kad1 = new Kademlia("Joshua", new NodeId("12345678947584567467"), 7574); Kademlia kad1 = new Kademlia("JoshuaK", new NodeId("ASF45678947584567467"), 7574);
Kademlia kad2 = new Kademlia("Crystal", new NodeId("12345678999324567838"), 7572); System.out.println("Created Node Kad 1: " + kad1.getNode().getNodeId());
Kademlia kad2 = new Kademlia("Crystal", new NodeId("ASERTKJDHGVHERJHGFLK"), 7572);
//NodeId diff12 = kad1.getNode().getNodeId().xor(kad2.getNode().getNodeId());
System.out.println("Created Node Kad 2: " + kad2.getNode().getNodeId());
// System.out.println(kad1.getNode().getNodeId() + " ^ " + kad2.getNode().getNodeId() + " = " + diff12);
// System.out.println("Kad 1 - Kad 2 distance: " + diff12.getFirstSetBitIndex());
/* Connecting 2 to 1 */ /* Connecting 2 to 1 */
System.out.println("Connecting Kad 1 and Kad 2");
kad1.connect(kad2.getNode()); kad1.connect(kad2.getNode());
System.out.println("Kad 1: "); // System.out.println("Kad 1: ");
System.out.println(kad1.getNode().getRoutingTable()); // System.out.println(kad1.getNode().getRoutingTable());
System.out.println("Kad 2: "); // System.out.println("Kad 2: ");
System.out.println(kad2.getNode().getRoutingTable()); // System.out.println(kad2.getNode().getRoutingTable());
/* Creating a new node 3 and connecting it to 1, hoping it'll get onto 2 also */ /* Creating a new node 3 and connecting it to 1, hoping it'll get onto 2 also */
Kademlia kad3 = new Kademlia("Jessica", new NodeId("88888736882323647625"), 7783); Kademlia kad3 = new Kademlia("Jessica", new NodeId("ASERTKJDOLKMNBVFR45G"), 7783);
kad3.connect(kad1.getNode()); System.out.println("\n\n\n\n\n\nCreated Node Kad 3: " + kad3.getNode().getNodeId());
System.out.println("Kad 3: ");
System.out.println("Connecting Kad 3 and Kad 2");
kad3.connect(kad2.getNode());
// NodeId diff32 = kad3.getNode().getNodeId().xor(kad2.getNode().getNodeId());
// NodeId diff31 = kad1.getNode().getNodeId().xor(kad3.getNode().getNodeId());
// System.out.println("Kad 3 - Kad 1 distance: " + diff31.getFirstSetBitIndex());
// System.out.println("Kad 3 - Kad 2 distance: " + diff32.getFirstSetBitIndex());
Kademlia kad4 = new Kademlia("Sandy", new NodeId("ASERTK85OLKMN85FR4SS"), 7789);
System.out.println("\n\n\n\n\n\nCreated Node Kad 4: " + kad4.getNode().getNodeId());
System.out.println("Connecting Kad 4 and Kad 2");
kad4.connect(kad2.getNode());
System.out.println("\n\nKad 1: " + kad1.getNode().getNodeId() + " Routing Table: ");
System.out.println(kad1.getNode().getRoutingTable());
System.out.println("\n\nKad 2: " + kad2.getNode().getNodeId() + " Routing Table: ");
System.out.println(kad2.getNode().getRoutingTable());
System.out.println("\n\nKad 3: " + kad3.getNode().getNodeId() + " Routing Table: ");
System.out.println(kad3.getNode().getRoutingTable()); System.out.println(kad3.getNode().getRoutingTable());
System.out.println("\n\nKad 4: " + kad4.getNode().getNodeId() + " Routing Table: ");
System.out.println(kad4.getNode().getRoutingTable());
} }
catch (IOException e) catch (IOException e)
{ {