package water.util;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import static water.H2O.OptArgs.SYSTEM_PROP_PREFIX;
import static water.util.ArrayUtils.toByteArray;
/**
* Utilities to support networking code.
*
* See:
* - http://www.tcpipguide.com/free/diagrams/ipv6scope.png for IPV6 Scope explanations
* - https://en.wikipedia.org/wiki/Multicast_address
*/
public class NetworkUtils {
// Google DNS https://developers.google.com/speed/public-dns/docs/using#important_before_you_start
public static byte[] GOOGLE_DNS_IPV4 = new byte[] {8, 8 , 8, 8};
public static byte[] GOOGLE_DNS_IPV6 = toByteArray(new int[] {0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88 });
/** Override IPv6 scope by a defined value */
private static String H2O_SYSTEM_SCOPE_PARAM = SYSTEM_PROP_PREFIX + "network.ipv6.scope";
/** Define timeout in ms to figure out if local ip is reachable */
private static String H2O_SYSTEM_LOCAL_IP_PING_TIMEOUT = SYSTEM_PROP_PREFIX + "network.ip.ping.timeout";
// See IPv6 Multicast scopes:
public static long SCOPE_IFACE_LOCAL = 0x0001000000000000L;
public static long SCOPE_LINK_LOCAL = 0x0002000000000000L;
public static long SCOPE_SITE_LOCAL = 0x0005000000000000L;
public static long SCOPE_ORG_LOCAL = 0x0008000000000000L;
public static long SCOPE_GLOBAL_LOCAL = 0x000e000000000000L;
public static long SCOPE_MASK = ~0x000f000000000000L;
public static int[] IPV4_MULTICAST_ALLOCATION_RANGE = new int[] { /* low */ 0xE1000000, /* high */ 0xEFFFFFFF };
// The preconfigured scopes of IPv6 multicast groups - see https://en.wikipedia.org/wiki/Multicast_address#IPv6
public static long[][] IPV6_MULTICAST_ALLOCATION_RANGE = new long[][] { /* low */ new long[] {0xff08000000000000L, 0x0L}, // T-flag for transient, 8 = organization scope (will be replace by real scope
/* high */ new long[] {0xff08FFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFFFL}};
public static boolean isIPv6Preferred() {
return Boolean.parseBoolean(System.getProperty("java.net.preferIPv6Addresses", "false"))
|| (System.getProperty("java.net.preferIPv4Addresses") != null && !Boolean.parseBoolean(System.getProperty("java.net.preferIPv4Addresses")));
}
public static boolean isIPv4Preferred() {
return Boolean.parseBoolean(System.getProperty("java.net.preferIPv4Addresses", "true"));
}
public static InetAddress getIPv4MulticastGroup(int hash) throws UnknownHostException {
return getIPv4MulticastGroup(hash, IPV4_MULTICAST_ALLOCATION_RANGE[0], IPV4_MULTICAST_ALLOCATION_RANGE[1]);
}
public static InetAddress getIPv4MulticastGroup(int hash, int lowIp, int highIp) throws UnknownHostException {
hash = hash & 0x7fffffff; // delete sign
int port = (hash % (highIp-lowIp+1)) + lowIp;
byte[] ip = new byte[4];
for( int i=0; i<4; i++ )
ip[i] = (byte)(port>>>((3-i)<<3));
return InetAddress.getByAddress(ip);
}
public static InetAddress getIPv6MulticastGroup(int hash, long scope) throws UnknownHostException {
return getIPv6MulticastGroup(hash,
IPV6_MULTICAST_ALLOCATION_RANGE[0],
IPV6_MULTICAST_ALLOCATION_RANGE[1], scope);
}
public static InetAddress getIPv6MulticastGroup(int hash, long[] lowIp, long[] highIp, long scope) throws UnknownHostException {
hash = hash & 0x7fffffff; // delete sign
byte[] ip = ArrayUtils.toByteArray(((lowIp[0] & SCOPE_MASK) | scope) | hash, lowIp[1] | hash); // Simple encoding of the hash into multicast group
return InetAddress.getByAddress(ip);
}
public static int getMulticastPort(int hash) {
hash = hash & 0x7fffffff; // delete sign
int port = (hash % (0xF0000000-0xE1000000))+0xE1000000;
return port>>>16;
}
/** Return IPv6 scope for given IPv6 address. */
public static long getIPv6Scope(InetAddress ip) {
Long value = OSUtils.getLongProperty(H2O_SYSTEM_SCOPE_PARAM) != null
? OSUtils.getLongProperty(H2O_SYSTEM_SCOPE_PARAM)
: OSUtils.getLongProperty(H2O_SYSTEM_SCOPE_PARAM, 16);
if (value != null && ArrayUtils.equalsAny(value,
SCOPE_IFACE_LOCAL, SCOPE_LINK_LOCAL,
SCOPE_SITE_LOCAL, SCOPE_ORG_LOCAL,
SCOPE_GLOBAL_LOCAL)) return value;
if (ip.isLoopbackAddress()) return SCOPE_IFACE_LOCAL;
if (ip.isLinkLocalAddress()) return SCOPE_LINK_LOCAL;
if (ip.isSiteLocalAddress()) return SCOPE_SITE_LOCAL;
return SCOPE_ORG_LOCAL;
}
public static boolean isUp(NetworkInterface iface) {
try { return iface.isUp(); } catch (SocketException e) {
return false;
}
}
public static boolean isReachable(NetworkInterface iface, InetAddress address, int timeout) {
try {
return address.isReachable(iface, 0, timeout);
} catch (IOException e) {
return false;
}
}
public static int getLocalIpPingTimeout() {
String value = System.getProperty(H2O_SYSTEM_LOCAL_IP_PING_TIMEOUT, "150" /* ms */);
try {
return Integer.valueOf(value);
} catch (NumberFormatException e) {
return 150;
}
}
}