/*
* CatSaver
* Copyright (C) 2015 HiHex Ltd.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package hihex.cs;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class IpAddresses {
private static final Pattern LAST_PART_PATTERN = Pattern.compile("(?:[0-9]+\\.)?[0-9a-fA-F]+\\]?$");
private static List<InetAddress> getAllAddresses() {
final ArrayList<InetAddress> addresses = new ArrayList<>(3);
try {
final Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
final NetworkInterface iface = interfaces.nextElement();
if (iface.isUp()) {
addresses.addAll(Collections.list(iface.getInetAddresses()));
}
}
} catch (final SocketException e) {
// Ignore exceptions
}
return addresses;
}
/**
* Computes the rank of an IP address. Lower-ranked IP have better chance to be shown to the user.
*/
private static int rankInetAddress(final InetAddress address) {
if (address instanceof Inet6Address) {
if (address.isLoopbackAddress()) {
return -1;
} else {
return -3;
}
} else if (address instanceof Inet4Address) {
final byte[] addressBytes = address.getAddress();
// Prefer 192.168.*.* to 10.*.*.* to 172.*.*.* to 127.*.*.*.
switch (addressBytes[0]) {
case (byte) 192:
return -6;
case 10:
return -5;
case (byte) 172:
return -4;
case 127:
return -2;
default:
return 0;
}
} else {
return 0;
}
}
static String addressToString(final InetAddress address) {
if (address instanceof Inet4Address) {
return address.getHostAddress();
} else if (address instanceof Inet6Address) {
String hostAddress = address.getHostAddress();
final int percentLoc = hostAddress.indexOf('%');
if (percentLoc >= 0) {
hostAddress = hostAddress.substring(0, percentLoc);
}
return '[' + hostAddress + ']';
} else {
return "localhost";
}
}
private static final Comparator<InetAddress> COMPARATOR = new Comparator<InetAddress>() {
@Override
public int compare(final InetAddress a, final InetAddress b) {
return Ints.compare(rankInetAddress(a), rankInetAddress(b));
}
};
public static String getBestIpAddress() {
final List<InetAddress> addresses = getAllAddresses();
final InetAddress bestAddress = Collections.min(addresses, COMPARATOR);
return addressToString(bestAddress);
}
public static List<String> getAllIpAddresses() {
final List<InetAddress> addresses = getAllAddresses();
Collections.sort(addresses, COMPARATOR);
return Lists.transform(addresses, new Function<InetAddress, String>() {
@Override
public String apply(final InetAddress input) {
return addressToString(input);
}
});
}
public static String extractLastPart(final String ipAddress) {
final Matcher matcher = LAST_PART_PATTERN.matcher(ipAddress);
if (!matcher.find()) {
return "NoIP";
}
final String group = matcher.group();
if (group.endsWith("]")) {
return '[' + group;
} else {
return group;
}
}
}