--- a/jdk/src/share/classes/java/net/Inet6Address.java Tue Jul 16 21:11:54 2013 +0400
+++ b/jdk/src/share/classes/java/net/Inet6Address.java Thu Jul 18 18:52:14 2013 +0100
@@ -28,7 +28,10 @@
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
import java.util.Enumeration;
+import java.util.Arrays;
/**
* This class represents an Internet Protocol version 6 (IPv6) address.
@@ -177,37 +180,192 @@
*/
private transient int cached_scope_id; // 0
- /**
- * Holds a 128-bit (16 bytes) IPv6 address.
- *
- * @serial
- */
- byte[] ipaddress;
+ private class Inet6AddressHolder {
+
+ private Inet6AddressHolder() {
+ ipaddress = new byte[INADDRSZ];
+ }
+
+ private Inet6AddressHolder(
+ byte[] ipaddress, int scope_id, boolean scope_id_set,
+ NetworkInterface ifname, boolean scope_ifname_set)
+ {
+ this.ipaddress = ipaddress;
+ this.scope_id = scope_id;
+ this.scope_id_set = scope_id_set;
+ this.scope_ifname_set = scope_ifname_set;
+ this.scope_ifname = ifname;
+ }
+
+ /**
+ * Holds a 128-bit (16 bytes) IPv6 address.
+ */
+ byte[] ipaddress;
+
+ /**
+ * scope_id. The scope specified when the object is created. If the object
+ * is created with an interface name, then the scope_id is not determined
+ * until the time it is needed.
+ */
+ int scope_id; // 0
+
+ /**
+ * This will be set to true when the scope_id field contains a valid
+ * integer scope_id.
+ */
+ boolean scope_id_set; // false
+
+ /**
+ * scoped interface. scope_id is derived from this as the scope_id of the first
+ * address whose scope is the same as this address for the named interface.
+ */
+ NetworkInterface scope_ifname; // null
- /**
- * scope_id. The scope specified when the object is created. If the object
- * is created with an interface name, then the scope_id is not determined
- * until the time it is needed.
- */
- private int scope_id; // 0
+ /**
+ * set if the object is constructed with a scoped
+ * interface instead of a numeric scope id.
+ */
+ boolean scope_ifname_set; // false;
+
+ void setAddr(byte addr[]) {
+ if (addr.length == INADDRSZ) { // normal IPv6 address
+ System.arraycopy(addr, 0, ipaddress, 0, INADDRSZ);
+ }
+ }
+
+ void init(byte addr[], int scope_id) {
+ setAddr(addr);
+
+ if (scope_id >= 0) {
+ this.scope_id = scope_id;
+ this.scope_id_set = true;
+ }
+ }
+
+ void init(byte addr[], NetworkInterface nif)
+ throws UnknownHostException
+ {
+ setAddr(addr);
+
+ if (nif != null) {
+ this.scope_id = deriveNumericScope(ipaddress, nif);
+ this.scope_id_set = true;
+ this.scope_ifname = nif;
+ this.scope_ifname_set = true;
+ }
+ }
+
+ String getHostAddress() {
+ String s = numericToTextFormat(ipaddress);
+ if (scope_ifname != null) { /* must check this first */
+ s = s + "%" + scope_ifname.getName();
+ } else if (scope_id_set) {
+ s = s + "%" + scope_id;
+ }
+ return s;
+ }
+
+ public boolean equals(Object o) {
+ if (! (o instanceof Inet6AddressHolder)) {
+ return false;
+ }
+ Inet6AddressHolder that = (Inet6AddressHolder)o;
- /**
- * This will be set to true when the scope_id field contains a valid
- * integer scope_id.
- */
- private boolean scope_id_set; // false
+ return Arrays.equals(this.ipaddress, that.ipaddress);
+ }
+
+ public int hashCode() {
+ if (ipaddress != null) {
+
+ int hash = 0;
+ int i=0;
+ while (i<INADDRSZ) {
+ int j=0;
+ int component=0;
+ while (j<4 && i<INADDRSZ) {
+ component = (component << 8) + ipaddress[i];
+ j++;
+ i++;
+ }
+ hash += component;
+ }
+ return hash;
+
+ } else {
+ return 0;
+ }
+ }
+
+ boolean isIPv4CompatibleAddress() {
+ if ((ipaddress[0] == 0x00) && (ipaddress[1] == 0x00) &&
+ (ipaddress[2] == 0x00) && (ipaddress[3] == 0x00) &&
+ (ipaddress[4] == 0x00) && (ipaddress[5] == 0x00) &&
+ (ipaddress[6] == 0x00) && (ipaddress[7] == 0x00) &&
+ (ipaddress[8] == 0x00) && (ipaddress[9] == 0x00) &&
+ (ipaddress[10] == 0x00) && (ipaddress[11] == 0x00)) {
+ return true;
+ }
+ return false;
+ }
+
+ boolean isMulticastAddress() {
+ return ((ipaddress[0] & 0xff) == 0xff);
+ }
- /**
- * scoped interface. scope_id is derived from this as the scope_id of the first
- * address whose scope is the same as this address for the named interface.
- */
- private transient NetworkInterface scope_ifname; // null
+ boolean isAnyLocalAddress() {
+ byte test = 0x00;
+ for (int i = 0; i < INADDRSZ; i++) {
+ test |= ipaddress[i];
+ }
+ return (test == 0x00);
+ }
+
+ boolean isLoopbackAddress() {
+ byte test = 0x00;
+ for (int i = 0; i < 15; i++) {
+ test |= ipaddress[i];
+ }
+ return (test == 0x00) && (ipaddress[15] == 0x01);
+ }
+
+ boolean isLinkLocalAddress() {
+ return ((ipaddress[0] & 0xff) == 0xfe
+ && (ipaddress[1] & 0xc0) == 0x80);
+ }
+
+
+ boolean isSiteLocalAddress() {
+ return ((ipaddress[0] & 0xff) == 0xfe
+ && (ipaddress[1] & 0xc0) == 0xc0);
+ }
- /**
- * set if the object is constructed with a scoped
- * interface instead of a numeric scope id.
- */
- private boolean scope_ifname_set; // false;
+ boolean isMCGlobal() {
+ return ((ipaddress[0] & 0xff) == 0xff
+ && (ipaddress[1] & 0x0f) == 0x0e);
+ }
+
+ boolean isMCNodeLocal() {
+ return ((ipaddress[0] & 0xff) == 0xff
+ && (ipaddress[1] & 0x0f) == 0x01);
+ }
+
+ boolean isMCLinkLocal() {
+ return ((ipaddress[0] & 0xff) == 0xff
+ && (ipaddress[1] & 0x0f) == 0x02);
+ }
+
+ boolean isMCSiteLocal() {
+ return ((ipaddress[0] & 0xff) == 0xff
+ && (ipaddress[1] & 0x0f) == 0x05);
+ }
+
+ boolean isMCOrgLocal() {
+ return ((ipaddress[0] & 0xff) == 0xff
+ && (ipaddress[1] & 0x0f) == 0x08);
+ }
+ }
+
+ private final transient Inet6AddressHolder holder6;
private static final long serialVersionUID = 6880410070516793377L;
@@ -216,27 +374,21 @@
Inet6Address() {
super();
- holder().hostName = null;
- ipaddress = new byte[INADDRSZ];
- holder().family = IPv6;
+ holder.init(null, IPv6);
+ holder6 = new Inet6AddressHolder();
}
/* checking of value for scope_id should be done by caller
* scope_id must be >= 0, or -1 to indicate not being set
*/
Inet6Address(String hostName, byte addr[], int scope_id) {
- holder().hostName = hostName;
- if (addr.length == INADDRSZ) { // normal IPv6 address
- holder().family = IPv6;
- ipaddress = addr.clone();
- }
- if (scope_id >= 0) {
- this.scope_id = scope_id;
- scope_id_set = true;
- }
+ holder.init(hostName, IPv6);
+ holder6 = new Inet6AddressHolder();
+ holder6.init(addr, scope_id);
}
Inet6Address(String hostName, byte addr[]) {
+ holder6 = new Inet6AddressHolder();
try {
initif (hostName, addr, null);
} catch (UnknownHostException e) {} /* cant happen if ifname is null */
@@ -245,12 +397,14 @@
Inet6Address (String hostName, byte addr[], NetworkInterface nif)
throws UnknownHostException
{
+ holder6 = new Inet6AddressHolder();
initif (hostName, addr, nif);
}
Inet6Address (String hostName, byte addr[], String ifname)
throws UnknownHostException
{
+ holder6 = new Inet6AddressHolder();
initstr (hostName, addr, ifname);
}
@@ -341,17 +495,13 @@
private void initif(String hostName, byte addr[], NetworkInterface nif)
throws UnknownHostException
{
- holder().hostName = hostName;
+ int family = -1;
+ holder6.init(addr, nif);
+
if (addr.length == INADDRSZ) { // normal IPv6 address
- holder().family = IPv6;
- ipaddress = addr.clone();
+ family = IPv6;
}
- if (nif != null) {
- scope_ifname = nif;
- scope_id = deriveNumericScope(nif);
- scope_id_set = true;
- scope_ifname_set = true; // for consistency
- }
+ holder.init(hostName, family);
}
/* check the two Ipv6 addresses and return false if they are both
@@ -359,17 +509,22 @@
* (ie. one is sitelocal and the other linklocal)
* return true otherwise.
*/
- private boolean differentLocalAddressTypes(Inet6Address other) {
- if (isLinkLocalAddress() && !other.isLinkLocalAddress())
+
+ private static boolean isDifferentLocalAddressType(
+ byte[] thisAddr, byte[] otherAddr) {
+
+ if (Inet6Address.isLinkLocalAddress(thisAddr) &&
+ !Inet6Address.isLinkLocalAddress(otherAddr)) {
return false;
- if (isSiteLocalAddress() && !other.isSiteLocalAddress())
+ }
+ if (Inet6Address.isSiteLocalAddress(thisAddr) &&
+ !Inet6Address.isSiteLocalAddress(otherAddr)) {
return false;
+ }
return true;
}
- private int deriveNumericScope(NetworkInterface ifc)
- throws UnknownHostException
- {
+ private static int deriveNumericScope (byte[] thisAddr, NetworkInterface ifc) throws UnknownHostException {
Enumeration<InetAddress> addresses = ifc.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress addr = addresses.nextElement();
@@ -378,46 +533,60 @@
}
Inet6Address ia6_addr = (Inet6Address)addr;
/* check if site or link local prefixes match */
- if (!differentLocalAddressTypes(ia6_addr)){
+ if (!isDifferentLocalAddressType(thisAddr, ia6_addr.getAddress())){
/* type not the same, so carry on searching */
continue;
}
/* found a matching address - return its scope_id */
- return ia6_addr.scope_id;
+ return ia6_addr.getScopeId();
}
throw new UnknownHostException ("no scope_id found");
}
- private int deriveNumericScope(String ifname) throws UnknownHostException {
+ private int deriveNumericScope (String ifname) throws UnknownHostException {
Enumeration<NetworkInterface> en;
try {
en = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e) {
- throw new UnknownHostException(
- "could not enumerate local network interfaces");
+ throw new UnknownHostException ("could not enumerate local network interfaces");
}
while (en.hasMoreElements()) {
NetworkInterface ifc = en.nextElement();
- if (ifc.getName().equals(ifname)) {
- Enumeration<InetAddress> addresses = ifc.getInetAddresses();
- while (addresses.hasMoreElements()) {
- InetAddress addr = addresses.nextElement();
- if (!(addr instanceof Inet6Address)) {
- continue;
- }
- Inet6Address ia6_addr = (Inet6Address)addr;
- /* check if site or link local prefixes match */
- if (!differentLocalAddressTypes(ia6_addr)){
- /* type not the same, so carry on searching */
- continue;
- }
- /* found a matching address - return its scope_id */
- return ia6_addr.scope_id;
- }
+ if (ifc.getName().equals (ifname)) {
+ return deriveNumericScope(holder6.ipaddress, ifc);
}
}
- throw new UnknownHostException(
- "No matching address found for interface : " +ifname);
+ throw new UnknownHostException ("No matching address found for interface : " +ifname);
+ }
+
+ /**
+ * @serialField ipaddress byte[]
+ * @serialField scope_id int
+ * @serialField scope_id_set boolean
+ * @serialField scope_ifname_set boolean
+ * @serialField ifname String
+ */
+
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("ipaddress", byte[].class),
+ new ObjectStreamField("scope_id", int.class),
+ new ObjectStreamField("scope_id_set", boolean.class),
+ new ObjectStreamField("scope_ifname_set", boolean.class),
+ new ObjectStreamField("ifname", String.class)
+ };
+
+ private static final long FIELDS_OFFSET;
+ private static final sun.misc.Unsafe UNSAFE;
+
+ static {
+ try {
+ sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
+ FIELDS_OFFSET = unsafe.objectFieldOffset(
+ Inet6Address.class.getDeclaredField("holder6"));
+ UNSAFE = unsafe;
+ } catch (ReflectiveOperationException e) {
+ throw new Error(e);
+ }
}
/**
@@ -427,35 +596,41 @@
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
+ NetworkInterface scope_ifname = null;
if (getClass().getClassLoader() != null) {
throw new SecurityException ("invalid address type");
}
- s.defaultReadObject();
+ ObjectInputStream.GetField gf = s.readFields();
+ byte[] ipaddress = (byte[])gf.get("ipaddress", null);
+ int scope_id = (int)gf.get("scope_id", -1);
+ boolean scope_id_set = (boolean)gf.get("scope_id_set", false);
+ boolean scope_ifname_set = (boolean)gf.get("scope_ifname_set", false);
+ String ifname = (String)gf.get("ifname", null);
- if (ifname != null && !ifname.equals("")) {
+ if (ifname != null && !"".equals (ifname)) {
try {
scope_ifname = NetworkInterface.getByName(ifname);
- if (scope_ifname != null) {
+ if (scope_ifname == null) {
+ /* the interface does not exist on this system, so we clear
+ * the scope information completely */
+ scope_id_set = false;
+ scope_ifname_set = false;
+ scope_id = 0;
+ } else {
scope_ifname_set = true;
try {
- scope_id = deriveNumericScope(scope_ifname);
+ scope_id = deriveNumericScope (ipaddress, scope_ifname);
} catch (UnknownHostException e) {
// typically should not happen, but it may be that
// the machine being used for deserialization has
// the same interface name but without IPv6 configured.
}
- } else {
- /* the interface does not exist on this system, so we clear
- * the scope information completely */
- scope_id_set = false;
- scope_ifname_set = false;
- scope_id = 0;
}
} catch (SocketException e) {}
+ }
- }
/* if ifname was not supplied, then the numeric info is used */
ipaddress = ipaddress.clone();
@@ -466,9 +641,38 @@
ipaddress.length);
}
- if (holder().getFamily() != IPv6) {
+ if (holder.getFamily() != IPv6) {
throw new InvalidObjectException("invalid address family type");
}
+
+ Inet6AddressHolder h = new Inet6AddressHolder(
+ ipaddress, scope_id, scope_id_set, scope_ifname, scope_ifname_set
+ );
+
+ UNSAFE.putObject(this, FIELDS_OFFSET, h);
+ }
+
+ /**
+ * default behavior is overridden in order to write the
+ * scope_ifname field as a String, rather than a NetworkInterface
+ * which is not serializable
+ */
+ private synchronized void writeObject(ObjectOutputStream s)
+ throws IOException
+ {
+ String ifname = null;
+
+ if (holder6.scope_ifname != null) {
+ ifname = holder6.scope_ifname.getName();
+ holder6.scope_ifname_set = true;
+ }
+ ObjectOutputStream.PutField pfields = s.putFields();
+ pfields.put("ipaddress", holder6.ipaddress);
+ pfields.put("scope_id", holder6.scope_id);
+ pfields.put("scope_id_set", holder6.scope_id_set);
+ pfields.put("scope_ifname_set", holder6.scope_ifname_set);
+ pfields.put("ifname", ifname);
+ s.writeFields();
}
/**
@@ -483,7 +687,7 @@
*/
@Override
public boolean isMulticastAddress() {
- return ((ipaddress[0] & 0xff) == 0xff);
+ return holder6.isMulticastAddress();
}
/**
@@ -496,11 +700,7 @@
*/
@Override
public boolean isAnyLocalAddress() {
- byte test = 0x00;
- for (int i = 0; i < INADDRSZ; i++) {
- test |= ipaddress[i];
- }
- return (test == 0x00);
+ return holder6.isAnyLocalAddress();
}
/**
@@ -513,11 +713,7 @@
*/
@Override
public boolean isLoopbackAddress() {
- byte test = 0x00;
- for (int i = 0; i < 15; i++) {
- test |= ipaddress[i];
- }
- return (test == 0x00) && (ipaddress[15] == 0x01);
+ return holder6.isLoopbackAddress();
}
/**
@@ -530,6 +726,11 @@
*/
@Override
public boolean isLinkLocalAddress() {
+ return holder6.isLinkLocalAddress();
+ }
+
+ /* static version of above */
+ static boolean isLinkLocalAddress(byte[] ipaddress) {
return ((ipaddress[0] & 0xff) == 0xfe
&& (ipaddress[1] & 0xc0) == 0x80);
}
@@ -544,6 +745,11 @@
*/
@Override
public boolean isSiteLocalAddress() {
+ return holder6.isSiteLocalAddress();
+ }
+
+ /* static version of above */
+ static boolean isSiteLocalAddress(byte[] ipaddress) {
return ((ipaddress[0] & 0xff) == 0xfe
&& (ipaddress[1] & 0xc0) == 0xc0);
}
@@ -559,8 +765,7 @@
*/
@Override
public boolean isMCGlobal() {
- return ((ipaddress[0] & 0xff) == 0xff
- && (ipaddress[1] & 0x0f) == 0x0e);
+ return holder6.isMCGlobal();
}
/**
@@ -574,8 +779,7 @@
*/
@Override
public boolean isMCNodeLocal() {
- return ((ipaddress[0] & 0xff) == 0xff
- && (ipaddress[1] & 0x0f) == 0x01);
+ return holder6.isMCNodeLocal();
}
/**
@@ -589,8 +793,7 @@
*/
@Override
public boolean isMCLinkLocal() {
- return ((ipaddress[0] & 0xff) == 0xff
- && (ipaddress[1] & 0x0f) == 0x02);
+ return holder6.isMCLinkLocal();
}
/**
@@ -604,8 +807,7 @@
*/
@Override
public boolean isMCSiteLocal() {
- return ((ipaddress[0] & 0xff) == 0xff
- && (ipaddress[1] & 0x0f) == 0x05);
+ return holder6.isMCSiteLocal();
}
/**
@@ -619,10 +821,8 @@
*/
@Override
public boolean isMCOrgLocal() {
- return ((ipaddress[0] & 0xff) == 0xff
- && (ipaddress[1] & 0x0f) == 0x08);
+ return holder6.isMCOrgLocal();
}
-
/**
* Returns the raw IP address of this {@code InetAddress} object. The result
* is in network byte order: the highest order byte of the address is in
@@ -632,7 +832,7 @@
*/
@Override
public byte[] getAddress() {
- return ipaddress.clone();
+ return holder6.ipaddress.clone();
}
/**
@@ -644,7 +844,7 @@
* @since 1.5
*/
public int getScopeId() {
- return scope_id;
+ return holder6.scope_id;
}
/**
@@ -655,7 +855,7 @@
* @since 1.5
*/
public NetworkInterface getScopedInterface() {
- return scope_ifname;
+ return holder6.scope_ifname;
}
/**
@@ -669,13 +869,7 @@
*/
@Override
public String getHostAddress() {
- String s = numericToTextFormat(ipaddress);
- if (scope_ifname != null) { /* must check this first */
- s = s + "%" + scope_ifname.getName();
- } else if (scope_id_set) {
- s = s + "%" + scope_id;
- }
- return s;
+ return holder6.getHostAddress();
}
/**
@@ -685,25 +879,7 @@
*/
@Override
public int hashCode() {
- if (ipaddress != null) {
-
- int hash = 0;
- int i=0;
- while (i<INADDRSZ) {
- int j=0;
- int component=0;
- while (j<4 && i<INADDRSZ) {
- component = (component << 8) + ipaddress[i];
- j++;
- i++;
- }
- hash += component;
- }
- return hash;
-
- } else {
- return 0;
- }
+ return holder6.hashCode();
}
/**
@@ -728,12 +904,8 @@
return false;
Inet6Address inetAddr = (Inet6Address)obj;
- for (int i = 0; i < INADDRSZ; i++) {
- if (ipaddress[i] != inetAddr.ipaddress[i])
- return false;
- }
- return true;
+ return holder6.equals(inetAddr.holder6);
}
/**
@@ -746,15 +918,7 @@
* @since 1.4
*/
public boolean isIPv4CompatibleAddress() {
- if ((ipaddress[0] == 0x00) && (ipaddress[1] == 0x00) &&
- (ipaddress[2] == 0x00) && (ipaddress[3] == 0x00) &&
- (ipaddress[4] == 0x00) && (ipaddress[5] == 0x00) &&
- (ipaddress[6] == 0x00) && (ipaddress[7] == 0x00) &&
- (ipaddress[8] == 0x00) && (ipaddress[9] == 0x00) &&
- (ipaddress[10] == 0x00) && (ipaddress[11] == 0x00)) {
- return true;
- }
- return false;
+ return holder6.isIPv4CompatibleAddress();
}
// Utilities
@@ -784,24 +948,4 @@
* Perform class load-time initializations.
*/
private static native void init();
-
- /**
- * Following field is only used during (de)/serialization
- */
- private String ifname;
-
- /**
- * default behavior is overridden in order to write the
- * scope_ifname field as a String, rather than a NetworkInterface
- * which is not serializable
- */
- private synchronized void writeObject(java.io.ObjectOutputStream s)
- throws IOException
- {
- if (scope_ifname != null) {
- ifname = scope_ifname.getName();
- scope_ifname_set = true;
- }
- s.defaultWriteObject();
- }
}