diff --git a/README.md b/README.md
index cee310af..86b34f58 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,13 @@ $ ./run.sh config/kademlia.cfg
Follow PeerSim [documentation](http://peersim.sourceforge.net/tutorialed/)
+## Contribution
+If you want to contribute:
+* Fork the repo to your repo
+* Write your contribution
+* Rebase your code (here's a [tutorial](https://www.howtogeek.com/849210/git-rebase/)) to make sure the changes introduced into the main repo are take into account in your contribution
+* Create a pull request
+
## Code Documentation
TBC
diff --git a/simulator/config/dasprotocol.cfg b/simulator/config/dasprotocol.cfg
new file mode 100644
index 00000000..ba4f7c31
--- /dev/null
+++ b/simulator/config/dasprotocol.cfg
@@ -0,0 +1,106 @@
+# ::::::::::::::::::::::::::::::::::::::::::::::::::::::
+# :: Kademlia Default Configuration
+# ::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+# ::::: GLOBAL ::::::
+
+# Network size
+SIZE 1000
+
+# Random seed
+K 5
+
+MINDELAY 100
+MAXDELAY 100
+
+#Simulation time in ms
+SIM_TIME 1000*60*60
+
+#Traffic generator is executed every TRAFFIC_STEP
+TRAFFIC_STEP 300000 #10000000/SIZE
+#Tracing module is executed every OBSERVER_STEP
+OBSERVER_STEP 100000
+#Turbulence module is executed every TURBULENCE_STEP enabling churning
+TURBULENCE_STEP (SIM_TIME*20)/SIZE #100000000/SIZE
+
+
+# add network config parameters to simulation
+random.seed 24680
+simulation.experiments 1
+simulation.endtime SIM_TIME
+network.size SIZE
+
+
+# Peersim protocols enabled in each node
+
+#A protocol that stores links. It does nothing apart from that. Use by default
+protocol.0link peersim.core.IdleProtocol
+
+#A protocol that stores links. It does nothing apart from that. Use by default
+protocol.1uniftr peersim.transport.UniformRandomTransport
+protocol.1uniftr.mindelay MINDELAY
+protocol.1uniftr.maxdelay MAXDELAY
+
+#transport layer that reliably delivers messages with a random delay, emulating TCP
+protocol.2unreltr peersim.transport.UnreliableTransport
+protocol.2unreltr.drop 0
+protocol.2unreltr.transport 1uniftr
+
+#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table.
+#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P
+protocol.3kademlia peersim.kademlia.KademliaProtocol
+protocol.3kademlia.transport 2unreltr
+protocol.3kademlia.BITS 256
+protocol.3kademlia.NBUCKETS 17
+protocol.3kademlia.FINDMODE 1
+
+#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table.
+#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P
+protocol.4dasprotocol peersim.kademlia.das.DASProtocol
+protocol.4dasprotocol.transport 2unreltr
+protocol.4dasprotocol.kademlia 3kademlia
+
+
+protocol.5evildasprotocol peersim.kademlia.das.EvilDASProtocol
+protocol.5evildasprotocol.transport 2unreltr
+protocol.5evildasprotocol.kademlia 3kademlia
+init.1uniqueNodeID.protocolEvildas 5evildasprotocol
+
+
+# ::::: INITIALIZERS :::::
+#Class that initializes nodes with kademlia protocol and generates uniform ids
+init.1uniqueNodeID peersim.kademlia.das.CustomDistributionDas
+init.1uniqueNodeID.protocolkad 3kademlia
+init.1uniqueNodeID.protocoldas 4dasprotocol
+init.1uniqueNodeID.protocolEvildas 5evildasprotocol
+
+#Adds initial state to the routing tables
+init.2statebuilder peersim.kademlia.StateBuilder
+init.2statebuilder.protocol 3kademlia
+init.2statebuilder.transport 2unreltr
+
+# ::::: CONTROLS :::::
+
+#TrafficGenerator class sends and initial
+control.0traffic peersim.kademlia.das.TrafficGeneratorSample
+control.0traffic.kadprotocol 3kademlia
+control.0traffic.dasprotocol 4dasprotocol
+control.0traffic.step TRAFFIC_STEP
+control.0traffic.mapping_fn 2
+control.0traffic.sample_copy_per_node 3
+control.0traffic.block_dim_size 512
+
+# turbulence
+#control.2turbolenceAdd peersim.kademlia.Turbulence
+#control.2turbolenceAdd.protocol 3kademlia
+#control.2turbolenceAdd.transport 2unreltr
+#control.2turbolenceAdd.step TURBULENCE_STEP
+#control.2turbolenceAdd.p_idle 0.5
+#control.2turbolenceAdd.p_rem 0.25
+#control.2turbolenceAdd.p_add 0.25
+
+# ::::: OBSERVER :::::
+#The observer is executed every OBSERVER_STEP and will generate data traces
+control.3 peersim.kademlia.KademliaObserver
+control.3.protocol 3kademlia
+control.3.step OBSERVER_STEP
diff --git a/simulator/config/dasprotocoldouble.cfg b/simulator/config/dasprotocoldouble.cfg
new file mode 100644
index 00000000..33f14be0
--- /dev/null
+++ b/simulator/config/dasprotocoldouble.cfg
@@ -0,0 +1,105 @@
+# ::::::::::::::::::::::::::::::::::::::::::::::::::::::
+# :: Kademlia Default Configuration
+# ::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+# ::::: GLOBAL ::::::
+
+# Network size
+SIZE 2000
+
+# Random seed
+K 5
+
+MINDELAY 100
+MAXDELAY 100
+
+#Simulation time in ms
+SIM_TIME 1000*60*60
+
+#Traffic generator is executed every TRAFFIC_STEP
+TRAFFIC_STEP 300000 #10000000/SIZE
+#Tracing module is executed every OBSERVER_STEP
+OBSERVER_STEP 100000
+#Turbulence module is executed every TURBULENCE_STEP enabling churning
+TURBULENCE_STEP (SIM_TIME*20)/SIZE #100000000/SIZE
+
+
+# add network config parameters to simulation
+random.seed 24680
+simulation.experiments 1
+simulation.endtime SIM_TIME
+network.size SIZE
+
+
+# Peersim protocols enabled in each node
+
+#A protocol that stores links. It does nothing apart from that. Use by default
+protocol.0link peersim.core.IdleProtocol
+
+#A protocol that stores links. It does nothing apart from that. Use by default
+protocol.1uniftr peersim.transport.UniformRandomTransport
+protocol.1uniftr.mindelay MINDELAY
+protocol.1uniftr.maxdelay MAXDELAY
+
+#transport layer that reliably delivers messages with a random delay, emulating TCP
+protocol.2unreltr peersim.transport.UnreliableTransport
+protocol.2unreltr.drop 0
+protocol.2unreltr.transport 1uniftr
+
+#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table.
+#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P
+protocol.3kademlia peersim.kademlia.KademliaProtocol
+protocol.3kademlia.transport 2unreltr
+protocol.3kademlia.BITS 256
+protocol.3kademlia.NBUCKETS 17
+protocol.3kademlia.FINDMODE 1
+
+#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table.
+#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P
+protocol.4dasprotocol peersim.kademlia.das.DASProtocol
+protocol.4dasprotocol.transport 2unreltr
+protocol.4dasprotocol.kademlia 3kademlia
+
+protocol.5evildasprotocol peersim.kademlia.das.EvilDASProtocol
+protocol.5evildasprotocol.transport 2unreltr
+protocol.5evildasprotocol.kademlia 3kademlia
+init.1uniqueNodeID.protocolEvildas 5evildasprotocol
+
+# ::::: INITIALIZERS :::::
+#Class that initializes nodes with kademlia protocol and generates uniform ids
+init.1uniqueNodeID peersim.kademlia.das.CustomDistributionDas
+init.1uniqueNodeID.protocolkad 3kademlia
+init.1uniqueNodeID.protocoldas 4dasprotocol
+init.1uniqueNodeID.protocolEvildas 5evildasprotocol
+
+
+#Adds initial state to the routing tables
+init.2statebuilder peersim.kademlia.StateBuilder
+init.2statebuilder.protocol 3kademlia
+init.2statebuilder.transport 2unreltr
+
+# ::::: CONTROLS :::::
+
+#TrafficGenerator class sends and initial
+control.0traffic peersim.kademlia.das.TrafficGeneratorDoubleSample
+control.0traffic.kadprotocol 3kademlia
+control.0traffic.dasprotocol 4dasprotocol
+control.0traffic.step TRAFFIC_STEP
+control.0traffic.mapping_fn 2
+control.0traffic.sample_copy_per_node 2
+control.0traffic.block_dim_size 100
+
+# turbulence
+#control.2turbolenceAdd peersim.kademlia.Turbulence
+#control.2turbolenceAdd.protocol 3kademlia
+#control.2turbolenceAdd.transport 2unreltr
+#control.2turbolenceAdd.step TURBULENCE_STEP
+#control.2turbolenceAdd.p_idle 0.5
+#control.2turbolenceAdd.p_rem 0.25
+#control.2turbolenceAdd.p_add 0.25
+
+# ::::: OBSERVER :::::
+#The observer is executed every OBSERVER_STEP and will generate data traces
+control.3 peersim.kademlia.KademliaObserver
+control.3.protocol 3kademlia
+control.3.step OBSERVER_STEP
diff --git a/simulator/config/kademlia.cfg b/simulator/config/kademlia.cfg
index 093ab0ee..b78a48c1 100755
--- a/simulator/config/kademlia.cfg
+++ b/simulator/config/kademlia.cfg
@@ -22,7 +22,8 @@ TRAFFIC_STEP 300000 #10000000/SIZE
OBSERVER_STEP 100000
#Turbulence module is executed every TURBULENCE_STEP enabling churning
TURBULENCE_STEP (SIM_TIME*20)/SIZE #100000000/SIZE
-
+#Every REFRESH_STEP nodes check a random bucket for dead nodes
+REFRESH_STEP 100000
# add network config parameters to simulation
random.seed 24680
@@ -71,6 +72,10 @@ control.0traffic peersim.kademlia.TrafficGenerator
control.0traffic.protocol 3kademlia
control.0traffic.step TRAFFIC_STEP
+#refresh buckets
+control.1 peersim.kademlia.RefreshBuckets
+control.1.step REFRESH_STEP
+
# turbulence
#control.2turbolenceAdd peersim.kademlia.Turbulence
#control.2turbolenceAdd.protocol 3kademlia
diff --git a/simulator/config/kademlia_sample_put.cfg b/simulator/config/kademlia_sample_put.cfg
new file mode 100755
index 00000000..f2972558
--- /dev/null
+++ b/simulator/config/kademlia_sample_put.cfg
@@ -0,0 +1,90 @@
+# ::::::::::::::::::::::::::::::::::::::::::::::::::::::
+# :: Kademlia Default Configuration
+# ::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+# ::::: GLOBAL ::::::
+
+# Network size
+SIZE 1000
+
+# Random seed
+K 5
+
+MINDELAY 100
+MAXDELAY 100
+
+#Simulation time in ms
+SIM_TIME 1000*60*60
+
+#Traffic generator is executed every TRAFFIC_STEP
+TRAFFIC_STEP 300000 #10000000/SIZE
+#Tracing module is executed every OBSERVER_STEP
+OBSERVER_STEP 100000
+#Turbulence module is executed every TURBULENCE_STEP enabling churning
+TURBULENCE_STEP (SIM_TIME*20)/SIZE #100000000/SIZE
+
+
+# add network config parameters to simulation
+random.seed 24680
+simulation.experiments 1
+simulation.endtime SIM_TIME
+network.size SIZE
+
+
+# Peersim protocols enabled in each node
+
+#A protocol that stores links. It does nothing apart from that. Use by default
+protocol.0link peersim.core.IdleProtocol
+
+#A protocol that stores links. It does nothing apart from that. Use by default
+protocol.1uniftr peersim.transport.UniformRandomTransport
+protocol.1uniftr.mindelay MINDELAY
+protocol.1uniftr.maxdelay MAXDELAY
+
+#transport layer that reliably delivers messages with a random delay, emulating TCP
+protocol.2unreltr peersim.transport.UnreliableTransport
+protocol.2unreltr.drop 0
+protocol.2unreltr.transport 1uniftr
+
+#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table.
+#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P
+protocol.3kademlia peersim.kademlia.KademliaProtocol
+protocol.3kademlia.transport 2unreltr
+protocol.3kademlia.BITS 256
+protocol.3kademlia.NBUCKETS 17
+protocol.3kademlia.FINDMODE 1
+
+# ::::: INITIALIZERS :::::
+#Class that initializes nodes with kademlia protocol and generates uniform ids
+init.1uniqueNodeID peersim.kademlia.CustomDistribution
+init.1uniqueNodeID.protocol 3kademlia
+
+#Adds initial state to the routing tables
+init.2statebuilder peersim.kademlia.StateBuilder
+init.2statebuilder.protocol 3kademlia
+init.2statebuilder.transport 2unreltr
+
+# ::::: CONTROLS :::::
+
+#TrafficGenerator class sends and initial
+control.0traffic peersim.kademlia.das.TrafficGeneratorSamplePut
+control.0traffic.protocol 3kademlia
+control.0traffic.step TRAFFIC_STEP
+control.0traffic.mapping_fn 2
+control.0traffic.sample_copy_per_node 5
+control.0traffic.block_dim_size 20
+
+# turbulence
+#control.2turbolenceAdd peersim.kademlia.Turbulence
+#control.2turbolenceAdd.protocol 3kademlia
+#control.2turbolenceAdd.transport 2unreltr
+#control.2turbolenceAdd.step TURBULENCE_STEP
+#control.2turbolenceAdd.p_idle 0.5
+#control.2turbolenceAdd.p_rem 0.25
+#control.2turbolenceAdd.p_add 0.25
+
+# ::::: OBSERVER :::::
+#The observer is executed every OBSERVER_STEP and will generate data traces
+control.3 peersim.kademlia.KademliaObserver
+control.3.protocol 3kademlia
+control.3.step OBSERVER_STEP
diff --git a/simulator/config/malicious/maliciousScenario.cfg b/simulator/config/malicious/maliciousScenario.cfg
new file mode 100644
index 00000000..aa3eb2e5
--- /dev/null
+++ b/simulator/config/malicious/maliciousScenario.cfg
@@ -0,0 +1,102 @@
+# ::::::::::::::::::::::::::::::::::::::::::::::::::::::
+# :: Kademlia Default Configuration
+# ::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+# ::::: GLOBAL ::::::
+
+# Network size
+SIZE 100
+
+# Random seed
+K 5
+
+MINDELAY 100
+MAXDELAY 100
+
+#Simulation time in ms
+SIM_TIME 1000*60*60
+
+#Traffic generator is executed every TRAFFIC_STEP
+TRAFFIC_STEP 300000 #10000000/SIZE
+#Tracing module is executed every OBSERVER_STEP
+OBSERVER_STEP 100000
+#Turbulence module is executed every TURBULENCE_STEP enabling churning
+TURBULENCE_STEP (SIM_TIME*20)/SIZE #100000000/SIZE
+
+
+# add network config parameters to simulation
+random.seed 24680
+simulation.experiments 1
+simulation.endtime SIM_TIME
+network.size SIZE
+
+
+# Peersim protocols enabled in each node
+
+#A protocol that stores links. It does nothing apart from that. Use by default
+protocol.0link peersim.core.IdleProtocol
+
+#A protocol that stores links. It does nothing apart from that. Use by default
+protocol.1uniftr peersim.transport.UniformRandomTransport
+protocol.1uniftr.mindelay MINDELAY
+protocol.1uniftr.maxdelay MAXDELAY
+
+#transport layer that reliably delivers messages with a random delay, emulating TCP
+protocol.2unreltr peersim.transport.UnreliableTransport
+protocol.2unreltr.drop 0
+protocol.2unreltr.transport 1uniftr
+
+#Kademlia protocol with 256 bits identifiers and 17 buckets in the routing table.
+#Use FINDMODE 1 to send FINDMODE messages looking for distance to specific node instead of sending the id of the node like in DEVP2P
+protocol.3kademlia peersim.kademlia.KademliaProtocol
+protocol.3kademlia.transport 2unreltr
+protocol.3kademlia.BITS 256
+protocol.3kademlia.NBUCKETS 17
+protocol.3kademlia.FINDMODE 1
+
+protocol.4dasprotocol peersim.kademlia.das.DASProtocol
+protocol.4dasprotocol.transport 2unreltr
+protocol.4dasprotocol.kademlia 3kademlia
+
+protocol.5evildasprotocol peersim.kademlia.das.EvilDASProtocol
+protocol.5evildasprotocol.transport 2unreltr
+protocol.5evildasprotocol.kademlia 3kademlia
+
+# ::::: INITIALIZERS :::::
+#Class that initializes nodes with kademlia protocol and generates uniform ids
+init.1uniqueNodeID peersim.kademlia.das.CustomDistributionDas
+init.1uniqueNodeID.protocolkad 3kademlia
+init.1uniqueNodeID.protocoldas 4dasprotocol
+init.1uniqueNodeID.protocolEvildas 5evildasprotocol
+init.1uniqueNodeID.evilNodeRatio 0.1
+
+#Adds initial state to the routing tables
+init.2statebuilder peersim.kademlia.StateBuilder
+init.2statebuilder.protocol 3kademlia
+init.2statebuilder.transport 2unreltr
+
+# ::::: CONTROLS :::::
+
+#TrafficGenerator class sends and initial
+control.0traffic peersim.kademlia.das.TrafficGeneratorSample
+control.0traffic.kadprotocol 3kademlia
+control.0traffic.dasprotocol 4dasprotocol
+control.0traffic.step TRAFFIC_STEP
+control.0traffic.mapping_fn 2
+control.0traffic.sample_copy_per_node 3
+control.0traffic.block_dim_size 512
+
+# turbulence
+#control.2turbolenceAdd peersim.kademlia.Turbulence
+#control.2turbolenceAdd.protocol 3kademlia
+#control.2turbolenceAdd.transport 2unreltr
+#control.2turbolenceAdd.step TURBULENCE_STEP
+#control.2turbolenceAdd.p_idle 0.5
+#control.2turbolenceAdd.p_rem 0.25
+#control.2turbolenceAdd.p_add 0.25
+
+# ::::: OBSERVER :::::
+#The observer is executed every OBSERVER_STEP and will generate data traces
+control.3 peersim.kademlia.KademliaObserver
+control.3.protocol 3kademlia
+control.3.step OBSERVER_STEP
diff --git a/simulator/pom.xml b/simulator/pom.xml
index 43342e94..25e0be0a 100644
--- a/simulator/pom.xml
+++ b/simulator/pom.xml
@@ -31,7 +31,7 @@
org.json
json
- 20200518
+ 20230227
org.junit.jupiter
diff --git a/simulator/src/main/java/peersim/core/GeneralNode.java b/simulator/src/main/java/peersim/core/GeneralNode.java
index d2a6d513..5df01bd0 100644
--- a/simulator/src/main/java/peersim/core/GeneralNode.java
+++ b/simulator/src/main/java/peersim/core/GeneralNode.java
@@ -20,6 +20,7 @@
import peersim.config.*;
import peersim.kademlia.KademliaProtocol;
+import peersim.kademlia.das.DASProtocol;
/** This is the default {@link Node} class that is used to compose the {@link Network}. */
public class GeneralNode implements Node {
@@ -51,6 +52,9 @@ public class GeneralNode implements Node {
/** The KademliaProtocol instance that this node is running. */
private KademliaProtocol kadProtocol;
+ /** The DASProtocol instance that this node is running. */
+ private DASProtocol dasProtocol;
+
// ================ constructor and initialization =================
// =================================================================
@@ -180,8 +184,18 @@ public void setKademliaProtocol(KademliaProtocol proto) {
this.kadProtocol = proto;
}
+ // ------------------------------------------------------------------
+ public void setDASProtocol(DASProtocol proto) {
+ this.dasProtocol = proto;
+ }
+
// ------------------------------------------------------------------
+ public DASProtocol getDASProtocol() {
+ return this.dasProtocol;
+ }
+
+ // ------------------------------------------------------------------
/**
* Returns the ID of this node. The IDs are generated using a counter (i.e. they are not random).
*/
diff --git a/simulator/src/main/java/peersim/core/Node.java b/simulator/src/main/java/peersim/core/Node.java
index 4a664192..54a712b0 100644
--- a/simulator/src/main/java/peersim/core/Node.java
+++ b/simulator/src/main/java/peersim/core/Node.java
@@ -19,6 +19,7 @@
package peersim.core;
import peersim.kademlia.KademliaProtocol;
+import peersim.kademlia.das.DASProtocol;
/**
* Class that represents one node with a network address. An {@link Network} is made of a set of
@@ -94,4 +95,16 @@ public interface Node extends Fallible, Cloneable {
* Kademlia Protocols.
*/
public void setKademliaProtocol(KademliaProtocol proto);
+
+ /**
+ * Returns the DAS Protocol used by the node. This is useful when nodes use different types of DAS
+ * Protocols and saves the caller from determining which protocol ID to use for each node.
+ */
+ public DASProtocol getDASProtocol();
+
+ /**
+ * Sets the DAS Protocol used by the node. This is useful when nodes use different types of DAS
+ * Protocols.
+ */
+ public void setDASProtocol(DASProtocol proto);
}
diff --git a/simulator/src/main/java/peersim/kademlia/KBucket.java b/simulator/src/main/java/peersim/kademlia/KBucket.java
index 439c6d16..8326527c 100755
--- a/simulator/src/main/java/peersim/kademlia/KBucket.java
+++ b/simulator/src/main/java/peersim/kademlia/KBucket.java
@@ -1,8 +1,11 @@
package peersim.kademlia;
import java.math.BigInteger;
-import java.util.TreeMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
import peersim.core.CommonState;
+import peersim.core.Node;
/**
* This class implements a kademlia k-bucket. Function for the management of the neighbours update
@@ -12,23 +15,86 @@
* @version 1.0
*/
public class KBucket implements Cloneable {
+ // Replacement bucket
+ protected List replacements;
+
+ protected RoutingTable rTable;
// k-bucket array
- protected TreeMap neighbours = null;
+ protected List neighbours = null;
+
+ // k-bucket size, max replacement bucket size
+ protected int k, maxReplacements;
- // empty costructor
+ // empty constructor
public KBucket() {
- neighbours = new TreeMap();
+ neighbours = new ArrayList();
+ replacements = new ArrayList();
+ }
+
+ public KBucket(RoutingTable rTable, int k, int maxReplacements) {
+ neighbours = new ArrayList();
+ replacements = new ArrayList();
+ this.k = k;
+ this.maxReplacements = maxReplacements;
+ this.rTable = rTable;
+ }
+
+ public void checkAndReplaceLast() {
+ if (neighbours.size() == 0 || CommonState.getTime() == 0)
+ // Entry has moved, don't replace it.
+ return;
+
+ // System.out.println("Replace node "+neighbours.get(neighbours.size()-1)+" at
+ // "+CommonState.getTime());
+
+ // Get a random node
+ Random random = new Random();
+
+ int min = 0;
+ int max = neighbours.size();
+ BigInteger randomIndex = new BigInteger(String.valueOf(random.nextInt(max - min + 1) + min));
+
+ // KademliaProtocol object to access nodeIDtoNode()
+ KademliaProtocol kProtocol = new KademliaProtocol(null);
+
+ Node node = kProtocol.nodeIdtoNode(randomIndex);
+
+ // System.out.println("Replace node "+neighbours.get(neighbours.size()-1)+" at
+ // "+CommonState.getTime());
+
+ // System.out.println("checkAndReplaceLast "+remote.getNode().getId()+" at
+ // "+CommonState.getTime()+" at "+rTable.nodeId);
+
+ if (node.getFailState() != Node.OK) {
+ // Still the last entry.
+ removeNeighbour(randomIndex);
+
+ if (replacements.size() > 0) {
+ // Random rand = new Random();
+ // BigInteger n = replacements.get(rand.nextInt(replacements.size()));
+ BigInteger n = replacements.get(CommonState.r.nextInt(replacements.size()));
+ addNeighbour(n);
+ removeReplacement(n);
+ }
+ }
}
// add a neighbour to this k-bucket
public boolean addNeighbour(BigInteger node) {
- long time = CommonState.getTime();
- if (neighbours.size() < KademliaCommonConfig.K) { // k-bucket isn't full
- neighbours.put(node, time); // add neighbour to the tail of the list
+ if (neighbours.size() < k) { // k-bucket isn't full
+
+ neighbours.add(node); // add neighbour to the tail of the list
+ removeReplacement(node);
+
return true;
+
+ } else {
+
+ addReplacement(node);
+
+ return false;
}
- return false;
}
// remove a neighbour from this k-bucket
@@ -36,10 +102,27 @@ public void removeNeighbour(BigInteger node) {
neighbours.remove(node);
}
+ public void addReplacement(BigInteger node) {
+ if (!replacements.contains(node)) {
+ replacements.add(0, node);
+
+ if (replacements.size() > maxReplacements) {
+ // Replacements is full - remove the last item
+ replacements.remove(replacements.size() - 1);
+ }
+ }
+ }
+
+ public void removeReplacement(BigInteger node) {
+ if (replacements.size() > 0) {
+ replacements.remove(node);
+ }
+ }
+
public Object clone() {
KBucket dolly = new KBucket();
- for (BigInteger node : neighbours.keySet()) {
- dolly.neighbours.put(new BigInteger(node.toByteArray()), 0l);
+ for (BigInteger node : neighbours) {
+ dolly.neighbours.add(new BigInteger(node.toByteArray()));
}
return dolly;
}
@@ -47,7 +130,7 @@ public Object clone() {
public String toString() {
String res = "{\n";
- for (BigInteger node : neighbours.keySet()) {
+ for (BigInteger node : neighbours) {
res += node + "\n";
}
diff --git a/simulator/src/main/java/peersim/kademlia/KademliaEvents.java b/simulator/src/main/java/peersim/kademlia/KademliaEvents.java
new file mode 100644
index 00000000..5724600e
--- /dev/null
+++ b/simulator/src/main/java/peersim/kademlia/KademliaEvents.java
@@ -0,0 +1,11 @@
+package peersim.kademlia;
+
+import java.math.BigInteger;
+import peersim.kademlia.operations.Operation;
+
+public interface KademliaEvents {
+
+ public void nodesFound(Operation op, BigInteger[] neighbours);
+
+ public void operationComplete(Operation op);
+}
diff --git a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java
index 85d6e725..82528b74 100755
--- a/simulator/src/main/java/peersim/kademlia/KademliaObserver.java
+++ b/simulator/src/main/java/peersim/kademlia/KademliaObserver.java
@@ -10,6 +10,7 @@
import peersim.core.CommonState;
import peersim.core.Control;
import peersim.core.Network;
+import peersim.kademlia.operations.Operation;
import peersim.util.IncrementalStats;
/**
@@ -45,6 +46,9 @@ public class KademliaObserver implements Control {
private static HashMap> messages =
new HashMap>();
+ private static HashMap> find_log =
+ new HashMap>();
+
/** Name of the folder where experiment logs are written */
private static String logFolderName;
@@ -57,13 +61,16 @@ public KademliaObserver(String prefix) {
logFolderName = "./logs";
}
+ /** Message writeMap */
private static void writeMap(Map> map, String filename) {
try (FileWriter writer = new FileWriter(filename)) {
Set keySet = map.entrySet().iterator().next().getValue().keySet();
+
String header = "";
for (Object key : keySet) {
header += key + ",";
}
+
// remove the last comma
header = header.substring(0, header.length() - 1);
header += "\n";
@@ -72,7 +79,7 @@ private static void writeMap(Map> map, String filena
for (Map entry : messages.values()) {
String line = "";
for (Object key : keySet) {
- line += "," + entry.get(key).toString();
+ line += entry.get(key).toString() + ",";
}
// remove the last comma
line = line.substring(0, line.length() - 1);
@@ -85,6 +92,36 @@ private static void writeMap(Map> map, String filena
}
}
+ /** Write map find operation */
+ private static void writeMapFind(Map> map, String filename) {
+ try (FileWriter writer = new FileWriter(filename)) {
+ Set keySet = map.entrySet().iterator().next().getValue().keySet();
+ String header = "";
+ for (Object key : keySet) {
+ header += key + ",";
+ }
+
+ // remove the last comma
+ header = header.substring(0, header.length() - 1);
+ header += "\n";
+ writer.write(header);
+
+ for (Map entry : find_log.values()) {
+ String line = "";
+ for (Object key : keySet) {
+ line += entry.get(key).toString() + ",";
+ }
+ // remove the last comma
+ line = line.substring(0, line.length());
+ line += "\n";
+ writer.write(line);
+ }
+ writer.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
public static void writeOut() {
File directory = new File(logFolderName);
if (!directory.exists()) {
@@ -93,6 +130,9 @@ public static void writeOut() {
if (!messages.isEmpty()) {
writeMap(messages, logFolderName + "/" + "messages.csv");
}
+ if (!find_log.isEmpty()) {
+ writeMapFind(find_log, logFolderName + "/" + "operation.csv");
+ }
}
/**
@@ -138,4 +178,15 @@ public static void reportMsg(Message m, boolean sent) {
assert (!messages.keySet().contains(String.valueOf(m.id)));
messages.put(String.valueOf(m.id), m.toMap(sent));
}
+
+ public static void reportOperation(Operation op) {
+ // messages without source are control messages sent by the traffic control
+ // we don't want to log them
+ /*if (fLog.src == null) {
+ return;
+ }
+ find_log.put(String.valueOf(fLog.id), fLog.toMap());*/
+ op.setStopTime(CommonState.getTime() - op.getTimestamp());
+ find_log.put(String.valueOf(op.getId()), op.toMap());
+ }
}
diff --git a/simulator/src/main/java/peersim/kademlia/KademliaProtocol.java b/simulator/src/main/java/peersim/kademlia/KademliaProtocol.java
index dd7f9ab9..bb5dcca1 100755
--- a/simulator/src/main/java/peersim/kademlia/KademliaProtocol.java
+++ b/simulator/src/main/java/peersim/kademlia/KademliaProtocol.java
@@ -9,7 +9,6 @@
*/
import java.math.BigInteger;
import java.util.Arrays;
-// logging
import java.util.LinkedHashMap;
import java.util.TreeMap;
import java.util.logging.ConsoleHandler;
@@ -25,6 +24,7 @@
import peersim.edsim.EDSimulator;
import peersim.kademlia.operations.FindOperation;
import peersim.kademlia.operations.GetOperation;
+import peersim.kademlia.operations.Operation;
import peersim.kademlia.operations.PutOperation;
import peersim.transport.UnreliableTransport;
@@ -47,7 +47,7 @@ public class KademliaProtocol implements Cloneable, EDProtocol {
private static boolean _ALREADY_INSTALLED = false;
/** routing table of this pastry node */
- private RoutingTable routingTable;
+ protected RoutingTable routingTable;
/** trace message sent for timeout purpose */
private TreeMap sentMsg;
@@ -63,6 +63,9 @@ public class KademliaProtocol implements Cloneable, EDProtocol {
private KeyValueStore kv;
+ public LinkedHashMap findLog;
+ private KademliaEvents callback;
+
/**
* Replicate this object by returning an identical copy.
* It is called by the initializer and do not fill any particular field.
@@ -96,9 +99,13 @@ public KademliaProtocol(String prefix) {
findOp = new LinkedHashMap();
+ findLog = new LinkedHashMap();
+
tid = Configuration.getPid(prefix + "." + PAR_TRANSPORT);
kv = new KeyValueStore();
+
+ // System.out.println("New kademliaprotocol");
}
/**
@@ -130,7 +137,7 @@ private void _init() {
* @param searchNodeId BigInteger
* @return Node
*/
- private Node nodeIdtoNode(BigInteger searchNodeId) {
+ public Node nodeIdtoNode(BigInteger searchNodeId) {
if (searchNodeId == null) return null;
int inf = 0;
@@ -141,7 +148,7 @@ private Node nodeIdtoNode(BigInteger searchNodeId) {
m = (inf + sup) / 2;
BigInteger mId =
- ((KademliaProtocol) Network.get(m).getProtocol(kademliaid)).getNode().getId();
+ ((KademliaProtocol) Network.get(m).getProtocol(kademliaid)).getKademliaNode().getId();
if (mId.equals(searchNodeId)) return Network.get(m);
@@ -152,13 +159,16 @@ private Node nodeIdtoNode(BigInteger searchNodeId) {
// perform a traditional search for more reliability (maybe the network is not ordered)
BigInteger mId;
for (int i = Network.size() - 1; i >= 0; i--) {
- mId = ((KademliaProtocol) Network.get(i).getProtocol(kademliaid)).getNode().getId();
+ mId = ((KademliaProtocol) Network.get(i).getProtocol(kademliaid)).getKademliaNode().getId();
if (mId.equals(searchNodeId)) return Network.get(i);
}
return null;
}
+ public Node getNode() {
+ return nodeIdtoNode(this.getKademliaNode().getId());
+ }
/**
* Perform the required operation upon receiving a message in response to a ROUTE message.
* Update the find operation record with the closest set of neighbour received. Than, send as many
@@ -173,57 +183,56 @@ private void handleResponse(Message m, int myPid) {
if (m.src != null) {
routingTable.addNeighbour(m.src.getId());
}
-
- // get corresponding find operation (using the message field operationId)
FindOperation fop = this.findOp.get(m.operationId);
if (fop != null) {
fop.elaborateResponse((BigInteger[]) m.body);
-
- logger.info("Handleresponse FindOperation " + fop.getId() + " " + fop.getAvailableRequests());
+ fop.AddMessage(m.id);
+ logger.warning(
+ "Handleresponse FindOperation " + fop.getId() + " " + fop.getAvailableRequests());
// save received neighbour in the closest Set of fin operation
BigInteger[] neighbours = (BigInteger[]) m.body;
+ if (callback != null) callback.nodesFound(fop, neighbours);
for (BigInteger neighbour : neighbours) routingTable.addNeighbour(neighbour);
if (!fop.isFinished() && Arrays.asList(neighbours).contains(fop.getDestNode())) {
logger.warning("Found node " + fop.getDestNode());
-
+ if (callback != null) callback.operationComplete(fop);
KademliaObserver.find_ok.add(1);
fop.setFinished(true);
}
- if (fop instanceof GetOperation && m.value != null) {
+ if (fop instanceof GetOperation && m.value != null && !fop.isFinished()) {
fop.setFinished(true);
+ if (callback != null) callback.operationComplete(fop);
((GetOperation) fop).setValue(m.value);
logger.warning(
"Getprocess finished found " + ((GetOperation) fop).getValue() + " hops " + fop.nrHops);
}
- while (fop.getAvailableRequests() > 0) { // I can send a new find request
+ while (fop.getAvailableRequests() > 0 && !fop.isFinished()) { // I can send a new find request
// get an available neighbour
BigInteger neighbour = fop.getNeighbour();
if (neighbour != null) {
- if (!fop.isFinished()) {
- // create a new request to send to neighbour
- Message request;
- if (fop instanceof GetOperation) request = new Message(Message.MSG_GET);
- else if (KademliaCommonConfig.FINDMODE == 0) request = new Message(Message.MSG_FIND);
- else request = new Message(Message.MSG_FIND_DIST);
- request.operationId = m.operationId;
- request.src = this.getNode();
- request.dst = nodeIdtoNode(neighbour).getKademliaProtocol().getNode();
- if (KademliaCommonConfig.FINDMODE == 0 || request.getType() == Message.MSG_GET)
- request.body = fop.getDestNode();
- else request.body = Util.logDistance(fop.getDestNode(), (BigInteger) fop.getBody());
- // increment hop count
- fop.nrHops++;
-
- // send find request
- sendMessage(request, neighbour, myPid);
- }
+ // create a new request to send to neighbour
+ Message request;
+ if (fop instanceof GetOperation) request = new Message(Message.MSG_GET);
+ else if (KademliaCommonConfig.FINDMODE == 0) request = new Message(Message.MSG_FIND);
+ else request = new Message(Message.MSG_FIND_DIST);
+ request.operationId = m.operationId;
+ request.src = this.getKademliaNode();
+ request.dst = nodeIdtoNode(neighbour).getKademliaProtocol().getKademliaNode();
+ if (KademliaCommonConfig.FINDMODE == 0 || request.getType() == Message.MSG_GET)
+ request.body = fop.getDestNode();
+ else request.body = Util.logDistance(fop.getDestNode(), (BigInteger) fop.getBody());
+ // increment hop count
+ fop.nrHops++;
+ fop.AddMessage(m.id);
+ // send find request
+ sendMessage(request, neighbour, myPid);
} else if (fop.getAvailableRequests()
== KademliaCommonConfig.ALPHA) { // no new neighbour and no outstanding requests
// search operation finished
@@ -233,23 +242,25 @@ private void handleResponse(Message m, int myPid) {
// create a put request
Message request = new Message(Message.MSG_PUT);
request.operationId = m.operationId;
- request.src = this.getNode();
- request.dst = nodeIdtoNode(id).getKademliaProtocol().getNode();
+ request.src = this.getKademliaNode();
+ request.dst = nodeIdtoNode(id).getKademliaProtocol().getKademliaNode();
request.body = ((PutOperation) fop).getBody();
request.value = ((PutOperation) fop).getValue();
// increment hop count
fop.nrHops++;
+ fop.AddMessage(m.id);
sendMessage(request, id, myPid);
}
logger.warning("Sending PUT_VALUE to " + fop.getNeighboursList().size() + " nodes");
} else if (fop instanceof GetOperation) {
findOp.remove(fop.getId());
logger.warning("Getprocess finished not found ");
-
+ KademliaObserver.reportOperation(fop);
} else {
findOp.remove(fop.getId());
+ KademliaObserver.reportOperation(fop);
}
-
+ if (callback != null) callback.operationComplete(fop);
if (fop.getBody().equals("Automatically Generated Traffic")
&& fop.getClosest().containsKey(fop.getDestNode())) {
// update statistics
@@ -262,11 +273,15 @@ private void handleResponse(Message m, int myPid) {
return;
} else { // no neighbour available but exists oustanding request to wait
+ logger.warning(" no neighbour available but exists oustanding request to wait");
return;
}
}
- } else {
- System.err.println("There has been some error in the protocol");
+ if (fop.isFinished() && fop.getAvailableRequests() == KademliaCommonConfig.ALPHA) {
+ logger.warning("Operation completed. reporting...");
+ KademliaObserver.reportOperation(fop);
+ findOp.remove(fop.getId());
+ }
}
}
@@ -277,7 +292,8 @@ private void handleResponse(Message m, int myPid) {
* @param m Message
* @param myPid the sender Pid
*/
- private void handlePut(Message m, int myPid) {
+ private void handlePut(Message m) {
+ logger.warning("Handle put sample:" + m.body);
kv.add((BigInteger) m.body, m.value);
}
@@ -292,7 +308,6 @@ private void handleFind(Message m, int myPid) {
// get the ALPHA closest node to destNode
logger.info("handleFind received from " + m.src.getId() + " " + m.operationId);
-
BigInteger[] neighbours = new BigInteger[KademliaCommonConfig.K];
if (m.getType() == Message.MSG_FIND || m.getType() == Message.MSG_GET) {
neighbours = this.routingTable.getNeighbours((BigInteger) m.body, m.src.getId());
@@ -307,7 +322,7 @@ private void handleFind(Message m, int myPid) {
Message response = new Message(Message.MSG_RESPONSE, neighbours);
response.operationId = m.operationId;
response.dst = m.dst;
- response.src = this.getNode();
+ response.src = this.getKademliaNode();
response.ackId = m.id; // set ACK number
if (m.getType() == Message.MSG_GET) {
@@ -324,7 +339,7 @@ private void handleFind(Message m, int myPid) {
* @param m Message received (contains the node to find)
* @param myPid the sender Pid
*/
- private void handleInit(Message m, int myPid) {
+ public Operation handleInit(Message m, int myPid) {
logger.info("handleInitFind " + (BigInteger) m.body);
KademliaObserver.find_op.add(1);
@@ -333,6 +348,7 @@ private void handleInit(Message m, int myPid) {
// FindOperation fop = new FindOperation(m.dest, m.timestamp);
FindOperation fop;
+
switch (m.type) {
case Message.MSG_INIT_FIND:
fop = new FindOperation(this.node.getId(), (BigInteger) m.body, m.timestamp);
@@ -354,20 +370,22 @@ private void handleInit(Message m, int myPid) {
// get the ALPHA closest node to srcNode and add to find operation
BigInteger[] neighbours =
- this.routingTable.getNeighbours((BigInteger) m.body, this.getNode().getId());
+ this.routingTable.getNeighbours((BigInteger) m.body, this.getKademliaNode().getId());
fop.elaborateResponse(neighbours);
fop.setAvailableRequests(KademliaCommonConfig.ALPHA);
+
// set message operation id
m.operationId = fop.getId();
-
- m.src = this.getNode();
+ m.src = this.getKademliaNode();
// send ALPHA messages
for (int i = 0; i < KademliaCommonConfig.ALPHA; i++) {
BigInteger nextNode = fop.getNeighbour();
if (nextNode != null) {
m.dst =
- nodeIdtoNode(nextNode).getKademliaProtocol().getNode(); // new KademliaNode(nextNode);
+ nodeIdtoNode(nextNode)
+ .getKademliaProtocol()
+ .getKademliaNode(); // new KademliaNode(nextNode);
// set message type depending on find mode
if (m.type == Message.MSG_INIT_GET) m.type = Message.MSG_GET;
else if (KademliaCommonConfig.FINDMODE == 0) m.type = Message.MSG_FIND;
@@ -377,11 +395,15 @@ private void handleInit(Message m, int myPid) {
}
logger.info("sendMessage to " + nextNode);
-
- sendMessage(m.copy(), nextNode, myPid);
- fop.nrHops++;
+ Message mbis = m.copy();
+ fop.AddMessage(mbis.id);
+ sendMessage(mbis, nextNode, myPid);
+ if (m.getType() == Message.MSG_FIND_DIST) {
+ fop.nrHops++;
+ }
}
}
+ return fop;
}
/**
@@ -392,14 +414,14 @@ private void handleInit(Message m, int myPid) {
* @param destId the Id of the destination node
* @param myPid the sender Pid
*/
- public void sendMessage(Message m, BigInteger destId, int myPid) {
+ private void sendMessage(Message m, BigInteger destId, int myPid) {
// add destination to routing table
this.routingTable.addNeighbour(destId);
// int destpid;
assert m.src != null;
assert m.dst != null;
- Node src = nodeIdtoNode(this.getNode().getId());
+ Node src = nodeIdtoNode(this.getKademliaNode().getId());
Node dest = nodeIdtoNode(destId);
// destpid = dest.getKademliaProtocol().getProtocolID();
@@ -428,7 +450,6 @@ public void processEvent(Node myNode, int myPid, Object event) {
// Parse message content Activate the correct event manager fot the particular event
this.kademliaid = myPid;
-
Message m;
if (event instanceof Message) {
m = (Message) event;
@@ -450,7 +471,13 @@ public void processEvent(Node myNode, int myPid, Object event) {
break;
case Message.MSG_FIND:
+ m = (Message) event;
+ handleFind(m, myPid);
+ break;
case Message.MSG_FIND_DIST:
+ m = (Message) event;
+ handleFind(m, myPid);
+ break;
case Message.MSG_GET:
m = (Message) event;
handleFind(m, myPid);
@@ -458,7 +485,7 @@ public void processEvent(Node myNode, int myPid, Object event) {
case Message.MSG_PUT:
m = (Message) event;
- handlePut(m, myPid);
+ handlePut(m);
break;
case Message.MSG_EMPTY:
@@ -487,10 +514,29 @@ public void processEvent(Node myNode, int myPid, Object event) {
}
break;*/
}
+ /*if (event instanceof Message) {
+ OpLogging fLog;
+
+ m = (Message) event;
+ if (this.findLog.get(m.operationId) == null) {
+ fLog = new OpLogging(m.operationId, this.node.getId(), CommonState.getTime(), m.getType());
+ findLog.put(m.operationId, fLog);
+ } else {
+ fLog = this.findLog.get(m.operationId);
+ }
+ /*Operation Logging */
+ /*fLog.AddMessage(m.id);
+ fLog.SetStop(CommonState.getTime());
+ findLog.put(m.operationId, fLog);
+ }
+
+ for (Map.Entry entry : findLog.entrySet()) {
+ KademliaObserver.reportFindOp(entry.getValue());
+ }*/
}
/** get the current Node */
- public KademliaNode getNode() {
+ public KademliaNode getKademliaNode() {
return this.node;
}
@@ -499,11 +545,21 @@ public RoutingTable getRoutingTable() {
return this.routingTable;
}
+ public void refreshBuckets() {
+ // logger.warning("Calling refreshbuckets");
+ routingTable.refreshBuckets();
+ }
+
/** Set the protocol ID for this node. */
public void setProtocolID(int protocolID) {
this.kademliaid = protocolID;
}
+ /** Get the protocol ID for this node. */
+ public int getProtocolID() {
+ return this.kademliaid;
+ }
+
/**
* set the current NodeId
*
@@ -530,4 +586,12 @@ public synchronized String format(LogRecord lr) {
});
logger.addHandler(handler);
}
+
+ public Logger getLogger() {
+ return this.logger;
+ }
+
+ public void setEventsCallback(KademliaEvents callback) {
+ this.callback = callback;
+ }
}
diff --git a/simulator/src/main/java/peersim/kademlia/KeyValueStore.java b/simulator/src/main/java/peersim/kademlia/KeyValueStore.java
index 2732cbbf..64a63dfb 100644
--- a/simulator/src/main/java/peersim/kademlia/KeyValueStore.java
+++ b/simulator/src/main/java/peersim/kademlia/KeyValueStore.java
@@ -1,6 +1,7 @@
package peersim.kademlia;
import java.math.BigInteger;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
@@ -90,6 +91,15 @@ public Object get(BigInteger key) {
}
}
+ /**
+ * Get all objectrs
+ *
+ * @return All objects in the store
+ */
+ public Collection