diff --git a/.gitignore b/.gitignore index 2d302dcd8..b8ccd69e9 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ doc/package-list .project /target/ .settings/org.eclipse.* +/bin/ diff --git a/compile.bat b/compile.bat old mode 100755 new mode 100644 index c739943b7..490d222f4 --- a/compile.bat +++ b/compile.bat @@ -2,7 +2,7 @@ set targetdir=target IF NOT EXIST "%targetdir%" mkdir %targetdir% -javac -sourcepath src -d %targetdir% -extdirs lib/ src/core/*.java src/movement/*.java src/report/*.java src/routing/*.java src/gui/*.java src/input/*.java src/applications/*.java src/interfaces/*.java +javac -sourcepath src -d %targetdir% -extdirs lib/ src/core/*.java src/movement/*.java src/report/*.java src/routing/*.java src/gui/*.java src/input/*.java src/applications/*.java src/interfaces/*.java src/buffermanagement/*.java src/routing/community/*.java src/routing/centrality/*.java diff --git a/compile.sh b/compile.sh old mode 100755 new mode 100644 index dfcb4cd6b..c5678942f --- a/compile.sh +++ b/compile.sh @@ -2,7 +2,7 @@ targetdir=target if [ ! -d "$targetdir" ]; then mkdir $targetdir; fi -javac -sourcepath src -d $targetdir -extdirs lib/ src/core/*.java src/movement/*.java src/report/*.java src/routing/*.java src/gui/*.java src/input/*.java src/applications/*.java src/interfaces/*.java +javac -sourcepath src -d $targetdir -extdirs lib/ src/core/*.java src/movement/*.java src/report/*.java src/routing/*.java src/gui/*.java src/input/*.java src/applications/*.java src/interfaces/*.java src/buffermanagement/*.java src/routing/community/*.java src/routing/centrality/*.java if [ ! -d "$targetdir/gui/buttonGraphics" ]; then cp -R src/gui/buttonGraphics target/gui/; fi diff --git a/default_settings.txt b/default_settings.txt index fc266f1ba..fd4742934 100644 --- a/default_settings.txt +++ b/default_settings.txt @@ -41,6 +41,8 @@ Scenario.nrofHostGroups = 6 # router: router used to route messages (valid class name from routing package) # activeTimes: Time intervals when the nodes in the group are active (start1, end1, start2, end2, ...) # msgTtl : TTL (minutes) of the messages created by this host group, default=infinite +# dropPolicy: if specified a custom drop policy is used (see the classes in the buffermanagement package). +# dropMsgBeingSent: define if the custom drop policy is allowed to drop messages being sent. ## Group and movement model specific settings # pois: Points Of Interest indexes and probabilities (poiIndex1, poiProb1, poiIndex2, poiProb2, ... ) diff --git a/doc/create_docs.sh b/doc/create_docs.sh old mode 100755 new mode 100644 diff --git a/example_settings/bubblerap_settings.txt b/example_settings/bubblerap_settings.txt new file mode 100644 index 000000000..da576d565 --- /dev/null +++ b/example_settings/bubblerap_settings.txt @@ -0,0 +1,15 @@ +Scenario.nrofHostGroups = 1 +Group1.router = BubbleRapRouter +Group1.nrofHosts = 126 + +# Configure the community detection algorithm +BubbleRapRouter.communityAlg = DistributedKCliqueCommunityDetection +BubbleRapRouter.k = 3 +BubbleRapRouter.familiarThreshold = 3600 + +# Configure the centrality algorithm +BubbleRapRouter.centralityAlg = CWindowCentrality +BubbleRapRouter.timeWindow = 86400 + +Report.report1 = CommunityReport +Report.report2 = CentralityReport diff --git a/example_settings/drop_policy_settings.txt b/example_settings/drop_policy_settings.txt new file mode 100644 index 000000000..1283cc0eb --- /dev/null +++ b/example_settings/drop_policy_settings.txt @@ -0,0 +1,4 @@ +# Configure the drop policy used +Group.dropPolicy = MOFODropPolicy +# Defines if messages being sent can be dropped, the default value is true +Group.dropMsgBeingSent = false \ No newline at end of file diff --git a/one.sh b/one.sh old mode 100755 new mode 100644 diff --git a/src/buffermanagement/DropPolicy.java b/src/buffermanagement/DropPolicy.java new file mode 100644 index 000000000..d1be9fb1f --- /dev/null +++ b/src/buffermanagement/DropPolicy.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package buffermanagement; + +import core.Message; +import core.Settings; +import routing.ActiveRouter; + + +/** + * Defines the basic structure for implementing a message drop policy. A message drop policy is used by the hosts + * when their buffers haven't enough space to receive an incoming message. + */ +public abstract class DropPolicy { + + /** + * Drop message being sent -setting id ({@value}). The configuration that defines + * if messages being sent can be dropped. + */ + private static final String DROP_MSG_BEING_SENT = "dropMsgBeingSent"; + + /** + * Defines if messages being sent can be dropped. + */ + protected boolean dropMsgBeingSent = true; + + /** + * Constructor with the signature required to be instantiated by the simulator. + * @param s Settings applied + */ + public DropPolicy(Settings s) { + if (s.contains(DROP_MSG_BEING_SENT)) { + this.dropMsgBeingSent = s.getBoolean(DROP_MSG_BEING_SENT); + } + } + + /** + * Try to remove messages from the buffer until enough space for receive the incoming message is freed. + * @param router A reference to the receiver router. + * @param incomingMessage The incoming message. + * @return True if it was possible to freed enough space, false otherwise. + */ + public abstract boolean makeRoomForMessage(ActiveRouter router, Message incomingMessage); +} diff --git a/src/buffermanagement/EDropPolicy.java b/src/buffermanagement/EDropPolicy.java new file mode 100644 index 000000000..8c976e4a7 --- /dev/null +++ b/src/buffermanagement/EDropPolicy.java @@ -0,0 +1,76 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package buffermanagement; + +import java.util.Iterator; +import core.Message; +import core.Settings; +import routing.ActiveRouter; + +/** + * Implementation of the E-Drop policy as proposed in the paper + * "E-DROP: An Effective Drop Buffer Management Policy for DTN Routing Protocols" + * that can be found at + * http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.206.3719&rep=rep1&type=pdf + */ +public class EDropPolicy extends DropPolicy { + + /** + * Store a settings reference to pass to FIFO constructor when needed. + */ + private Settings settings; + + public EDropPolicy(Settings s) { + super(s); + this.settings = s; + + // It doesn't need specific settings. + } + + @Override + public boolean makeRoomForMessage(ActiveRouter router, Message incomingMessage) { + + int size = incomingMessage == null ? 0 : incomingMessage.getSize(); + + if (size > router.getBufferSize()) { + return false; // message too big for the buffer + } + + long freeBuffer = router.getFreeBufferSize(); + + while (freeBuffer < size) { + Iterator iter = router.getMessageCollection().iterator(); + + if (!iter.hasNext()) { + return false; // There is no message that can be dropped + } + + // Try to find a message with size greater or equals to the incoming message size + Message msg = null; + while (iter.hasNext()) { + Message temp = iter.next(); + if (temp.getSize() >= size && (this.dropMsgBeingSent || !router.isSending(temp.getId()))) { + msg = temp; + break; + } + } + + // If there is a message to drop + if (msg != null) { + router.deleteMessage(msg.getId(), true); + freeBuffer += msg.getSize(); + } + else { + // If there aren't messages with size equals or greater than the incoming, works like FIFO + FIFODropPolicy fifo = new FIFODropPolicy(this.settings); + return fifo.makeRoomForMessage(router, incomingMessage); + } + } + return true; + } + + +} diff --git a/src/buffermanagement/FIFODropPolicy.java b/src/buffermanagement/FIFODropPolicy.java new file mode 100644 index 000000000..70febcf68 --- /dev/null +++ b/src/buffermanagement/FIFODropPolicy.java @@ -0,0 +1,78 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package buffermanagement; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +import core.Message; +import core.Settings; +import routing.ActiveRouter; + +/** + * Drop the messages that arrived first, i.e., the messages that have the minimum + * receive time. + */ +public class FIFODropPolicy extends DropPolicy{ + + public FIFODropPolicy(Settings s) { + super(s); + // It doesn't need specific settings. + } + + @Override + public boolean makeRoomForMessage(ActiveRouter router, Message incomingMessage) { + + int size = incomingMessage == null ? 0 : incomingMessage.getSize(); + + // Check if the incoming message size exceeds the buffer capacity + if (size > router.getBufferSize()) { + return false; + } + + long freeBuffer = router.getFreeBufferSize(); + + // Check if there is enough space to receive the message before sorting the buffer + if (freeBuffer >= size) { + return true; + } + + // Sort the messages by receive time + ArrayList messages = new ArrayList(router.getMessageCollection()); + Collections.sort(messages, new FIFOComparator()); + + /* Delete messages from the buffer until there is enough space */ + while (freeBuffer < size) { + + if (messages.size() == 0) { + return false; // couldn't remove more messages + } + + // Get the message that was received first + Message msg = messages.remove(0); + + // Check if the router is sending this message + if (this.dropMsgBeingSent || !router.isSending(msg.getId())) { + // Delete the message and send signal "drop" + router.deleteMessage(msg.getId(), true); + freeBuffer += msg.getSize(); + } + } + + return true; + } + + private class FIFOComparator implements Comparator { + + @Override + public int compare(Message m1, Message m2) { + return ((Double)m1.getReceiveTime()).compareTo(m2.getReceiveTime()); + } + + } + +} diff --git a/src/buffermanagement/MOFODropPolicy.java b/src/buffermanagement/MOFODropPolicy.java new file mode 100644 index 000000000..0aece92ba --- /dev/null +++ b/src/buffermanagement/MOFODropPolicy.java @@ -0,0 +1,78 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package buffermanagement; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import core.Message; +import core.Settings; +import routing.ActiveRouter; + +/** + * Drop the messages with the maximum number of transmissions first, i.e., the most forwarded + * messages. + */ +public class MOFODropPolicy extends DropPolicy { + + + public MOFODropPolicy(Settings s) { + super(s); + // It doesn't need specific settings. + } + + @Override + public boolean makeRoomForMessage(ActiveRouter router, Message incomingMessage) { + + int size = incomingMessage == null ? 0 : incomingMessage.getSize(); + + if (size > router.getBufferSize()) { + return false; // message too big for the buffer + } + + long freeBuffer = router.getFreeBufferSize(); + + // Check if there is enough space to receive the message before sorting the buffer + if (freeBuffer >= size) { + return true; + } + + // Sort the messages by forward count + ArrayList messages = new ArrayList(router.getMessageCollection()); + Collections.sort(messages, new MOFOComparator()); + + /* Delete messages from the buffer until there is enough space */ + while (freeBuffer < size) { + + if (messages.size() == 0) { + return false; // couldn't remove more messages + } + + // Get the message that was most forwarded + Message msg = messages.remove(messages.size()-1); + + // Check if the router is sending this message + if (this.dropMsgBeingSent || !router.isSending(msg.getId())) { + // Delete the message and send signal "drop" + router.deleteMessage(msg.getId(), true); + freeBuffer += msg.getSize(); + } + } + + return true; + + } + + private class MOFOComparator implements Comparator { + + @Override + public int compare(Message msg0, Message msg1) { + return ((Integer)msg0.getForwardCount()).compareTo(msg1.getForwardCount()); + } + + } + +} diff --git a/src/buffermanagement/PassiveDropPolicy.java b/src/buffermanagement/PassiveDropPolicy.java new file mode 100644 index 000000000..ed3b62a93 --- /dev/null +++ b/src/buffermanagement/PassiveDropPolicy.java @@ -0,0 +1,35 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package buffermanagement; + +import core.Message; +import core.Settings; +import routing.ActiveRouter; + +/** + * This implementation always refuses to drop a message. It can be used for specific tests. + */ +public class PassiveDropPolicy extends DropPolicy{ + + public PassiveDropPolicy(Settings s) { + super(s); + // It doesn't need specific settings. + } + + @Override + public boolean makeRoomForMessage(ActiveRouter router, Message incomingMessage) { + + // Get the incoming message size. + int size = incomingMessage == null ? 0 : incomingMessage.getSize(); + + // Get the available space. + long freeBuffer = router.getFreeBufferSize(); + + // Return if it is possible to receive the incoming message, it does not drop any messages + return size <= freeBuffer; + } + +} diff --git a/src/buffermanagement/SHLIDropPolicy.java b/src/buffermanagement/SHLIDropPolicy.java new file mode 100644 index 000000000..45cc1951f --- /dev/null +++ b/src/buffermanagement/SHLIDropPolicy.java @@ -0,0 +1,74 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package buffermanagement; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +import core.Message; +import core.Settings; +import routing.ActiveRouter; + +public class SHLIDropPolicy extends DropPolicy { + + public SHLIDropPolicy(Settings s) { + super(s); + // It doesn't need specific settings. + } + + @Override + public boolean makeRoomForMessage(ActiveRouter router, Message incomingMessage) { + + int size = incomingMessage == null ? 0 : incomingMessage.getSize(); + + if (size > router.getBufferSize()) { + return false; // Message too big for the buffer + } + + long freeBuffer = router.getFreeBufferSize(); + + // Check if there is enough space to receive the message before sorting the buffer + if (freeBuffer >= size) { + return true; + } + + // Sort the messages by ttl + ArrayList messages = new ArrayList(router.getMessageCollection()); + Collections.sort(messages, new SHLIComparator()); + + /* delete messages from the buffer until there's enough space */ + while (freeBuffer < size) { + + if (messages.size() == 0) { + return false; // Couldn't remove more messages + } + + // Get the message with minimum ttl + Message msg = messages.remove(0); + + // Check if the router is sending this message + if (this.dropMsgBeingSent || !router.isSending(msg.getId())) { + router.deleteMessage(msg.getId(), true); + freeBuffer += msg.getSize(); + } + } + return true; + + } + + private class SHLIComparator implements Comparator { + + @Override + public int compare(Message msg0, Message msg1) { + return ((Integer)msg0.getTtl()).compareTo(msg1.getTtl()); + } + + } + + + +} diff --git a/src/core/DTNHost.java b/src/core/DTNHost.java index 258be0450..15f902429 100644 --- a/src/core/DTNHost.java +++ b/src/core/DTNHost.java @@ -71,7 +71,7 @@ public DTNHost(List msgLs, //this.name = groupId + ((NetworkInterface)net.get(1)).getAddress(); this.msgListeners = msgLs; - this.movListeners = movLs; + this.movListeners = movLs == null ? new ArrayList() : movLs; // create instances by replicating the prototypes this.movement = mmProto.replicate(); @@ -537,5 +537,16 @@ public boolean equals(DTNHost otherHost) { public int compareTo(DTNHost h) { return this.getAddress() - h.getAddress(); } + + /** + * Registers a new movement listener. This method can be used by + * routers that need to keep track of nodes movement. + * @param listener The listener to add. + */ + public void addMovementListener(MovementListener listener) { + if (!this.movListeners.contains(listener)) { + this.movListeners.add(listener); + } + } } diff --git a/src/core/Message.java b/src/core/Message.java index d037b890b..d7bb3a2e6 100644 --- a/src/core/Message.java +++ b/src/core/Message.java @@ -34,6 +34,9 @@ public class Message implements Comparable { private double timeCreated; /** Initial TTL of the message */ private int initTtl; + + /** Stores how many times the message was forwarded to other hosts **/ + private int forwardCount; /** if a response to this message is required, this is the size of the * response message (or 0 if no response is requested) */ @@ -359,5 +362,27 @@ public String getAppID() { public void setAppID(String appID) { this.appID = appID; } + + /** + * Must be called every time the message is forwarded. + */ + public void incrementForwardCount() { + this.forwardCount++; + } + + /** + * Return how many times the message was forwarded. + */ + public int getForwardCount() { + return this.forwardCount; + } + + /** + * Should be used only by the unit tests to create specific scenarios. + * @param fc New value for forward count. + */ + public void setForwardCount(int fc) { + this.forwardCount = fc; + } } diff --git a/src/report/CentralityReport.java b/src/report/CentralityReport.java new file mode 100644 index 000000000..2801324fa --- /dev/null +++ b/src/report/CentralityReport.java @@ -0,0 +1,48 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package report; + +import core.DTNHost; +import core.SimClock; +import core.SimScenario; +import core.UpdateListener; +import java.util.List; +import routing.MessageRouter; +import routing.centrality.ReportCentrality; +import routing.community.ReportCommunity; + +/** + * Reports the local and global centrality values of the nodes. + */ +public class CentralityReport extends Report implements UpdateListener{ + + private int simulationDuration; + + /** + * Constructor. + */ + public CentralityReport() { + init(); + simulationDuration = (int)Math.floor(SimScenario.getInstance().getEndTime()); + } + + @Override + public void updated(List hosts) { + int curTime = SimClock.getIntTime(); + // If it is the end of the simulation it is time to write the communities + if (curTime % simulationDuration == 0) { + for (DTNHost host : hosts) { + MessageRouter router = host.getRouter(); + if (router instanceof ReportCentrality) { + ReportCentrality report = (ReportCentrality) router; + this.write("" + host.getAddress() + " " + + report.getLocalCentrality() + " " + + report.getGlobalCentrality()); + } + } + } + } +} \ No newline at end of file diff --git a/src/report/CommunityReport.java b/src/report/CommunityReport.java new file mode 100644 index 000000000..3754096bb --- /dev/null +++ b/src/report/CommunityReport.java @@ -0,0 +1,56 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package report; + +import core.DTNHost; +import core.SimClock; +import core.SimScenario; +import core.UpdateListener; +import java.util.List; +import routing.MessageRouter; +import routing.community.ReportCommunity; + +/** + * + * Report the all the nodes' communities. + * + */ +public class CommunityReport extends Report implements UpdateListener { + + private int simulationDuration; + + /** + * + * Constructor. + * + */ + public CommunityReport() { + init(); + simulationDuration = (int) Math.floor(SimScenario.getInstance().getEndTime()); + } + + @Override + public void updated(List hosts) { + int curTime = SimClock.getIntTime(); + + // If it is the end of the simulation it is time to write the + // communities + if (curTime % simulationDuration == 0) { + for (DTNHost host : hosts) { + MessageRouter router = host.getRouter(); + if (router instanceof ReportCommunity) { + ReportCommunity report = (ReportCommunity) router; + StringBuilder strBuilder = new StringBuilder(); + strBuilder.append("" + host.getAddress() + " "); + for (DTNHost h : report.getCommunity()) { + strBuilder.append("" + h.getAddress() + " "); + } + this.write(strBuilder.toString()); + } + } + } + } +} \ No newline at end of file diff --git a/src/report/DeliveredMessageStatsReport.java b/src/report/DeliveredMessageStatsReport.java new file mode 100644 index 000000000..4bef6dcd5 --- /dev/null +++ b/src/report/DeliveredMessageStatsReport.java @@ -0,0 +1,39 @@ +package report; + +import core.DTNHost; +import core.Message; +import core.MessageListener; + +public class DeliveredMessageStatsReport extends Report implements MessageListener { + + @Override + public void newMessage(Message m) { + // TODO Auto-generated method stub + + } + + @Override + public void messageTransferStarted(Message m, DTNHost from, DTNHost to) { + // TODO Auto-generated method stub + + } + + @Override + public void messageDeleted(Message m, DTNHost where, boolean dropped) { + // TODO Auto-generated method stub + + } + + @Override + public void messageTransferAborted(Message m, DTNHost from, DTNHost to) { + // TODO Auto-generated method stub + + } + + @Override + public void messageTransferred(Message m, DTNHost from, DTNHost to, boolean firstDelivery) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/routing/ActiveRouter.java b/src/routing/ActiveRouter.java index 4c8a11f4e..0122cd064 100644 --- a/src/routing/ActiveRouter.java +++ b/src/routing/ActiveRouter.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Random; +import buffermanagement.DropPolicy; import routing.util.EnergyModel; import routing.util.MessageTransferAcceptPolicy; import routing.util.RoutingInfo; @@ -36,6 +37,12 @@ public abstract class ActiveRouter extends MessageRouter { /** should messages that final recipient marks as delivered be deleted * from message buffer */ protected boolean deleteDelivered; + + /** + * Drop policy -setting id ({@value}). The class name used as the drop + * policy implementation. + */ + public static final String DROP_POLICY_S = "dropPolicy"; /** prefix of all response message IDs */ public static final String RESPONSE_PREFIX = "R_"; @@ -48,6 +55,11 @@ public abstract class ActiveRouter extends MessageRouter { private MessageTransferAcceptPolicy policy; private EnergyModel energy; + + /** + * The drop policy used by the router. + */ + private DropPolicy dropPolicy; /** * Constructor. Creates a new message router based on the settings in @@ -60,6 +72,15 @@ public ActiveRouter(Settings s) { this.policy = new MessageTransferAcceptPolicy(s); this.deleteDelivered = s.getBoolean(DELETE_DELIVERED_S, false); + + // Create a drop policy object if it is specified in the settings. + if (s.contains(DROP_POLICY_S)) { + String dropPolicyClass = s.getSetting(DROP_POLICY_S); + this.dropPolicy = (DropPolicy) s.createIntializedObject("buffermanagement." + dropPolicyClass); + } + else { + this.dropPolicy = null; + } if (s.contains(EnergyModel.INIT_ENERGY_S)) { this.energy = new EnergyModel(s); @@ -77,6 +98,7 @@ protected ActiveRouter(ActiveRouter r) { this.deleteDelivered = r.deleteDelivered; this.policy = r.policy; this.energy = (r.energy != null ? r.energy.replicate() : null); + this.dropPolicy = r.dropPolicy; // The hosts of the same group share a single instance of drop policy } @Override @@ -122,7 +144,7 @@ public boolean requestDeliverableMessages(Connection con) { @Override public boolean createNewMessage(Message m) { - makeRoomForNewMessage(m.getSize()); + makeRoomForNewMessage(m); return super.createNewMessage(m); } @@ -251,7 +273,7 @@ protected int checkReceiving(Message m, DTNHost from) { } /* remove oldest messages but not the ones being sent */ - if (!makeRoomForMessage(m.getSize())) { + if (!makeRoomForMessage(m)) { return DENIED_NO_SPACE; // couldn't fit into buffer -> reject } @@ -261,11 +283,18 @@ protected int checkReceiving(Message m, DTNHost from) { /** * Removes messages from the buffer (oldest first) until * there's enough space for the new message. - * @param size Size of the new message - * transferred, the transfer is aborted before message is removed + * @param incomingMessage The message that needs to be stored in the buffer. * @return True if enough space could be freed, false if not */ - protected boolean makeRoomForMessage(int size){ + protected boolean makeRoomForMessage(Message incomingMessage){ + + // Check if a custom drop policy is specified + if (this.dropPolicy != null) { + return this.dropPolicy.makeRoomForMessage(this, incomingMessage); + } + + int size = incomingMessage == null ? 0 : incomingMessage.getSize(); + if (size > this.getBufferSize()) { return false; // message too big for the buffer } @@ -305,10 +334,10 @@ protected void dropExpiredMessages() { * calls {@link #makeRoomForMessage(int)} and ignores the return value. * Therefore, if the message can't fit into buffer, the buffer is only * cleared from messages that are not being sent. - * @param size Size of the new message + * @param msg The new message */ - protected void makeRoomForNewMessage(int size) { - makeRoomForMessage(size); + protected void makeRoomForNewMessage(Message msg) { + makeRoomForMessage(msg); } @@ -607,7 +636,7 @@ else if (!con.isUp()) { if (removeCurrent) { // if the message being sent was holding excess buffer, free it if (this.getFreeBufferSize() < 0) { - this.makeRoomForMessage(0); + this.makeRoomForMessage(null); } sendingConnections.remove(i); } @@ -645,7 +674,13 @@ protected void transferAborted(Connection con) { } * Subclasses that are interested of the event may want to override this. * @param con The connection whose transfer was finalized */ - protected void transferDone(Connection con) { } + protected void transferDone(Connection con) { + // Use the connection copy of the message to retrieve the + // local copy of the message and then increment the forward count + Message msg = this.getMessage(con.getMessage().getId()); + if (msg != null) + msg.incrementForwardCount(); + } @Override public RoutingInfo getRoutingInfo() { @@ -656,5 +691,13 @@ public RoutingInfo getRoutingInfo() { } return top; } + + /** + * Used by the unit tests to verify what drop policy is active. + * @return The current drop policy. + */ + public DropPolicy getDropPolicy() { + return this.dropPolicy; + } } diff --git a/src/routing/BubbleRapRouter.java b/src/routing/BubbleRapRouter.java new file mode 100644 index 000000000..ede347024 --- /dev/null +++ b/src/routing/BubbleRapRouter.java @@ -0,0 +1,116 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package routing; + +import core.DTNHost; +import core.Message; +import core.MessageListener; +import core.Settings; +import java.util.List; +import routing.centrality.Centrality; +import routing.centrality.ReportCentrality; +import routing.community.ReportCommunity; + +/** + * BubbleRap routing implementation. + */ +public class BubbleRapRouter extends CommunityAndRankRouter implements ReportCentrality, ReportCommunity { + + /** + * Base namespace for configuration parameters. + */ + public static final String BUBBLERAP_NS = "BubbleRapRouter"; + /** + * Centrality algorithm -setting id ({@value}). + */ + public static final String CENTRALITY_ALG_S = "centralityAlg"; + /** + * The default class to use for centrality computation. + */ + public static final String DEFAULT_CENTRALITY_ALG = "CWindowCentrality"; + + /** + * A reference to a centrality instance. + */ + private Centrality centrality; + + /** + * Constructor. + * @param set A reference to simulation settings. + */ + public BubbleRapRouter(Settings set) { + super(set, BUBBLERAP_NS); + + Settings settings = new Settings(BUBBLERAP_NS); + String centralityAlg = settings.getSetting(CENTRALITY_ALG_S, DEFAULT_CENTRALITY_ALG); + this.centrality = (Centrality) settings.createIntializedObject("routing.centrality." + centralityAlg); + } + + /** + * Copy constructor. + * @param prot Prototype. + */ + public BubbleRapRouter(BubbleRapRouter prot) { + super(prot); + this.centrality = prot.centrality.replicate(); + } + + @Override + public double getGlobalRank() { + return this.centrality.getGlobalCentrality(this.getConHistory()); + } + + @Override + public double getLocalRank() { + return this.centrality.getLocalCentrality(this.getConHistory(), this.getCommunity()); + } + + @Override + public BubbleRapRouter replicate() { + return new BubbleRapRouter(this); + } + + @Override + public void init(DTNHost host, List mListeners) { + super.init(host, mListeners); + this.centrality.setHost(host); + } + + /** + * Used by unit tests. + * @param host + */ + public void setTestHost(DTNHost host) { + this.centrality.setHost(host); + this.comdetect.setHost(host); + } + + // Report interface implementation + + public double getLocalCentrality() + { + return this.getLocalRank(); + } + + public double getGlobalCentrality() + { + return this.getGlobalRank(); + } +} + + + + + + + + + + + + + + diff --git a/src/routing/CommunityAndRankRouter.java b/src/routing/CommunityAndRankRouter.java new file mode 100644 index 000000000..e8cbc8d81 --- /dev/null +++ b/src/routing/CommunityAndRankRouter.java @@ -0,0 +1,275 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package routing; + +import core.Connection; +import core.Coord; +import core.DTNHost; +import core.Message; +import core.MessageListener; +import core.MovementListener; +import core.Settings; +import core.SimClock; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import routing.community.CommunityDetection; +import routing.community.Duration; +import routing.community.ReportCommunity; +import util.Tuple; + +/** + * The base implementation for protocols based on communities and global/local + * rank. + */ +public abstract class CommunityAndRankRouter extends ActiveRouter implements ReportCommunity { + + /** + * Community algorithm -setting id ({@value}). + */ + public static final String COMMUNITY_ALG_S = "communityAlg"; + /** + * The default class to use for community detection. + */ + private static final String DEFAULT_COMMUNITY_ALG = "DistributedKCliqueCommunityDetection"; + + /** + * Instance of community detection algorithm. + */ + protected CommunityDetection comdetect; + + /** + * Used to check if the routing data exchange is done. + */ + private Set conStates; + + /** + * Store the current connections start time. + */ + private Map startedConnections; + + /** + * Track all the connection history between this node and others. + */ + private Map> conHistory; + + /** + * Constructor. + * + * @param set The settings object. + * @param namespace The base namespace for router configurations. + */ + public CommunityAndRankRouter(Settings set, String namespace) { + super(set); + + Settings settings = new Settings(namespace); + + String communityAlg = settings.getSetting(COMMUNITY_ALG_S, DEFAULT_COMMUNITY_ALG); + this.comdetect = (CommunityDetection) settings.createIntializedObject("routing.community." + communityAlg); + this.conStates = new HashSet(); + this.conHistory = new HashMap>(); + this.startedConnections = new HashMap(); + } + + /** + * Copy constructor. + * @param prot Prototype. + */ + public CommunityAndRankRouter(CommunityAndRankRouter prot) { + super(prot); + + this.comdetect = prot.comdetect.replicate(); + this.conStates = new HashSet(); + this.conHistory = new HashMap>(); + this.startedConnections = new HashMap(); + } + + @Override + public void init(DTNHost host, List mListeners) { + super.init(host, mListeners); + + // Set the host reference in the community detection instance. + this.comdetect.setHost(host); + } + + /** + * Return the global rank value of the node. + */ + public abstract double getGlobalRank(); + + /** + * Return the local rank value of the node. + */ + public abstract double getLocalRank(); + + /** + * Return the community of the node. + */ + public Set getCommunity() { + return this.comdetect.getCommunity(); + } + + @Override + public void changedConnection(Connection con) { + super.changedConnection(con); + + DTNHost otherHost = con.getOtherNode(getHost()); + CommunityAndRankRouter otherRouter = (CommunityAndRankRouter) otherHost.getRouter(); + + // Started a new connection + if (con.isUp()) { + this.startedConnections.put(otherHost, SimClock.getTime()); + if (!this.conStates.contains(con)) { + // Add the connection in the track list of the two routers + this.conStates.add(con); + otherRouter.conStates.add(con); + // Compute the community + // Create copies of familiar sets and communities, to ensure that the two nodes will receive + // the old vision (status before update) of the communities and familiar sets. + Set myFamiliarSet = new HashSet(this.comdetect.getFamiliarSet()); + HashSet otherFamiliarSet = new HashSet(otherRouter.comdetect.getFamiliarSet()); + HashSet myCommunity = new HashSet(this.comdetect.getCommunity()); + HashSet otherCommunity = new HashSet(otherRouter.comdetect.getCommunity()); + + this.comdetect.startContact(otherHost, otherCommunity, otherFamiliarSet, otherRouter.comdetect.getCommunityFamiliarSet()); + otherRouter.comdetect.startContact(getHost(), myCommunity, myFamiliarSet, this.comdetect.getCommunityFamiliarSet()); + } + } // A connection was finished + else { + + // Compute the contact duration and store in the connection history. + double startTime = this.startedConnections.remove(otherHost); + double endTime = SimClock.getTime(); + if (!this.conHistory.containsKey(otherHost)) { + this.getConHistory().put(otherHost, new ArrayList()); + } + this.getConHistory().get(otherHost).add(new Duration(startTime, endTime)); + + if (this.conStates.contains(con)) { + // Remove the connection from the exchange list. + this.conStates.remove(con); + otherRouter.conStates.remove(con); + + CommunityDetection othercomdetect = otherRouter.comdetect; + // Inform the community detection algorithm that the connection was finished + this.comdetect.endContact(otherHost, othercomdetect.getFamiliarSet(), othercomdetect.getCommunityFamiliarSet(), this.getConHistory().get(otherHost)); + othercomdetect.endContact(getHost(), this.comdetect.getFamiliarSet(), this.comdetect.getCommunityFamiliarSet(), this.getConHistory().get(otherHost)); + } + } + } + + @Override + public void update() { + super.update(); + + if (!canStartTransfer() || isTransferring()) { + return; // Nothing to transfer or is currently transferring + } + + // Try messages that could be delivered to final recipient + if (exchangeDeliverableMessages() != null) { + return; + } + + tryOtherMessages(); + } + + /** + * Process each message using community and rank information to decide + * if the message should be forwarded or not. + * @return A set of messages and connections to forward messages. + */ + protected Tuple tryOtherMessages() { + List> messages = new ArrayList>(); + + Collection msgCollection = getMessageCollection(); + + /** + * Process all messages + */ + for (Connection con : getConnections()) { + // Get the reference to the router of the other node + DTNHost otherNode = con.getOtherNode(getHost()); + final CommunityAndRankRouter otherRouter = (CommunityAndRankRouter) otherNode.getRouter(); + final double myLocalRank = getLocalRank(); + final double otherLocalRank = otherRouter.getLocalRank(); + final double myGlobalRank = getGlobalRank(); + final double otherGlobalRank = otherRouter.getGlobalRank(); + + if (otherRouter.isTransferring()) { + continue; // skip hosts that are transferring + } + + for (Message m : msgCollection) { + if (otherRouter.hasMessage(m.getId())) { + continue; // skip messages that the other one has + } + final DTNHost destHost = m.getTo(); + Message msg = shouldSend(destHost, otherRouter, myGlobalRank, otherGlobalRank, myLocalRank, otherLocalRank, m); + if (msg != null) { + messages.add(new Tuple(msg, con)); + } + } + + } + if (messages.isEmpty()) { + return null; + } + + return tryMessagesForConnected(messages); + } + + /** + * Return the connection history of the node. + */ + public Map> getConHistory() { + return conHistory; + } + + /** + * Method that decides whether to send or not the message to the other node. + * + * @param destHost The message destination. + * @param otherRouter The router of the other node. + * @param myGlobalRank My global rank value. + * @param otherGlobalRank The global rank value of the other node. + * @param myLocalRank My local rank value. + * @param otherLocalRank The local rank value of the other node. + * @param m The message to be evaluated. + * @return The message to be sent, null otherwise. + */ + protected Message shouldSend(DTNHost destHost, CommunityAndRankRouter otherRouter, + double myGlobalRank, double otherGlobalRank, + double myLocalRank, double otherLocalRank, Message m) { + // Bubble Rap specification + boolean meInCommunity = getCommunity().contains(destHost); + boolean otherInCommunity = otherRouter.getCommunity().contains(destHost); + + // First case, both aren't in the dest community + if (!meInCommunity && !otherInCommunity) { + // use global rank + if (otherGlobalRank > myGlobalRank) { + return m; + } + } // Second case, both are in the dest community + if (meInCommunity && otherInCommunity) { + // use local rank + if (otherLocalRank > myLocalRank) { + return m; + } + } // Third case, only other node is in the dest community + if (!meInCommunity && otherInCommunity) { + return m; + } + // + return null; + } + +} diff --git a/src/routing/EpidemicOracleRouter.java b/src/routing/EpidemicOracleRouter.java index 231e6da99..456a8a0b6 100644 --- a/src/routing/EpidemicOracleRouter.java +++ b/src/routing/EpidemicOracleRouter.java @@ -138,7 +138,7 @@ protected int checkReceiving(Message m) { } /* remove oldest messages but not the ones being sent */ - if (!makeRoomForMessage(m.getSize())) { + if (!makeRoomForMessage(m)) { return DENIED_NO_SPACE; // couldn't fit into buffer -> reject } diff --git a/src/routing/MessageRouter.java b/src/routing/MessageRouter.java index 3ed363a1c..860652b65 100644 --- a/src/routing/MessageRouter.java +++ b/src/routing/MessageRouter.java @@ -291,7 +291,7 @@ public long getFreeBufferSize() { * Returns the host this router is in * @return The host object */ - protected DTNHost getHost() { + public DTNHost getHost() { return this.host; } diff --git a/src/routing/SprayAndWaitRouter.java b/src/routing/SprayAndWaitRouter.java index 566b02429..1e8f949a1 100644 --- a/src/routing/SprayAndWaitRouter.java +++ b/src/routing/SprayAndWaitRouter.java @@ -77,7 +77,7 @@ public Message messageTransferred(String id, DTNHost from) { @Override public boolean createNewMessage(Message msg) { - makeRoomForNewMessage(msg.getSize()); + makeRoomForNewMessage(msg); msg.setTtl(this.msgTtl); msg.addProperty(MSG_COUNT_PROPERTY, new Integer(initialNrofCopies)); diff --git a/src/routing/centrality/CWindowCentrality.java b/src/routing/centrality/CWindowCentrality.java new file mode 100644 index 000000000..e8a5e9480 --- /dev/null +++ b/src/routing/centrality/CWindowCentrality.java @@ -0,0 +1,212 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package routing.centrality; + +import core.DTNHost; +import core.Settings; +import core.SimClock; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import routing.community.Duration; + +/** + * CWindow centrality algorithm implementation. + */ +public class CWindowCentrality extends Centrality { + + /** + * Width of time window into which to group past history -setting id + * {@value} + */ + public static final String CENTRALITY_WINDOW_SETTING = "timeWindow"; + /** + * Interval between successive updates to centrality values -setting id + * {@value} + */ + public static final String COMPUTATION_INTERVAL_SETTING = "computeInterval"; + + /** + * Time to wait before recomputing centrality values (node degree) + */ + protected static int COMPUTE_INTERVAL = 600; // seconds, i.e. 10 minutes + /** + * Width of each time interval in which to count the node's degree + */ + protected static int CENTRALITY_TIME_WINDOW = 86400; // 24 hrs, from literature + + /** + * Saved global centrality from last computation + */ + protected double globalCentrality; + /** + * Saved local centrality from last computation + */ + protected double localCentrality; + + /** + * timestamp of last global centrality computation + */ + protected int lastGlobalComputationTime; + /** + * timestamp of last local centrality computation + */ + protected int lastLocalComputationTime; + + /** + * Constructor that receives specific settings. + * @param s A reference to simulation settings. + */ + public CWindowCentrality(Settings s) { + if (s.contains(CENTRALITY_WINDOW_SETTING)) { + CENTRALITY_TIME_WINDOW = s.getInt(CENTRALITY_WINDOW_SETTING); + } + + if (s.contains(COMPUTATION_INTERVAL_SETTING)) { + COMPUTE_INTERVAL = s.getInt(COMPUTATION_INTERVAL_SETTING); + } + } + + /** + * Copy constructor. + * @param proto Prototype. + */ + public CWindowCentrality(CWindowCentrality proto) { + // set these back in time (negative values) to do one computation at the + // start of the sim + this.lastGlobalComputationTime = this.lastLocalComputationTime + = -COMPUTE_INTERVAL; + } + + @Override + public double getGlobalCentrality(Map> connHistory) { + if (SimClock.getIntTime() - this.lastGlobalComputationTime < COMPUTE_INTERVAL) { + return globalCentrality; + } + + // initialize + int epochCount = SimClock.getIntTime() / CENTRALITY_TIME_WINDOW; + int[] centralities = new int[epochCount]; + int epoch, timeNow = SimClock.getIntTime(); + Map> nodesCountedInEpoch + = new HashMap>(); + + for (int i = 0; i < epochCount; i++) { + nodesCountedInEpoch.put(i, new HashSet()); + } + + /* + * For each node, loop through connection history until we crossed all + * the epochs we need to cover + */ + for (Map.Entry> entry : connHistory.entrySet()) { + DTNHost h = entry.getKey(); + for (Duration d : entry.getValue()) { + int timePassed = (int) (timeNow - d.end); + + // if we reached the end of the last epoch, we're done with this node + if (timePassed >= CENTRALITY_TIME_WINDOW * epochCount) { + break; + } + + // compute the epoch this contact belongs to + epoch = timePassed / CENTRALITY_TIME_WINDOW; + + // Only consider each node once per epoch + Set nodesAlreadyCounted = nodesCountedInEpoch.get(epoch); + if (nodesAlreadyCounted.contains(h)) { + continue; + } + + // increment the degree for the given epoch + centralities[epoch]++; + nodesAlreadyCounted.add(h); + } + } + + // compute and return average node degree + int sum = 0; + for (int i = 0; i < epochCount; i++) { + sum += centralities[i]; + } + this.globalCentrality = ((double) sum) / epochCount; + + this.lastGlobalComputationTime = SimClock.getIntTime(); + + return this.globalCentrality; + } + + @Override + public double getLocalCentrality(Map> connHistory, Set community) { + if (SimClock.getIntTime() - this.lastLocalComputationTime < COMPUTE_INTERVAL) { + return localCentrality; + } + + // centralities will hold the count of unique encounters in each epoch + int epochCount = SimClock.getIntTime() / CENTRALITY_TIME_WINDOW; + int[] centralities = new int[epochCount]; + int epoch, timeNow = SimClock.getIntTime(); + Map> nodesCountedInEpoch + = new HashMap>(); + + for (int i = 0; i < epochCount; i++) { + nodesCountedInEpoch.put(i, new HashSet()); + } + + /* + * For each node, loop through connection history until we crossed all + * the epochs we need to cover + */ + for (Map.Entry> entry : connHistory.entrySet()) { + DTNHost h = entry.getKey(); + + // if the host isn't in the local community, we don't consider it + if (!community.contains(h)) { + continue; + } + + for (Duration d : entry.getValue()) { + int timePassed = (int) (timeNow - d.end); + + // if we reached the end of the last epoch, we're done with this node + if (timePassed >= CENTRALITY_TIME_WINDOW * epochCount) { + break; + } + + // compute the epoch this contact belongs to + epoch = timePassed / CENTRALITY_TIME_WINDOW; + + // Only consider each node once per epoch + Set nodesAlreadyCounted = nodesCountedInEpoch.get(epoch); + if (nodesAlreadyCounted.contains(h)) { + continue; + } + + // increment the degree for the given epoch + centralities[epoch]++; + nodesAlreadyCounted.add(h); + } + } + + // compute and return average node degree + int sum = 0; + for (int i = 0; i < epochCount; i++) { + sum += centralities[i]; + } + this.localCentrality = ((double) sum) / epochCount; + + this.lastLocalComputationTime = SimClock.getIntTime(); + + return this.localCentrality; + } + + @Override + public CWindowCentrality replicate() { + return new CWindowCentrality(this); + } +} diff --git a/src/routing/centrality/Centrality.java b/src/routing/centrality/Centrality.java new file mode 100644 index 000000000..11a3d5adf --- /dev/null +++ b/src/routing/centrality/Centrality.java @@ -0,0 +1,62 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package routing.centrality; + +import core.DTNHost; +import java.util.List; +import java.util.Map; +import java.util.Set; +import routing.community.Duration; + +/** + * The base interface for implementing centrality detection algorithms. + */ +public abstract class Centrality { + + /** + * Store the node's related to this centrality computation algorithm. + */ + protected DTNHost host; + + /** + * Returns the computed global centrality based on the connection history + * passed as an argument. The global centrality measures the centrality + * of the node taking into account all the nodes all in the simulation. + * + * @param connHistory Contact History on which to compute centrality + * @return Value corresponding to the global centrality + */ + public abstract double getGlobalCentrality(Map> connHistory); + + /** + * Returns the computed local centrality based on the connection history and + * community detection objects passed as parameters. The local centrality measures + * the centrality taking into account only the nodes in the local community. + * + * @param connHistory Contact history on which to compute centrality + * @param community The community of the node. + * @return Value corresponding to the local centrality + */ + public abstract double getLocalCentrality(Map> connHistory, + Set community); + + /** + * Duplicates a Centrality object. This is a convention of the ONE to easily + * create multiple instances of objects based on defined settings. + * + * @return A duplicate Centrality instance + */ + public abstract Centrality replicate(); + + /** + * Set the host related to this instance of centrality computation. + * + * @param host The host related to this instance. + */ + public void setHost(DTNHost host) { + this.host = host; + } +} diff --git a/src/routing/centrality/ExternalCentrality.java b/src/routing/centrality/ExternalCentrality.java new file mode 100644 index 000000000..a46a26b6e --- /dev/null +++ b/src/routing/centrality/ExternalCentrality.java @@ -0,0 +1,104 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package routing.centrality; + +import core.DTNHost; +import java.util.Map; +import util.Tuple; +import core.Settings; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import routing.community.Duration; + +/** + * Loads the centrality values from an external file. + * The file is expected to have in each line the following structure: + * + */ +public class ExternalCentrality extends Centrality { + + /** + * Configuration id for the centrality file. + */ + public static final String CENTRALITY_FILE_S = "centralityFile"; + + /** + * Stores the centrality values to use later. + */ + private static Map> values; + + /** + * Constructor. + * @param s A reference to simulation settings. + */ + public ExternalCentrality(Settings s) { + // Load centrality values from an external file. + if (values == null) { + values = new HashMap>(); + String filename = s.getSetting(CENTRALITY_FILE_S); + + FileReader file = null; + BufferedReader reader = null; + try { + file = new FileReader(filename); + reader = new BufferedReader(file); + String line = reader.readLine(); + while (line != null) { + + String[] temp = line.split(" "); + values.put(Integer.parseInt(temp[0]), + new Tuple(Double.parseDouble(temp[1]), + Double.parseDouble(temp[2]))); + + line = reader.readLine(); + } + } + catch (FileNotFoundException exc) { + System.out.println(String.format("The file %s was not found.", filename)); + System.exit(1); + } + catch (IOException exc) { + System.out.println(String.format("Error while reading the file %s. Details: \n%s", filename, exc.getMessage())); + System.exit(1); + } + finally { + try { + reader.close(); + file.close(); + } + catch (IOException exc) { + // Nothing to do here + } + } + + } + } + + public ExternalCentrality(ExternalCentrality prot) { + // Copy instance level settings if needed + } + + @Override + public double getGlobalCentrality(Map> connHistory) { + return values.get(this.host.getAddress()).getValue(); + } + + @Override + public double getLocalCentrality(Map> connHistory, Set community) { + return values.get(this.host.getAddress()).getKey(); + } + + @Override + public ExternalCentrality replicate() { + return new ExternalCentrality(this); + } +} diff --git a/src/routing/centrality/ReportCentrality.java b/src/routing/centrality/ReportCentrality.java new file mode 100644 index 000000000..b805f6046 --- /dev/null +++ b/src/routing/centrality/ReportCentrality.java @@ -0,0 +1,20 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ +package routing.centrality; + +/** + * Used by the CentralityReport to get the global and local centrality from routers. + */ +public interface ReportCentrality { + /** + * Get the node's local centrality value. + */ + public double getLocalCentrality(); + + /** + * Get the node's global centrality value. + */ + public double getGlobalCentrality(); +} diff --git a/src/routing/community/CommunityDetection.java b/src/routing/community/CommunityDetection.java new file mode 100644 index 000000000..62b39e921 --- /dev/null +++ b/src/routing/community/CommunityDetection.java @@ -0,0 +1,78 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package routing.community; + +import core.DTNHost; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * The interface for community detection algorithms. The algorithms can keep track + * of connection status and are responsible for determining whether a given host + * is a member of a community or not. + */ +public abstract class CommunityDetection +{ + /** + * The host attached to this community detection instance. + */ + protected DTNHost host; + + /** + * Set the host related to this community detection instance. + * @param host + */ + public void setHost(DTNHost host) { + this.host = host; + } + + /** + * Return the familiar set of this node. + */ + public abstract Set getFamiliarSet(); + + /** + * Return the familiar set of all the community members. + */ + public abstract Map> getCommunityFamiliarSet(); + + /** + * Called to inform that the node is in contact with another node. + * @param otherHost A reference to the other node. + * @param otherCommunity The other node's community. + * @param otherFamiliarSet The other node's familiar set. + * @param otherFSOfC The familiar set of the other node's community members. + */ + public abstract void startContact(DTNHost otherHost, Set otherCommunity, + Set otherFamiliarSet, Map> otherFSOfC); + + /** + * Called to inform the object that a contact was lost. + * + * @param otherHost Host that is now disconnected from this object + * @param otherFamiliarSet The familiar set of the other node. + * @param otherFSOfC The familiar set ot the other node's community members. + * @param connHistory Entire connection history between this host and the peer + */ + public abstract void endContact(DTNHost otherHost, Set otherFamiliarSet, + Map> otherFSOfC, List connHistory); + + /** + * Returns a set of hosts that are members of the local community of this + * object. This method is only provided for reporting. + * + * @return the Set representation of the local community + */ + public abstract Set getCommunity(); + + /** + * Duplicates this CommunityDetection object. + * + * @return A semantically equal copy of this CommunityDetection object + */ + public abstract CommunityDetection replicate(); +} \ No newline at end of file diff --git a/src/routing/community/DistributedKCliqueCommunityDetection.java b/src/routing/community/DistributedKCliqueCommunityDetection.java new file mode 100644 index 000000000..ff12ef86c --- /dev/null +++ b/src/routing/community/DistributedKCliqueCommunityDetection.java @@ -0,0 +1,166 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package routing.community; + +import core.DTNHost; +import core.Settings; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Implementation of the Distributed K-Clique community detection algorithm as + * proposed in the paper "Distributed Community Detection in Delay Tolerant Networks". + */ +public class DistributedKCliqueCommunityDetection extends CommunityDetection { + + /** + * Configuration id for setting the parameter K in the algorithm. + */ + public static final String K_SETTING = "k"; + /** + * Configuration id for setting the parameter familiar threshold + * in the algorithm. + */ + public static final String FAMILIAR_SETTING = "familiarThreshold"; + + /** + * Stores the familiar set of hosts. + */ + protected Set familiarSet; + /** + * Stores the current local community. + */ + protected Set localCommunity; + /** + * Stores references to the familiar sets of + * the hosts in the local community. + */ + protected Map> familiarsOfMyCommunity; + + /** + * The parameter k. + */ + protected double k; + /** + * The parameter familiar threshold. + */ + protected double familiarThreshold; + + /** + * Basic constructor that loads the specific configurations. + * @param s Settings reference. + */ + public DistributedKCliqueCommunityDetection(Settings s) { + this.k = s.getDouble(K_SETTING); + this.familiarThreshold = s.getDouble(FAMILIAR_SETTING); + this.familiarSet = new HashSet(); + this.localCommunity = new HashSet(); + this.familiarsOfMyCommunity = new HashMap>(); + } + + /** + * Copy constructor. + * @param proto The origin of the copy. + */ + public DistributedKCliqueCommunityDetection(DistributedKCliqueCommunityDetection proto) { + this.k = proto.k; + this.familiarThreshold = proto.familiarThreshold; + // Initializes all the sets without copying + familiarSet = new HashSet(); + localCommunity = new HashSet(); + this.familiarsOfMyCommunity = new HashMap>(); + } + + @Override + public void setHost(DTNHost host) { + super.setHost(host); + // Add the host to its own community. + this.localCommunity.add(host); + } + + @Override + public Set getFamiliarSet() { + return this.familiarSet; + } + + @Override + public Map> getCommunityFamiliarSet() { + return this.familiarsOfMyCommunity; + } + + @Override + public void startContact(DTNHost otherHost, Set otherCommunity, + Set otherFamiliarSet, Map> otherFSOfC) { + if (!this.localCommunity.contains(otherHost)) { + + // Get the intersection between my local community and the other host familiar set + HashSet intersection = new HashSet(this.localCommunity); + intersection.retainAll(otherFamiliarSet); + if (intersection.size() >= (this.k - 1)) { + this.localCommunity.add(otherHost); + this.familiarsOfMyCommunity.put(otherHost, otherFamiliarSet); + this.wasAdded(otherFSOfC); + } + } + } + + /** + * Analyze the similarity between my local community and the + * familiar set of the other host in the familiar set of the + * added host. + * @param otherFSOfC The familiar set of the added host. + */ + private void wasAdded(Map> otherFSOfC) { + for (DTNHost host: otherFSOfC.keySet()) { + if (!this.localCommunity.contains(host)) { + // Get the intersection between my local community and the other host familiar set + HashSet intersection = new HashSet(this.localCommunity); + intersection.retainAll(otherFSOfC.get(host)); + if (intersection.size() >= (this.k - 1)) { + this.localCommunity.add(host); + this.familiarsOfMyCommunity.put(host, otherFSOfC.get(host)); + } + } + } + } + + @Override + public void endContact(DTNHost otherHost, Set otherFamiliarSet, Map> otherFSOfC, List connHistory) { + if (this.familiarSet.contains(otherHost)) { + return; + } + + // Compute cumulative contact duration with this peer + Iterator i = connHistory.iterator(); + double time = 0; + while (i.hasNext()) { + Duration d = i.next(); + time += d.end - d.start; + } + + // If cumulative duration is greater or equals than threshold, add + if (time >= this.familiarThreshold) { + this.familiarSet.add(otherHost); + this.localCommunity.add(otherHost); + this.familiarsOfMyCommunity.put(otherHost, otherFamiliarSet); + this.wasAdded(otherFSOfC); + } + } + + @Override + public DistributedKCliqueCommunityDetection replicate() { + return new DistributedKCliqueCommunityDetection(this); + } + + @Override + public Set getCommunity() { + return this.localCommunity; + } +} diff --git a/src/routing/community/Duration.java b/src/routing/community/Duration.java new file mode 100644 index 000000000..3d4c4c73a --- /dev/null +++ b/src/routing/community/Duration.java @@ -0,0 +1,28 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package routing.community; + +/** + * A helper class for the community package that stores a start and end value + * for some abstract duration. Generally, in this package, the duration being + * stored is a time duration. + */ +public class Duration +{ + /** The start value */ + public double start; + + /** The end value */ + public double end; + + /** + * Standard constructor that assigns s to start and e to end. + * + * @param s Initial start value + * @param e Initial end value + */ + public Duration(double s, double e) {start = s; end = e;} +} diff --git a/src/routing/community/ExternalCommunityDetection.java b/src/routing/community/ExternalCommunityDetection.java new file mode 100644 index 000000000..64176abf2 --- /dev/null +++ b/src/routing/community/ExternalCommunityDetection.java @@ -0,0 +1,149 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package routing.community; + +import core.DTNHost; +import core.Settings; +import core.SimScenario; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Loads the communities from an external file. + * The file is expected to have the following structure in each line: + * )> + */ +public class ExternalCommunityDetection extends CommunityDetection { + + /** + * The configuration id for the file with the list of communities. + * The has a format with each line describing a community of the + * first number present. + */ + public static final String COMMUNITY_FILE_S = "communityFile"; + + /** + * Static container shared by all instances that is filled with + * the file information about the communities. + */ + private static Map> values; + + /** + * Stores the local community. + */ + private Set localCommunity; + + + /** + * Constructor + * @param s Reference to simulator settings. + */ + public ExternalCommunityDetection(Settings s) { + // Load communities from an external file. + if (values == null) { + values = new HashMap>(); + String filename = s.getSetting(COMMUNITY_FILE_S); + FileReader file = null; + BufferedReader buffer = null; + try { + file = new FileReader(filename); + buffer = new BufferedReader(file); + String line = buffer.readLine(); + while (line != null) { + + String[] temp = line.split(" "); + int hostaddress = Integer.parseInt(temp[0]); + Set hosts = new HashSet(); + for (int i = 1; i < temp.length; i++) { + int hostid = Integer.parseInt(temp[i]); + hosts.add(hostid); + } + values.put(hostaddress, hosts); + line = buffer.readLine(); + } + } + catch (FileNotFoundException exc) { + System.out.println(String.format("File %s not found", filename)); + System.exit(1); + } + catch (IOException exc) { + System.out.println(String.format("Error reading the file %s: \n%s", filename, exc.getMessage())); + System.exit(1); + } + finally { + try { + buffer.close(); + file.close(); + } + catch(IOException exc) { + // Nothing to do here + } + } + } + } + + /** + * Copy constructor. + * @param prot Origin of the copy. + */ + public ExternalCommunityDetection(ExternalCommunityDetection prot) { + // Copy instance specific settings + } + + @Override + public Set getCommunity() { + if (this.localCommunity == null) { + if (values.containsKey(this.host.getAddress())) { + Set temp = values.get(this.host.getAddress()); + this.localCommunity = new HashSet(); + for (DTNHost host : SimScenario.getInstance().getHosts()) { + if (temp.contains(host.getAddress())) { + this.localCommunity.add(host); + } + } + } else { + this.localCommunity = new HashSet(); + } + } + return this.localCommunity; + } + + @Override + public ExternalCommunityDetection replicate() { + return new ExternalCommunityDetection(this); + } + + @Override + public Set getFamiliarSet() { + return new HashSet(); + } + + @Override + public Map> getCommunityFamiliarSet() { + return new HashMap>(); + } + + @Override + public void startContact(DTNHost otherHost, Set otherCommunity, Set otherFamiliarSet, Map> otherFSOfC) { + // Nothing to do here + } + + @Override + public void endContact(DTNHost otherHost, Set otherFamiliarSet, Map> otherFSOfC, List connHistory) { + // Nothing to do here + } +} diff --git a/src/routing/community/ReportCommunity.java b/src/routing/community/ReportCommunity.java new file mode 100644 index 000000000..b7c468a95 --- /dev/null +++ b/src/routing/community/ReportCommunity.java @@ -0,0 +1,20 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package routing.community; + +import core.DTNHost; +import java.util.Set; + +/** + * Interface used by the CommunityReport. + */ +public interface ReportCommunity { + + /** + * Get the node's current community. + */ + public Set getCommunity(); +} diff --git a/src/test/AbstractDropPolicyTest.java b/src/test/AbstractDropPolicyTest.java new file mode 100644 index 000000000..93f06e5a9 --- /dev/null +++ b/src/test/AbstractDropPolicyTest.java @@ -0,0 +1,52 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package test; + +import routing.EpidemicRouter; + +/** + * Basic tests of the message drop policies implementations. + */ +public class AbstractDropPolicyTest extends AbstractRouterTest { + + private String dropPolicyClass; + + /** + * Constructor. + * @param dropPolicyClass The drop policy class name. + */ + public AbstractDropPolicyTest(String dropPolicyClass) { + this.dropPolicyClass = dropPolicyClass; + } + + /** Use three routers to do the tests **/ + protected EpidemicRouter r0; + protected EpidemicRouter r1; + protected EpidemicRouter r2; + protected EpidemicRouter r3; + + @Override + protected void setUp() throws Exception { + ts.setNameSpace("Group1"); + ts.putSetting("dropPolicy", this.dropPolicyClass); + //ts.putSetting("bufferSize", "3"); + setRouterProto(new EpidemicRouter(ts)); + super.setUp(); + + // Adjust the routers references + r0 = (EpidemicRouter)h0.getRouter(); + r1 = (EpidemicRouter)h1.getRouter(); + r2 = (EpidemicRouter)h2.getRouter(); + r3 = (EpidemicRouter)h3.getRouter(); + + } + + protected void advanceWorld(int seconds) { + clock.advance(1); + updateAllNodes(); + } + +} diff --git a/src/test/BubbleRapRouterTest.java b/src/test/BubbleRapRouterTest.java new file mode 100644 index 000000000..6a228c174 --- /dev/null +++ b/src/test/BubbleRapRouterTest.java @@ -0,0 +1,218 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package test; + +import core.DTNHost; +import core.Message; +import core.MessageListener; +import core.SimScenario; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import routing.BubbleRapRouter; +import routing.CommunityAndRankRouter; +import routing.MessageRouter; +import routing.centrality.ExternalCentrality; +import routing.community.ExternalCommunityDetection; +import static test.AbstractRouterTest.ts; + +/** + * Tests of the bubble rap router implementation. + */ +public class BubbleRapRouterTest extends AbstractRouterTest { + + private BubbleRapRouter r0; + private BubbleRapRouter r1; + private BubbleRapRouter r2; + private BubbleRapRouter r3; + private BubbleRapRouter r4; + private BubbleRapRouter r5; + private BubbleRapRouter r6; + private Message m1; + private Message m2; + + @Override + protected void setUp() throws Exception { + ts.setNameSpace(null); + ts.putSetting("Group1" + "." + SimScenario.GROUP_ID_S, "n"); + ts.putSetting("Group1" + "." + SimScenario.NROF_HOSTS_S, "0"); + ts.putSetting("Group1" + "." + SimScenario.NROF_INTERF_S, "0"); + ts.putSetting("Group1" + "." + SimScenario.MOVEMENT_MODEL_S, "StationaryMovement"); + ts.putSetting("Group1" + "." + SimScenario.ROUTER_S, "PassiveRouter"); + ts.putSetting("Group1" + "." + "nodeLocation", "0, 0"); + + ts.putSetting(MessageRouter.B_SIZE_S, "" + BUFFER_SIZE); + ts.putSetting(BubbleRapRouter.BUBBLERAP_NS + "." + BubbleRapRouter.CENTRALITY_ALG_S, "ExternalCentrality"); + ts.putSetting(BubbleRapRouter.BUBBLERAP_NS + "." + ExternalCentrality.CENTRALITY_FILE_S, "test_files/centrality"); + ts.putSetting(BubbleRapRouter.BUBBLERAP_NS + "." + CommunityAndRankRouter.COMMUNITY_ALG_S, "ExternalCommunityDetection"); + ts.putSetting(BubbleRapRouter.BUBBLERAP_NS + "." + ExternalCommunityDetection.COMMUNITY_FILE_S, "test_files/communities"); + + BubbleRapRouter router = new BubbleRapRouter(ts); + setRouterProto(router); + super.setUp(); + SimScenario.getInstance().getHosts().add(h0); + SimScenario.getInstance().getHosts().add(h1); + SimScenario.getInstance().getHosts().add(h2); + SimScenario.getInstance().getHosts().add(h3); + SimScenario.getInstance().getHosts().add(h4); + SimScenario.getInstance().getHosts().add(h5); + SimScenario.getInstance().getHosts().add(h6); + m1 = new Message(h0, h6, msgId1, 1); + m2 = new Message(h3, h6, msgId2, 1); + r0 = (BubbleRapRouter) h0.getRouter(); + r0.setTestHost(h0); + r1 = (BubbleRapRouter) h1.getRouter(); + r1.setTestHost(h1); + r2 = (BubbleRapRouter) h2.getRouter(); + r2.setTestHost(h2); + r3 = (BubbleRapRouter) h3.getRouter(); + r3.setTestHost(h3); + r4 = (BubbleRapRouter) h4.getRouter(); + r4.setTestHost(h4); + r5 = (BubbleRapRouter) h5.getRouter(); + r5.setTestHost(h5); + r6 = (BubbleRapRouter) h6.getRouter(); + r6.setTestHost(h6); + } + + private void advanceWorld(int seconds) { + clock.advance(1); + updateAllNodes(); + } + + public void testDirectDelivery() { + // Create the message + h0.createNewMessage(m1); + checkCreates(1); + updateAllNodes(); + + // h0 -> h6 + h0.forceConnection(h6, h0.getInterfaces().get(0).getInterfaceType(), true); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_START); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h6); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h6); + assertTrue(mc.getLastFirstDelivery()); + h0.forceConnection(h6, h0.getInterfaces().get(0).getInterfaceType(), false); + advanceWorld(1); +// assertFalse(mc.next()); + } + + public void testToTargetCommunity() { + // Create the message + h0.createNewMessage(m1); + checkCreates(1); + updateAllNodes(); + + // h0 -> h5 + h0.forceConnection(h5, h0.getInterfaces().get(0).getInterfaceType(), true); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_START); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h5); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h5); + assertFalse(mc.getLastFirstDelivery()); + h0.forceConnection(h5, h0.getInterfaces().get(0).getInterfaceType(), false); + advanceWorld(1); + assertFalse(mc.next()); + } + + public void testToGreaterLocalRank() { + //Create the message + h3.createNewMessage(m2); + checkCreates(1); + updateAllNodes(); + + // h3 -> h4 + h3.forceConnection(h4, h3.getInterfaces().get(0).getInterfaceType(), true); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_START); + assertEquals(mc.getLastFrom(), h3); + assertEquals(mc.getLastTo(), h4); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + assertEquals(mc.getLastFrom(), h3); + assertEquals(mc.getLastTo(), h4); + assertFalse(mc.getLastFirstDelivery()); + h3.forceConnection(h4, h3.getInterfaces().get(0).getInterfaceType(), false); + advanceWorld(1); + assertFalse(mc.next()); + + } + + public void testToLesserLocalRank() { + //Create the message + h3.createNewMessage(m2); + checkCreates(1); + updateAllNodes(); + + // h3 -> h5 + h3.forceConnection(h5, h3.getInterfaces().get(0).getInterfaceType(), true); + advanceWorld(1); + assertFalse(mc.next()); + } + + public void testToGreaterGlobalRank() { + // Create the message + h0.createNewMessage(m1); + checkCreates(1); + updateAllNodes(); + + // h0 -> h1 + h0.forceConnection(h1, h0.getInterfaces().get(0).getInterfaceType(), true); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_START); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h1); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h1); + assertFalse(mc.getLastFirstDelivery()); + h3.forceConnection(h0, h1.getInterfaces().get(0).getInterfaceType(), false); + advanceWorld(1); + assertFalse(mc.next()); + } + + public void testToLesserGlobalRank() { + // Create the message + h0.createNewMessage(m1); + checkCreates(1); + updateAllNodes(); + + // h0 -> h2 + h0.forceConnection(h2, h0.getInterfaces().get(0).getInterfaceType(), true); + advanceWorld(1); + assertFalse(mc.next()); + } + + public void testToOutsideTargetCommunity() { + //Create the message + h3.createNewMessage(m2); + checkCreates(1); + updateAllNodes(); + + // h3 -> h4 + h3.forceConnection(h0, h3.getInterfaces().get(0).getInterfaceType(), true); + advanceWorld(1); + assertFalse(mc.next()); + } +} diff --git a/src/test/CommunityAndRankRouterTest.java b/src/test/CommunityAndRankRouterTest.java new file mode 100644 index 000000000..df397a736 --- /dev/null +++ b/src/test/CommunityAndRankRouterTest.java @@ -0,0 +1,397 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package test; + +import core.DTNHost; +import core.Message; +import core.Settings; +import core.SimScenario; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import routing.CommunityAndRankRouter; +import routing.MessageRouter; +import routing.SprayAndWaitRouter; +import static test.AbstractRouterTest.ts; + +/** + * Unit tests for CommunityAndRankRouter class. + */ +public class CommunityAndRankRouterTest extends AbstractRouterTest { + + private static final String ROUTER_NS = "RouterTest"; + + private int[] localRank = new int[]{10, 20, 30, 40}; + private int[] globalRank = new int[]{10, 20, 30, 40}; + private ArrayList> communities; + private Message m1; + + private class RouterTest extends CommunityAndRankRouter { + + public RouterTest(Settings set) { + super(set, ROUTER_NS); + } + + public RouterTest(RouterTest p) { + super(p); + } + + @Override + public double getGlobalRank() { + return globalRank[getHost().getAddress()]; + } + + @Override + public double getLocalRank() { + return localRank[getHost().getAddress()]; + } + + @Override + public Set getCommunity() { + return communities.get(getHost().getAddress()); + } + + @Override + public MessageRouter replicate() { + return new RouterTest(this); + } + + } + + private RouterTest r0; + private RouterTest r1; + private RouterTest r2; + private RouterTest r3; + + @Override + protected void setUp() throws Exception { + ts.setNameSpace(null); + ts.putSetting(MessageRouter.B_SIZE_S, "" + BUFFER_SIZE); + ts.putSetting(ROUTER_NS + ".k", "3"); + ts.putSetting(ROUTER_NS + ".familiarThreshold", "700"); + setRouterProto(new RouterTest(ts)); + super.setUp(); + this.communities = new ArrayList>(); + this.communities.add(new HashSet(Arrays.asList(new DTNHost[]{h0, h1}))); + this.communities.add(new HashSet(Arrays.asList(new DTNHost[]{h2, h1}))); + this.communities.add(new HashSet(Arrays.asList(new DTNHost[]{h2, h3}))); + this.communities.add(new HashSet(Arrays.asList(new DTNHost[]{h2, h3}))); + m1 = new Message(h0, h3, msgId1, 1); + r0 = (RouterTest) h0.getRouter(); + r1 = (RouterTest) h1.getRouter(); + r2 = (RouterTest) h2.getRouter(); + r3 = (RouterTest) h3.getRouter(); + } + + private void advanceWorld(int seconds) { + clock.advance(1); + updateAllNodes(); + } + + /** + * Test delivery when have a contact with the destination + */ + public void testDirectDelivery() { + // Create a new message + h0.createNewMessage(m1); + checkCreates(1); + updateAllNodes(); + + // Contact between h0 and h3 -- source and destination of m1 + h0.forceConnection(h3, h0.getInterfaces().get(0).getInterfaceType(), true); + + advanceWorld(1); + + assertTrue(mc.next()); + // The last event was start of a message transfer + assertEquals(mc.getLastType(), mc.TYPE_START); + // Verify the ID of the message + assertEquals(mc.getLastMsg().getId(), msgId1); + // Transfer was from host + assertEquals(mc.getLastFrom(), h0); + // Transfer was to host + assertEquals(mc.getLastTo(), h3); + + advanceWorld(1); + + assertTrue(mc.next()); + // The message transfer has been completed + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h3); + // This was the first delivery from m1 to h3 + assertTrue(mc.getLastFirstDelivery()); + + } + + /** + * Test transfer when both arent in the destination community and global rank of the other node + * is greater. + */ + public void testTransferGlobalRank() { + // Create a new message + h0.createNewMessage(m1); + checkCreates(1); + updateAllNodes(); + + // Contact between h0 and h1 -- h1 has greater global rank and is not in the destination community + h0.forceConnection(h1, h0.getInterfaces().get(0).getInterfaceType(), true); + + advanceWorld(1); + + assertTrue(mc.next()); + // The last event was start of a message transfer + assertEquals(mc.getLastType(), mc.TYPE_START); + // Verify the ID of the message + assertEquals(mc.getLastMsg().getId(), msgId1); + // Transfer was from host + assertEquals(mc.getLastFrom(), h0); + // Transfer was to host + assertEquals(mc.getLastTo(), h1); + + advanceWorld(1); + + assertTrue(mc.next()); + // The message transfer has been completed + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h1); + // This was the first delivery from m1 to h3 + assertFalse(mc.getLastFirstDelivery()); + } + + /** + * Test transfer when both are in the destination community and local rank of the other node + * is greater. + */ + public void testTransferLocalRank() { + globalRank[0] = 100; + communities.get(0).add(h3); + communities.get(1).add(h3); + + // Create a new message + h0.createNewMessage(m1); + checkCreates(1); + updateAllNodes(); + + + + // Contact between h0 and h1 -- h1 has greater lobal rank, both are in the destination community + h0.forceConnection(h1, h0.getInterfaces().get(0).getInterfaceType(), true); + + advanceWorld(1); + + assertTrue(mc.next()); + // The last event was start of a message transfer + assertEquals(mc.getLastType(), mc.TYPE_START); + // Verify the ID of the message + assertEquals(mc.getLastMsg().getId(), msgId1); + // Transfer was from host + assertEquals(mc.getLastFrom(), h0); + // Transfer was to host + assertEquals(mc.getLastTo(), h1); + + advanceWorld(1); + + assertTrue(mc.next()); + // The message transfer has been completed + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h1); + // This was the first delivery from m1 to h3 + assertFalse(mc.getLastFirstDelivery()); + } + + /** + * Test transfer when both are in the destination community and local rank of the other node + * is lesser. + */ + public void testNotTransferLocalRank() { + localRank[0] = 100; + communities.get(0).add(h3); + communities.get(1).add(h3); + + // Create a new message + h0.createNewMessage(m1); + checkCreates(1); + updateAllNodes(); + + + + // Contact between h0 and h1 -- h1 has greater lobal rank, both are in the destination community + h0.forceConnection(h1, h0.getInterfaces().get(0).getInterfaceType(), true); + + advanceWorld(1); + + assertFalse(mc.next()); + } + + /** + * Test transfer when both arent in the destination community and global rank of the other node + * is lesser. + */ + public void testNotTransferGlobalRank() { + // Create a new message + h0.createNewMessage(m1); + checkCreates(1); + updateAllNodes(); + + globalRank[1] = 5; + // Contact between h0 and h1 -- h1 has lesser global rank and is not in the destination community + h0.forceConnection(h1, h0.getInterfaces().get(0).getInterfaceType(), true); + + advanceWorld(1); + + assertFalse(mc.next()); + } + + /** + * Test transfer when only the other node is in the destination community. + */ + public void testTransferDestCommunity() { + // Create a new message + h0.createNewMessage(m1); + checkCreates(1); + updateAllNodes(); + + // Contact between h0 and h2 -- h2 is in the destination community + h0.forceConnection(h2, h0.getInterfaces().get(0).getInterfaceType(), true); + + advanceWorld(1); + + assertTrue(mc.next()); + // The last event was start of a message transfer + assertEquals(mc.getLastType(), mc.TYPE_START); + // Verify the ID of the message + assertEquals(mc.getLastMsg().getId(), msgId1); + // Transfer was from host + assertEquals(mc.getLastFrom(), h0); + // Transfer was to host + assertEquals(mc.getLastTo(), h2); + + advanceWorld(1); + + assertTrue(mc.next()); + // The message transfer has been completed + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h2); + // This was the first delivery from m1 to h3 + assertFalse(mc.getLastFirstDelivery()); + } + + public void testDontRemoveDeliveredMessages() throws Exception { + ts.setNameSpace(null); + ts.putSetting(MessageRouter.B_SIZE_S, "" + BUFFER_SIZE); + ts.putSetting(ROUTER_NS + ".K", "3"); + ts.putSetting(ROUTER_NS + ".familiarThreshold", "700"); + setRouterProto(new RouterTest(ts)); + super.setUp(); + this.communities = new ArrayList>(); + this.communities.add(new HashSet(Arrays.asList(new DTNHost[]{h0, h1}))); + this.communities.add(new HashSet(Arrays.asList(new DTNHost[]{h2, h1}))); + this.communities.add(new HashSet(Arrays.asList(new DTNHost[]{h2, h3}))); + this.communities.add(new HashSet(Arrays.asList(new DTNHost[]{h2, h3}))); + m1 = new Message(h0, h3, msgId1, 1); + r0 = (RouterTest) h0.getRouter(); + r1 = (RouterTest) h1.getRouter(); + r2 = (RouterTest) h2.getRouter(); + r3 = (RouterTest) h3.getRouter(); + + + // Create the message to be sent + h0.createNewMessage(m1); + checkCreates(1); + updateAllNodes(); + + // t1 + // h0 -> h1, send the message + h0.forceConnection(h1, h0.getInterfaces().get(0).getInterfaceType(), true); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_START); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + h0.forceConnection(h1, h0.getInterfaces().get(0).getInterfaceType(), false); + assertTrue(r0.hasMessage(msgId1)); + assertTrue(r1.hasMessage(msgId1)); + + // t2 + // h1 -> h2 + h1.forceConnection(h2, h1.getInterfaces().get(0).getInterfaceType(), true); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_START); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + h1.forceConnection(h2, h1.getInterfaces().get(0).getInterfaceType(), false); + assertTrue(r0.hasMessage(msgId1)); + assertTrue(r1.hasMessage(msgId1)); + assertTrue(r2.hasMessage(msgId1)); + + // t3 + // h2 -> h3 + h2.forceConnection(h3, h2.getInterfaces().get(0).getInterfaceType(), true); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_START); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + h2.forceConnection(h3, h2.getInterfaces().get(0).getInterfaceType(), false); + advanceWorld(1); + assertFalse(mc.next()); + assertTrue(r0.hasMessage(msgId1)); + assertTrue(r1.hasMessage(msgId1)); + assertTrue(r2.hasMessage(msgId1)); + assertFalse(r3.hasMessage(msgId1)); + } + + public void testAlreadyHasTheMessage() { + // Create a new message + h0.createNewMessage(m1); + checkCreates(1); + updateAllNodes(); + + // Contact between h0 and h2 -- h2 is in the destination community + h0.forceConnection(h2, h0.getInterfaces().get(0).getInterfaceType(), true); + + advanceWorld(1); + + assertTrue(mc.next()); + // The last event was start of a message transfer + assertEquals(mc.getLastType(), mc.TYPE_START); + // Verify the ID of the message + assertEquals(mc.getLastMsg().getId(), msgId1); + // Transfer was from host + assertEquals(mc.getLastFrom(), h0); + // Transfer was to host + assertEquals(mc.getLastTo(), h2); + + advanceWorld(1); + + assertTrue(mc.next()); + // The message transfer has been completed + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h2); + assertFalse(mc.getLastFirstDelivery()); + + // Close connection + h0.forceConnection(h2, h0.getInterfaces().get(0).getInterfaceType(), false); + advanceWorld(1); + assertFalse(mc.next()); + + h0.forceConnection(h2, h0.getInterfaces().get(0).getInterfaceType(), true); + advanceWorld(1); + assertFalse(mc.next()); + + + } +} diff --git a/src/test/EDropPolicyTest.java b/src/test/EDropPolicyTest.java new file mode 100644 index 000000000..87318fd8f --- /dev/null +++ b/src/test/EDropPolicyTest.java @@ -0,0 +1,169 @@ +/* + * Copyright 2016 Aalto University, ComNet + * Released under GPLv3. See LICENSE.txt for details. + */ + +package test; + +import buffermanagement.EDropPolicy; +import buffermanagement.FIFODropPolicy; +import core.Message; + +/** + * Tests the basic functionality of EDropPolicy implementation. + */ +public class EDropPolicyTest extends AbstractDropPolicyTest { + + public EDropPolicyTest() { + super("EDropPolicy"); + } + + @Override + protected void setUp() throws Exception { + ts.putSetting("Group1.bufferSize", "5"); + super.setUp(); + } + + /** + * Test the case when the buffer of the receiver is empty + */ + public void testBufferFree() { + assertTrue(r0.getDropPolicy() instanceof EDropPolicy); + + Message m1 = new Message(h0, h3, msgId1, 1); + h0.createNewMessage(m1); + checkCreates(1); + advanceWorld(1); + + h0.connect(h1); + advanceWorld(1); + + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_START); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h1); + assertFalse(mc.getLastFirstDelivery()); + + assertFalse(mc.next()); + } + + /** + * Test the case when exists a message with exact the same size of the incoming + * message and can be deleted. + */ + public void testDropEquals() { + + assertTrue(r0.getDropPolicy() instanceof EDropPolicy); + + Message m1 = new Message(h0, h1, msgId1, 1); + h0.createNewMessage(m1); + checkCreates(1); + advanceWorld(1); + + Message m2 = new Message(h0, h1, msgId2, 2); + h0.createNewMessage(m2); + checkCreates(1); + advanceWorld(1); + + Message m3 = new Message(h0, h1, msgId3, 1); + h0.createNewMessage(m3); + checkCreates(1); + advanceWorld(1); + + + Message m4 = new Message(h0, h1, msgId4, 2); + h0.createNewMessage(m4); + + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_DELETE); + assertTrue(mc.getLastDropped()); + assertFalse(h0.getMessageCollection().contains(m2)); + checkCreates(1); + advanceWorld(1); + assertFalse(mc.next()); + + } + + /** + * Test the case when exists a message with the size greater than the incoming + * message and can be deleted. + */ + public void testDropGreater() { + + assertTrue(r0.getDropPolicy() instanceof EDropPolicy); + + Message m1 = new Message(h0, h1, msgId1, 1); + h0.createNewMessage(m1); + checkCreates(1); + advanceWorld(1); + + Message m2 = new Message(h0, h1, msgId2, 1); + h0.createNewMessage(m2); + checkCreates(1); + advanceWorld(1); + + Message m3 = new Message(h0, h1, msgId3, 3); + h0.createNewMessage(m3); + checkCreates(1); + advanceWorld(1); + + + Message m4 = new Message(h0, h1, msgId4, 2); + h0.createNewMessage(m4); + + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_DELETE); + assertTrue(mc.getLastDropped()); + assertFalse(h0.getMessageCollection().contains(m3)); + checkCreates(1); + advanceWorld(1); + assertFalse(mc.next()); + + } + + /** + * Test the case when there is no message with size greater or equals + * the incoming message. In this situation the policy works like FIFO. + */ + public void testDropFIFO() { + + assertTrue(r0.getDropPolicy() instanceof EDropPolicy); + + Message m1 = new Message(h0, h1, msgId1, 1); + h0.createNewMessage(m1); + checkCreates(1); + advanceWorld(1); + + Message m2 = new Message(h0, h1, msgId2, 2); + h0.createNewMessage(m2); + checkCreates(1); + advanceWorld(1); + + Message m3 = new Message(h0, h1, msgId3, 2); + h0.createNewMessage(m3); + checkCreates(1); + advanceWorld(1); + + + Message m4 = new Message(h0, h1, msgId4, 3); + h0.createNewMessage(m4); + + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_DELETE); + assertTrue(mc.getLastDropped()); + assertFalse(h0.getMessageCollection().contains(m1)); + + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_DELETE); + assertTrue(mc.getLastDropped()); + assertFalse(h0.getMessageCollection().contains(m2)); + checkCreates(1); + advanceWorld(1); + assertFalse(mc.next()); + + } + +} diff --git a/src/test/FIFODropPolicyTest.java b/src/test/FIFODropPolicyTest.java new file mode 100644 index 000000000..614d4a92e --- /dev/null +++ b/src/test/FIFODropPolicyTest.java @@ -0,0 +1,90 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package test; + +import buffermanagement.FIFODropPolicy; +import core.Message; + +/** + * Tests the basic functionality of FIFODropPolicy implementation. + */ +public class FIFODropPolicyTest extends AbstractDropPolicyTest { + + public FIFODropPolicyTest() { + super("FIFODropPolicy"); + } + + @Override + protected void setUp() throws Exception { + ts.putSetting("Group1.bufferSize", "3"); + super.setUp(); + } + + /** + * Test the case when the buffer of the receiver is empty + */ + public void testBufferFree() { + assertTrue(r0.getDropPolicy() instanceof FIFODropPolicy); + + Message m1 = new Message(h0, h3, msgId1, 1); + h0.createNewMessage(m1); + checkCreates(1); + advanceWorld(1); + + h0.connect(h1); + advanceWorld(1); + + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_START); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h1); + assertFalse(mc.getLastFirstDelivery()); + } + + /** + * Test the drop logic. + */ + public void testDrop() { + + assertTrue(r0.getDropPolicy() instanceof FIFODropPolicy); + + Message m1 = new Message(h0, h1, msgId1, 1); + h0.createNewMessage(m1); + checkCreates(1); + advanceWorld(1); + + Message m2 = new Message(h0, h1, msgId2, 1); + h0.createNewMessage(m2); + checkCreates(1); + advanceWorld(1); + + Message m3 = new Message(h0, h1, msgId3, 1); + h0.createNewMessage(m3); + checkCreates(1); + advanceWorld(1); + + + Message m4 = new Message(h0, h1, msgId4, 2); + h0.createNewMessage(m4); + + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_DELETE); + assertTrue(mc.getLastDropped()); + assertFalse(h0.getMessageCollection().contains(m1)); + + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_DELETE); + assertTrue(mc.getLastDropped()); + assertFalse(h0.getMessageCollection().contains(m2)); + + + + } + +} diff --git a/src/test/MOFODropPolicyTest.java b/src/test/MOFODropPolicyTest.java new file mode 100644 index 000000000..ae0b3c504 --- /dev/null +++ b/src/test/MOFODropPolicyTest.java @@ -0,0 +1,144 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package test; + +import buffermanagement.MOFODropPolicy; +import core.Message; + +/** + * Test cases for the MOFO (Most Forwarded) drop policy implementation. + * @author michael + * + */ +public class MOFODropPolicyTest extends AbstractDropPolicyTest { + + public MOFODropPolicyTest() { + super("MOFODropPolicy"); + } + + @Override + protected void setUp() throws Exception { + ts.putSetting("Group1.bufferSize", "3"); + super.setUp(); + } + + /** + * Test the case when the buffer of the receiver is empty + */ + public void testBufferFree() { + assertTrue(r0.getDropPolicy() instanceof MOFODropPolicy); + + Message m1 = new Message(h0, h3, msgId1, 1); + h0.createNewMessage(m1); + checkCreates(1); + advanceWorld(1); + + h0.connect(h1); + advanceWorld(1); + + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_START); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h1); + assertFalse(mc.getLastFirstDelivery()); + } + + /** + * Test the message forward counter. + */ + public void testForwardCounter() { + Message m1 = new Message(h0, h1, msgId1, 1); + h0.createNewMessage(m1); + checkCreates(1); + updateAllNodes(); + + h0.connect(h2); + advanceWorld(1); + + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_START); + assertEquals(mc.getLastMsg().getId(), msgId1); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h2); + + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h2); + assertFalse(mc.getLastFirstDelivery()); + + assertEquals(m1.getForwardCount(), 1); + assertEquals(((Message)h2.getMessageCollection().toArray()[0]).getForwardCount(), 0); + + disconnect(h0); + h0.connect(h1); + + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_START); + assertEquals(mc.getLastMsg().getId(), msgId1); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h1); + + advanceWorld(1); + + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h1); + assertTrue(mc.getLastFirstDelivery()); + + assertEquals(m1.getForwardCount(), 2); + assertEquals(((Message)h2.getMessageCollection().toArray()[0]).getForwardCount(), 0); + + } + + + /** + * Test the basic logic of the drop policy. + */ + public void testDrop() { + assertTrue(r0.getDropPolicy() instanceof MOFODropPolicy); + + Message m1 = new Message(h0, h1, msgId1, 1); + m1.setForwardCount(2); + h0.createNewMessage(m1); + checkCreates(1); + advanceWorld(1); + + Message m2 = new Message(h0, h1, msgId2, 1); + m2.setForwardCount(1); + h0.createNewMessage(m2); + checkCreates(1); + advanceWorld(1); + + Message m3 = new Message(h0, h1, msgId3, 1); + m3.setForwardCount(3); + h0.createNewMessage(m3); + checkCreates(1); + advanceWorld(1); + + + Message m4 = new Message(h0, h1, msgId4, 2); + h0.createNewMessage(m4); + + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_DELETE); + assertTrue(mc.getLastDropped()); + assertFalse(h0.getMessageCollection().contains(m3)); + + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_DELETE); + assertTrue(mc.getLastDropped()); + assertFalse(h0.getMessageCollection().contains(m1)); + + } + +} diff --git a/src/test/PassiveDropPolicyTest.java b/src/test/PassiveDropPolicyTest.java new file mode 100644 index 000000000..195f2a93c --- /dev/null +++ b/src/test/PassiveDropPolicyTest.java @@ -0,0 +1,70 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package test; + +import buffermanagement.FIFODropPolicy; +import buffermanagement.PassiveDropPolicy; +import core.Message; + +/** + * Test cases for the passive drop policy implementation. + */ +public class PassiveDropPolicyTest extends AbstractDropPolicyTest { + + public PassiveDropPolicyTest() { + super("PassiveDropPolicy"); + } + + @Override + protected void setUp() throws Exception { + ts.putSetting("Group1.bufferSize", "1"); + super.setUp(); + } + + /** + * Test the case when the buffer of the receiver is empty + */ + public void testBufferFree() { + assertTrue(r0.getDropPolicy() instanceof PassiveDropPolicy); + + Message m1 = new Message(h0, h3, msgId1, 1); + h0.createNewMessage(m1); + checkCreates(1); + advanceWorld(1); + + h0.connect(h1); + advanceWorld(1); + + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_START); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h1); + assertFalse(mc.getLastFirstDelivery()); + } + + /** + * Test the basic logic of the drop policy. + */ + public void testDontDrop() { + assertTrue(r0.getDropPolicy() instanceof PassiveDropPolicy); + + Message m1 = new Message(h0, h1, msgId1, 1); + h0.createNewMessage(m1); + checkCreates(1); + advanceWorld(1); + + Message m2 = new Message(h0, h1, msgId2, 1); + h0.createNewMessage(m2); + checkCreates(1); + advanceWorld(1); + + assertTrue(h0.getMessageCollection().contains(m1)); + } + +} diff --git a/src/test/SHLIDropPolicyTest.java b/src/test/SHLIDropPolicyTest.java new file mode 100644 index 000000000..9f3c85537 --- /dev/null +++ b/src/test/SHLIDropPolicyTest.java @@ -0,0 +1,87 @@ +/* + * Copyright 2016, Michael D. Silva (micdoug.silva@gmail.com) + * Released under GPLv3. See LICENSE.txt for details. + */ + +package test; + +import buffermanagement.PassiveDropPolicy; +import buffermanagement.SHLIDropPolicy; +import core.Message; + +public class SHLIDropPolicyTest extends AbstractDropPolicyTest { + + public SHLIDropPolicyTest() { + super("SHLIDropPolicy"); + } + + @Override + protected void setUp() throws Exception { + ts.putSetting("Group.msgTtl", "100"); + ts.putSetting("Group1.bufferSize", "3"); + super.setUp(); + } + + /** + * Test the case when the buffer of the receiver is empty + */ + public void testBufferFree() { + assertTrue(r0.getDropPolicy() instanceof SHLIDropPolicy); + + Message m1 = new Message(h0, h3, msgId1, 1); + h0.createNewMessage(m1); + checkCreates(1); + advanceWorld(1); + + h0.connect(h1); + advanceWorld(1); + + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_START); + advanceWorld(1); + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_RELAY); + assertEquals(mc.getLastFrom(), h0); + assertEquals(mc.getLastTo(), h1); + assertFalse(mc.getLastFirstDelivery()); + } + + public void testDrop() { + assertTrue(r0.getDropPolicy() instanceof SHLIDropPolicy); + + Message m1 = new Message(h0, h1, msgId1, 1); + h0.createNewMessage(m1); + checkCreates(1); + advanceWorld(1); + + Message m2 = new Message(h0, h1, msgId2, 1); + h0.createNewMessage(m2); + checkCreates(1); + advanceWorld(1); + + Message m3 = new Message(h0, h1, msgId3, 1); + h0.createNewMessage(m3); + checkCreates(1); + advanceWorld(1); + + m1.setTtl(10); + m2.setTtl(8); + m3.setTtl(7); + + + Message m4 = new Message(h0, h1, msgId4, 2); + h0.createNewMessage(m4); + + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_DELETE); + assertTrue(mc.getLastDropped()); + assertFalse(h0.getMessageCollection().contains(m2)); + + assertTrue(mc.next()); + assertEquals(mc.getLastType(), mc.TYPE_DELETE); + assertTrue(mc.getLastDropped()); + assertFalse(h0.getMessageCollection().contains(m3)); + + } + +} diff --git a/test_files/centrality b/test_files/centrality new file mode 100644 index 000000000..b70263310 --- /dev/null +++ b/test_files/centrality @@ -0,0 +1,7 @@ +0 0 1 +1 0 2 +2 0 1 +3 1 0 +4 2 0 +5 1 0 +6 0 0 diff --git a/test_files/communities b/test_files/communities new file mode 100644 index 000000000..695e209ea --- /dev/null +++ b/test_files/communities @@ -0,0 +1,7 @@ +0 0 1 2 +1 0 1 2 +2 0 1 2 3 +3 3 4 5 6 +4 3 4 5 6 +5 3 4 5 6 +6 3 4 5 6 diff --git a/toolkit/ccdfPlotter.pl b/toolkit/ccdfPlotter.pl old mode 100755 new mode 100644 diff --git a/toolkit/createCircles.pl b/toolkit/createCircles.pl old mode 100755 new mode 100644 diff --git a/toolkit/createCreates.pl b/toolkit/createCreates.pl old mode 100755 new mode 100644 diff --git a/toolkit/delProb.pl b/toolkit/delProb.pl old mode 100755 new mode 100644 diff --git a/toolkit/dtnsim2parser.pl b/toolkit/dtnsim2parser.pl old mode 100755 new mode 100644 diff --git a/toolkit/getStats.pl b/toolkit/getStats.pl old mode 100755 new mode 100644 diff --git a/toolkit/transimsParser.pl b/toolkit/transimsParser.pl old mode 100755 new mode 100644