From 64928aea7c2fdcd6efe646bdcd6638758390c59b Mon Sep 17 00:00:00 2001 From: Kangping Date: Wed, 14 Aug 2024 23:05:04 +0800 Subject: [PATCH] [android] handles unscoped ipv6 link-local address (#296) On Android devices before Android U, the scope ID of Ipv6 link-local address is not set when it's returned to the caller via NsdServiceInfo. To make the LLA usable, this commit sets the missing scope ID to the interface ID of the current active default network. --- .../openthread_commissioner/app/build.gradle | 2 +- .../app/BorderAgentDiscoverer.java | 55 ++++++++++++++++--- .../commissioner/app/BorderAgentInfo.java | 4 +- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/android/openthread_commissioner/app/build.gradle b/android/openthread_commissioner/app/build.gradle index 6aa612ab..8c65ec09 100644 --- a/android/openthread_commissioner/app/build.gradle +++ b/android/openthread_commissioner/app/build.gradle @@ -97,7 +97,7 @@ dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) - implementation 'com.google.guava:guava:31.1-jre' + implementation 'com.google.guava:guava:33.2.1-android' implementation 'androidx.appcompat:appcompat:1.2.0' implementation "androidx.concurrent:concurrent-futures:1.1.0" implementation 'androidx.constraintlayout:constraintlayout:2.0.2' diff --git a/android/openthread_commissioner/app/src/main/java/io/openthread/commissioner/app/BorderAgentDiscoverer.java b/android/openthread_commissioner/app/src/main/java/io/openthread/commissioner/app/BorderAgentDiscoverer.java index 38c1eca3..73114c19 100644 --- a/android/openthread_commissioner/app/src/main/java/io/openthread/commissioner/app/BorderAgentDiscoverer.java +++ b/android/openthread_commissioner/app/src/main/java/io/openthread/commissioner/app/BorderAgentDiscoverer.java @@ -30,12 +30,17 @@ import android.Manifest.permission; import android.content.Context; +import android.net.ConnectivityManager; +import android.net.Network; import android.net.nsd.NsdManager; import android.net.nsd.NsdServiceInfo; import android.net.wifi.WifiManager; import android.util.Log; import androidx.annotation.Nullable; import androidx.annotation.RequiresPermission; +import com.google.common.net.InetAddresses; +import java.net.Inet6Address; +import java.net.InetAddress; import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; @@ -52,13 +57,14 @@ public class BorderAgentDiscoverer implements NsdManager.DiscoveryListener { private static final String KEY_NETWORK_NAME = "nn"; private static final String KEY_EXTENDED_PAN_ID = "xp"; - private WifiManager.MulticastLock wifiMulticastLock; - private NsdManager nsdManager; - private BorderAgentListener borderAgentListener; + private final WifiManager.MulticastLock wifiMulticastLock; + private final NsdManager nsdManager; + private final ConnectivityManager connManager; + private final BorderAgentListener borderAgentListener; private ExecutorService executor = Executors.newSingleThreadExecutor(); - private BlockingQueue unresolvedServices = new ArrayBlockingQueue<>(256); - private AtomicBoolean isResolvingService = new AtomicBoolean(false); + private final BlockingQueue unresolvedServices = new ArrayBlockingQueue<>(256); + private final AtomicBoolean isResolvingService = new AtomicBoolean(false); private boolean isScanning = false; @@ -74,7 +80,8 @@ public BorderAgentDiscoverer(Context context, BorderAgentListener borderAgentLis WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); wifiMulticastLock = wifi.createMulticastLock("multicastLock"); - nsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE); + nsdManager = context.getSystemService(NsdManager.class); + connManager = context.getSystemService(ConnectivityManager.class); this.borderAgentListener = borderAgentListener; } @@ -112,7 +119,7 @@ public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { public void onServiceResolved(NsdServiceInfo serviceInfo) { BorderAgentInfo borderAgent = getBorderAgentInfo(serviceInfo); if (borderAgent != null) { - Log.d(TAG, "successfully resolved service: " + serviceInfo.toString()); + Log.d(TAG, "successfully resolved service: " + serviceInfo); Log.d( TAG, "successfully resolved service: " + serviceInfo.getHost().getCanonicalHostName()); @@ -214,10 +221,42 @@ private BorderAgentInfo getBorderAgentInfo(NsdServiceInfo serviceInfo) { id, new String(attrs.get(KEY_NETWORK_NAME)), attrs.get(KEY_EXTENDED_PAN_ID), - serviceInfo.getHost(), + handleNsdServiceAddress(serviceInfo.getHost()), serviceInfo.getPort()); } + /** + * Properly handles the {@link InetAddress} within a discovered {@link NsdServiceInfo}. + * + *

For example, adds the scope ID to an IPv6 link-local address to make is usable. + */ + private InetAddress handleNsdServiceAddress(InetAddress address) { + if (!(address instanceof Inet6Address)) { + return address; + } + + Inet6Address address6 = (Inet6Address) address; + + if (!address6.isLinkLocalAddress() || address6.getScopeId() != 0) { + return address6; + } + + // Sets the scope ID for IPv6 link-local address if it's missing. This can + // happen before Android U. + + // Assume the mDNS service is discovered on the current active default network + Network network = connManager.getActiveNetwork(); + if (network == null) { + return address6; + } + String interfaceName = connManager.getLinkProperties(network).getInterfaceName(); + if (interfaceName == null) { + return address6; + } + + return InetAddresses.forString(address6.getHostAddress() + "%" + interfaceName); + } + @Nullable private byte[] getBorderAgentId(NsdServiceInfo serviceInfo) { Map attrs = serviceInfo.getAttributes(); diff --git a/android/openthread_commissioner/app/src/main/java/io/openthread/commissioner/app/BorderAgentInfo.java b/android/openthread_commissioner/app/src/main/java/io/openthread/commissioner/app/BorderAgentInfo.java index a916be67..d5bcfe83 100644 --- a/android/openthread_commissioner/app/src/main/java/io/openthread/commissioner/app/BorderAgentInfo.java +++ b/android/openthread_commissioner/app/src/main/java/io/openthread/commissioner/app/BorderAgentInfo.java @@ -48,9 +48,9 @@ public BorderAgentInfo( @NonNull byte[] extendedPanId, @NonNull InetAddress host, @NonNull int port) { - this.id = id == null ? null : id.clone(); + this.id = (id == null ? null : id.clone()); this.networkName = networkName; - this.extendedPanId = extendedPanId == null ? null : extendedPanId.clone(); + this.extendedPanId = (extendedPanId == null ? null : extendedPanId.clone()); this.host = host; this.port = port; }