From 3344511603906d081762c77ceea793be144cf222 Mon Sep 17 00:00:00 2001 From: Joshua Kissoon Date: Sat, 22 Feb 2014 19:37:04 +0530 Subject: [PATCH] Finished NodeLookupOperation functionality! Finally found the bug --- src/kademlia/core/Configuration.java | 4 +- src/kademlia/core/KadServer.java | 12 ++-- src/kademlia/core/Kademlia.java | 2 +- src/kademlia/message/NodeLookupReceiver.java | 2 +- src/kademlia/node/Node.java | 63 ++++++++++++++----- src/kademlia/node/NodeId.java | 44 ++++++++----- .../operation/NodeLookupOperation.java | 15 +++++ src/kademlia/routing/KadBucket.java | 5 +- src/kademlia/routing/RoutingTable.java | 18 ++++-- src/kademlia/tests/NodeConnectionTest.java | 45 ++++++++++--- 10 files changed, 153 insertions(+), 57 deletions(-) diff --git a/src/kademlia/core/Configuration.java b/src/kademlia/core/Configuration.java index d04da07..28dd6a9 100644 --- a/src/kademlia/core/Configuration.java +++ b/src/kademlia/core/Configuration.java @@ -16,7 +16,7 @@ public class Configuration * If no reply received from a node in this period (in milliseconds) * consider the node unresponsive. * */ - public static long RESPONSE_TIMEOUT = 3000; + public static long RESPONSE_TIMEOUT = 1500; /** * Maximum number of milliseconds for performing an operation. @@ -36,7 +36,7 @@ public class Configuration /** * Bucket size. * */ - public static int K = 3; + public static int K = 5; /** * Size of replacement cache. diff --git a/src/kademlia/core/KadServer.java b/src/kademlia/core/KadServer.java index 498582d..3028605 100644 --- a/src/kademlia/core/KadServer.java +++ b/src/kademlia/core/KadServer.java @@ -35,6 +35,8 @@ public class KadServer private final HashMap receivers; private final Timer timer; // Schedule future tasks private final HashMap tasks; // Keep track of scheduled tasks + + private final Node localNode; /* Factories */ private final MessageFactory messageFactory; @@ -47,10 +49,12 @@ public class KadServer 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.socket = new DatagramSocket(udpPort); + + this.localNode = localNode; this.messageFactory = mFactory; @@ -128,7 +132,7 @@ public class KadServer 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 */ @@ -163,9 +167,7 @@ public class KadServer Message msg = messageFactory.createMessage(messCode, din); din.close(); - System.out.println("Message Received: " + msg); - - System.out.println("Receivers: " + receivers); + System.out.println(this.localNode.getNodeId() + " Message Received: " + msg); /* Get a receiver for this message */ Receiver receiver; diff --git a/src/kademlia/core/Kademlia.java b/src/kademlia/core/Kademlia.java index 34da90b..1a242ab 100644 --- a/src/kademlia/core/Kademlia.java +++ b/src/kademlia/core/Kademlia.java @@ -49,7 +49,7 @@ public class Kademlia this.name = name; this.localNode = new Node(defaultId, InetAddress.getLocalHost(), udpPort); 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); /* Schedule Recurring RestoreOperation */ diff --git a/src/kademlia/message/NodeLookupReceiver.java b/src/kademlia/message/NodeLookupReceiver.java index 91a899e..5119ec8 100644 --- a/src/kademlia/message/NodeLookupReceiver.java +++ b/src/kademlia/message/NodeLookupReceiver.java @@ -39,7 +39,7 @@ public class NodeLookupReceiver implements Receiver 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. */ this.localNode.getRoutingTable().insert(origin); diff --git a/src/kademlia/node/Node.java b/src/kademlia/node/Node.java index 2370dcf..8cfbd16 100644 --- a/src/kademlia/node/Node.java +++ b/src/kademlia/node/Node.java @@ -117,6 +117,28 @@ public class Node implements Streamable 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 * */ @@ -145,23 +167,36 @@ public class Node implements Streamable { Node n1 = (Node) o1; Node n2 = (Node) o2; - - 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 + if(n1.getNodeId().equals(n2.getNodeId())) { 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; } } } diff --git a/src/kademlia/node/NodeId.java b/src/kademlia/node/NodeId.java index 7d0a324..a0fa583 100644 --- a/src/kademlia/node/NodeId.java +++ b/src/kademlia/node/NodeId.java @@ -8,13 +8,14 @@ package kademlia.node; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; +import java.math.BigInteger; import java.util.Arrays; import java.util.Random; import kademlia.message.Streamable; public class NodeId implements Streamable { - + public final static int ID_LENGTH = 160; private byte[] keyBytes; @@ -38,7 +39,7 @@ public class NodeId implements Streamable keyBytes = new byte[ID_LENGTH / 8]; new Random().nextBytes(keyBytes); } - + public NodeId(byte[] bytes) { this.keyBytes = bytes; @@ -55,7 +56,7 @@ public class NodeId implements Streamable { this.fromStream(in); } - + public byte[] getBytes() { return this.keyBytes; @@ -71,7 +72,7 @@ public class NodeId implements Streamable @Override public boolean equals(Object o) { - + if (o instanceof NodeId) { NodeId nid = (NodeId) o; @@ -79,11 +80,13 @@ public class NodeId implements Streamable } return false; } - + @Override 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[] nidBytes = nid.getBytes(); + for (int i = 0; i < ID_LENGTH / 8; 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() { int prefixLength = 0; - + for (byte b : this.keyBytes) { if (b == 0) @@ -168,14 +176,14 @@ public class NodeId implements Streamable } return ID_LENGTH - prefixLength; } - + @Override public void toStream(DataOutput out) throws IOException { /* Add the NodeId to the stream */ out.write(this.getBytes()); } - + @Override public void fromStream(DataInput in) throws IOException { @@ -183,14 +191,16 @@ public class NodeId implements Streamable in.readFully(input); this.keyBytes = input; } - + @Override public String toString() { - StringBuilder sb = new StringBuilder("NodeId: "); - sb.append(new String(this.keyBytes)); - - return sb.toString(); + // StringBuilder sb = new StringBuilder("NodeId: "); + BigInteger bi = new BigInteger(1, this.keyBytes); + return String.format("%0" + (this.keyBytes.length << 1) + "X", bi); + //sb.append(Hex.encodeBase64URLSafeString(this.keyBytes)); + + //return sb.toString(); } - + } diff --git a/src/kademlia/operation/NodeLookupOperation.java b/src/kademlia/operation/NodeLookupOperation.java index 565315e..3d4c6b0 100644 --- a/src/kademlia/operation/NodeLookupOperation.java +++ b/src/kademlia/operation/NodeLookupOperation.java @@ -125,11 +125,20 @@ public class NodeLookupOperation implements Operation, Receiver for (Node o : list) { /* 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)) { + System.out.println("Adding unasked node " + o.getNodeId()); 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 */ ArrayList 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()) { @@ -256,6 +270,7 @@ public class NodeLookupOperation implements Operation, Receiver /* Add the origin node to our routing table */ Node origin = msg.getOrigin(); + System.out.println(this.localNode.getNodeId() + " Lookup Operation Response From: " + origin.getNodeId()); this.localNode.getRoutingTable().insert(origin); /* Set that we've completed ASKing the origin node */ diff --git a/src/kademlia/routing/KadBucket.java b/src/kademlia/routing/KadBucket.java index 3200ed0..d846f46 100644 --- a/src/kademlia/routing/KadBucket.java +++ b/src/kademlia/routing/KadBucket.java @@ -7,7 +7,6 @@ package kademlia.routing; import java.util.ArrayList; import java.util.HashMap; -import java.util.Map; import kademlia.node.Node; import kademlia.node.NodeId; @@ -42,7 +41,9 @@ public class KadBucket implements Bucket } else { + //System.out.println("Adding new node - " + n.getNodeId() + " to bucket depth: " + this.depth); nodes.put(n.getNodeId(), n); + //System.out.println(this); } } @@ -92,7 +93,7 @@ public class KadBucket implements Bucket @Override public String toString() { - StringBuilder sb = new StringBuilder("Printing bucket at depth: "); + StringBuilder sb = new StringBuilder("Bucket at depth: "); sb.append(this.depth); sb.append("\n Nodes: \n"); for (Node n : this.nodes.values()) diff --git a/src/kademlia/routing/RoutingTable.java b/src/kademlia/routing/RoutingTable.java index a5bef7d..5be6adb 100644 --- a/src/kademlia/routing/RoutingTable.java +++ b/src/kademlia/routing/RoutingTable.java @@ -12,7 +12,7 @@ import kademlia.node.NodeId; public class RoutingTable { - private final Node node; // The current node + private final Node localNode; // The current node 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 } - public RoutingTable(Node node) + public RoutingTable(Node localNode) { - this.node = node; + this.localNode = localNode; /* Initialize all of the buckets to a specific depth */ for (int i = 0; i < NodeId.ID_LENGTH; i++) @@ -39,7 +39,11 @@ public class RoutingTable public void insert(Node n) { /* 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 */ this.buckets[bucketId].insert(n); @@ -53,7 +57,7 @@ public class RoutingTable public void remove(Node n) { /* 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 (this.buckets[bucketId].containNode(n)) @@ -75,7 +79,7 @@ public class RoutingTable ArrayList closest = new ArrayList<>(num); /* 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 */ for (Node c : this.buckets[bucketNumber].getNodes()) @@ -158,12 +162,14 @@ public class RoutingTable StringBuilder sb = new StringBuilder("\nPrinting Routing Table Started ***************** \n"); for (KadBucket b : this.buckets) { + // System.out.println("Bucket: " + b); if (b.numNodes() > 0) { sb.append("# nodes in Bucket with depth "); sb.append(b.getDepth()); sb.append(": "); sb.append(b.numNodes()); + sb.append("\n"); sb.append(b.toString()); sb.append("\n"); } diff --git a/src/kademlia/tests/NodeConnectionTest.java b/src/kademlia/tests/NodeConnectionTest.java index 947bdd6..312fa03 100644 --- a/src/kademlia/tests/NodeConnectionTest.java +++ b/src/kademlia/tests/NodeConnectionTest.java @@ -17,22 +17,49 @@ public class NodeConnectionTest try { /* Setting up 2 Kad networks */ - Kademlia kad1 = new Kademlia("Joshua", new NodeId("12345678947584567467"), 7574); - Kademlia kad2 = new Kademlia("Crystal", new NodeId("12345678999324567838"), 7572); + Kademlia kad1 = new Kademlia("JoshuaK", new NodeId("ASF45678947584567467"), 7574); + 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 */ + System.out.println("Connecting Kad 1 and Kad 2"); kad1.connect(kad2.getNode()); - System.out.println("Kad 1: "); - System.out.println(kad1.getNode().getRoutingTable()); - System.out.println("Kad 2: "); - System.out.println(kad2.getNode().getRoutingTable()); +// System.out.println("Kad 1: "); +// System.out.println(kad1.getNode().getRoutingTable()); +// System.out.println("Kad 2: "); +// System.out.println(kad2.getNode().getRoutingTable()); /* 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); - kad3.connect(kad1.getNode()); - System.out.println("Kad 3: "); + Kademlia kad3 = new Kademlia("Jessica", new NodeId("ASERTKJDOLKMNBVFR45G"), 7783); + System.out.println("\n\n\n\n\n\nCreated Node Kad 3: " + kad3.getNode().getNodeId()); + + 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("\n\nKad 4: " + kad4.getNode().getNodeId() + " Routing Table: "); + System.out.println(kad4.getNode().getRoutingTable()); } catch (IOException e) {