diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/connection/ConnectionRegistry.java b/bramble-api/src/main/java/org/briarproject/bramble/api/connection/ConnectionRegistry.java index 715a4da9e..6afc2ee7e 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/connection/ConnectionRegistry.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/connection/ConnectionRegistry.java @@ -40,6 +40,12 @@ public interface ConnectionRegistry { */ Collection getConnectedContacts(TransportId t); + /** + * Returns any contacts that are connected via the given transport, or via + * any transport that's preferred to the given transport. + */ + Collection getConnectedOrPreferredContacts(TransportId t); + /** * Returns true if the given contact is connected via the given transport. */ diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/PluginConfig.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/PluginConfig.java index 6bf13cedd..4da41d6d2 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/PluginConfig.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/PluginConfig.java @@ -1,10 +1,12 @@ package org.briarproject.bramble.api.plugin; +import org.briarproject.bramble.api.Pair; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory; import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory; import java.util.Collection; +import java.util.List; @NotNullByDefault public interface PluginConfig { @@ -14,4 +16,10 @@ public interface PluginConfig { Collection getSimplexFactories(); boolean shouldPoll(); + + /** + * Returns a list of transport preferences. For each pair in the list, + * the first transport is preferred to the second. + */ + List> getTransportPreferences(); } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/connection/ConnectionRegistryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/connection/ConnectionRegistryImpl.java index 1bba22593..0f580a4cd 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/connection/ConnectionRegistryImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/connection/ConnectionRegistryImpl.java @@ -1,11 +1,13 @@ package org.briarproject.bramble.connection; import org.briarproject.bramble.api.Multiset; +import org.briarproject.bramble.api.Pair; import org.briarproject.bramble.api.connection.ConnectionRegistry; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.PendingContactId; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.PluginConfig; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.event.ConnectionClosedEvent; import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent; @@ -16,7 +18,6 @@ import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionOpenedE import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -28,6 +29,7 @@ import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.ThreadSafe; import javax.inject.Inject; +import static java.util.Collections.emptyList; import static java.util.logging.Level.INFO; import static java.util.logging.Logger.getLogger; @@ -39,6 +41,7 @@ class ConnectionRegistryImpl implements ConnectionRegistry { getLogger(ConnectionRegistryImpl.class.getName()); private final EventBus eventBus; + private final List> preferences; private final Object lock = new Object(); @GuardedBy("lock") @@ -49,8 +52,9 @@ class ConnectionRegistryImpl implements ConnectionRegistry { private final Set connectedPendingContacts; @Inject - ConnectionRegistryImpl(EventBus eventBus) { + ConnectionRegistryImpl(EventBus eventBus, PluginConfig pluginConfig) { this.eventBus = eventBus; + preferences = pluginConfig.getTransportPreferences(); contactConnections = new HashMap<>(); contactCounts = new Multiset<>(); connectedPendingContacts = new HashSet<>(); @@ -106,7 +110,7 @@ class ConnectionRegistryImpl implements ConnectionRegistry { public Collection getConnectedContacts(TransportId t) { synchronized (lock) { Multiset m = contactConnections.get(t); - if (m == null) return Collections.emptyList(); + if (m == null) return emptyList(); List ids = new ArrayList<>(m.keySet()); if (LOG.isLoggable(INFO)) LOG.info(ids.size() + " contacts connected: " + t); @@ -114,6 +118,26 @@ class ConnectionRegistryImpl implements ConnectionRegistry { } } + @Override + public Collection getConnectedOrPreferredContacts( + TransportId t) { + synchronized (lock) { + Multiset m = contactConnections.get(t); + if (m == null) return emptyList(); + Set ids = new HashSet<>(m.keySet()); + for (Pair pair : preferences) { + if (pair.getSecond().equals(t)) { + TransportId better = pair.getFirst(); + Multiset m1 = contactConnections.get(better); + if (m1 != null) ids.addAll(m1.keySet()); + } + } + if (LOG.isLoggable(INFO)) + LOG.info(ids.size() + " contacts connected or preferred: " + t); + return ids; + } + } + @Override public boolean isConnected(ContactId c, TransportId t) { synchronized (lock) { diff --git a/bramble-core/src/test/java/org/briarproject/bramble/connection/ConnectionRegistryImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/connection/ConnectionRegistryImplTest.java index 3edf4ddc8..51da97ae2 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/connection/ConnectionRegistryImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/connection/ConnectionRegistryImplTest.java @@ -4,6 +4,7 @@ import org.briarproject.bramble.api.connection.ConnectionRegistry; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.PendingContactId; import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.plugin.PluginConfig; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.event.ConnectionClosedEvent; import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent; @@ -18,6 +19,7 @@ import org.junit.Test; import java.util.Collection; import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; import static org.briarproject.bramble.test.TestUtils.getContactId; import static org.briarproject.bramble.test.TestUtils.getRandomId; @@ -30,6 +32,7 @@ import static org.junit.Assert.fail; public class ConnectionRegistryImplTest extends BrambleMockTestCase { private final EventBus eventBus = context.mock(EventBus.class); + private final PluginConfig pluginConfig = context.mock(PluginConfig.class); private final ContactId contactId = getContactId(); private final ContactId contactId1 = getContactId(); @@ -40,7 +43,13 @@ public class ConnectionRegistryImplTest extends BrambleMockTestCase { @Test public void testRegisterAndUnregister() { - ConnectionRegistry c = new ConnectionRegistryImpl(eventBus); + context.checking(new Expectations() {{ + allowing(pluginConfig).getTransportPreferences(); + will(returnValue(emptyMap())); + }}); + + ConnectionRegistry c = + new ConnectionRegistryImpl(eventBus, pluginConfig); // The registry should be empty assertEquals(emptyList(), c.getConnectedContacts(transportId)); @@ -122,7 +131,13 @@ public class ConnectionRegistryImplTest extends BrambleMockTestCase { @Test public void testRegisterAndUnregisterPendingContacts() { - ConnectionRegistry c = new ConnectionRegistryImpl(eventBus); + context.checking(new Expectations() {{ + allowing(pluginConfig).getTransportPreferences(); + will(returnValue(emptyMap())); + }}); + + ConnectionRegistry c = + new ConnectionRegistryImpl(eventBus, pluginConfig); context.checking(new Expectations() {{ oneOf(eventBus).broadcast(with(any( diff --git a/bramble-core/src/test/java/org/briarproject/bramble/test/TestPluginConfigModule.java b/bramble-core/src/test/java/org/briarproject/bramble/test/TestPluginConfigModule.java index 689d4c5bd..f081d887f 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/test/TestPluginConfigModule.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/test/TestPluginConfigModule.java @@ -1,5 +1,6 @@ package org.briarproject.bramble.test; +import org.briarproject.bramble.api.Pair; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.PluginCallback; import org.briarproject.bramble.api.plugin.PluginConfig; @@ -10,12 +11,14 @@ import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin; import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory; import java.util.Collection; +import java.util.List; import javax.annotation.Nullable; import dagger.Module; import dagger.Provides; +import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static org.briarproject.bramble.test.TestUtils.getTransportId; @@ -85,6 +88,12 @@ public class TestPluginConfigModule { public boolean shouldPoll() { return false; } + + + @Override + public List> getTransportPreferences() { + return emptyList(); + } }; return pluginConfig; } diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/DesktopPluginModule.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/DesktopPluginModule.java index c00bd99d7..05e28499d 100644 --- a/bramble-java/src/main/java/org/briarproject/bramble/plugin/DesktopPluginModule.java +++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/DesktopPluginModule.java @@ -1,12 +1,16 @@ package org.briarproject.bramble.plugin; +import org.briarproject.bramble.api.Pair; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.io.TimeoutMonitor; import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.lifecycle.ShutdownManager; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.BackoffFactory; +import org.briarproject.bramble.api.plugin.BluetoothConstants; +import org.briarproject.bramble.api.plugin.LanTcpConstants; import org.briarproject.bramble.api.plugin.PluginConfig; +import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory; import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory; import org.briarproject.bramble.api.reliability.ReliabilityLayerFactory; @@ -17,6 +21,7 @@ import org.briarproject.bramble.plugin.tcp.WanTcpPluginFactory; import java.security.SecureRandom; import java.util.Collection; +import java.util.List; import java.util.concurrent.Executor; import dagger.Module; @@ -24,6 +29,7 @@ import dagger.Provides; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; @Module public class DesktopPluginModule extends PluginModule { @@ -61,6 +67,13 @@ public class DesktopPluginModule extends PluginModule { public boolean shouldPoll() { return true; } + + @Override + public List> getTransportPreferences() { + // Prefer LAN to Bluetooth + return singletonList( + new Pair<>(LanTcpConstants.ID, BluetoothConstants.ID)); + } }; return pluginConfig; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java b/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java index b9e074897..d2dace83c 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java @@ -8,6 +8,7 @@ import android.os.StrictMode; import com.vanniktech.emoji.RecentEmoji; import org.briarproject.bramble.api.FeatureFlags; +import org.briarproject.bramble.api.Pair; import org.briarproject.bramble.api.battery.BatteryManager; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.KeyStrengthener; @@ -20,7 +21,10 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.network.NetworkManager; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.BackoffFactory; +import org.briarproject.bramble.api.plugin.BluetoothConstants; +import org.briarproject.bramble.api.plugin.LanTcpConstants; import org.briarproject.bramble.api.plugin.PluginConfig; +import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory; import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory; import org.briarproject.bramble.api.reporting.DevConfig; @@ -48,6 +52,7 @@ import java.io.File; import java.security.GeneralSecurityException; import java.security.SecureRandom; import java.util.Collection; +import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.ScheduledExecutorService; @@ -62,6 +67,7 @@ import static android.content.Context.MODE_PRIVATE; import static android.os.Build.VERSION.SDK_INT; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_ONION_ADDRESS; import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_PUBLIC_KEY_HEX; import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD; @@ -153,6 +159,14 @@ public class AppModule { public boolean shouldPoll() { return true; } + + + @Override + public List> getTransportPreferences() { + // Prefer LAN to Bluetooth + return singletonList( + new Pair<>(LanTcpConstants.ID, BluetoothConstants.ID)); + } }; return pluginConfig; } diff --git a/briar-headless/src/main/java/org/briarproject/briar/headless/HeadlessModule.kt b/briar-headless/src/main/java/org/briarproject/briar/headless/HeadlessModule.kt index 5f622c83b..f1b354192 100644 --- a/briar-headless/src/main/java/org/briarproject/briar/headless/HeadlessModule.kt +++ b/briar-headless/src/main/java/org/briarproject/briar/headless/HeadlessModule.kt @@ -4,13 +4,13 @@ import com.fasterxml.jackson.databind.ObjectMapper import dagger.Module import dagger.Provides import org.briarproject.bramble.api.FeatureFlags +import org.briarproject.bramble.api.Pair import org.briarproject.bramble.api.battery.BatteryManager import org.briarproject.bramble.api.db.DatabaseConfig import org.briarproject.bramble.api.event.EventBus import org.briarproject.bramble.api.lifecycle.IoExecutor import org.briarproject.bramble.api.network.NetworkManager -import org.briarproject.bramble.api.plugin.BackoffFactory -import org.briarproject.bramble.api.plugin.PluginConfig +import org.briarproject.bramble.api.plugin.* import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory import org.briarproject.bramble.api.system.Clock @@ -33,6 +33,7 @@ import org.briarproject.briar.headless.forums.HeadlessForumModule import org.briarproject.briar.headless.messaging.HeadlessMessagingModule import java.io.File import java.util.Collections.emptyList +import java.util.Collections.singletonList import java.util.concurrent.Executor import javax.inject.Singleton import javax.net.SocketFactory @@ -88,6 +89,8 @@ internal class HeadlessModule(private val appDir: File) { override fun getDuplexFactories(): Collection = duplex override fun getSimplexFactories(): Collection = emptyList() override fun shouldPoll(): Boolean = true + override fun getTransportPreferences(): List> = + singletonList(Pair(LanTcpConstants.ID, BluetoothConstants.ID)) } } diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/HeadlessTestModule.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/HeadlessTestModule.kt index e0e70fac2..4d4bee12c 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/HeadlessTestModule.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/HeadlessTestModule.kt @@ -4,8 +4,12 @@ import com.fasterxml.jackson.databind.ObjectMapper import dagger.Module import dagger.Provides import org.briarproject.bramble.api.FeatureFlags +import org.briarproject.bramble.api.Pair import org.briarproject.bramble.api.db.DatabaseConfig +import org.briarproject.bramble.api.plugin.BluetoothConstants +import org.briarproject.bramble.api.plugin.LanTcpConstants import org.briarproject.bramble.api.plugin.PluginConfig +import org.briarproject.bramble.api.plugin.TransportId import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory import org.briarproject.bramble.network.JavaNetworkModule @@ -19,6 +23,7 @@ import org.briarproject.briar.headless.forums.HeadlessForumModule import org.briarproject.briar.headless.messaging.HeadlessMessagingModule import java.io.File import java.util.Collections.emptyList +import java.util.Collections.singletonList import javax.inject.Singleton @Module( @@ -55,6 +60,8 @@ internal class HeadlessTestModule(private val appDir: File) { override fun getDuplexFactories(): Collection = emptyList() override fun getSimplexFactories(): Collection = emptyList() override fun shouldPoll(): Boolean = false + override fun getTransportPreferences(): List> = + singletonList(Pair(LanTcpConstants.ID, BluetoothConstants.ID)) } }