/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.bips.p2p; import android.net.Uri; import com.android.bips.BuiltInPrintService; import com.android.bips.discovery.DiscoveredPrinter; import com.android.bips.discovery.P2pDiscovery; import java.net.Inet4Address; import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; import java.util.BitSet; import java.util.regex.Pattern; /** * Provide tools for conversions and querying P2P status */ public class P2pUtils { private static final Pattern IPV4_PATTERN = Pattern.compile("^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}" + "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"); /** Return true if path is known to be on the named network interface */ static boolean isOnInterface(String interfaceName, Uri path) { NetworkInterface networkInterface = toNetworkInterface(interfaceName); Inet4Address inet4Address = toInet4Address(path); return networkInterface != null && inet4Address != null && isOnInterface(networkInterface, inet4Address); } /** If possible, find the x.x.x.x host part of path, without performing any name resolution */ private static Inet4Address toInet4Address(Uri path) { if (!IPV4_PATTERN.matcher(path.getHost()).find()) { return null; } try { return (Inet4Address) InetAddress.getByName(path.getHost()); } catch (UnknownHostException ignored) { } return null; } /** Return {@link NetworkInterface} corresponding to the supplied name, or null */ private static NetworkInterface toNetworkInterface(String name) { if (name == null) { return null; } try { return NetworkInterface.getByName(name); } catch (SocketException e) { return null; } } /** * Return true if the printer's path is P2P */ public static boolean isP2p(DiscoveredPrinter printer) { return printer.path.getScheme().equals(P2pDiscovery.SCHEME_P2P); } /** * Return true if the printer's path is on the currently connected P2P interface */ public static boolean isOnConnectedInterface(BuiltInPrintService service, DiscoveredPrinter printer) { String connectedInterface = service.getP2pMonitor().getConnectedInterface(); return connectedInterface != null && P2pUtils.isOnInterface(connectedInterface, printer.path); } /** Return true if the supplied remote address is on the network interface */ static boolean isOnInterface(NetworkInterface iface, Inet4Address address) { long addressLong = toLong(address); for (InterfaceAddress ifaceAddress : iface.getInterfaceAddresses()) { if (!(ifaceAddress.getAddress() instanceof Inet4Address)) { continue; } Inet4Address networkAddress = (Inet4Address) ifaceAddress.getAddress(); BitSet bitSet = new BitSet(32); bitSet.set(32 - ifaceAddress.getNetworkPrefixLength(), 32); long netMask = bitSet.toLongArray()[0]; if ((toLong(networkAddress) & netMask) == (addressLong & netMask)) { return true; } } return false; } private static long toLong(Inet4Address address) { byte[] bytes = address.getAddress(); return ((bytes[0] & 0xFFL) << 24) + ((bytes[1] & 0xFFL) << 16) + ((bytes[2] & 0xFFL) << 8) + (bytes[3] & 0xFFL); } }