package com.openfarmanager.android.utils;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import com.openfarmanager.android.App;
import java.text.ParseException;
import java.util.StringTokenizer;
/**
* A set of static methods for IPv4 addreses processing, conversion and validation.
*
* @author nvv && bav
*/
public class NetworkCalculator {
private static final String TAG = "NetworkUtils";
public static final String[] tunnelSubnets = {"192.168.0.0/16", "172.16.0.0/12", "10.0.0.0/8"};
public static final String ipPattern = "(\\d{1,3}\\.){3}\\d{1,3}";
/**
* Converts IP address from <code>int</code> to <code>String</code>
* representation.
*
* @param address given IP address
* @return IP address as string like "x.x.x.x"
*/
public static String ipIntToStringRevert(int address) {
return String.format("%d.%d.%d.%d", address & 0xff, address >> 8 & 0xff,
address >> 16 & 0xff, address >> 24 & 0xff);
}
public static byte[] ipIntToBytesReverted(int address) {
byte[] ip = new byte[4];
ip[0] = (byte) (address & 0xff);
ip[1] = (byte) (address >> 8 & 0xff);
ip[2] = (byte) (address >> 16 & 0xff);
ip[3] = (byte) (address >> 24 & 0xff);
return ip;
}
public static String ipIntToString(int address) {
StringBuilder sb = new StringBuilder(15);
sb.append((address >>> 24) & 0xFF).append('.')
.append((address >>> 16) & 0xFF).append('.')
.append((address >>> 8) & 0xFF).append('.')
.append((address) & 0xFF);
return sb.toString();
}
public static String revertIpAddress(String ipAddress) throws ParseException {
if (null == ipAddress) {
throw new ParseException("Can't parse internet address", 0);
}
String[] octets = ipAddress.split("[.]");
if (4 != octets.length) {
throw new ParseException("Can't parse internet address", 0);
}
String revertedIp = "";
for (int i = 3; i >= 0; i--) {
revertedIp += octets[i];
if (i > 0) {
revertedIp += ".";
}
}
return revertedIp;
}
public static byte[] ipIntToByteArray(int value) {
return new byte[]{
(byte) (value >>> 24),
(byte) (value >>> 16),
(byte) (value >>> 8),
(byte) value};
}
/**
* Converts IP address from <code>byte[]</code> to <code>String</code>
* representation.
*
* @param address given IP address
* @return IP address as string like "x.x.x.x"
*/
public static String ipBytesToString(byte[] address) {
return ((((int) address[0]) & 0xFF) + "." +
(((int) address[1]) & 0xFF) + "." +
(((int) address[2]) & 0xFF) + "." +
(((int) address[3]) & 0xFF));
}
/**
* Converts IP address from <code>byte</code> array to <code>int</code>
* representation.
*
* @param _addr given IP address
* @return IP address as int value
*/
public static int ipBytesToInt(byte[] _addr) {
int address;
address = _addr[3] & 0xFF;
address |= ((_addr[2] << 8) & 0xFF00);
address |= ((_addr[1] << 16) & 0xFF0000);
address |= ((_addr[0] << 24) & 0xFF000000);
return address;
}
/**
* Converts IP address from <code>String</code> to <code>byte</code> array
* representation.
*
* @param address given IP address as string like "x.x.x.x"
* @return IP address as four bytes
*/
public static byte[] ipStringToBytes(String address) {
StringTokenizer st = new StringTokenizer(address, ".");
int i = 0;
byte[] ip = new byte[4];
while (st.hasMoreTokens()) {
int a = Integer.parseInt(st.nextToken());
ip[i++] = (byte) a;
}
return ip;
}
/**
* Converts IP address from <code>String</code> to <code>int</code>
* representation.
*
* @param address given IP address as string like "x.x.x.x"
* @return IP address as int value
* @throws java.text.ParseException is string cannot be parsed
*/
public static int ipStringToInt(String address) {
return ipBytesToInt(ipStringToBytes(address));
}
/**
* Splits string representation of IPv4 address it array of integer numbers.
*
* @param ip IP address as string
* @return array of integers numbers
* @throws java.text.ParseException if string cannot be parsed
*/
public static int[] ipStringToIntArray(String ip) throws ParseException {
String[] values = ip.split("[.]");
int[] intValues = new int[4];
int i = 0;
try {
for (String str : values) {
intValues[i++] = Integer.parseInt(str, 10);
}
} catch (Exception e) {
throw new ParseException("Can't parse internet address", 0);
}
if (i < 4) // To short internet address
throw new ParseException("Invalid internet address", 0);
return intValues;
}
/**
* Corrects string representation of IP address if necessary, removing redundant leading zeros in each number and
* checking each number to be between 0 and 255
*
* @param ip address as string
* @return corrected IP address as string
*/
public static String checkIp(String ip) {
StringTokenizer st = new StringTokenizer(ip, ".");
boolean first = true;
String newIp = "";
try {
while (st.hasMoreTokens()) {
int value = Integer.parseInt(st.nextToken(), 10);
if (value < 0 || value > 255) {
return null;
}
if (first) {
newIp += Integer.toString(value);
first = false;
} else {
newIp += '.' + Integer.toString(value);
}
}
} catch (Exception e) {
return null;
}
return newIp;
}
/**
* Corrects string representation of IP address if necessary, removing redundant leading zeros in each number.
* Also checks equality of ip address and some reserved ip addresses.
*
* @param ip IP address as string
* @return corrected IP address as string
*/
public static String correctIp(String ip) {
ip = ip.trim();
String newIp = checkIp(ip);
if (newIp == null || newIp.equals("0.0.0.0") || newIp.equals("255.255.255.255") || !newIp.matches(ipPattern)) {
return null;
}
return newIp;
}
/**
* Checks the correctness of IP address mask for local subnet.
*
* @param mask IP mask to check
* @return true if IP mask is corect
*/
public static boolean isCorrectMask(String mask) {
try {
ipStringToIntArray(mask);
} catch (ParseException e) {
return false;
}
String[] masks = {"0.0.0.0", "128.0.0.0", "192.0.0.0", "224.0.0.0", "240.0.0.0", "248.0.0.0",
"252.0.0.0", "254.0.0.0", "255.0.0.0", "255.128.0.0", "255.192.0.0", "255.224.0.0",
"255.240.0.0", "255.248.0.0", "255.252.0.0", "255.254.0.0", "255.255.0.0",
"255.255.128.0", "255.255.192.0", "255.255.224.0", "255.255.240.0", "255.255.248.0",
"255.255.252.0", "255.255.254.0", "255.255.255.0", "255.255.255.128", "255.255.255.192",
"255.255.255.224", "255.255.255.240", "255.255.255.248", "255.255.255.252",
"255.255.255.254", "255.255.255.255"
};
try {
for (String mask1 : masks) {
if (correctIp(mask).equals(mask1)) {
return true;
}
}
} catch (NullPointerException e) {
return false;
}
return false;
}
public static boolean isValidIp(String address) {
int[] intValues;
try {
intValues = ipStringToIntArray(address);
} catch (ParseException e) {
return false;
}
for (int quad : intValues) {
if (quad < 0 || quad > 255) {
return false;
}
}
return true;
}
/**
* Checks the correctness of IP address depending of local subnetnet class which is determining by first one ore two
* numbers of IP address.
*
* @param ip IP to check
* @return true if IP is correct
*/
public static boolean isCorrectIp(String ip) {
int[] intValues;
try {
intValues = ipStringToIntArray(ip);
} catch (ParseException e) {
return false;
}
if ((intValues[0] == 10) &&
(intValues[1] >= 0 && intValues[1] <= 255) &&
(intValues[2] >= 0 && intValues[2] <= 255) &&
(intValues[3] >= 0 && intValues[3] <= 255)) {
return true;
} else if ((intValues[0] == 172) && (intValues[1] >= 16 && intValues[1] <= 31) &&
(intValues[2] >= 0 && intValues[2] <= 255) &&
(intValues[3] >= 0 && intValues[3] <= 255)) {
return true;
} else if ((intValues[0] == 192) && (intValues[1] == 168) &&
(intValues[2] >= 0 && intValues[2] <= 255) &&
(intValues[3] >= 0 && intValues[3] <= 255)) {
return true;
}
return false;
}
public static String getTunnelSubnet(String ip) {
if (!isCorrectIp(ip)) {
throw new IllegalArgumentException("String [" + ip + "] is not correct virtual subnet IP address");
}
if (ip.startsWith("192")) {
return tunnelSubnets[0];
} else if (ip.startsWith("172")) {
return tunnelSubnets[1];
} else {
return tunnelSubnets[2];
}
}
/**
* Convert CIDR subnet mask to quad form in network byte order
*
* @param maskLen CIDR subnet mask
* @return subnet mask in network byte order
*/
public static byte[] cidrToQuad(int maskLen) {
if (maskLen < 0 || maskLen > 32) {
throw new IllegalArgumentException("CIDR mask should be in range 0-32.");
}
byte[] addr = new byte[4];
int mask = (0xFFFFFFFF << (32 - maskLen));
addr[0] = (byte) ((mask >>> 24) & 0xFF);
addr[1] = (byte) ((mask >>> 16) & 0xFF);
addr[2] = (byte) ((mask >>> 8) & 0xFF);
addr[3] = (byte) (mask & 0xFF);
return addr;
}
/**
* Convert network mask in a quad form to a CIDR mask length
*
* @param mask network mask in a quad form
* @return CIDR mask length
*/
public static int quadToCidr(byte mask[]) {
if (mask.length != 4) {
throw new IllegalArgumentException("Mask should be 4 bytes long.");
}
int maskLen = 0;
int intMask = NetworkCalculator.ipBytesToInt(mask);
// check either provided mask is contiguous
// and calculate mask length
for (int j = 0; j < 32 && intMask < 0; j++) {
maskLen++;
intMask <<= 1;
}
if (intMask > 0) {
throw new IllegalArgumentException("The subnet mask has to be contiguous.");
}
return maskLen;
}
public static byte[] networkStartIp(byte[] ipAddress, byte[] mask) {
return AND(ipAddress, mask);
}
public static byte[] networkStartIp(String ipAddress, String mask) throws ParseException {
return networkStartIp(NetworkCalculator.ipStringToBytes(ipAddress), NetworkCalculator.ipStringToBytes(mask));
}
public static int numberOfAddressesInMask(String mask) throws ParseException {
int len = NetworkCalculator.quadToCidr(NetworkCalculator.ipStringToBytes(mask));
return (int) Math.pow(2, 32 - len);
}
public static int numberOfAddressesInMask(byte mask[]) {
int len = NetworkCalculator.quadToCidr(mask);
return (int) Math.pow(2, 32 - len);
}
public static byte[][] allAddressesInSubnet(byte[] startIp, int numberOfAddressesInMask) throws ParseException {
byte[][] addresses = new byte[numberOfAddressesInMask][];
int start = ipBytesToInt(startIp);
for (int i = 0; i < numberOfAddressesInMask; i++) {
addresses[i] = ipStringToBytes(ipIntToString(start++));
}
return addresses;
}
public static String[] allStringAddressesInSubnet(byte[] startIp, int numberOfAddressesInMask) throws ParseException {
String[] addresses = new String[numberOfAddressesInMask];
int start = ipBytesToInt(startIp);
for (int i = 0; i < numberOfAddressesInMask; i++) {
addresses[i] = ipIntToString(start++);
}
return addresses;
}
public static byte[][] allAddressesInSubnet(String ipAddress, String mask) throws ParseException {
byte[] startIp = networkStartIp(ipAddress, mask);
int numberOfAddressesInMask = numberOfAddressesInMask(mask);
return allAddressesInSubnet(startIp, numberOfAddressesInMask);
}
public static byte[][] allAddressesInSubnet(int ipAddress, int mask) throws ParseException {
return allAddressesInSubnet(ipIntToString(ipAddress), ipIntToString(mask));
}
public static String[] allStringAddressesInSubnet(String ipAddress, String mask) throws ParseException {
byte[] startIp = networkStartIp(ipAddress, mask);
int numberOfAddressesInMask = numberOfAddressesInMask(mask);
return allStringAddressesInSubnet(startIp, numberOfAddressesInMask);
}
public static String[] allStringAddressesInSubnet(int ipAddress, int mask) throws ParseException {
return allStringAddressesInSubnet(ipIntToString(ipAddress), ipIntToString(mask));
}
public static String[] allStringAddressesInSubnet(byte[] ipAddress, byte[] mask) throws ParseException {
return allStringAddressesInSubnet(ipBytesToString(ipAddress), ipBytesToString(mask));
}
public static byte[] AND(byte[] a1, byte[] a2) {
byte[] r = new byte[a1.length];
for (int i = 0; i < a1.length; i++) {
r[i] = new Integer(a1[i] & a2[i]).byteValue();
}
return r;
}
public static byte[] XOR(byte[] a1, byte[] a2) {
byte[] r = new byte[a1.length];
for (int i = 0; i < a1.length; i++) {
r[i] = new Integer(a1[i] ^ a2[i]).byteValue();
}
return r;
}
public static byte[] NOT(byte[] a) {
byte[] r = new byte[a.length];
for (int i = 0; i < a.length; i++) {
r[i] = new Integer(~a[i]).byteValue();
}
return r;
}
public static boolean isNetworkAvailable() {
return NetworkInfo.State.CONNECTED == getState();
}
public static NetworkInfo.State getState() {
ConnectivityManager mgr = (ConnectivityManager) App.sInstance.getSystemService(Context.CONNECTIVITY_SERVICE);
if (mgr != null) {
try {
NetworkInfo info = mgr.getActiveNetworkInfo();
if (info != null) {
return info.getState();
}
} catch (SecurityException ignored) {
}
}
return null;
}
}