Home | History | Annotate | Download | only in p2p
      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 */
     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 */
     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 */
     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      */
     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      */
     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 */
     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 
    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