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
This commit is contained in:
Joshua Kissoon 2014-02-19 21:21:18 +05:30
parent 1de348fc72
commit 9eca0614f2
6 changed files with 118 additions and 26 deletions

View File

@ -51,8 +51,8 @@ public class MessageFactory
return new SimpleReceiver(); return new SimpleReceiver();
case ConnectMessage.CODE: case ConnectMessage.CODE:
return new ConnectReceiver(server, this.localNode); return new ConnectReceiver(server, this.localNode);
case NodeLookupMessage.CODE case NodeLookupMessage.CODE:
return new NodeLookupReceiver(); return new NodeLookupReceiver(server, this.localNode);
} }
} }
} }

View File

@ -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<Node> 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
{
}
}

View File

@ -14,7 +14,7 @@ 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 +38,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 +55,7 @@ public class NodeId implements Streamable
{ {
this.fromStream(in); this.fromStream(in);
} }
public byte[] getBytes() public byte[] getBytes()
{ {
return this.keyBytes; return this.keyBytes;
@ -64,13 +64,26 @@ public class NodeId implements Streamable
/** /**
* Compares a NodeId to this NodeId * 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 * @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]); result[i] = (byte) (this.keyBytes[i] ^ nidBytes[i]);
} }
return new NodeId(result); return new NodeId(result);
} }
@ -122,7 +135,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)
@ -155,14 +168,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
{ {
@ -170,14 +183,14 @@ 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)); sb.append(new String(this.keyBytes));
return sb.toString(); return sb.toString();
} }
} }

View File

@ -6,17 +6,20 @@
package kademlia.routing; package kademlia.routing;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import kademlia.node.Node; import kademlia.node.Node;
import kademlia.node.NodeId;
public class KadBucket implements Bucket public class KadBucket implements Bucket
{ {
private final int depth; private final int depth;
private final ArrayList<Node> nodes; private final HashMap<NodeId, Node> 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 */ /*@todo Check if the bucket is filled already and handle this */
/* Check if the contact is already in the bucket */ /* 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 If it is, then move it to the front */
/* @todo Possibly use a doubly linked list instead of an ArrayList */ /* @todo Possibly use a doubly linked list instead of an ArrayList */
} }
else else
{ {
nodes.add(n); nodes.put(n.getNodeId(), n);
} }
} }
@ -52,7 +55,7 @@ public class KadBucket implements Bucket
*/ */
public boolean containNode(Node n) 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) public void removeNode(Node n)
{ {
this.nodes.remove(n); this.nodes.remove(n.getNodeId());
} }
public int numNodes() public int numNodes()
@ -78,12 +81,12 @@ public class KadBucket implements Bucket
@Override @Override
public void markDead(Node n) public void markDead(Node n)
{ {
this.nodes.remove(n); this.nodes.remove(n.getNodeId());
} }
public ArrayList<Node> getNodes() public ArrayList<Node> getNodes()
{ {
return this.nodes; return new ArrayList<>(this.nodes.values());
} }
@Override @Override
@ -92,7 +95,7 @@ public class KadBucket implements Bucket
StringBuilder sb = new StringBuilder("Printing bucket at depth: "); StringBuilder sb = new StringBuilder("Printing 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) for (Node n : this.nodes.values())
{ {
sb.append("Node: "); sb.append("Node: ");
sb.append(n.getNodeId().toString()); sb.append(n.getNodeId().toString());

View File

@ -164,6 +164,7 @@ public class RoutingTable
sb.append(b.getDepth()); sb.append(b.getDepth());
sb.append(": "); sb.append(": ");
sb.append(b.numNodes()); sb.append(b.numNodes());
sb.append(b.toString());
sb.append("\n"); sb.append("\n");
} }
} }

View File

@ -17,8 +17,8 @@ public class NodeConnectionTest
try try
{ {
/* Setting up 2 Kad networks */ /* Setting up 2 Kad networks */
Kademlia kad1 = new Kademlia("Joshua", new NodeId("12345678901234567890"), 7574); Kademlia kad1 = new Kademlia("Joshua", new NodeId("12345678947584567467"), 7574);
Kademlia kad2 = new Kademlia("Crystal", new NodeId("12345678901234567891"), 7572); Kademlia kad2 = new Kademlia("Crystal", new NodeId("12345678999324567838"), 7572);
/* Connecting 2 to 1 */ /* Connecting 2 to 1 */
kad1.connect(kad2.getNode()); kad1.connect(kad2.getNode());