1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.connectivity.mdns; 18 19 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 20 import static android.net.NetworkCapabilities.TRANSPORT_VPN; 21 import static android.net.NetworkCapabilities.TRANSPORT_WIFI; 22 23 import static com.android.net.module.util.HandlerUtils.ensureRunningOnHandlerThread; 24 import static com.android.server.connectivity.mdns.util.MdnsUtils.isNetworkMatched; 25 26 import android.annotation.NonNull; 27 import android.annotation.Nullable; 28 import android.annotation.RequiresApi; 29 import android.annotation.SuppressLint; 30 import android.content.BroadcastReceiver; 31 import android.content.Context; 32 import android.content.Intent; 33 import android.content.IntentFilter; 34 import android.net.ConnectivityManager; 35 import android.net.ConnectivityManager.NetworkCallback; 36 import android.net.LinkAddress; 37 import android.net.LinkProperties; 38 import android.net.Network; 39 import android.net.NetworkCapabilities; 40 import android.net.NetworkRequest; 41 import android.net.TetheringManager; 42 import android.net.TetheringManager.TetheringEventCallback; 43 import android.net.wifi.p2p.WifiP2pGroup; 44 import android.net.wifi.p2p.WifiP2pInfo; 45 import android.net.wifi.p2p.WifiP2pManager; 46 import android.os.Build; 47 import android.os.Handler; 48 import android.os.Looper; 49 import android.util.ArrayMap; 50 import android.util.SparseArray; 51 52 import com.android.internal.annotations.VisibleForTesting; 53 import com.android.net.module.util.CollectionUtils; 54 import com.android.net.module.util.LinkPropertiesUtils.CompareResult; 55 import com.android.net.module.util.SharedLog; 56 57 import java.io.IOException; 58 import java.net.NetworkInterface; 59 import java.net.SocketException; 60 import java.util.ArrayList; 61 import java.util.List; 62 import java.util.Objects; 63 64 /** 65 * The {@link MdnsSocketProvider} manages the multiple sockets for mDns. 66 * 67 * <p>This class is not thread safe, it is intended to be used only from the looper thread. 68 * However, the constructor is an exception, as it is called on another thread; 69 * therefore for thread safety all members of this class MUST either be final or initialized 70 * to their default value (0, false or null). 71 * 72 */ 73 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 74 public class MdnsSocketProvider { 75 private static final String TAG = MdnsSocketProvider.class.getSimpleName(); 76 private static final boolean DBG = MdnsDiscoveryManager.DBG; 77 // This buffer size matches what MdnsSocketClient uses currently. 78 // But 1440 should generally be enough because of standard Ethernet. 79 // Note: mdnsresponder mDNSEmbeddedAPI.h uses 8940 for Ethernet jumbo frames. 80 private static final int READ_BUFFER_SIZE = 2048; 81 private static final int IFACE_IDX_NOT_EXIST = -1; 82 @NonNull private final Context mContext; 83 @NonNull private final Looper mLooper; 84 @NonNull private final Handler mHandler; 85 @NonNull private final Dependencies mDependencies; 86 @NonNull private final NetworkCallback mNetworkCallback; 87 @NonNull private final TetheringEventCallback mTetheringEventCallback; 88 @NonNull private final AbstractSocketNetlinkMonitor mSocketNetlinkMonitor; 89 @NonNull private final SharedLog mSharedLog; 90 private final ArrayMap<Network, SocketInfo> mNetworkSockets = new ArrayMap<>(); 91 private final ArrayMap<String, SocketInfo> mTetherInterfaceSockets = new ArrayMap<>(); 92 private final ArrayMap<Network, LinkProperties> mActiveNetworksLinkProperties = 93 new ArrayMap<>(); 94 private final ArrayMap<Network, int[]> mActiveNetworksTransports = new ArrayMap<>(); 95 private final ArrayMap<SocketCallback, Network> mCallbacksToRequestedNetworks = 96 new ArrayMap<>(); 97 private final List<String> mLocalOnlyInterfaces = new ArrayList<>(); 98 private final List<String> mTetheredInterfaces = new ArrayList<>(); 99 // mIfaceIdxToLinkProperties should not be cleared in maybeStopMonitoringSockets() because 100 // the netlink monitor is never stop and the old states must be kept. 101 private final SparseArray<LinkProperties> mIfaceIdxToLinkProperties = new SparseArray<>(); 102 private final byte[] mPacketReadBuffer = new byte[READ_BUFFER_SIZE]; 103 @NonNull 104 private final SocketRequestMonitor mSocketRequestMonitor; 105 private boolean mMonitoringSockets = false; 106 private boolean mRequestStop = false; 107 private String mWifiP2pTetherInterface = null; 108 109 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 110 @Override 111 public void onReceive(Context context, Intent intent) { 112 final String newP2pIface = getWifiP2pInterface(intent); 113 114 if (!mMonitoringSockets || !hasAllNetworksRequest()) { 115 mWifiP2pTetherInterface = newP2pIface; 116 return; 117 } 118 119 // If already serving from the correct interface, nothing to do. 120 if (Objects.equals(mWifiP2pTetherInterface, newP2pIface)) return; 121 122 if (mWifiP2pTetherInterface != null) { 123 if (newP2pIface != null) { 124 mSharedLog.wtf("Wifi p2p interface is changed from " + mWifiP2pTetherInterface 125 + " to " + newP2pIface + " without null broadcast"); 126 } 127 // Remove the socket. 128 removeTetherInterfaceSocket(mWifiP2pTetherInterface); 129 } 130 131 // Update mWifiP2pTetherInterface 132 mWifiP2pTetherInterface = newP2pIface; 133 134 // Check whether the socket for wifi p2p interface is created or not. 135 final boolean socketAlreadyExists = mTetherInterfaceSockets.get(newP2pIface) != null; 136 if (newP2pIface != null && !socketAlreadyExists) { 137 // Create a socket for wifi p2p interface. 138 final int ifaceIndex = 139 mDependencies.getNetworkInterfaceIndexByName(newP2pIface, mSharedLog); 140 createSocket(LOCAL_NET, createLPForTetheredInterface(newP2pIface, ifaceIndex)); 141 } 142 } 143 }; 144 145 @Nullable getWifiP2pInterface(final Intent intent)146 private static String getWifiP2pInterface(final Intent intent) { 147 final WifiP2pGroup group = 148 intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP); 149 final WifiP2pInfo p2pInfo = 150 intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO); 151 if (group == null || p2pInfo == null) { 152 return null; 153 } 154 155 if (!p2pInfo.groupFormed) { 156 return null; 157 } else { 158 return group.getInterface(); 159 } 160 } 161 MdnsSocketProvider(@onNull Context context, @NonNull Looper looper, @NonNull SharedLog sharedLog, @NonNull SocketRequestMonitor socketRequestMonitor)162 public MdnsSocketProvider(@NonNull Context context, @NonNull Looper looper, 163 @NonNull SharedLog sharedLog, 164 @NonNull SocketRequestMonitor socketRequestMonitor) { 165 this(context, looper, new Dependencies(), sharedLog, socketRequestMonitor); 166 } 167 168 @SuppressLint("NewApi") MdnsSocketProvider(@onNull Context context, @NonNull Looper looper, @NonNull Dependencies deps, @NonNull SharedLog sharedLog, @NonNull SocketRequestMonitor socketRequestMonitor)169 MdnsSocketProvider(@NonNull Context context, @NonNull Looper looper, 170 @NonNull Dependencies deps, @NonNull SharedLog sharedLog, 171 @NonNull SocketRequestMonitor socketRequestMonitor) { 172 mContext = context; 173 mLooper = looper; 174 mHandler = new Handler(looper); 175 mDependencies = deps; 176 mSharedLog = sharedLog; 177 mSocketRequestMonitor = socketRequestMonitor; 178 mNetworkCallback = new NetworkCallback() { 179 @Override 180 public void onLost(Network network) { 181 mActiveNetworksLinkProperties.remove(network); 182 mActiveNetworksTransports.remove(network); 183 removeNetworkSocket(network); 184 } 185 186 @Override 187 public void onCapabilitiesChanged(@NonNull Network network, 188 @NonNull NetworkCapabilities networkCapabilities) { 189 mActiveNetworksTransports.put(network, networkCapabilities.getTransportTypes()); 190 } 191 192 @Override 193 public void onLinkPropertiesChanged(Network network, LinkProperties lp) { 194 handleLinkPropertiesChanged(network, lp); 195 } 196 }; 197 mTetheringEventCallback = new TetheringEventCallback() { 198 @Override 199 public void onLocalOnlyInterfacesChanged(@NonNull List<String> interfaces) { 200 handleTetherInterfacesChanged(mLocalOnlyInterfaces, interfaces); 201 } 202 203 @Override 204 public void onTetheredInterfacesChanged(@NonNull List<String> interfaces) { 205 handleTetherInterfacesChanged(mTetheredInterfaces, interfaces); 206 } 207 }; 208 209 mSocketNetlinkMonitor = mDependencies.createSocketNetlinkMonitor(mHandler, 210 mSharedLog.forSubComponent("NetlinkMonitor"), new NetLinkMessageProcessor()); 211 212 // Register a intent receiver to listen wifi p2p interface changes. 213 // Note: The wifi p2p interface change is only notified via 214 // TetheringEventCallback#onLocalOnlyInterfacesChanged if the device is the wifi p2p group 215 // owner. In this case, MdnsSocketProvider will receive duplicate interface changes and must 216 // ignore the later notification because the socket has already been created. There is only 217 // one notification from the wifi p2p connection change intent if the device is not the wifi 218 // p2p group owner. 219 final IntentFilter intentFilter = 220 new IntentFilter(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); 221 mContext.registerReceiver( 222 mIntentReceiver, intentFilter, null /* broadcastPermission */, mHandler); 223 } 224 225 /** 226 * Dependencies of MdnsSocketProvider, for injection in tests. 227 */ 228 @VisibleForTesting 229 public static class Dependencies { 230 /*** Get network interface by given interface name */ getNetworkInterfaceByName(@onNull String interfaceName)231 public NetworkInterfaceWrapper getNetworkInterfaceByName(@NonNull String interfaceName) 232 throws SocketException { 233 final NetworkInterface ni = NetworkInterface.getByName(interfaceName); 234 return ni == null ? null : new NetworkInterfaceWrapper(ni); 235 } 236 237 /*** Create a MdnsInterfaceSocket */ createMdnsInterfaceSocket( @onNull NetworkInterface networkInterface, int port, @NonNull Looper looper, @NonNull byte[] packetReadBuffer, @NonNull SharedLog sharedLog)238 public MdnsInterfaceSocket createMdnsInterfaceSocket( 239 @NonNull NetworkInterface networkInterface, int port, @NonNull Looper looper, 240 @NonNull byte[] packetReadBuffer, @NonNull SharedLog sharedLog) throws IOException { 241 return new MdnsInterfaceSocket(networkInterface, port, looper, packetReadBuffer, 242 sharedLog); 243 } 244 245 /*** Get network interface by given interface name */ getNetworkInterfaceIndexByName(@onNull final String ifaceName, @NonNull SharedLog sharedLog)246 public int getNetworkInterfaceIndexByName(@NonNull final String ifaceName, 247 @NonNull SharedLog sharedLog) { 248 final NetworkInterface iface; 249 try { 250 iface = NetworkInterface.getByName(ifaceName); 251 } catch (SocketException e) { 252 sharedLog.e("Error querying interface", e); 253 return IFACE_IDX_NOT_EXIST; 254 } 255 if (iface == null) { 256 sharedLog.e("Interface not found: " + ifaceName); 257 return IFACE_IDX_NOT_EXIST; 258 } 259 return iface.getIndex(); 260 } 261 /*** Creates a SocketNetlinkMonitor */ createSocketNetlinkMonitor( @onNull final Handler handler, @NonNull final SharedLog log, @NonNull final NetLinkMonitorCallBack cb)262 public AbstractSocketNetlinkMonitor createSocketNetlinkMonitor( 263 @NonNull final Handler handler, 264 @NonNull final SharedLog log, 265 @NonNull final NetLinkMonitorCallBack cb) { 266 return SocketNetLinkMonitorFactory.createNetLinkMonitor(handler, log, cb); 267 } 268 } 269 /** 270 * The callback interface for the netlink monitor messages. 271 */ 272 public interface NetLinkMonitorCallBack { 273 /** 274 * Handles the interface address add or update. 275 */ addOrUpdateInterfaceAddress(int ifaceIdx, @NonNull LinkAddress newAddress)276 void addOrUpdateInterfaceAddress(int ifaceIdx, @NonNull LinkAddress newAddress); 277 278 279 /** 280 * Handles the interface address delete. 281 */ deleteInterfaceAddress(int ifaceIdx, @NonNull LinkAddress deleteAddress)282 void deleteInterfaceAddress(int ifaceIdx, @NonNull LinkAddress deleteAddress); 283 } 284 private class NetLinkMessageProcessor implements NetLinkMonitorCallBack { 285 286 @Override addOrUpdateInterfaceAddress(int ifaceIdx, @NonNull final LinkAddress newAddress)287 public void addOrUpdateInterfaceAddress(int ifaceIdx, 288 @NonNull final LinkAddress newAddress) { 289 290 LinkProperties linkProperties; 291 linkProperties = mIfaceIdxToLinkProperties.get(ifaceIdx); 292 if (linkProperties == null) { 293 linkProperties = new LinkProperties(); 294 mIfaceIdxToLinkProperties.put(ifaceIdx, linkProperties); 295 } 296 boolean updated = linkProperties.addLinkAddress(newAddress); 297 298 if (!updated) { 299 return; 300 } 301 maybeUpdateTetheringSocketAddress(ifaceIdx, linkProperties.getLinkAddresses()); 302 } 303 304 @Override deleteInterfaceAddress(int ifaceIdx, @NonNull LinkAddress deleteAddress)305 public void deleteInterfaceAddress(int ifaceIdx, @NonNull LinkAddress deleteAddress) { 306 LinkProperties linkProperties; 307 boolean updated = false; 308 linkProperties = mIfaceIdxToLinkProperties.get(ifaceIdx); 309 if (linkProperties != null) { 310 updated = linkProperties.removeLinkAddress(deleteAddress); 311 if (linkProperties.getLinkAddresses().isEmpty()) { 312 mIfaceIdxToLinkProperties.remove(ifaceIdx); 313 } 314 } 315 316 if (linkProperties == null || !updated) { 317 return; 318 } 319 maybeUpdateTetheringSocketAddress(ifaceIdx, linkProperties.getLinkAddresses()); 320 321 } 322 } 323 /*** Data class for storing socket related info */ 324 private static class SocketInfo { 325 final MdnsInterfaceSocket mSocket; 326 final List<LinkAddress> mAddresses; 327 final int[] mTransports; 328 @NonNull final SocketKey mSocketKey; 329 SocketInfo(MdnsInterfaceSocket socket, List<LinkAddress> addresses, int[] transports, @NonNull SocketKey socketKey)330 SocketInfo(MdnsInterfaceSocket socket, List<LinkAddress> addresses, int[] transports, 331 @NonNull SocketKey socketKey) { 332 mSocket = socket; 333 mAddresses = new ArrayList<>(addresses); 334 mTransports = transports; 335 mSocketKey = socketKey; 336 } 337 } 338 339 /*** Start monitoring sockets by listening callbacks for sockets creation or removal */ 340 @SuppressLint("NewApi") startMonitoringSockets()341 public void startMonitoringSockets() { 342 ensureRunningOnHandlerThread(mHandler); 343 mRequestStop = false; // Reset stop request flag. 344 if (mMonitoringSockets) { 345 mSharedLog.v("Already monitoring sockets."); 346 return; 347 } 348 mSharedLog.i("Start monitoring sockets."); 349 mContext.getSystemService(ConnectivityManager.class).registerNetworkCallback( 350 new NetworkRequest.Builder().clearCapabilities().build(), 351 mNetworkCallback, mHandler); 352 353 final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class); 354 tetheringManager.registerTetheringEventCallback(mHandler::post, mTetheringEventCallback); 355 356 if (mSocketNetlinkMonitor.isSupported()) { 357 mHandler.post(mSocketNetlinkMonitor::startMonitoring); 358 } 359 mMonitoringSockets = true; 360 } 361 /** 362 * Start netlink monitor. 363 */ startNetLinkMonitor()364 public void startNetLinkMonitor() { 365 ensureRunningOnHandlerThread(mHandler); 366 if (mSocketNetlinkMonitor.isSupported()) { 367 mSocketNetlinkMonitor.startMonitoring(); 368 } 369 } 370 371 @SuppressLint("NewApi") maybeStopMonitoringSockets()372 private void maybeStopMonitoringSockets() { 373 if (!mMonitoringSockets) return; // Already unregistered. 374 if (!mRequestStop) return; // No stop request. 375 376 // Only unregister the network callback if there is no socket request. 377 if (mCallbacksToRequestedNetworks.isEmpty()) { 378 mSharedLog.i("Stop monitoring sockets."); 379 mContext.getSystemService(ConnectivityManager.class) 380 .unregisterNetworkCallback(mNetworkCallback); 381 382 final TetheringManager tetheringManager = mContext.getSystemService( 383 TetheringManager.class); 384 tetheringManager.unregisterTetheringEventCallback(mTetheringEventCallback); 385 // Clear all saved status. 386 mActiveNetworksLinkProperties.clear(); 387 mNetworkSockets.clear(); 388 mTetherInterfaceSockets.clear(); 389 mLocalOnlyInterfaces.clear(); 390 mTetheredInterfaces.clear(); 391 mMonitoringSockets = false; 392 } 393 // The netlink monitor is not stopped here because the MdnsSocketProvider need to listen 394 // to all the netlink updates when the system is up and running. 395 } 396 397 /*** Request to stop monitoring sockets and unregister callbacks */ requestStopWhenInactive()398 public void requestStopWhenInactive() { 399 ensureRunningOnHandlerThread(mHandler); 400 if (!mMonitoringSockets) { 401 mSharedLog.v("Monitoring sockets hasn't been started."); 402 return; 403 } 404 mRequestStop = true; 405 maybeStopMonitoringSockets(); 406 } 407 matchRequestedNetwork(Network network)408 private boolean matchRequestedNetwork(Network network) { 409 return hasAllNetworksRequest() 410 || mCallbacksToRequestedNetworks.containsValue(network); 411 } 412 hasAllNetworksRequest()413 private boolean hasAllNetworksRequest() { 414 return mCallbacksToRequestedNetworks.containsValue(null); 415 } 416 handleLinkPropertiesChanged(Network network, LinkProperties lp)417 private void handleLinkPropertiesChanged(Network network, LinkProperties lp) { 418 mActiveNetworksLinkProperties.put(network, lp); 419 if (!matchRequestedNetwork(network)) { 420 if (DBG) { 421 mSharedLog.v("Ignore LinkProperties change. There is no request for the" 422 + " Network:" + network); 423 } 424 return; 425 } 426 427 final NetworkAsKey networkKey = new NetworkAsKey(network); 428 final SocketInfo socketInfo = mNetworkSockets.get(network); 429 if (socketInfo == null) { 430 createSocket(networkKey, lp); 431 } else { 432 updateSocketInfoAddress(network, socketInfo, lp.getLinkAddresses()); 433 } 434 } maybeUpdateTetheringSocketAddress(int ifaceIndex, @NonNull final List<LinkAddress> updatedAddresses)435 private void maybeUpdateTetheringSocketAddress(int ifaceIndex, 436 @NonNull final List<LinkAddress> updatedAddresses) { 437 for (int i = 0; i < mTetherInterfaceSockets.size(); ++i) { 438 String tetheringInterfaceName = mTetherInterfaceSockets.keyAt(i); 439 if (mDependencies.getNetworkInterfaceIndexByName(tetheringInterfaceName, mSharedLog) 440 == ifaceIndex) { 441 updateSocketInfoAddress(null /* network */, 442 mTetherInterfaceSockets.valueAt(i), updatedAddresses); 443 return; 444 } 445 } 446 } 447 updateSocketInfoAddress(@ullable final Network network, @NonNull final SocketInfo socketInfo, @NonNull final List<LinkAddress> addresses)448 private void updateSocketInfoAddress(@Nullable final Network network, 449 @NonNull final SocketInfo socketInfo, 450 @NonNull final List<LinkAddress> addresses) { 451 // Update the addresses of this socket. 452 socketInfo.mAddresses.clear(); 453 socketInfo.mAddresses.addAll(addresses); 454 // Try to join the group again. 455 socketInfo.mSocket.joinGroup(addresses); 456 457 notifyAddressesChanged(network, socketInfo, addresses); 458 } createLPForTetheredInterface(@onNull final String interfaceName, int ifaceIndex)459 private LinkProperties createLPForTetheredInterface(@NonNull final String interfaceName, 460 int ifaceIndex) { 461 final LinkProperties linkProperties = 462 new LinkProperties(mIfaceIdxToLinkProperties.get(ifaceIndex)); 463 linkProperties.setInterfaceName(interfaceName); 464 return linkProperties; 465 } 466 handleTetherInterfacesChanged(List<String> current, List<String> updated)467 private void handleTetherInterfacesChanged(List<String> current, List<String> updated) { 468 if (!hasAllNetworksRequest()) { 469 // Currently, the network for tethering can not be requested, so the sockets for 470 // tethering are only created if there is a request for all networks (interfaces). 471 // Therefore, only update the interface list and skip this change if no such request. 472 if (DBG) { 473 mSharedLog.v("Ignore tether interfaces change. There is no request for all" 474 + " networks."); 475 } 476 current.clear(); 477 current.addAll(updated); 478 return; 479 } 480 481 final CompareResult<String> interfaceDiff = new CompareResult<>( 482 current, updated); 483 for (String name : interfaceDiff.added) { 484 // Check if a socket has been created for the interface 485 final SocketInfo socketInfo = mTetherInterfaceSockets.get(name); 486 if (socketInfo != null) { 487 if (DBG) { 488 mSharedLog.i("Socket is existed for interface:" + name); 489 } 490 continue; 491 } 492 493 int ifaceIndex = mDependencies.getNetworkInterfaceIndexByName(name, mSharedLog); 494 createSocket(LOCAL_NET, createLPForTetheredInterface(name, ifaceIndex)); 495 } 496 for (String name : interfaceDiff.removed) { 497 removeTetherInterfaceSocket(name); 498 } 499 current.clear(); 500 current.addAll(updated); 501 } 502 createSocket(NetworkKey networkKey, LinkProperties lp)503 private void createSocket(NetworkKey networkKey, LinkProperties lp) { 504 final String interfaceName = lp.getInterfaceName(); 505 if (interfaceName == null) { 506 mSharedLog.e("Can not create socket with null interface name."); 507 return; 508 } 509 510 try { 511 final NetworkInterfaceWrapper networkInterface = 512 mDependencies.getNetworkInterfaceByName(interfaceName); 513 // There are no transports for tethered interfaces. Other interfaces should always 514 // have transports since LinkProperties updates are always sent after 515 // NetworkCapabilities updates. 516 final int[] transports; 517 if (networkKey == LOCAL_NET) { 518 transports = new int[0]; 519 } else { 520 final int[] knownTransports = 521 mActiveNetworksTransports.get(((NetworkAsKey) networkKey).mNetwork); 522 if (knownTransports != null) { 523 transports = knownTransports; 524 } else { 525 mSharedLog.wtf("transports is missing for key: " + networkKey); 526 transports = new int[0]; 527 } 528 } 529 if (networkInterface == null || !isMdnsCapableInterface(networkInterface, transports)) { 530 return; 531 } 532 533 mSharedLog.log("Create socket on net:" + networkKey + ", ifName:" + interfaceName); 534 final MdnsInterfaceSocket socket = mDependencies.createMdnsInterfaceSocket( 535 networkInterface.getNetworkInterface(), MdnsConstants.MDNS_PORT, mLooper, 536 mPacketReadBuffer, mSharedLog.forSubComponent( 537 MdnsInterfaceSocket.class.getSimpleName() + "/" + interfaceName)); 538 final List<LinkAddress> addresses = lp.getLinkAddresses(); 539 final Network network = 540 networkKey == LOCAL_NET ? null : ((NetworkAsKey) networkKey).mNetwork; 541 final SocketKey socketKey = new SocketKey(network, networkInterface.getIndex()); 542 // TODO: technically transport types are mutable, although generally not in ways that 543 // would meaningfully impact the logic using it here. Consider updating logic to 544 // support transports being added/removed. 545 final SocketInfo socketInfo = new SocketInfo(socket, addresses, transports, socketKey); 546 if (networkKey == LOCAL_NET) { 547 mTetherInterfaceSockets.put(interfaceName, socketInfo); 548 } else { 549 mNetworkSockets.put(network, socketInfo); 550 } 551 // Try to join IPv4/IPv6 group. 552 socket.joinGroup(addresses); 553 554 // Notify the listeners which need this socket. 555 notifySocketCreated(network, socketInfo); 556 } catch (IOException e) { 557 mSharedLog.e("Create socket failed ifName:" + interfaceName, e); 558 } 559 } 560 isMdnsCapableInterface( @onNull NetworkInterfaceWrapper iface, @NonNull int[] transports)561 private boolean isMdnsCapableInterface( 562 @NonNull NetworkInterfaceWrapper iface, @NonNull int[] transports) { 563 try { 564 // Never try mDNS on cellular, or on interfaces with incompatible flags 565 if (CollectionUtils.contains(transports, TRANSPORT_CELLULAR) 566 || iface.isLoopback() 567 || iface.isVirtual() 568 || !iface.isUp()) { 569 return false; 570 } 571 572 // Otherwise, always try mDNS on non-VPN Wifi. 573 if (!CollectionUtils.contains(transports, TRANSPORT_VPN) 574 && CollectionUtils.contains(transports, TRANSPORT_WIFI)) { 575 return true; 576 } 577 578 // For other transports, or no transports (tethering downstreams), do mDNS based on the 579 // interface flags. This is not always reliable (for example some Wifi interfaces may 580 // not have the MULTICAST flag even though they can do mDNS, and some cellular 581 // interfaces may have the BROADCAST or MULTICAST flags), so checks are done based on 582 // transports above in priority. 583 return iface.supportsMulticast(); 584 } catch (SocketException e) { 585 mSharedLog.e("Error checking interface flags", e); 586 return false; 587 } 588 } 589 removeNetworkSocket(Network network)590 private void removeNetworkSocket(Network network) { 591 final SocketInfo socketInfo = mNetworkSockets.remove(network); 592 if (socketInfo == null) return; 593 594 socketInfo.mSocket.destroy(); 595 notifyInterfaceDestroyed(network, socketInfo); 596 mSocketRequestMonitor.onSocketDestroyed(network, socketInfo.mSocket); 597 mSharedLog.log("Remove socket on net:" + network); 598 } 599 removeTetherInterfaceSocket(String interfaceName)600 private void removeTetherInterfaceSocket(String interfaceName) { 601 final SocketInfo socketInfo = mTetherInterfaceSockets.remove(interfaceName); 602 if (socketInfo == null) return; 603 socketInfo.mSocket.destroy(); 604 notifyInterfaceDestroyed(null /* network */, socketInfo); 605 mSocketRequestMonitor.onSocketDestroyed(null /* network */, socketInfo.mSocket); 606 mSharedLog.log("Remove socket on ifName:" + interfaceName); 607 } 608 notifySocketCreated(Network network, SocketInfo socketInfo)609 private void notifySocketCreated(Network network, SocketInfo socketInfo) { 610 for (int i = 0; i < mCallbacksToRequestedNetworks.size(); i++) { 611 final Network requestedNetwork = mCallbacksToRequestedNetworks.valueAt(i); 612 if (isNetworkMatched(requestedNetwork, network)) { 613 mCallbacksToRequestedNetworks.keyAt(i).onSocketCreated(socketInfo.mSocketKey, 614 socketInfo.mSocket, socketInfo.mAddresses); 615 mSocketRequestMonitor.onSocketRequestFulfilled(network, socketInfo.mSocket, 616 socketInfo.mTransports); 617 } 618 } 619 } 620 notifyInterfaceDestroyed(Network network, SocketInfo socketInfo)621 private void notifyInterfaceDestroyed(Network network, SocketInfo socketInfo) { 622 for (int i = 0; i < mCallbacksToRequestedNetworks.size(); i++) { 623 final Network requestedNetwork = mCallbacksToRequestedNetworks.valueAt(i); 624 if (isNetworkMatched(requestedNetwork, network)) { 625 mCallbacksToRequestedNetworks.keyAt(i) 626 .onInterfaceDestroyed(socketInfo.mSocketKey, socketInfo.mSocket); 627 } 628 } 629 } 630 notifyAddressesChanged(Network network, SocketInfo socketInfo, List<LinkAddress> addresses)631 private void notifyAddressesChanged(Network network, SocketInfo socketInfo, 632 List<LinkAddress> addresses) { 633 for (int i = 0; i < mCallbacksToRequestedNetworks.size(); i++) { 634 final Network requestedNetwork = mCallbacksToRequestedNetworks.valueAt(i); 635 if (isNetworkMatched(requestedNetwork, network)) { 636 mCallbacksToRequestedNetworks.keyAt(i) 637 .onAddressesChanged(socketInfo.mSocketKey, socketInfo.mSocket, addresses); 638 } 639 } 640 } 641 retrieveAndNotifySocketFromNetwork(Network network, SocketCallback cb)642 private void retrieveAndNotifySocketFromNetwork(Network network, SocketCallback cb) { 643 final SocketInfo socketInfo = mNetworkSockets.get(network); 644 if (socketInfo == null) { 645 final LinkProperties lp = mActiveNetworksLinkProperties.get(network); 646 if (lp == null) { 647 // The requested network is not existed. Maybe wait for LinkProperties change later. 648 if (DBG) mSharedLog.v("There is no LinkProperties for this network:" + network); 649 return; 650 } 651 createSocket(new NetworkAsKey(network), lp); 652 } else { 653 // Notify the socket for requested network. 654 cb.onSocketCreated(socketInfo.mSocketKey, socketInfo.mSocket, socketInfo.mAddresses); 655 mSocketRequestMonitor.onSocketRequestFulfilled(network, socketInfo.mSocket, 656 socketInfo.mTransports); 657 } 658 } 659 retrieveAndNotifySocketFromInterface(String interfaceName, SocketCallback cb)660 private void retrieveAndNotifySocketFromInterface(String interfaceName, SocketCallback cb) { 661 final SocketInfo socketInfo = mTetherInterfaceSockets.get(interfaceName); 662 if (socketInfo == null) { 663 int ifaceIndex = mDependencies.getNetworkInterfaceIndexByName(interfaceName, 664 mSharedLog); 665 createSocket( 666 LOCAL_NET, 667 createLPForTetheredInterface(interfaceName, ifaceIndex)); 668 } else { 669 // Notify the socket for requested network. 670 cb.onSocketCreated(socketInfo.mSocketKey, socketInfo.mSocket, socketInfo.mAddresses); 671 mSocketRequestMonitor.onSocketRequestFulfilled(null /* socketNetwork */, 672 socketInfo.mSocket, socketInfo.mTransports); 673 } 674 } 675 676 /** 677 * Request a socket for given network. 678 * 679 * @param network the required network for a socket. Null means create sockets on all possible 680 * networks (interfaces). 681 * @param cb the callback to listen the socket creation. 682 */ requestSocket(@ullable Network network, @NonNull SocketCallback cb)683 public void requestSocket(@Nullable Network network, @NonNull SocketCallback cb) { 684 ensureRunningOnHandlerThread(mHandler); 685 mSharedLog.log("requestSocket for net:" + network); 686 mCallbacksToRequestedNetworks.put(cb, network); 687 if (network == null) { 688 // Does not specify a required network, create sockets for all possible 689 // networks (interfaces). 690 for (int i = 0; i < mActiveNetworksLinkProperties.size(); i++) { 691 retrieveAndNotifySocketFromNetwork(mActiveNetworksLinkProperties.keyAt(i), cb); 692 } 693 694 for (String localInterface : mLocalOnlyInterfaces) { 695 retrieveAndNotifySocketFromInterface(localInterface, cb); 696 } 697 698 for (String tetheredInterface : mTetheredInterfaces) { 699 retrieveAndNotifySocketFromInterface(tetheredInterface, cb); 700 } 701 702 if (mWifiP2pTetherInterface != null 703 && !mLocalOnlyInterfaces.contains(mWifiP2pTetherInterface)) { 704 retrieveAndNotifySocketFromInterface(mWifiP2pTetherInterface, cb); 705 } 706 } else { 707 retrieveAndNotifySocketFromNetwork(network, cb); 708 } 709 } 710 711 /*** Unrequest the socket */ unrequestSocket(@onNull SocketCallback cb)712 public void unrequestSocket(@NonNull SocketCallback cb) { 713 ensureRunningOnHandlerThread(mHandler); 714 mSharedLog.log("unrequestSocket"); 715 mCallbacksToRequestedNetworks.remove(cb); 716 if (hasAllNetworksRequest()) { 717 // Still has a request for all networks (interfaces). 718 return; 719 } 720 721 // Check if remaining requests are matched any of sockets. 722 for (int i = mNetworkSockets.size() - 1; i >= 0; i--) { 723 final Network network = mNetworkSockets.keyAt(i); 724 if (matchRequestedNetwork(network)) continue; 725 final SocketInfo info = mNetworkSockets.removeAt(i); 726 info.mSocket.destroy(); 727 mSocketRequestMonitor.onSocketDestroyed(network, info.mSocket); 728 mSharedLog.log("Remove socket on net:" + network + " after unrequestSocket"); 729 } 730 731 // Remove all sockets for tethering interface because these sockets do not have associated 732 // networks, and they should invoke by a request for all networks (interfaces). If there is 733 // no such request, the sockets for tethering interface should be removed. 734 for (int i = mTetherInterfaceSockets.size() - 1; i >= 0; i--) { 735 final SocketInfo info = mTetherInterfaceSockets.valueAt(i); 736 info.mSocket.destroy(); 737 mSocketRequestMonitor.onSocketDestroyed(null /* network */, info.mSocket); 738 mSharedLog.log("Remove socket on ifName:" + mTetherInterfaceSockets.keyAt(i) 739 + " after unrequestSocket"); 740 } 741 mTetherInterfaceSockets.clear(); 742 743 // Try to unregister network callback. 744 maybeStopMonitoringSockets(); 745 } 746 747 748 /** 749 * Callback used to register socket requests. 750 */ 751 public interface SocketCallback { 752 /** 753 * Notify the socket was created for the registered request. 754 * 755 * This may be called immediately when the request is registered with an existing socket, 756 * if it had been created previously for other requests. 757 */ onSocketCreated(@onNull SocketKey socketKey, @NonNull MdnsInterfaceSocket socket, @NonNull List<LinkAddress> addresses)758 default void onSocketCreated(@NonNull SocketKey socketKey, 759 @NonNull MdnsInterfaceSocket socket, @NonNull List<LinkAddress> addresses) {} 760 761 /** 762 * Notify that the interface was destroyed, so the provided socket cannot be used anymore. 763 * 764 * This indicates that although the socket was still requested, it had to be destroyed. 765 */ onInterfaceDestroyed(@onNull SocketKey socketKey, @NonNull MdnsInterfaceSocket socket)766 default void onInterfaceDestroyed(@NonNull SocketKey socketKey, 767 @NonNull MdnsInterfaceSocket socket) {} 768 769 /** 770 * Notify the interface addresses have changed for the network. 771 */ onAddressesChanged(@onNull SocketKey socketKey, @NonNull MdnsInterfaceSocket socket, @NonNull List<LinkAddress> addresses)772 default void onAddressesChanged(@NonNull SocketKey socketKey, 773 @NonNull MdnsInterfaceSocket socket, @NonNull List<LinkAddress> addresses) {} 774 } 775 776 /** 777 * Global callback indicating when sockets are created or destroyed for requests. 778 */ 779 public interface SocketRequestMonitor { 780 /** 781 * Indicates that the socket was used to fulfill the request of one requester. 782 * 783 * There is always at most one socket created for each interface. The interface is available 784 * in {@link MdnsInterfaceSocket#getInterface()}. 785 * @param socketNetwork The network of the socket interface, if any. 786 * @param socket The socket that was provided to a requester. 787 * @param transports Array of TRANSPORT_* from {@link NetworkCapabilities}. Empty if the 788 * interface is not part of a network with known transports. 789 */ onSocketRequestFulfilled(@ullable Network socketNetwork, @NonNull MdnsInterfaceSocket socket, @NonNull int[] transports)790 default void onSocketRequestFulfilled(@Nullable Network socketNetwork, 791 @NonNull MdnsInterfaceSocket socket, @NonNull int[] transports) {} 792 793 /** 794 * Indicates that a previously created socket was destroyed. 795 * 796 * @param socketNetwork The network of the socket interface, if any. 797 * @param socket The destroyed socket. 798 */ onSocketDestroyed(@ullable Network socketNetwork, @NonNull MdnsInterfaceSocket socket)799 default void onSocketDestroyed(@Nullable Network socketNetwork, 800 @NonNull MdnsInterfaceSocket socket) {} 801 } 802 803 private interface NetworkKey { 804 } 805 806 private static final NetworkKey LOCAL_NET = new NetworkKey() { 807 @Override 808 public String toString() { 809 return "NetworkKey:LOCAL_NET"; 810 } 811 }; 812 813 private static class NetworkAsKey implements NetworkKey { 814 private final Network mNetwork; 815 NetworkAsKey(Network network)816 NetworkAsKey(Network network) { 817 this.mNetwork = network; 818 } 819 820 @Override hashCode()821 public int hashCode() { 822 return mNetwork.hashCode(); 823 } 824 825 @Override equals(@ullable Object other)826 public boolean equals(@Nullable Object other) { 827 if (!(other instanceof NetworkAsKey)) { 828 return false; 829 } 830 return mNetwork.equals(((NetworkAsKey) other).mNetwork); 831 } 832 833 @Override toString()834 public String toString() { 835 return "NetworkAsKey{ network=" + mNetwork + " }"; 836 } 837 } 838 } 839