diff --git a/src/core/Connection.java b/src/core/Connection.java index a5092b312..cba94a457 100644 --- a/src/core/Connection.java +++ b/src/core/Connection.java @@ -64,7 +64,7 @@ public boolean isTransferring() { * @return true if the given node is the initiator of the connection */ public boolean isInitiator(DTNHost node) { - return node == this.fromNode; + return node.equals(this.fromNode); } /** @@ -216,6 +216,13 @@ public NetworkInterface getOtherInterface(NetworkInterface i) { } } + /** + * Returns the interface specified as originator of the connection + */ + public NetworkInterface getFromInterface() { + return this.fromInterface; + } + /** * Returns a String presentation of the connection. */ diff --git a/src/core/NetworkInterface.java b/src/core/NetworkInterface.java index 6d1581739..6262bcb3c 100644 --- a/src/core/NetworkInterface.java +++ b/src/core/NetworkInterface.java @@ -25,6 +25,8 @@ abstract public class NetworkInterface implements ModuleCommunicationListener { public static final String TRANSMIT_SPEED_S = "transmitSpeed"; /** scanning interval -setting id ({@value})*/ public static final String SCAN_INTERVAL_S = "scanInterval"; + /** bidirectional connections -setting id ({@value})*/ + public static final String BIDI_CONN_S = "bidirectionalConnections"; /** * Sub-namespace for the network related settings in the Group namespace @@ -71,6 +73,9 @@ abstract public class NetworkInterface implements ModuleCommunicationListener { /** this interface's activeness jitter value */ private int activenessJitterValue; + /** whether or not created connections are bi-directional */ + protected boolean bidirectionalConnections; + static { DTNSim.registerForReset(NetworkInterface.class.getCanonicalName()); reset(); @@ -94,6 +99,8 @@ public NetworkInterface(Settings s) { this.transmitSpeed = s.getInt(TRANSMIT_SPEED_S); ensurePositiveValue(transmitRange, TRANSMIT_RANGE_S); ensurePositiveValue(transmitSpeed, TRANSMIT_SPEED_S); + + this.bidirectionalConnections = s.getBoolean(BIDI_CONN_S, true); } /** @@ -114,6 +121,9 @@ public NetworkInterface(NetworkInterface ni) { this.interfacetype = ni.interfacetype; this.transmitRange = ni.transmitRange; this.transmitSpeed = ni.transmitSpeed; + + this.bidirectionalConnections = ni.bidirectionalConnections; + this.scanInterval = ni.scanInterval; this.ah = ni.ah; @@ -183,6 +193,10 @@ public void setGroupSettings(Settings s) { s.restoreSubNameSpace(); } + public boolean isBidirectionalConnections() { + return this.bidirectionalConnections; + } + /** * For checking what interface type this interface is */ @@ -319,12 +333,22 @@ protected void connect(Connection con, NetworkInterface anotherInterface) { this.connections.add(con); notifyConnectionListeners(CON_UP, anotherInterface.getHost()); + if (this.bidirectionalConnections != + anotherInterface.isBidirectionalConnections()) { + throw new SimError("Bidirectional connections are " + + this.bidirectionalConnections + " for " + this + " but " + + anotherInterface.isBidirectionalConnections() + " for " + + anotherInterface + ", which is unsupported"); + } + // set up bidirectional connection - anotherInterface.getConnections().add(con); + if (this.bidirectionalConnections) { + anotherInterface.getConnections().add(con); + anotherInterface.getHost().connectionUp(con); + } // inform routers about the connection this.host.connectionUp(con); - anotherInterface.getHost().connectionUp(con); } /** @@ -338,13 +362,15 @@ protected void disconnect(Connection con, notifyConnectionListeners(CON_DOWN, anotherInterface.getHost()); // tear down bidirectional connection - if (!anotherInterface.getConnections().remove(con)) { + if (this.bidirectionalConnections && + !anotherInterface.getConnections().remove(con)) { throw new SimError("No connection " + con + " found in " + anotherInterface); } this.host.connectionDown(con); - anotherInterface.getHost().connectionDown(con); + if (this.bidirectionalConnections) + anotherInterface.getHost().connectionDown(con); } /** @@ -479,13 +505,15 @@ private void removeConnectionByIndex(int index, notifyConnectionListeners(CON_DOWN, anotherNode); // tear down bidirectional connection - if (!anotherInterface.getConnections().remove(con)) { + if (this.bidirectionalConnections && + !anotherInterface.getConnections().remove(con)) { throw new SimError("No connection " + con + " found in " + anotherNode); } this.host.connectionDown(con); - anotherNode.connectionDown(con); + if (this.bidirectionalConnections) + anotherNode.connectionDown(con); connections.remove(index); } diff --git a/src/routing/ActiveRouter.java b/src/routing/ActiveRouter.java index 4c8a11f4e..cdd646804 100644 --- a/src/routing/ActiveRouter.java +++ b/src/routing/ActiveRouter.java @@ -101,7 +101,7 @@ public void changedConnection(Connection con) { @Override public boolean requestDeliverableMessages(Connection con) { - if (isTransferring()) { + if (con.isTransferring()) { return false; } @@ -228,11 +228,7 @@ protected boolean canStartTransfer() { * does not fit into buffer */ protected int checkReceiving(Message m, DTNHost from) { - if (isTransferring()) { - return TRY_LATER_BUSY; // only one connection at a time - } - - if ( hasMessage(m.getId()) || isDeliveredMessage(m) || + if (hasMessage(m.getId()) || isDeliveredMessage(m) || super.isBlacklistedMessage(m.getId())) { return DENIED_OLD; // already seen this message -> reject it } @@ -485,8 +481,11 @@ protected Connection exchangeDeliverableMessages() { // didn't start transfer to any node -> ask messages from connected for (Connection con : connections) { - if (con.getOtherNode(getHost()).requestDeliverableMessages(con)) { - return con; + // We may only request messages via outgoing connections if they are bidirectional + if (con.getFromInterface().isBidirectionalConnections()) { + if (con.getOtherNode(getHost()).requestDeliverableMessages(con)) { + return con; + } } } diff --git a/src/test/EpidemicRouterTest.java b/src/test/EpidemicRouterTest.java index 486b0f1b4..feb92e7c9 100644 --- a/src/test/EpidemicRouterTest.java +++ b/src/test/EpidemicRouterTest.java @@ -8,6 +8,7 @@ import routing.MessageRouter; import core.DTNHost; import core.Message; +import core.NetworkInterface; /** * Tests for EpidemicRouter and, due the simple nature of Epidemic router, @@ -619,4 +620,34 @@ public void testRandomSendingQ() throws Exception { assertNotSame(orderedIds, runMessageExchange(true)); assertNotSame(orderedIds, runMessageExchange(false)); } + + /** + * Checks that disabling bidirectionalty works + */ + public void testNonBidirectionalConnections() throws Exception { + ts.setNameSpace(TestUtils.IFACE_NS); + ts.putSetting(NetworkInterface.BIDI_CONN_S, "false"); + this.setUp(); + + Message m1 = new Message(h1, h2, msgId1, 1); + h1.createNewMessage(m1); + Message m2 = new Message(h2, h1, msgId2, 1); + h2.createNewMessage(m2); + mc.reset(); + + // check that both routers start the transfer simultaneously + h1.connect(h2); + h2.connect(h1); + updateAllNodes(); // h1 and h2 should start transfer + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertTrue(mc.next()); + assertEquals(mc.TYPE_START, mc.getLastType()); + assertFalse(mc.next()); + + // restore setting as other tests depend on default behavior + ts.setNameSpace(TestUtils.IFACE_NS); + ts.putSetting(NetworkInterface.BIDI_CONN_S, "true"); + this.setUp(); + } }