1 /* 2 * Copyright (C) 2017 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.bips.p2p; 18 19 import android.net.Uri; 20 21 import com.android.bips.BuiltInPrintService; 22 import com.android.bips.discovery.DiscoveredPrinter; 23 import com.android.bips.discovery.P2pDiscovery; 24 25 import java.net.Inet4Address; 26 import java.net.InetAddress; 27 import java.net.InterfaceAddress; 28 import java.net.NetworkInterface; 29 import java.net.SocketException; 30 import java.net.UnknownHostException; 31 import java.util.BitSet; 32 import java.util.regex.Pattern; 33 34 /** 35 * Provide tools for conversions and querying P2P status 36 */ 37 public class P2pUtils { 38 private static final Pattern IPV4_PATTERN = 39 Pattern.compile("^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}" 40 + "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"); 41 42 /** Return true if path is known to be on the named network interface */ isOnInterface(String interfaceName, Uri path)43 static boolean isOnInterface(String interfaceName, Uri path) { 44 NetworkInterface networkInterface = toNetworkInterface(interfaceName); 45 Inet4Address inet4Address = toInet4Address(path); 46 return networkInterface != null && inet4Address != null 47 && isOnInterface(networkInterface, inet4Address); 48 } 49 50 /** If possible, find the x.x.x.x host part of path, without performing any name resolution */ toInet4Address(Uri path)51 private static Inet4Address toInet4Address(Uri path) { 52 if (!IPV4_PATTERN.matcher(path.getHost()).find()) { 53 return null; 54 } 55 try { 56 return (Inet4Address) InetAddress.getByName(path.getHost()); 57 } catch (UnknownHostException ignored) { 58 } 59 return null; 60 } 61 62 /** Return {@link NetworkInterface} corresponding to the supplied name, or null */ toNetworkInterface(String name)63 private static NetworkInterface toNetworkInterface(String name) { 64 if (name == null) { 65 return null; 66 } 67 try { 68 return NetworkInterface.getByName(name); 69 } catch (SocketException e) { 70 return null; 71 } 72 } 73 74 /** 75 * Return true if the printer's path is P2P 76 */ isP2p(DiscoveredPrinter printer)77 public static boolean isP2p(DiscoveredPrinter printer) { 78 return printer.path.getScheme().equals(P2pDiscovery.SCHEME_P2P); 79 } 80 81 /** 82 * Return true if the printer's path is on the currently connected P2P interface 83 */ isOnConnectedInterface(BuiltInPrintService service, DiscoveredPrinter printer)84 public static boolean isOnConnectedInterface(BuiltInPrintService service, 85 DiscoveredPrinter printer) { 86 String connectedInterface = service.getP2pMonitor().getConnectedInterface(); 87 return connectedInterface != null 88 && P2pUtils.isOnInterface(connectedInterface, printer.path); 89 } 90 91 /** Return true if the supplied remote address is on the network interface */ isOnInterface(NetworkInterface iface, Inet4Address address)92 static boolean isOnInterface(NetworkInterface iface, Inet4Address address) { 93 long addressLong = toLong(address); 94 for (InterfaceAddress ifaceAddress : iface.getInterfaceAddresses()) { 95 if (!(ifaceAddress.getAddress() instanceof Inet4Address)) { 96 continue; 97 } 98 Inet4Address networkAddress = (Inet4Address) ifaceAddress.getAddress(); 99 100 BitSet bitSet = new BitSet(32); 101 bitSet.set(32 - ifaceAddress.getNetworkPrefixLength(), 32); 102 long netMask = bitSet.toLongArray()[0]; 103 104 if ((toLong(networkAddress) & netMask) == (addressLong & netMask)) { 105 return true; 106 } 107 } 108 return false; 109 } 110 toLong(Inet4Address address)111 private static long toLong(Inet4Address address) { 112 byte[] bytes = address.getAddress(); 113 return ((bytes[0] & 0xFFL) << 24) + ((bytes[1] & 0xFFL) << 16) 114 + ((bytes[2] & 0xFFL) << 8) + (bytes[3] & 0xFFL); 115 } 116 } 117