mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Don't interrupt connections until priority is set.
This maintains compatibility with older peers that don't know about priorities or transport preferences and will try to replace any connections we close.
This commit is contained in:
@@ -83,41 +83,16 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
|
||||
if (incoming) LOG.info("Incoming connection registered: " + t);
|
||||
else LOG.info("Outgoing connection registered: " + t);
|
||||
}
|
||||
List<InterruptibleConnection> toInterrupt;
|
||||
boolean firstConnection = false, interruptNewConnection = false;
|
||||
boolean firstConnection;
|
||||
synchronized (lock) {
|
||||
List<ConnectionRecord> recs = contactConnections.get(c);
|
||||
if (recs == null) {
|
||||
recs = new ArrayList<>();
|
||||
contactConnections.put(c, recs);
|
||||
}
|
||||
if (recs.isEmpty()) {
|
||||
toInterrupt = emptyList();
|
||||
firstConnection = true;
|
||||
} else {
|
||||
toInterrupt = new ArrayList<>(recs.size());
|
||||
for (ConnectionRecord rec : recs) {
|
||||
int compare = compare(t, rec.transportId);
|
||||
if (compare == -1) {
|
||||
// The old connection is better than the new one
|
||||
interruptNewConnection = true;
|
||||
} else if (compare == 1 && !rec.interrupted) {
|
||||
// The new connection is better than the old one
|
||||
toInterrupt.add(rec.conn);
|
||||
rec.interrupted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
firstConnection = recs.isEmpty();
|
||||
recs.add(new ConnectionRecord(t, conn));
|
||||
}
|
||||
if (interruptNewConnection) {
|
||||
LOG.info("Interrupting new connection");
|
||||
conn.interruptOutgoingSession();
|
||||
}
|
||||
for (InterruptibleConnection old : toInterrupt) {
|
||||
LOG.info("Interrupting old connection");
|
||||
old.interruptOutgoingSession();
|
||||
}
|
||||
eventBus.broadcast(new ConnectionOpenedEvent(c, t, incoming));
|
||||
if (firstConnection) {
|
||||
LOG.info("Contact connected");
|
||||
@@ -125,17 +100,6 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
private int compare(TransportId a, TransportId b) {
|
||||
if (getBetterTransports(a).contains(b)) return -1;
|
||||
else if (getBetterTransports(b).contains(a)) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
private List<TransportId> getBetterTransports(TransportId t) {
|
||||
List<TransportId> better = betterTransports.get(t);
|
||||
return better == null ? emptyList() : better;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPriority(ContactId c, TransportId t,
|
||||
InterruptibleConnection conn, Priority priority) {
|
||||
@@ -150,8 +114,9 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
|
||||
if (rec.conn == conn) {
|
||||
// Store the priority of this connection
|
||||
rec.priority = priority;
|
||||
} else if (rec.transportId.equals(t)) {
|
||||
int compare = compare(priority, rec.priority);
|
||||
} else if (rec.priority != null) {
|
||||
int compare = compareConnections(t, priority,
|
||||
rec.transportId, rec.priority);
|
||||
if (compare == -1) {
|
||||
// The old connection is better than the new one
|
||||
interruptNewConnection = true;
|
||||
@@ -173,8 +138,16 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
private int compare(Priority a, @Nullable Priority b) {
|
||||
return b == null ? 0 : Bytes.compare(a.getNonce(), b.getNonce());
|
||||
private int compareConnections(TransportId tA, Priority pA, TransportId tB,
|
||||
Priority pB) {
|
||||
if (getBetterTransports(tA).contains(tB)) return -1;
|
||||
if (getBetterTransports(tB).contains(tA)) return 1;
|
||||
return tA.equals(tB) ? Bytes.compare(pA.getNonce(), pB.getNonce()) : 0;
|
||||
}
|
||||
|
||||
private List<TransportId> getBetterTransports(TransportId t) {
|
||||
List<TransportId> better = betterTransports.get(t);
|
||||
return better == null ? emptyList() : better;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -184,12 +157,12 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
|
||||
if (incoming) LOG.info("Incoming connection unregistered: " + t);
|
||||
else LOG.info("Outgoing connection unregistered: " + t);
|
||||
}
|
||||
boolean lastConnection = false;
|
||||
boolean lastConnection;
|
||||
synchronized (lock) {
|
||||
List<ConnectionRecord> recs = contactConnections.get(c);
|
||||
if (recs == null || !recs.remove(new ConnectionRecord(t, conn)))
|
||||
throw new IllegalArgumentException();
|
||||
if (recs.isEmpty()) lastConnection = true;
|
||||
lastConnection = recs.isEmpty();
|
||||
}
|
||||
eventBus.broadcast(new ConnectionClosedEvent(c, t, incoming));
|
||||
if (lastConnection) {
|
||||
|
||||
@@ -177,6 +177,79 @@ public class ConnectionRegistryImplTest extends BrambleMockTestCase {
|
||||
c.getConnectedOrBetterContacts(transportId2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectionsAreNotInterruptedUnlessPriorityIsSet() {
|
||||
// Prefer transport 2 to transport 1
|
||||
context.checking(new Expectations() {{
|
||||
allowing(pluginConfig).getTransportPreferences();
|
||||
will(returnValue(
|
||||
singletonList(new Pair<>(transportId2, transportId1))));
|
||||
}});
|
||||
|
||||
ConnectionRegistry c =
|
||||
new ConnectionRegistryImpl(eventBus, pluginConfig);
|
||||
|
||||
// Connect via transport 1 (worse than 2) and set priority to low
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(eventBus).broadcast(with(any(ConnectionOpenedEvent.class)));
|
||||
oneOf(eventBus).broadcast(with(any(ContactConnectedEvent.class)));
|
||||
}});
|
||||
c.registerConnection(contactId1, transportId1, conn1, true);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
assertEquals(singletonList(contactId1),
|
||||
c.getConnectedContacts(transportId1));
|
||||
assertEquals(singletonList(contactId1),
|
||||
c.getConnectedOrBetterContacts(transportId1));
|
||||
|
||||
assertEquals(emptyList(), c.getConnectedContacts(transportId2));
|
||||
assertEquals(emptyList(), c.getConnectedOrBetterContacts(transportId2));
|
||||
|
||||
// Connect via transport 2 (better than 1) and set priority to high -
|
||||
// the old connection should not be interrupted, despite using a worse
|
||||
// transport, to remain compatible with old peers
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(eventBus).broadcast(with(any(ConnectionOpenedEvent.class)));
|
||||
}});
|
||||
c.registerConnection(contactId1, transportId2, conn2, true);
|
||||
c.setPriority(contactId1, transportId2, conn2, high);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
assertEquals(singletonList(contactId1),
|
||||
c.getConnectedContacts(transportId1));
|
||||
assertEquals(singletonList(contactId1),
|
||||
c.getConnectedOrBetterContacts(transportId1));
|
||||
|
||||
assertEquals(singletonList(contactId1),
|
||||
c.getConnectedContacts(transportId2));
|
||||
assertEquals(singletonList(contactId1),
|
||||
c.getConnectedOrBetterContacts(transportId2));
|
||||
|
||||
// Connect via transport 3 (no preference) and set priority to high -
|
||||
// again, no interruptions are expected
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(eventBus).broadcast(with(any(ConnectionOpenedEvent.class)));
|
||||
}});
|
||||
c.registerConnection(contactId1, transportId3, conn3, true);
|
||||
c.setPriority(contactId1, transportId3, conn3, high);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
assertEquals(singletonList(contactId1),
|
||||
c.getConnectedContacts(transportId1));
|
||||
assertEquals(singletonList(contactId1),
|
||||
c.getConnectedOrBetterContacts(transportId1));
|
||||
|
||||
assertEquals(singletonList(contactId1),
|
||||
c.getConnectedContacts(transportId2));
|
||||
assertEquals(singletonList(contactId1),
|
||||
c.getConnectedOrBetterContacts(transportId2));
|
||||
|
||||
assertEquals(singletonList(contactId1),
|
||||
c.getConnectedContacts(transportId3));
|
||||
assertEquals(singletonList(contactId1),
|
||||
c.getConnectedOrBetterContacts(transportId3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewConnectionIsInterruptedIfOldConnectionUsesBetterTransport() {
|
||||
// Prefer transport 1 to transport 2
|
||||
@@ -189,12 +262,13 @@ public class ConnectionRegistryImplTest extends BrambleMockTestCase {
|
||||
ConnectionRegistry c =
|
||||
new ConnectionRegistryImpl(eventBus, pluginConfig);
|
||||
|
||||
// Connect via transport 1 (better than 2)
|
||||
// Connect via transport 1 (better than 2) and set priority to low
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(eventBus).broadcast(with(any(ConnectionOpenedEvent.class)));
|
||||
oneOf(eventBus).broadcast(with(any(ContactConnectedEvent.class)));
|
||||
}});
|
||||
c.registerConnection(contactId1, transportId1, conn1, true);
|
||||
c.setPriority(contactId1, transportId1, conn1, low);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
assertEquals(singletonList(contactId1),
|
||||
@@ -208,13 +282,15 @@ public class ConnectionRegistryImplTest extends BrambleMockTestCase {
|
||||
assertEquals(singletonList(contactId1),
|
||||
c.getConnectedOrBetterContacts(transportId2));
|
||||
|
||||
// Connect via transport 2 (worse than 1) - the new connection should
|
||||
// be interrupted
|
||||
// Connect via transport 2 (worse than 1) and set priority to high -
|
||||
// the new connection should be interrupted because it uses a worse
|
||||
// transport
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(conn2).interruptOutgoingSession();
|
||||
oneOf(eventBus).broadcast(with(any(ConnectionOpenedEvent.class)));
|
||||
}});
|
||||
c.registerConnection(contactId1, transportId2, conn2, true);
|
||||
c.setPriority(contactId1, transportId2, conn2, high);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
assertEquals(singletonList(contactId1),
|
||||
@@ -227,11 +303,13 @@ public class ConnectionRegistryImplTest extends BrambleMockTestCase {
|
||||
assertEquals(singletonList(contactId1),
|
||||
c.getConnectedOrBetterContacts(transportId2));
|
||||
|
||||
// Connect via transport 3 (no preference)
|
||||
// Connect via transport 3 (no preference) and set priority to low -
|
||||
// no further interruptions
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(eventBus).broadcast(with(any(ConnectionOpenedEvent.class)));
|
||||
}});
|
||||
c.registerConnection(contactId1, transportId3, conn3, true);
|
||||
c.setPriority(contactId1, transportId3, conn3, low);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
assertEquals(singletonList(contactId1),
|
||||
@@ -285,12 +363,13 @@ public class ConnectionRegistryImplTest extends BrambleMockTestCase {
|
||||
ConnectionRegistry c =
|
||||
new ConnectionRegistryImpl(eventBus, pluginConfig);
|
||||
|
||||
// Connect via transport 1 (worse than 2)
|
||||
// Connect via transport 1 (worse than 2) and set priority to high
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(eventBus).broadcast(with(any(ConnectionOpenedEvent.class)));
|
||||
oneOf(eventBus).broadcast(with(any(ContactConnectedEvent.class)));
|
||||
}});
|
||||
c.registerConnection(contactId1, transportId1, conn1, true);
|
||||
c.setPriority(contactId1, transportId1, conn1, high);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
assertEquals(singletonList(contactId1),
|
||||
@@ -301,13 +380,15 @@ public class ConnectionRegistryImplTest extends BrambleMockTestCase {
|
||||
assertEquals(emptyList(), c.getConnectedContacts(transportId2));
|
||||
assertEquals(emptyList(), c.getConnectedOrBetterContacts(transportId2));
|
||||
|
||||
// Connect via transport 2 (better than 1) - the old connection should
|
||||
// be interrupted
|
||||
// Connect via transport 2 (better than 1) and set priority to low -
|
||||
// the old connection should be interrupted because it uses a worse
|
||||
// transport
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(conn1).interruptOutgoingSession();
|
||||
oneOf(eventBus).broadcast(with(any(ConnectionOpenedEvent.class)));
|
||||
}});
|
||||
c.registerConnection(contactId1, transportId2, conn2, true);
|
||||
c.setPriority(contactId1, transportId2, conn2, low);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
assertEquals(singletonList(contactId1),
|
||||
@@ -320,7 +401,8 @@ public class ConnectionRegistryImplTest extends BrambleMockTestCase {
|
||||
assertEquals(singletonList(contactId1),
|
||||
c.getConnectedOrBetterContacts(transportId2));
|
||||
|
||||
// Connect via transport 3 (no preference)
|
||||
// Connect via transport 3 (no preference) and set priority to high -
|
||||
// no further interruptions
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(eventBus).broadcast(with(any(ConnectionOpenedEvent.class)));
|
||||
}});
|
||||
|
||||
Reference in New Issue
Block a user