From 9eca0614f29e8af408cb0b8bef4e7770db01cdda Mon Sep 17 00:00:00 2001 From: Joshua Kissoon Date: Wed, 19 Feb 2014 21:21:18 +0530 Subject: [PATCH] Still working on NodeLookupRequest Updated the NodeId equals() and hashCode() methods; fixes the bug where several same NodeIds were being added to the routing table --- src/kademlia/message/MessageFactory.java | 4 +- src/kademlia/message/NodeLookupReceiver.java | 75 ++++++++++++++++++++ src/kademlia/node/NodeId.java | 39 ++++++---- src/kademlia/routing/KadBucket.java | 21 +++--- src/kademlia/routing/RoutingTable.java | 1 + src/kademlia/tests/NodeConnectionTest.java | 4 +- 6 files changed, 118 insertions(+), 26 deletions(-) create mode 100644 src/kademlia/message/NodeLookupReceiver.java diff --git a/src/kademlia/message/MessageFactory.java b/src/kademlia/message/MessageFactory.java index 454718b..7569a9f 100644 --- a/src/kademlia/message/MessageFactory.java +++ b/src/kademlia/message/MessageFactory.java @@ -51,8 +51,8 @@ public class MessageFactory return new SimpleReceiver(); case ConnectMessage.CODE: return new ConnectReceiver(server, this.localNode); - case NodeLookupMessage.CODE - return new NodeLookupReceiver(); + case NodeLookupMessage.CODE: + return new NodeLookupReceiver(server, this.localNode); } } } diff --git a/src/kademlia/message/NodeLookupReceiver.java b/src/kademlia/message/NodeLookupReceiver.java new file mode 100644 index 0000000..91a899e --- /dev/null +++ b/src/kademlia/message/NodeLookupReceiver.java @@ -0,0 +1,75 @@ +/** + * @author Joshua Kissoon + * @created 20140219 + * @desc Receives a ConnectMessage and sends an AcknowledgeMessage as reply + */ +package kademlia.message; + +import java.io.IOException; +import java.util.ArrayList; +import kademlia.core.Configuration; +import kademlia.core.KadServer; +import kademlia.node.Node; +import kademlia.operation.Receiver; + +public class NodeLookupReceiver implements Receiver +{ + + private final KadServer server; + private final Node localNode; + + public NodeLookupReceiver(KadServer server, Node local) + { + this.server = server; + this.localNode = local; + } + + /** + * Handle receiving a NodeLookupMessage + * Find the set of K nodes closest to the lookup ID and return them + * + * @param comm + * + * @throws java.io.IOException + */ + @Override + public void receive(Message incoming, int comm) throws IOException + { + NodeLookupMessage msg = (NodeLookupMessage) incoming; + + Node origin = msg.getOrigin(); + + System.out.println(this.localNode.getNodeId() + ": Received incoming NodeLookupMessage, sending NodeReplyMessage to: " + origin.getNodeId()); + + /* Update the local space by inserting the origin node. */ + this.localNode.getRoutingTable().insert(origin); + + /* Find nodes closest to the LookupId */ + ArrayList nodes = this.localNode.getRoutingTable().findClosest(msg.getLookupId(), Configuration.K); + + System.out.println("\nClosest Nodes: "); + for (Node n : nodes) + { + System.out.println(n.getNodeId()); + } + System.out.println(); + + /* Respond to the NodeLookupMessage */ + Message reply = new NodeReplyMessage(this.localNode, nodes); + + /* Let the Server send the reply */ + this.server.reply(origin, reply, comm); + } + + /** + * We don't need to do anything here + * + * @param comm + * + * @throws java.io.IOException + */ + @Override + public void timeout(int comm) throws IOException + { + } +} diff --git a/src/kademlia/node/NodeId.java b/src/kademlia/node/NodeId.java index 17cfd46..7d0a324 100644 --- a/src/kademlia/node/NodeId.java +++ b/src/kademlia/node/NodeId.java @@ -14,7 +14,7 @@ import kademlia.message.Streamable; public class NodeId implements Streamable { - + public final static int ID_LENGTH = 160; private byte[] keyBytes; @@ -38,7 +38,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 +55,7 @@ public class NodeId implements Streamable { this.fromStream(in); } - + public byte[] getBytes() { return this.keyBytes; @@ -64,13 +64,26 @@ public class NodeId implements Streamable /** * Compares a NodeId to this NodeId * - * @param nid The NodeId to compare to this NodeId + * @param o The NodeId to compare to this NodeId * * @return boolean Whether the 2 NodeIds are equal */ - public boolean equals(NodeId nid) + @Override + public boolean equals(Object o) { - return Arrays.equals(keyBytes, nid.getBytes()); + + if (o instanceof NodeId) + { + NodeId nid = (NodeId) o; + return Arrays.equals(this.getBytes(), nid.getBytes()); + } + return false; + } + + @Override + public int hashCode() + { + return Arrays.hashCode(this.getBytes()); } /** @@ -110,7 +123,7 @@ public class NodeId implements Streamable { result[i] = (byte) (this.keyBytes[i] ^ nidBytes[i]); } - + return new NodeId(result); } @@ -122,7 +135,7 @@ public class NodeId implements Streamable public int getFirstSetBitIndex() { int prefixLength = 0; - + for (byte b : this.keyBytes) { if (b == 0) @@ -155,14 +168,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 { @@ -170,14 +183,14 @@ 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(); } - + } diff --git a/src/kademlia/routing/KadBucket.java b/src/kademlia/routing/KadBucket.java index ddea413..3200ed0 100644 --- a/src/kademlia/routing/KadBucket.java +++ b/src/kademlia/routing/KadBucket.java @@ -6,17 +6,20 @@ package kademlia.routing; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; import kademlia.node.Node; +import kademlia.node.NodeId; public class KadBucket implements Bucket { private final int depth; - private final ArrayList nodes; + private final HashMap nodes; { - nodes = new ArrayList<>(); + nodes = new HashMap<>(); } /** @@ -32,14 +35,14 @@ public class KadBucket implements Bucket { /*@todo Check if the bucket is filled already and handle this */ /* Check if the contact is already in the bucket */ - if (this.nodes.contains(n)) + if (this.nodes.containsKey(n.getNodeId())) { /* @todo If it is, then move it to the front */ /* @todo Possibly use a doubly linked list instead of an ArrayList */ } else { - nodes.add(n); + nodes.put(n.getNodeId(), n); } } @@ -52,7 +55,7 @@ public class KadBucket implements Bucket */ public boolean containNode(Node n) { - return this.nodes.contains(n); + return this.nodes.containsKey(n.getNodeId()); } /** @@ -62,7 +65,7 @@ public class KadBucket implements Bucket */ public void removeNode(Node n) { - this.nodes.remove(n); + this.nodes.remove(n.getNodeId()); } public int numNodes() @@ -78,12 +81,12 @@ public class KadBucket implements Bucket @Override public void markDead(Node n) { - this.nodes.remove(n); + this.nodes.remove(n.getNodeId()); } public ArrayList getNodes() { - return this.nodes; + return new ArrayList<>(this.nodes.values()); } @Override @@ -92,7 +95,7 @@ public class KadBucket implements Bucket StringBuilder sb = new StringBuilder("Printing bucket at depth: "); sb.append(this.depth); sb.append("\n Nodes: \n"); - for (Node n : this.nodes) + for (Node n : this.nodes.values()) { sb.append("Node: "); sb.append(n.getNodeId().toString()); diff --git a/src/kademlia/routing/RoutingTable.java b/src/kademlia/routing/RoutingTable.java index 0c05991..a5bef7d 100644 --- a/src/kademlia/routing/RoutingTable.java +++ b/src/kademlia/routing/RoutingTable.java @@ -164,6 +164,7 @@ public class RoutingTable sb.append(b.getDepth()); sb.append(": "); sb.append(b.numNodes()); + sb.append(b.toString()); sb.append("\n"); } } diff --git a/src/kademlia/tests/NodeConnectionTest.java b/src/kademlia/tests/NodeConnectionTest.java index b5ffbd8..947bdd6 100644 --- a/src/kademlia/tests/NodeConnectionTest.java +++ b/src/kademlia/tests/NodeConnectionTest.java @@ -17,8 +17,8 @@ public class NodeConnectionTest try { /* Setting up 2 Kad networks */ - Kademlia kad1 = new Kademlia("Joshua", new NodeId("12345678901234567890"), 7574); - Kademlia kad2 = new Kademlia("Crystal", new NodeId("12345678901234567891"), 7572); + Kademlia kad1 = new Kademlia("Joshua", new NodeId("12345678947584567467"), 7574); + Kademlia kad2 = new Kademlia("Crystal", new NodeId("12345678999324567838"), 7572); /* Connecting 2 to 1 */ kad1.connect(kad2.getNode());