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