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));
+			}
+		}
+	}
 }