mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 21:59:54 +01:00
Avoid DB lookups where possible.
This commit is contained in:
@@ -1,17 +1,27 @@
|
|||||||
package net.sf.briar.api.db.event;
|
package net.sf.briar.api.db.event;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
import net.sf.briar.api.ContactId;
|
import net.sf.briar.api.ContactId;
|
||||||
|
import net.sf.briar.api.protocol.Transport;
|
||||||
|
|
||||||
/** An event that is broadcast when a contact's transports are updated. */
|
/** An event that is broadcast when a contact's transports are updated. */
|
||||||
public class RemoteTransportsUpdatedEvent extends DatabaseEvent {
|
public class RemoteTransportsUpdatedEvent extends DatabaseEvent {
|
||||||
|
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
|
private final Collection<Transport> transports;
|
||||||
|
|
||||||
public RemoteTransportsUpdatedEvent(ContactId contactId) {
|
public RemoteTransportsUpdatedEvent(ContactId contactId,
|
||||||
|
Collection<Transport> transports) {
|
||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
|
this.transports = transports;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContactId getContactId() {
|
public ContactId getContactId() {
|
||||||
return contactId;
|
return contactId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<Transport> getTransports() {
|
||||||
|
return transports;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1226,7 +1226,7 @@ DatabaseCleaner.Callback {
|
|||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
// Call the listeners outside the lock
|
// Call the listeners outside the lock
|
||||||
callListeners(new RemoteTransportsUpdatedEvent(c));
|
callListeners(new RemoteTransportsUpdatedEvent(c, t.getTransports()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeContact(ContactId c) throws DbException {
|
public void removeContact(ContactId c) throws DbException {
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ DatabaseListener {
|
|||||||
private final DatabaseComponent db;
|
private final DatabaseComponent db;
|
||||||
private final Executor executor;
|
private final Executor executor;
|
||||||
private final Cipher ivCipher; // Locking: this
|
private final Cipher ivCipher; // Locking: this
|
||||||
|
private final Set<TransportId> localTransportIds; // Locking: this
|
||||||
private final Map<Bytes, Context> expected; // Locking: this
|
private final Map<Bytes, Context> expected; // Locking: this
|
||||||
|
|
||||||
private boolean initialised = false; // Locking: this
|
private boolean initialised = false; // Locking: this
|
||||||
@@ -62,9 +63,15 @@ DatabaseListener {
|
|||||||
this.db = db;
|
this.db = db;
|
||||||
this.executor = executor;
|
this.executor = executor;
|
||||||
ivCipher = crypto.getIvCipher();
|
ivCipher = crypto.getIvCipher();
|
||||||
|
localTransportIds = new HashSet<TransportId>();
|
||||||
expected = new HashMap<Bytes, Context>();
|
expected = new HashMap<Bytes, Context>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Package access for testing
|
||||||
|
synchronized boolean isInitialised() {
|
||||||
|
return initialised;
|
||||||
|
}
|
||||||
|
|
||||||
// Locking: this
|
// Locking: this
|
||||||
private void initialise() throws DbException {
|
private void initialise() throws DbException {
|
||||||
assert !initialised;
|
assert !initialised;
|
||||||
@@ -76,7 +83,7 @@ DatabaseListener {
|
|||||||
try {
|
try {
|
||||||
for(TransportId t : transports) {
|
for(TransportId t : transports) {
|
||||||
TransportIndex i = db.getRemoteIndex(c, t);
|
TransportIndex i = db.getRemoteIndex(c, t);
|
||||||
if(i == null) continue;
|
if(i == null) continue; // Contact doesn't support transport
|
||||||
ConnectionWindow w = db.getConnectionWindow(c, i);
|
ConnectionWindow w = db.getConnectionWindow(c, i);
|
||||||
for(Entry<Long, byte[]> e : w.getUnseen().entrySet()) {
|
for(Entry<Long, byte[]> e : w.getUnseen().entrySet()) {
|
||||||
Context ctx = new Context(c, t, i, e.getKey());
|
Context ctx = new Context(c, t, i, e.getKey());
|
||||||
@@ -89,6 +96,7 @@ DatabaseListener {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
localTransportIds.addAll(transports);
|
||||||
expected.putAll(ivs);
|
expected.putAll(ivs);
|
||||||
initialised = true;
|
initialised = true;
|
||||||
}
|
}
|
||||||
@@ -100,7 +108,8 @@ DatabaseListener {
|
|||||||
ErasableKey ivKey = crypto.deriveIvKey(secret, true);
|
ErasableKey ivKey = crypto.deriveIvKey(secret, true);
|
||||||
try {
|
try {
|
||||||
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
||||||
return new Bytes(ivCipher.doFinal(iv));
|
byte[] encryptedIv = ivCipher.doFinal(iv);
|
||||||
|
return new Bytes(encryptedIv);
|
||||||
} catch(BadPaddingException badCipher) {
|
} catch(BadPaddingException badCipher) {
|
||||||
throw new RuntimeException(badCipher);
|
throw new RuntimeException(badCipher);
|
||||||
} catch(IllegalBlockSizeException badCipher) {
|
} catch(IllegalBlockSizeException badCipher) {
|
||||||
@@ -127,8 +136,9 @@ DatabaseListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConnectionContext acceptConnection(TransportId t,
|
// Package access for testing
|
||||||
byte[] encryptedIv) throws DbException {
|
ConnectionContext acceptConnection(TransportId t, byte[] encryptedIv)
|
||||||
|
throws DbException {
|
||||||
if(encryptedIv.length != IV_LENGTH)
|
if(encryptedIv.length != IV_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
@@ -189,11 +199,12 @@ DatabaseListener {
|
|||||||
});
|
});
|
||||||
} else if(e instanceof RemoteTransportsUpdatedEvent) {
|
} else if(e instanceof RemoteTransportsUpdatedEvent) {
|
||||||
// Update the expected IVs for the contact
|
// Update the expected IVs for the contact
|
||||||
final ContactId c =
|
RemoteTransportsUpdatedEvent r = (RemoteTransportsUpdatedEvent) e;
|
||||||
((RemoteTransportsUpdatedEvent) e).getContactId();
|
final ContactId c = r.getContactId();
|
||||||
|
final Collection<Transport> transports = r.getTransports();
|
||||||
executor.execute(new Runnable() {
|
executor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
updateContact(c);
|
updateContact(c, transports);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -212,7 +223,7 @@ DatabaseListener {
|
|||||||
for(ContactId c : db.getContacts()) {
|
for(ContactId c : db.getContacts()) {
|
||||||
try {
|
try {
|
||||||
TransportIndex i = db.getRemoteIndex(c, t);
|
TransportIndex i = db.getRemoteIndex(c, t);
|
||||||
if(i == null) continue;
|
if(i == null) continue; // Contact doesn't support transport
|
||||||
ConnectionWindow w = db.getConnectionWindow(c, i);
|
ConnectionWindow w = db.getConnectionWindow(c, i);
|
||||||
for(Entry<Long, byte[]> e : w.getUnseen().entrySet()) {
|
for(Entry<Long, byte[]> e : w.getUnseen().entrySet()) {
|
||||||
Context ctx = new Context(c, t, i, e.getKey());
|
Context ctx = new Context(c, t, i, e.getKey());
|
||||||
@@ -228,33 +239,26 @@ DatabaseListener {
|
|||||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
localTransportIds.add(t);
|
||||||
expected.putAll(ivs);
|
expected.putAll(ivs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void updateContact(ContactId c) {
|
private synchronized void updateContact(ContactId c,
|
||||||
|
Collection<Transport> transports) {
|
||||||
if(!initialised) return;
|
if(!initialised) return;
|
||||||
// Don't recalculate IVs for transports that are already known
|
// The ID <-> index mappings may have changed, so recalculate everything
|
||||||
Set<TransportIndex> known = new HashSet<TransportIndex>();
|
|
||||||
for(Context ctx : expected.values()) {
|
|
||||||
if(ctx.contactId.equals(c)) known.add(ctx.transportIndex);
|
|
||||||
}
|
|
||||||
Set<TransportIndex> current = new HashSet<TransportIndex>();
|
|
||||||
Map<Bytes, Context> ivs = new HashMap<Bytes, Context>();
|
Map<Bytes, Context> ivs = new HashMap<Bytes, Context>();
|
||||||
try {
|
try {
|
||||||
for(Transport transport : db.getLocalTransports()) {
|
for(Transport transport: transports) {
|
||||||
TransportId t = transport.getId();
|
TransportId t = transport.getId();
|
||||||
TransportIndex i = db.getRemoteIndex(c, t);
|
if(!localTransportIds.contains(t)) continue;
|
||||||
if(i == null) continue;
|
TransportIndex i = transport.getIndex();
|
||||||
current.add(i);
|
ConnectionWindow w = db.getConnectionWindow(c, i);
|
||||||
// If the transport is not already known, calculate the IVs
|
for(Entry<Long, byte[]> e : w.getUnseen().entrySet()) {
|
||||||
if(!known.contains(i)) {
|
Context ctx = new Context(c, t, i, e.getKey());
|
||||||
ConnectionWindow w = db.getConnectionWindow(c, i);
|
ivs.put(calculateIv(ctx, e.getValue()), ctx);
|
||||||
for(Entry<Long, byte[]> e : w.getUnseen().entrySet()) {
|
|
||||||
Context ctx = new Context(c, t, i, e.getKey());
|
|
||||||
ivs.put(calculateIv(ctx, e.getValue()), ctx);
|
|
||||||
}
|
|
||||||
w.erase();
|
|
||||||
}
|
}
|
||||||
|
w.erase();
|
||||||
}
|
}
|
||||||
} catch(NoSuchContactException e) {
|
} catch(NoSuchContactException e) {
|
||||||
// The contact was removed - clean up in removeContact()
|
// The contact was removed - clean up in removeContact()
|
||||||
@@ -263,14 +267,10 @@ DatabaseListener {
|
|||||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Remove any IVs that are no longer current
|
// Remove the old IVs
|
||||||
Iterator<Context> it = expected.values().iterator();
|
Iterator<Context> it = expected.values().iterator();
|
||||||
while(it.hasNext()) {
|
while(it.hasNext()) if(it.next().contactId.equals(c)) it.remove();
|
||||||
Context ctx = it.next();
|
// Store the new IVs
|
||||||
if(ctx.contactId.equals(c) && !current.contains(ctx.transportIndex))
|
|
||||||
it.remove();
|
|
||||||
}
|
|
||||||
// Add any IVs that were not previously known
|
|
||||||
expected.putAll(ivs);
|
expected.putAll(ivs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package net.sf.briar.transport;
|
|||||||
|
|
||||||
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
|
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -16,13 +17,13 @@ import net.sf.briar.api.ContactId;
|
|||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.ErasableKey;
|
import net.sf.briar.api.crypto.ErasableKey;
|
||||||
import net.sf.briar.api.db.DatabaseComponent;
|
import net.sf.briar.api.db.DatabaseComponent;
|
||||||
import net.sf.briar.api.db.DbException;
|
import net.sf.briar.api.db.event.ContactRemovedEvent;
|
||||||
|
import net.sf.briar.api.db.event.RemoteTransportsUpdatedEvent;
|
||||||
|
import net.sf.briar.api.db.event.TransportAddedEvent;
|
||||||
import net.sf.briar.api.protocol.Transport;
|
import net.sf.briar.api.protocol.Transport;
|
||||||
import net.sf.briar.api.protocol.TransportId;
|
import net.sf.briar.api.protocol.TransportId;
|
||||||
import net.sf.briar.api.protocol.TransportIndex;
|
import net.sf.briar.api.protocol.TransportIndex;
|
||||||
import net.sf.briar.api.transport.ConnectionContext;
|
import net.sf.briar.api.transport.ConnectionContext;
|
||||||
import net.sf.briar.api.transport.ConnectionRecogniser;
|
|
||||||
import net.sf.briar.api.transport.ConnectionRecogniser.Callback;
|
|
||||||
import net.sf.briar.api.transport.ConnectionWindow;
|
import net.sf.briar.api.transport.ConnectionWindow;
|
||||||
import net.sf.briar.crypto.CryptoModule;
|
import net.sf.briar.crypto.CryptoModule;
|
||||||
import net.sf.briar.plugins.ImmediateExecutor;
|
import net.sf.briar.plugins.ImmediateExecutor;
|
||||||
@@ -41,8 +42,7 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
|||||||
private final byte[] inSecret;
|
private final byte[] inSecret;
|
||||||
private final TransportId transportId;
|
private final TransportId transportId;
|
||||||
private final TransportIndex localIndex, remoteIndex;
|
private final TransportIndex localIndex, remoteIndex;
|
||||||
private final Collection<Transport> transports;
|
private final Collection<Transport> localTransports, remoteTransports;
|
||||||
private final ConnectionWindow connectionWindow;
|
|
||||||
|
|
||||||
public ConnectionRecogniserImplTest() {
|
public ConnectionRecogniserImplTest() {
|
||||||
super();
|
super();
|
||||||
@@ -54,51 +54,486 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
|||||||
transportId = new TransportId(TestUtils.getRandomId());
|
transportId = new TransportId(TestUtils.getRandomId());
|
||||||
localIndex = new TransportIndex(13);
|
localIndex = new TransportIndex(13);
|
||||||
remoteIndex = new TransportIndex(7);
|
remoteIndex = new TransportIndex(7);
|
||||||
Transport transport = new Transport(transportId, localIndex,
|
Map<String, String> properties = Collections.singletonMap("foo", "bar");
|
||||||
Collections.singletonMap("foo", "bar"));
|
Transport localTransport = new Transport(transportId, localIndex,
|
||||||
transports = Collections.singletonList(transport);
|
properties);
|
||||||
connectionWindow = new ConnectionWindowImpl(crypto, remoteIndex,
|
localTransports = Collections.singletonList(localTransport);
|
||||||
inSecret);
|
Transport remoteTransport = new Transport(transportId, remoteIndex,
|
||||||
|
properties);
|
||||||
|
remoteTransports = Collections.singletonList(remoteTransport);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUnexpectedIv() throws Exception {
|
public void testUnexpectedIv() throws Exception {
|
||||||
|
final ConnectionWindow window = createConnectionWindow(remoteIndex);
|
||||||
Mockery context = new Mockery();
|
Mockery context = new Mockery();
|
||||||
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(db).addListener(with(any(ConnectionRecogniserImpl.class)));
|
|
||||||
// Initialise
|
// Initialise
|
||||||
|
oneOf(db).addListener(with(any(ConnectionRecogniserImpl.class)));
|
||||||
oneOf(db).getLocalTransports();
|
oneOf(db).getLocalTransports();
|
||||||
will(returnValue(transports));
|
will(returnValue(localTransports));
|
||||||
oneOf(db).getContacts();
|
oneOf(db).getContacts();
|
||||||
will(returnValue(Collections.singletonList(contactId)));
|
will(returnValue(Collections.singletonList(contactId)));
|
||||||
oneOf(db).getRemoteIndex(contactId, transportId);
|
oneOf(db).getRemoteIndex(contactId, transportId);
|
||||||
will(returnValue(remoteIndex));
|
will(returnValue(remoteIndex));
|
||||||
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
||||||
will(returnValue(connectionWindow));
|
will(returnValue(window));
|
||||||
}});
|
}});
|
||||||
Executor executor = new ImmediateExecutor();
|
Executor executor = new ImmediateExecutor();
|
||||||
ConnectionRecogniser c = new ConnectionRecogniserImpl(crypto, db,
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
executor);
|
executor);
|
||||||
c.acceptConnection(transportId, new byte[IV_LENGTH], new Callback() {
|
assertNull(c.acceptConnection(transportId, new byte[IV_LENGTH]));
|
||||||
|
|
||||||
public void connectionAccepted(ConnectionContext ctx) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void connectionRejected() {
|
|
||||||
// Expected
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleException(DbException e) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpectedIv() throws Exception {
|
public void testExpectedIv() throws Exception {
|
||||||
|
final ConnectionWindow window = createConnectionWindow(remoteIndex);
|
||||||
|
Mockery context = new Mockery();
|
||||||
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
// Initialise
|
||||||
|
oneOf(db).addListener(with(any(ConnectionRecogniserImpl.class)));
|
||||||
|
oneOf(db).getLocalTransports();
|
||||||
|
will(returnValue(localTransports));
|
||||||
|
oneOf(db).getContacts();
|
||||||
|
will(returnValue(Collections.singletonList(contactId)));
|
||||||
|
oneOf(db).getRemoteIndex(contactId, transportId);
|
||||||
|
will(returnValue(remoteIndex));
|
||||||
|
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
||||||
|
will(returnValue(window));
|
||||||
|
// Update the window
|
||||||
|
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
||||||
|
will(returnValue(window));
|
||||||
|
oneOf(db).setConnectionWindow(contactId, remoteIndex, window);
|
||||||
|
}});
|
||||||
|
Executor executor = new ImmediateExecutor();
|
||||||
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
|
executor);
|
||||||
|
byte[] encryptedIv = calculateIv();
|
||||||
|
// The IV should not be expected by the wrong transport
|
||||||
|
TransportId wrong = new TransportId(TestUtils.getRandomId());
|
||||||
|
assertNull(c.acceptConnection(wrong, encryptedIv));
|
||||||
|
// The IV should be expected by the right transport
|
||||||
|
ConnectionContext ctx = c.acceptConnection(transportId, encryptedIv);
|
||||||
|
assertNotNull(ctx);
|
||||||
|
assertEquals(contactId, ctx.getContactId());
|
||||||
|
assertEquals(remoteIndex, ctx.getTransportIndex());
|
||||||
|
assertEquals(3, ctx.getConnectionNumber());
|
||||||
|
// The IV should no longer be expected
|
||||||
|
assertNull(c.acceptConnection(transportId, encryptedIv));
|
||||||
|
// The window should have advanced
|
||||||
|
Map<Long, byte[]> unseen = window.getUnseen();
|
||||||
|
assertEquals(19, unseen.size());
|
||||||
|
for(int i = 0; i < 19; i++) {
|
||||||
|
assertEquals(i != 3, unseen.containsKey(Long.valueOf(i)));
|
||||||
|
}
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testContactRemovedAfterInit() throws Exception {
|
||||||
|
final ConnectionWindow window = createConnectionWindow(remoteIndex);
|
||||||
|
Mockery context = new Mockery();
|
||||||
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
// Initialise before removing contact
|
||||||
|
oneOf(db).addListener(with(any(ConnectionRecogniserImpl.class)));
|
||||||
|
oneOf(db).getLocalTransports();
|
||||||
|
will(returnValue(localTransports));
|
||||||
|
oneOf(db).getContacts();
|
||||||
|
will(returnValue(Collections.singletonList(contactId)));
|
||||||
|
oneOf(db).getRemoteIndex(contactId, transportId);
|
||||||
|
will(returnValue(remoteIndex));
|
||||||
|
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
||||||
|
will(returnValue(window));
|
||||||
|
}});
|
||||||
|
Executor executor = new ImmediateExecutor();
|
||||||
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
|
executor);
|
||||||
|
byte[] encryptedIv = calculateIv();
|
||||||
|
// Ensure the recogniser is initialised
|
||||||
|
assertFalse(c.isInitialised());
|
||||||
|
assertNull(c.acceptConnection(transportId, new byte[IV_LENGTH]));
|
||||||
|
assertTrue(c.isInitialised());
|
||||||
|
// Remove the contact
|
||||||
|
c.eventOccurred(new ContactRemovedEvent(contactId));
|
||||||
|
// The IV should not be expected
|
||||||
|
assertNull(c.acceptConnection(transportId, encryptedIv));
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testContactRemovedBeforeInit() throws Exception {
|
||||||
|
Mockery context = new Mockery();
|
||||||
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
// Initialise after removing contact
|
||||||
|
oneOf(db).addListener(with(any(ConnectionRecogniserImpl.class)));
|
||||||
|
oneOf(db).getLocalTransports();
|
||||||
|
will(returnValue(localTransports));
|
||||||
|
oneOf(db).getContacts();
|
||||||
|
will(returnValue(Collections.emptyList()));
|
||||||
|
}});
|
||||||
|
Executor executor = new ImmediateExecutor();
|
||||||
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
|
executor);
|
||||||
|
byte[] encryptedIv = calculateIv();
|
||||||
|
// Remove the contact
|
||||||
|
c.eventOccurred(new ContactRemovedEvent(contactId));
|
||||||
|
// The IV should not be expected
|
||||||
|
assertFalse(c.isInitialised());
|
||||||
|
assertNull(c.acceptConnection(transportId, encryptedIv));
|
||||||
|
assertTrue(c.isInitialised());
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLocalTransportAddedAfterInit() throws Exception {
|
||||||
|
final ConnectionWindow window = createConnectionWindow(remoteIndex);
|
||||||
|
Mockery context = new Mockery();
|
||||||
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
// Initialise before adding transport
|
||||||
|
oneOf(db).addListener(with(any(ConnectionRecogniserImpl.class)));
|
||||||
|
oneOf(db).getLocalTransports();
|
||||||
|
will(returnValue(Collections.emptyList()));
|
||||||
|
oneOf(db).getContacts();
|
||||||
|
will(returnValue(Collections.singletonList(contactId)));
|
||||||
|
// Add the transport
|
||||||
|
oneOf(db).getContacts();
|
||||||
|
will(returnValue(Collections.singletonList(contactId)));
|
||||||
|
oneOf(db).getRemoteIndex(contactId, transportId);
|
||||||
|
will(returnValue(remoteIndex));
|
||||||
|
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
||||||
|
will(returnValue(window));
|
||||||
|
// Update the window
|
||||||
|
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
||||||
|
will(returnValue(window));
|
||||||
|
oneOf(db).setConnectionWindow(contactId, remoteIndex, window);
|
||||||
|
}});
|
||||||
|
Executor executor = new ImmediateExecutor();
|
||||||
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
|
executor);
|
||||||
|
byte[] encryptedIv = calculateIv();
|
||||||
|
// The IV should not be expected
|
||||||
|
assertFalse(c.isInitialised());
|
||||||
|
assertNull(c.acceptConnection(transportId, encryptedIv));
|
||||||
|
assertTrue(c.isInitialised());
|
||||||
|
// Add the transport
|
||||||
|
c.eventOccurred(new TransportAddedEvent(transportId));
|
||||||
|
// The IV should be expected
|
||||||
|
ConnectionContext ctx = c.acceptConnection(transportId, encryptedIv);
|
||||||
|
assertNotNull(ctx);
|
||||||
|
assertEquals(contactId, ctx.getContactId());
|
||||||
|
assertEquals(remoteIndex, ctx.getTransportIndex());
|
||||||
|
assertEquals(3, ctx.getConnectionNumber());
|
||||||
|
// The IV should no longer be expected
|
||||||
|
assertNull(c.acceptConnection(transportId, encryptedIv));
|
||||||
|
// The window should have advanced
|
||||||
|
Map<Long, byte[]> unseen = window.getUnseen();
|
||||||
|
assertEquals(19, unseen.size());
|
||||||
|
for(int i = 0; i < 19; i++) {
|
||||||
|
assertEquals(i != 3, unseen.containsKey(Long.valueOf(i)));
|
||||||
|
}
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLocalTransportAddedBeforeInit() throws Exception {
|
||||||
|
final ConnectionWindow window = createConnectionWindow(remoteIndex);
|
||||||
|
Mockery context = new Mockery();
|
||||||
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
// Initialise after adding transport
|
||||||
|
oneOf(db).addListener(with(any(ConnectionRecogniserImpl.class)));
|
||||||
|
oneOf(db).getLocalTransports();
|
||||||
|
will(returnValue(localTransports));
|
||||||
|
oneOf(db).getContacts();
|
||||||
|
will(returnValue(Collections.singletonList(contactId)));
|
||||||
|
oneOf(db).getRemoteIndex(contactId, transportId);
|
||||||
|
will(returnValue(remoteIndex));
|
||||||
|
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
||||||
|
will(returnValue(window));
|
||||||
|
// Update the window
|
||||||
|
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
||||||
|
will(returnValue(window));
|
||||||
|
oneOf(db).setConnectionWindow(contactId, remoteIndex, window);
|
||||||
|
}});
|
||||||
|
Executor executor = new ImmediateExecutor();
|
||||||
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
|
executor);
|
||||||
|
byte[] encryptedIv = calculateIv();
|
||||||
|
// Add the transport
|
||||||
|
c.eventOccurred(new TransportAddedEvent(transportId));
|
||||||
|
// The IV should be expected
|
||||||
|
assertFalse(c.isInitialised());
|
||||||
|
ConnectionContext ctx = c.acceptConnection(transportId, encryptedIv);
|
||||||
|
assertTrue(c.isInitialised());
|
||||||
|
assertNotNull(ctx);
|
||||||
|
assertEquals(contactId, ctx.getContactId());
|
||||||
|
assertEquals(remoteIndex, ctx.getTransportIndex());
|
||||||
|
assertEquals(3, ctx.getConnectionNumber());
|
||||||
|
// The IV should no longer be expected
|
||||||
|
assertNull(c.acceptConnection(transportId, encryptedIv));
|
||||||
|
// The window should have advanced
|
||||||
|
Map<Long, byte[]> unseen = window.getUnseen();
|
||||||
|
assertEquals(19, unseen.size());
|
||||||
|
for(int i = 0; i < 19; i++) {
|
||||||
|
assertEquals(i != 3, unseen.containsKey(Long.valueOf(i)));
|
||||||
|
}
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoteTransportAddedAfterInit() throws Exception {
|
||||||
|
final ConnectionWindow window = createConnectionWindow(remoteIndex);
|
||||||
|
Mockery context = new Mockery();
|
||||||
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
// Initialise before updating the contact
|
||||||
|
oneOf(db).addListener(with(any(ConnectionRecogniserImpl.class)));
|
||||||
|
oneOf(db).getLocalTransports();
|
||||||
|
will(returnValue(localTransports));
|
||||||
|
oneOf(db).getContacts();
|
||||||
|
will(returnValue(Collections.singletonList(contactId)));
|
||||||
|
oneOf(db).getRemoteIndex(contactId, transportId);
|
||||||
|
will(returnValue(null));
|
||||||
|
// Update the contact
|
||||||
|
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
||||||
|
will(returnValue(window));
|
||||||
|
// Update the window
|
||||||
|
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
||||||
|
will(returnValue(window));
|
||||||
|
oneOf(db).setConnectionWindow(contactId, remoteIndex, window);
|
||||||
|
}});
|
||||||
|
Executor executor = new ImmediateExecutor();
|
||||||
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
|
executor);
|
||||||
|
byte[] encryptedIv = calculateIv();
|
||||||
|
// The IV should not be expected
|
||||||
|
assertFalse(c.isInitialised());
|
||||||
|
assertNull(c.acceptConnection(transportId, encryptedIv));
|
||||||
|
assertTrue(c.isInitialised());
|
||||||
|
// Update the contact
|
||||||
|
c.eventOccurred(new RemoteTransportsUpdatedEvent(contactId,
|
||||||
|
remoteTransports));
|
||||||
|
// The IV should be expected
|
||||||
|
ConnectionContext ctx = c.acceptConnection(transportId, encryptedIv);
|
||||||
|
assertNotNull(ctx);
|
||||||
|
assertEquals(contactId, ctx.getContactId());
|
||||||
|
assertEquals(remoteIndex, ctx.getTransportIndex());
|
||||||
|
assertEquals(3, ctx.getConnectionNumber());
|
||||||
|
// The IV should no longer be expected
|
||||||
|
assertNull(c.acceptConnection(transportId, encryptedIv));
|
||||||
|
// The window should have advanced
|
||||||
|
Map<Long, byte[]> unseen = window.getUnseen();
|
||||||
|
assertEquals(19, unseen.size());
|
||||||
|
for(int i = 0; i < 19; i++) {
|
||||||
|
assertEquals(i != 3, unseen.containsKey(Long.valueOf(i)));
|
||||||
|
}
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoteTransportAddedBeforeInit() throws Exception {
|
||||||
|
final ConnectionWindow window = createConnectionWindow(remoteIndex);
|
||||||
|
Mockery context = new Mockery();
|
||||||
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
// Initialise after updating the contact
|
||||||
|
oneOf(db).addListener(with(any(ConnectionRecogniserImpl.class)));
|
||||||
|
oneOf(db).getLocalTransports();
|
||||||
|
will(returnValue(localTransports));
|
||||||
|
oneOf(db).getContacts();
|
||||||
|
will(returnValue(Collections.singletonList(contactId)));
|
||||||
|
oneOf(db).getRemoteIndex(contactId, transportId);
|
||||||
|
will(returnValue(remoteIndex));
|
||||||
|
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
||||||
|
will(returnValue(window));
|
||||||
|
// Update the window
|
||||||
|
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
||||||
|
will(returnValue(window));
|
||||||
|
oneOf(db).setConnectionWindow(contactId, remoteIndex, window);
|
||||||
|
}});
|
||||||
|
Executor executor = new ImmediateExecutor();
|
||||||
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
|
executor);
|
||||||
|
byte[] encryptedIv = calculateIv();
|
||||||
|
// Update the contact
|
||||||
|
c.eventOccurred(new RemoteTransportsUpdatedEvent(contactId,
|
||||||
|
remoteTransports));
|
||||||
|
// The IV should be expected
|
||||||
|
assertFalse(c.isInitialised());
|
||||||
|
ConnectionContext ctx = c.acceptConnection(transportId, encryptedIv);
|
||||||
|
assertTrue(c.isInitialised());
|
||||||
|
assertNotNull(ctx);
|
||||||
|
assertEquals(contactId, ctx.getContactId());
|
||||||
|
assertEquals(remoteIndex, ctx.getTransportIndex());
|
||||||
|
assertEquals(3, ctx.getConnectionNumber());
|
||||||
|
// The IV should no longer be expected
|
||||||
|
assertNull(c.acceptConnection(transportId, encryptedIv));
|
||||||
|
// The window should have advanced
|
||||||
|
Map<Long, byte[]> unseen = window.getUnseen();
|
||||||
|
assertEquals(19, unseen.size());
|
||||||
|
for(int i = 0; i < 19; i++) {
|
||||||
|
assertEquals(i != 3, unseen.containsKey(Long.valueOf(i)));
|
||||||
|
}
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoteTransportRemovedAfterInit() throws Exception {
|
||||||
|
final ConnectionWindow window = createConnectionWindow(remoteIndex);
|
||||||
|
Mockery context = new Mockery();
|
||||||
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
// Initialise before updating the contact
|
||||||
|
oneOf(db).addListener(with(any(ConnectionRecogniserImpl.class)));
|
||||||
|
oneOf(db).getLocalTransports();
|
||||||
|
will(returnValue(localTransports));
|
||||||
|
oneOf(db).getContacts();
|
||||||
|
will(returnValue(Collections.singletonList(contactId)));
|
||||||
|
oneOf(db).getRemoteIndex(contactId, transportId);
|
||||||
|
will(returnValue(remoteIndex));
|
||||||
|
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
||||||
|
will(returnValue(window));
|
||||||
|
}});
|
||||||
|
Executor executor = new ImmediateExecutor();
|
||||||
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
|
executor);
|
||||||
|
byte[] encryptedIv = calculateIv();
|
||||||
|
// Ensure the recogniser is initialised
|
||||||
|
assertFalse(c.isInitialised());
|
||||||
|
assertNull(c.acceptConnection(transportId, new byte[IV_LENGTH]));
|
||||||
|
assertTrue(c.isInitialised());
|
||||||
|
// Update the contact
|
||||||
|
c.eventOccurred(new RemoteTransportsUpdatedEvent(contactId,
|
||||||
|
Collections.<Transport>emptyList()));
|
||||||
|
// The IV should not be expected
|
||||||
|
assertNull(c.acceptConnection(transportId, encryptedIv));
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoteTransportRemovedBeforeInit() throws Exception {
|
||||||
|
Mockery context = new Mockery();
|
||||||
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
// Initialise after updating the contact
|
||||||
|
oneOf(db).addListener(with(any(ConnectionRecogniserImpl.class)));
|
||||||
|
oneOf(db).getLocalTransports();
|
||||||
|
will(returnValue(localTransports));
|
||||||
|
oneOf(db).getContacts();
|
||||||
|
will(returnValue(Collections.singletonList(contactId)));
|
||||||
|
oneOf(db).getRemoteIndex(contactId, transportId);
|
||||||
|
will(returnValue(null));
|
||||||
|
}});
|
||||||
|
Executor executor = new ImmediateExecutor();
|
||||||
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
|
executor);
|
||||||
|
byte[] encryptedIv = calculateIv();
|
||||||
|
// Update the contact
|
||||||
|
c.eventOccurred(new RemoteTransportsUpdatedEvent(contactId,
|
||||||
|
Collections.<Transport>emptyList()));
|
||||||
|
// The IV should not be expected
|
||||||
|
assertFalse(c.isInitialised());
|
||||||
|
assertNull(c.acceptConnection(transportId, encryptedIv));
|
||||||
|
assertTrue(c.isInitialised());
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoteTransportIndexChangedAfterInit() throws Exception {
|
||||||
|
// The contact changes the transport ID <-> index relationships
|
||||||
|
final TransportId transportId1 =
|
||||||
|
new TransportId(TestUtils.getRandomId());
|
||||||
|
final TransportIndex remoteIndex1 = new TransportIndex(11);
|
||||||
|
Map<String, String> properties = Collections.singletonMap("foo", "bar");
|
||||||
|
Transport remoteTransport = new Transport(transportId, remoteIndex1,
|
||||||
|
properties);
|
||||||
|
Transport remoteTransport1 = new Transport(transportId1, remoteIndex,
|
||||||
|
properties);
|
||||||
|
Collection<Transport> remoteTransports1 = Arrays.asList(
|
||||||
|
new Transport[] {remoteTransport, remoteTransport1});
|
||||||
|
// Use two local transports for this test
|
||||||
|
TransportIndex localIndex1 = new TransportIndex(17);
|
||||||
|
Transport localTransport = new Transport(transportId, localIndex,
|
||||||
|
properties);
|
||||||
|
Transport localTransport1 = new Transport(transportId1, localIndex1,
|
||||||
|
properties);
|
||||||
|
final Collection<Transport> localTransports1 = Arrays.asList(
|
||||||
|
new Transport[] {localTransport, localTransport1});
|
||||||
|
|
||||||
|
final ConnectionWindow window = createConnectionWindow(remoteIndex);
|
||||||
|
final ConnectionWindow window1 = createConnectionWindow(remoteIndex1);
|
||||||
|
Mockery context = new Mockery();
|
||||||
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
// Initialise before updating the contact
|
||||||
|
oneOf(db).addListener(with(any(ConnectionRecogniserImpl.class)));
|
||||||
|
oneOf(db).getLocalTransports();
|
||||||
|
will(returnValue(localTransports1));
|
||||||
|
oneOf(db).getContacts();
|
||||||
|
will(returnValue(Collections.singletonList(contactId)));
|
||||||
|
// First, transportId <-> remoteIndex, transportId1 <-> remoteIndex
|
||||||
|
oneOf(db).getRemoteIndex(contactId, transportId);
|
||||||
|
will(returnValue(remoteIndex));
|
||||||
|
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
||||||
|
will(returnValue(window));
|
||||||
|
oneOf(db).getRemoteIndex(contactId, transportId1);
|
||||||
|
will(returnValue(remoteIndex1));
|
||||||
|
oneOf(db).getConnectionWindow(contactId, remoteIndex1);
|
||||||
|
will(returnValue(window1));
|
||||||
|
// Later, transportId <-> remoteIndex1, transportId1 <-> remoteIndex
|
||||||
|
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
||||||
|
will(returnValue(window));
|
||||||
|
oneOf(db).getConnectionWindow(contactId, remoteIndex1);
|
||||||
|
will(returnValue(window1));
|
||||||
|
// Update the window
|
||||||
|
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
||||||
|
will(returnValue(window));
|
||||||
|
oneOf(db).setConnectionWindow(contactId, remoteIndex, window);
|
||||||
|
}});
|
||||||
|
Executor executor = new ImmediateExecutor();
|
||||||
|
ConnectionRecogniserImpl c = new ConnectionRecogniserImpl(crypto, db,
|
||||||
|
executor);
|
||||||
|
byte[] encryptedIv = calculateIv();
|
||||||
|
// Ensure the recogniser is initialised
|
||||||
|
assertFalse(c.isInitialised());
|
||||||
|
assertNull(c.acceptConnection(transportId, new byte[IV_LENGTH]));
|
||||||
|
assertTrue(c.isInitialised());
|
||||||
|
// Update the contact
|
||||||
|
c.eventOccurred(new RemoteTransportsUpdatedEvent(contactId,
|
||||||
|
remoteTransports1));
|
||||||
|
// The IV should not be expected by the old transport
|
||||||
|
assertNull(c.acceptConnection(transportId, encryptedIv));
|
||||||
|
// The IV should be expected by the new transport
|
||||||
|
ConnectionContext ctx = c.acceptConnection(transportId1, encryptedIv);
|
||||||
|
assertNotNull(ctx);
|
||||||
|
assertEquals(contactId, ctx.getContactId());
|
||||||
|
assertEquals(remoteIndex, ctx.getTransportIndex());
|
||||||
|
assertEquals(3, ctx.getConnectionNumber());
|
||||||
|
// The IV should no longer be expected
|
||||||
|
assertNull(c.acceptConnection(transportId1, encryptedIv));
|
||||||
|
// The window should have advanced
|
||||||
|
Map<Long, byte[]> unseen = window.getUnseen();
|
||||||
|
assertEquals(19, unseen.size());
|
||||||
|
for(int i = 0; i < 19; i++) {
|
||||||
|
assertEquals(i != 3, unseen.containsKey(Long.valueOf(i)));
|
||||||
|
}
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConnectionWindow createConnectionWindow(TransportIndex index) {
|
||||||
|
return new ConnectionWindowImpl(crypto, index, inSecret) {
|
||||||
|
@Override
|
||||||
|
public void erase() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] calculateIv() throws Exception {
|
||||||
// Calculate the shared secret for connection number 3
|
// Calculate the shared secret for connection number 3
|
||||||
byte[] secret = inSecret;
|
byte[] secret = inSecret;
|
||||||
for(int i = 0; i < 4; i++) {
|
for(int i = 0; i < 4; i++) {
|
||||||
@@ -109,85 +544,6 @@ public class ConnectionRecogniserImplTest extends TestCase {
|
|||||||
Cipher ivCipher = crypto.getIvCipher();
|
Cipher ivCipher = crypto.getIvCipher();
|
||||||
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
||||||
byte[] iv = IvEncoder.encodeIv(true, remoteIndex.getInt(), 3);
|
byte[] iv = IvEncoder.encodeIv(true, remoteIndex.getInt(), 3);
|
||||||
byte[] encryptedIv = ivCipher.doFinal(iv);
|
return ivCipher.doFinal(iv);
|
||||||
|
|
||||||
Mockery context = new Mockery();
|
|
||||||
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(db).addListener(with(any(ConnectionRecogniserImpl.class)));
|
|
||||||
// Initialise
|
|
||||||
oneOf(db).getLocalTransports();
|
|
||||||
will(returnValue(transports));
|
|
||||||
oneOf(db).getContacts();
|
|
||||||
will(returnValue(Collections.singletonList(contactId)));
|
|
||||||
oneOf(db).getRemoteIndex(contactId, transportId);
|
|
||||||
will(returnValue(remoteIndex));
|
|
||||||
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
|
||||||
will(returnValue(connectionWindow));
|
|
||||||
// Update the window
|
|
||||||
oneOf(db).getConnectionWindow(contactId, remoteIndex);
|
|
||||||
will(returnValue(connectionWindow));
|
|
||||||
oneOf(db).setConnectionWindow(contactId, remoteIndex,
|
|
||||||
connectionWindow);
|
|
||||||
}});
|
|
||||||
Executor executor = new ImmediateExecutor();
|
|
||||||
ConnectionRecogniser c = new ConnectionRecogniserImpl(crypto, db,
|
|
||||||
executor);
|
|
||||||
// The IV should not be expected by the wrong transport
|
|
||||||
TransportId wrong = new TransportId(TestUtils.getRandomId());
|
|
||||||
c.acceptConnection(wrong, encryptedIv, new Callback() {
|
|
||||||
|
|
||||||
public void connectionAccepted(ConnectionContext ctx) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void connectionRejected() {
|
|
||||||
// Expected
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleException(DbException e) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// The IV should be expected by the right transport
|
|
||||||
c.acceptConnection(transportId, encryptedIv, new Callback() {
|
|
||||||
|
|
||||||
public void connectionAccepted(ConnectionContext ctx) {
|
|
||||||
assertNotNull(ctx);
|
|
||||||
assertEquals(contactId, ctx.getContactId());
|
|
||||||
assertEquals(remoteIndex, ctx.getTransportIndex());
|
|
||||||
assertEquals(3L, ctx.getConnectionNumber());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void connectionRejected() {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleException(DbException e) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// The IV should no longer be expected
|
|
||||||
c.acceptConnection(transportId, encryptedIv, new Callback() {
|
|
||||||
|
|
||||||
public void connectionAccepted(ConnectionContext ctx) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void connectionRejected() {
|
|
||||||
// Expected
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleException(DbException e) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// The window should have advanced
|
|
||||||
Map<Long, byte[]> unseen = connectionWindow.getUnseen();
|
|
||||||
assertEquals(19, unseen.size());
|
|
||||||
for(int i = 0; i < 19; i++) {
|
|
||||||
assertEquals(i != 3, unseen.containsKey(Long.valueOf(i)));
|
|
||||||
}
|
|
||||||
context.assertIsSatisfied();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user