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