package io.nextop; import io.nextop.util.HexBytes; import java.net.InetAddress; import java.nio.CharBuffer; import java.util.Arrays; /** limited version of {@link java.net.InetAddress} that * only does IP (no DNS lookups) */ public abstract class Ip { public static Ip valueOf(String s) { for (int i = 0, n = s.length(); i < n; ++i) { switch (s.charAt(i)) { case '.': return V4.valueOf(s); case ':': return V6.valueOfV6(s); } } throw new IllegalArgumentException(); } public static Ip valueOf(InetAddress address) { return create(address.getAddress()); } public static Ip create(byte[] address) { switch (address.length) { case 4: return V4.create(address); case 16: return V6.create(address); default: throw new IllegalArgumentException(); } } protected final byte[] bytes; private final int hashCode; protected Ip(byte[] bytes) { this.bytes = bytes; hashCode = Arrays.hashCode(bytes); } public byte[] getAddress() { return bytes.clone(); } @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object obj) { if (!(obj instanceof Ip)) { return false; } Ip b = (Ip) obj; return hashCode == b.hashCode && Arrays.equals(bytes, b.bytes); } public static class V4 extends Ip { public static Ip valueOf(String s) { byte[] bytes = new byte[4]; int i = 0; int j = 0; int n = s.length(); int m = 0; for (; m < 4 && j <= n; ++j) { if (n == j || '.' == s.charAt(j)) { if (i == j) { throw new IllegalArgumentException(); } int b = Integer.parseInt(s.substring(i, j)); if (b < 0 || 255 < b) { throw new IllegalArgumentException(); } bytes[m] = (byte) b; ++m; i = j + 1; } } if (4 != m) { throw new IllegalArgumentException(); } return new V4(bytes); } public static V4 create(byte[] bytes) { if (4 != bytes.length) { throw new IllegalArgumentException(); } return new V4(bytes); } private V4(byte[] bytes) { super(bytes); } @Override public String toString() { return String.format("%d.%d.%d.%d", 0xFF & bytes[0], 0xFF & bytes[1], 0xFF & bytes[2], 0xFF & bytes[3]); } } public static class V6 extends Ip { public static Ip valueOfV6(String s) { if (32 + 7 != s.length()) { throw new IllegalArgumentException(); } byte[] bytes = new byte[16]; int i = 0; int j = 0; int n = s.length(); int m = 0; for (; m < 16 && j <= n; ++j) { if (n == j || ':' == s.charAt(j)) { if (i == j) { // an empty block at the end is shorthand for remaining 0s if (n - 1 == j) { while (m < 16) { bytes[m] = 0; ++m; } } else { throw new IllegalArgumentException(); } } else { byte[] b2 = HexBytes.valueOf(s.substring(i, j)); if (2 != b2.length) { throw new IllegalArgumentException(); } bytes[m] = b2[0]; bytes[m + 1] = b2[1]; m += 2; i = j + 1; } } } if (16 != m) { throw new IllegalArgumentException(); } return new V6(bytes); } public static V6 create(byte[] bytes) { if (16 != bytes.length) { throw new IllegalArgumentException(); } return new V6(bytes); } private V6(byte[] bytes) { super(bytes); } @Override public String toString() { CharBuffer cb = CharBuffer.allocate(32 + 7); for (int i = 0; i < 8; ++i) { if (0 < i) { cb.put(':'); } HexBytes.toString(bytes, 2 * i, 2, cb); } return new String(cb.array()); } } }