diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml index ed7498d..9092fc0 100644 --- a/nbproject/build-impl.xml +++ b/nbproject/build-impl.xml @@ -80,9 +80,12 @@ is divided into following sections: - - - + + + + + + @@ -1199,11 +1202,14 @@ is divided into following sections: - + + + + - + @@ -1277,7 +1283,7 @@ is divided into following sections: - + Some tests failed; see details above. diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties index 2dd29bc..cc9dd93 100644 --- a/nbproject/genfiles.properties +++ b/nbproject/genfiles.properties @@ -4,5 +4,5 @@ build.xml.stylesheet.CRC32=8064a381@1.68.1.46 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. nbproject/build-impl.xml.data.CRC32=7e563d6e -nbproject/build-impl.xml.script.CRC32=5c6dd9f7 -nbproject/build-impl.xml.stylesheet.CRC32=5a01deb7@1.68.1.46 +nbproject/build-impl.xml.script.CRC32=934ae712 +nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.74.1.48 diff --git a/src/kademlia/core/KadServer.java b/src/kademlia/core/KadServer.java index cea718f..1512d8f 100644 --- a/src/kademlia/core/KadServer.java +++ b/src/kademlia/core/KadServer.java @@ -1,8 +1,3 @@ -/** - * @author Joshua Kissoon - * @created 20140215 - * @desc This server handles sending and receiving messages - */ package kademlia.core; import java.io.ByteArrayInputStream; @@ -23,6 +18,11 @@ import kademlia.message.MessageFactory; import kademlia.node.Node; import kademlia.operation.Receiver; +/** + * @author Joshua Kissoon + * @created 20140215 + * @desc This server handles sending and receiving messages + */ public class KadServer { diff --git a/src/kademlia/core/Kademlia.java b/src/kademlia/core/Kademlia.java index dd82451..1186422 100644 --- a/src/kademlia/core/Kademlia.java +++ b/src/kademlia/core/Kademlia.java @@ -16,7 +16,8 @@ import kademlia.node.NodeId; import kademlia.operation.ConnectOperation; import kademlia.operation.ContentLookupOperation; import kademlia.operation.Operation; -import kademlia.operation.RefreshOperation; +import kademlia.operation.BucketRefreshOperation; +import kademlia.operation.KadRefreshOperation; import kademlia.operation.StoreOperation; /** @@ -79,7 +80,7 @@ public class Kademlia try { /* Runs a RefreshOperation to refresh K-Buckets and stored content */ - new RefreshOperation(server, localNode).execute(); + new BucketRefreshOperation(server, localNode).execute(); } catch (IOException e) { @@ -174,6 +175,16 @@ public class Kademlia return contentFound; } + /** + * Allow the user of the System to call refresh even out of the normal Kad refresh timing + * + * @throws java.io.IOException + */ + public void refresh() throws IOException + { + new KadRefreshOperation(server, localNode).execute(); + } + /** * @return String The ID of the owner of this local network */ diff --git a/src/kademlia/node/NodeId.java b/src/kademlia/node/NodeId.java index 21b9b1f..515de7c 100644 --- a/src/kademlia/node/NodeId.java +++ b/src/kademlia/node/NodeId.java @@ -42,11 +42,16 @@ public class NodeId implements Streamable new Random().nextBytes(keyBytes); } + /** + * Generate the NodeId from a given byte[] + * + * @param bytes + */ public NodeId(byte[] bytes) { if (bytes.length != ID_LENGTH / 8) { - throw new IllegalArgumentException("Specified Data need to be " + (ID_LENGTH / 8) + " characters long."); + throw new IllegalArgumentException("Specified Data need to be " + (ID_LENGTH / 8) + " characters long. Data Given: '" + new String(bytes) + "'"); } this.keyBytes = bytes; } diff --git a/src/kademlia/operation/RefreshOperation.java b/src/kademlia/operation/BucketRefreshOperation.java similarity index 54% rename from src/kademlia/operation/RefreshOperation.java rename to src/kademlia/operation/BucketRefreshOperation.java index 3f0d911..c7c15b3 100644 --- a/src/kademlia/operation/RefreshOperation.java +++ b/src/kademlia/operation/BucketRefreshOperation.java @@ -1,23 +1,25 @@ package kademlia.operation; import java.io.IOException; +import java.util.List; import kademlia.core.KadServer; import kademlia.node.Node; +import kademlia.node.NodeId; /** - * At each time interval t, nodes need to refresh their K-Buckets and their Data Storage - * This Operation will manage refreshing the K-Buckets and data storage + * At each time interval t, nodes need to refresh their K-Buckets + * This operation takes care of refreshing this node's K-Buckets * * @author Joshua Kissoon * @created 20140224 */ -public class RefreshOperation implements Operation +public class BucketRefreshOperation implements Operation { private final KadServer server; private final Node localNode; - public RefreshOperation(KadServer server, Node localNode) + public BucketRefreshOperation(KadServer server, Node localNode) { this.server = server; this.localNode = localNode; @@ -26,6 +28,17 @@ public class RefreshOperation implements Operation @Override public synchronized void execute() throws IOException { + System.out.println("Bucket Refresh Operation Started"); + + /* Get a list of NodeIds for each distance from the LocalNode NodeId */ + List refreshIds = this.localNode.getRoutingTable().getRefreshList(); + + /* Test whether each nodeId in this list is a different distance from our current NID */ + for (NodeId nid : refreshIds) + { + System.out.println(nid.xor(localNode.getNodeId()).getFirstSetBitIndex()); + } + /* @todo Do a Node Lookup operation to refresh K-Buckets */ new NodeLookupOperation(this.server, this.localNode, this.localNode.getNodeId()).execute(); @@ -34,9 +47,5 @@ public class RefreshOperation implements Operation * This is better than asking closest nodes for data, * since the data may not always come from the closest nodes */ - /** - * @todo Delete any content on this node that this node is not one of the K-Closest nodes to - * @todo Delete any expired content - */ } } diff --git a/src/kademlia/operation/ContentRefreshOperation.java b/src/kademlia/operation/ContentRefreshOperation.java new file mode 100644 index 0000000..774ec39 --- /dev/null +++ b/src/kademlia/operation/ContentRefreshOperation.java @@ -0,0 +1,19 @@ +package kademlia.operation; + +/** + * Refresh the data on this node by sending the data to the K-Closest nodes to the data + * + * @author Joshua Kissoon + * @since 20140306 + */ +public class ContentRefreshOperation +{ + + public void execute() + { + /** + * @todo Delete any content on this node that this node is not one of the K-Closest nodes to + * @todo Delete any expired content + */ + } +} diff --git a/src/kademlia/operation/KadRefreshOperation.java b/src/kademlia/operation/KadRefreshOperation.java new file mode 100644 index 0000000..a56de57 --- /dev/null +++ b/src/kademlia/operation/KadRefreshOperation.java @@ -0,0 +1,33 @@ +package kademlia.operation; + +import java.io.IOException; +import kademlia.core.KadServer; +import kademlia.node.Node; + +/** + * An operation that handles refreshing the entire Kademlia Systems including buckets and content + * + * @author Joshua Kissoon + * @since 20140306 + */ +public class KadRefreshOperation implements Operation +{ + + private final KadServer server; + private final Node localNode; + + public KadRefreshOperation(KadServer server, Node localNode) + { + this.server = server; + this.localNode = localNode; + } + + @Override + public void execute() throws IOException + { + /* Run our BucketRefreshOperation to refresh buckets */ + new BucketRefreshOperation(server, localNode).execute(); + + /* After buckets have been refreshed, we refresh content */ + } +} diff --git a/src/kademlia/routing/RoutingTable.java b/src/kademlia/routing/RoutingTable.java index fe5ad63..261b97c 100644 --- a/src/kademlia/routing/RoutingTable.java +++ b/src/kademlia/routing/RoutingTable.java @@ -6,6 +6,7 @@ package kademlia.routing; import java.util.ArrayList; +import java.util.BitSet; import java.util.List; import kademlia.node.Node; import kademlia.node.NodeId; @@ -73,7 +74,7 @@ public class RoutingTable * @param target The NodeId to find contacts close to * @param num The number of contacts to find * - * @return List A List of num contacts closest to target + * @return List A List of contacts closest to target */ public List findClosest(NodeId target, int num) { @@ -145,7 +146,10 @@ public class RoutingTable return closest; } - public List getAllNodes() + /** + * @return List A List of all Nodes in this RoutingTable + */ + public List getAllNodes() { List nodes = new ArrayList<>(); @@ -157,6 +161,53 @@ public class RoutingTable return nodes; } + /** + * Each bucket need to be refreshed at every time interval t. + * Here we return an identifier in each bucket's range; + * this identifier will then be used to look for nodes closest to this identifier + * allowing the bucket to be refreshed. + * + * The first bucket containing only the local node is skipped. + * + * @return List A list of NodeIds for each distance (1 - NodeId.ID_LENGTH) from the LocalNode NodeId + */ + public List getRefreshList() + { + List refreshList = new ArrayList<>(NodeId.ID_LENGTH); + + for (int i = 1; i < NodeId.ID_LENGTH; i++) + { + /* Construct a NodeId that is i bits away from the current node Id */ + System.out.println("\nGenerating a new NodeId "); + BitSet temp = new BitSet(NodeId.ID_LENGTH); + + /* Fill the first i parts with 1 */ + for (int j = 0; j < i; j++) + { + System.out.println("Got here 1 - j: " + j); + temp.set(j); + } + + /* Fill the last parts with 0 */ + for (int j = i; j < NodeId.ID_LENGTH; j++) + { + System.out.println("Got here 2 - j: " + j); + temp.set(j, false); + } + + /** + * LocalNode NodeId xor the Bits we generated will give a new NodeId + * i distance away from our LocalNode NodeId, we add this to our refreshList + */ + System.out.println("Bits: " + temp); + NodeId nid = this.localNode.getNodeId().xor(new NodeId(temp.toByteArray())); + System.out.println("NodeId: " + nid); + refreshList.add(nid); + } + + return refreshList; + } + @Override public String toString() { diff --git a/src/kademlia/tests/RefreshOperationTest.java b/src/kademlia/tests/RefreshOperationTest.java new file mode 100644 index 0000000..0758b24 --- /dev/null +++ b/src/kademlia/tests/RefreshOperationTest.java @@ -0,0 +1,45 @@ +package kademlia.tests; + +import java.io.IOException; +import java.util.List; +import kademlia.core.GetParameter; +import kademlia.core.Kademlia; +import kademlia.dht.KadContent; +import kademlia.node.NodeId; + +/** + * Testing sending and receiving content between 2 Nodes on a network + * + * @author Joshua Kissoon + * @since 20140224 + */ +public class RefreshOperationTest +{ + + public static void main(String[] args) + { + try + { + /* Setting up 2 Kad networks */ + Kademlia kad1 = new Kademlia("JoshuaK", new NodeId("ASF45678947584567467"), 7574); + Kademlia kad2 = new Kademlia("Crystal", new NodeId("ASERTKJDHGVHERJHGFLK"), 7572); + kad2.connect(kad1.getNode()); + + /* Lets create the content and share it */ + DHTContentImpl c = new DHTContentImpl(kad2.getOwnerId(), "Some Data"); + kad2.put(c); + + /* Lets retrieve the content */ + GetParameter gp = new GetParameter(c.getKey()); + gp.setType(DHTContentImpl.TYPE); + gp.setOwnerId(c.getOwnerId()); + List conte = kad2.get(gp, 1); + + kad2.refresh(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } +}