diff --git a/api/net/sf/briar/api/transport/ConnectionWindow.java b/api/net/sf/briar/api/transport/ConnectionWindow.java index f04b6c4a1692276b775b528bb89b9a254f230a9e..b8e39cb8e9599bb846f2fea6c13fa321df0e6211 100644 --- a/api/net/sf/briar/api/transport/ConnectionWindow.java +++ b/api/net/sf/briar/api/transport/ConnectionWindow.java @@ -1,5 +1,7 @@ package net.sf.briar.api.transport; +import java.util.Collection; + public interface ConnectionWindow { long getCentre(); @@ -9,4 +11,6 @@ public interface ConnectionWindow { boolean isSeen(long connectionNumber); void setSeen(long connectionNumber); + + Collection<Long> getUnseenConnectionNumbers(); } diff --git a/components/net/sf/briar/transport/ConnectionWindowImpl.java b/components/net/sf/briar/transport/ConnectionWindowImpl.java index fe0c1735a3f57b68bf933f7aa2f5c04856b54869..956a5c722a072235edb610757dc22b0f0be81a48 100644 --- a/components/net/sf/briar/transport/ConnectionWindowImpl.java +++ b/components/net/sf/briar/transport/ConnectionWindowImpl.java @@ -1,5 +1,8 @@ package net.sf.briar.transport; +import java.util.ArrayList; +import java.util.Collection; + import net.sf.briar.api.transport.ConnectionWindow; class ConnectionWindowImpl implements ConnectionWindow { @@ -28,6 +31,15 @@ class ConnectionWindowImpl implements ConnectionWindow { return (bitmap & mask) != 0; } + private int getOffset(long connectionNumber) { + if(connectionNumber < 0L) throw new IllegalArgumentException(); + if(connectionNumber > MAX_32_BIT_UNSIGNED) + throw new IllegalArgumentException(); + int offset = (int) (connectionNumber - centre) + 16; + if(offset < 0 || offset > 31) throw new IllegalArgumentException(); + return offset; + } + public void setSeen(long connectionNumber) { int offset = getOffset(connectionNumber); int mask = 0x80000000 >>> offset; @@ -40,12 +52,16 @@ class ConnectionWindowImpl implements ConnectionWindow { } } - private int getOffset(long connectionNumber) { - if(connectionNumber < 0L) throw new IllegalArgumentException(); - if(connectionNumber > MAX_32_BIT_UNSIGNED) - throw new IllegalArgumentException(); - int offset = (int) (connectionNumber - centre) + 16; - if(offset < 0 || offset > 31) throw new IllegalArgumentException(); - return offset; + public Collection<Long> getUnseenConnectionNumbers() { + Collection<Long> unseen = new ArrayList<Long>(); + for(int i = 0; i < 32; i++) { + int mask = 0x80000000 >>> i; + if((bitmap & mask) == 0) { + long c = centre - 16 + i; + if(c >= 0L && c <= MAX_32_BIT_UNSIGNED) unseen.add(c); + } + } + assert unseen.contains(centre) || centre == MAX_32_BIT_UNSIGNED + 1; + return unseen; } } diff --git a/test/net/sf/briar/transport/ConnectionWindowImplTest.java b/test/net/sf/briar/transport/ConnectionWindowImplTest.java index 32a32ff6a7298146ca2390e7a5906a7f4c70fa03..c95dc19eddebb4cd2e5a3544095bbe544dabe189 100644 --- a/test/net/sf/briar/transport/ConnectionWindowImplTest.java +++ b/test/net/sf/briar/transport/ConnectionWindowImplTest.java @@ -1,5 +1,7 @@ package net.sf.briar.transport; +import java.util.Collection; + import junit.framework.TestCase; import org.junit.Test; @@ -71,7 +73,7 @@ public class ConnectionWindowImplTest extends TestCase { } @Test - public void testCannotSetSameValueTwice() { + public void testCannotSetSeenTwice() { ConnectionWindowImpl w = new ConnectionWindowImpl(0L, 0); w.setSeen(15); try { @@ -79,4 +81,43 @@ public class ConnectionWindowImplTest extends TestCase { fail(); } catch(IllegalArgumentException expected) {} } + + @Test + public void testGetUnseenConnectionNumbers() { + ConnectionWindowImpl w = new ConnectionWindowImpl(0L, 0); + // Centre is 0; window should cover 0 to 15, inclusive, with none seen + Collection<Long> unseen = w.getUnseenConnectionNumbers(); + assertEquals(16, unseen.size()); + for(int i = 0; i < 16; i++) { + assertTrue(unseen.contains(Long.valueOf(i))); + assertFalse(w.isSeen(i)); + } + w.setSeen(3); + w.setSeen(4); + // Centre is 5; window should cover 0 to 20, inclusive, with two seen + unseen = w.getUnseenConnectionNumbers(); + assertEquals(19, unseen.size()); + for(int i = 0; i < 21; i++) { + if(i == 3 || i == 4) { + assertFalse(unseen.contains(Long.valueOf(i))); + assertTrue(w.isSeen(i)); + } else { + assertTrue(unseen.contains(Long.valueOf(i))); + assertFalse(w.isSeen(i)); + } + } + w.setSeen(19); + // Centre is 20; window should cover 4 to 35, inclusive, with two seen + unseen = w.getUnseenConnectionNumbers(); + assertEquals(30, unseen.size()); + for(int i = 4; i < 36; i++) { + if(i == 4 || i == 19) { + assertFalse(unseen.contains(Long.valueOf(i))); + assertTrue(w.isSeen(i)); + } else { + assertTrue(unseen.contains(Long.valueOf(i))); + assertFalse(w.isSeen(i)); + } + } + } }