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