|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.nio.ch; |
|
|
|
import java.net.Inet4Address; |
|
import java.net.Inet6Address; |
|
import java.net.InetAddress; |
|
import java.net.InetSocketAddress; |
|
import java.net.ProtocolFamily; |
|
import java.net.SocketException; |
|
import java.net.StandardProtocolFamily; |
|
import java.net.UnknownHostException; |
|
import java.nio.channels.UnsupportedAddressTypeException; |
|
|
|
import jdk.internal.access.JavaNetInetAddressAccess; |
|
import jdk.internal.access.SharedSecrets; |
|
import jdk.internal.misc.Unsafe; |
|
import jdk.internal.util.ArraysSupport; |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
class NativeSocketAddress { |
|
private static final JavaNetInetAddressAccess JNINA = SharedSecrets.getJavaNetInetAddressAccess(); |
|
private static final Unsafe UNSAFE = Unsafe.getUnsafe(); |
|
private static final long ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class); |
|
|
|
private static final int AF_INET = AFINET(); |
|
private static final int AF_INET6 = AFINET6(); |
|
|
|
private static final int SIZEOF_SOCKADDR4 = sizeofSockAddr4(); |
|
private static final int SIZEOF_SOCKADDR6 = sizeofSockAddr6(); |
|
private static final int SIZEOF_SOCKETADDRESS = Math.max(SIZEOF_SOCKADDR4, SIZEOF_SOCKADDR6); |
|
private static final int SIZEOF_FAMILY = sizeofFamily(); |
|
private static final int OFFSET_FAMILY = offsetFamily(); |
|
private static final int OFFSET_SIN4_PORT = offsetSin4Port(); |
|
private static final int OFFSET_SIN4_ADDR = offsetSin4Addr(); |
|
private static final int OFFSET_SIN6_PORT = offsetSin6Port(); |
|
private static final int OFFSET_SIN6_ADDR = offsetSin6Addr(); |
|
private static final int OFFSET_SIN6_SCOPE_ID = offsetSin6ScopeId(); |
|
private static final int OFFSET_SIN6_FLOWINFO = offsetSin6FlowInfo(); |
|
|
|
|
|
private final long address; |
|
|
|
long address() { |
|
return address; |
|
} |
|
|
|
NativeSocketAddress() { |
|
long base = UNSAFE.allocateMemory(SIZEOF_SOCKETADDRESS); |
|
UNSAFE.setMemory(base, SIZEOF_SOCKETADDRESS, (byte) 0); |
|
this.address = base; |
|
} |
|
|
|
|
|
|
|
*/ |
|
static NativeSocketAddress[] allocate(int count) { |
|
NativeSocketAddress[] array = new NativeSocketAddress[count]; |
|
for (int i = 0; i < count; i++) { |
|
try { |
|
array[i] = new NativeSocketAddress(); |
|
} catch (OutOfMemoryError e) { |
|
freeAll(array); |
|
throw e; |
|
} |
|
} |
|
return array; |
|
} |
|
|
|
|
|
|
|
*/ |
|
static void freeAll(NativeSocketAddress[] array) { |
|
for (int i = 0; i < array.length; i++) { |
|
NativeSocketAddress sa = array[i]; |
|
if (sa != null) { |
|
UNSAFE.freeMemory(sa.address); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
int encode(ProtocolFamily protocolFamily, InetSocketAddress isa) { |
|
if (protocolFamily == StandardProtocolFamily.INET) { |
|
|
|
InetAddress ia = isa.getAddress(); |
|
if (!(ia instanceof Inet4Address)) |
|
throw new UnsupportedAddressTypeException(); |
|
putFamily(AF_INET); |
|
putAddress(AF_INET, ia); |
|
putPort(AF_INET, isa.getPort()); |
|
return SIZEOF_SOCKADDR4; |
|
} else { |
|
|
|
putFamily(AF_INET6); |
|
putAddress(AF_INET6, isa.getAddress()); |
|
putPort(AF_INET6, isa.getPort()); |
|
UNSAFE.putInt(address + OFFSET_SIN6_FLOWINFO, 0); |
|
return SIZEOF_SOCKADDR6; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
InetSocketAddress decode() throws SocketException { |
|
int family = family(); |
|
if (family != AF_INET && family != AF_INET6) |
|
throw new SocketException("Socket family not recognized"); |
|
return new InetSocketAddress(address(family), port(family)); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private int mismatch(NativeSocketAddress other) { |
|
int i = ArraysSupport.vectorizedMismatch(null, |
|
this.address, |
|
null, |
|
other.address, |
|
SIZEOF_SOCKETADDRESS, |
|
ArraysSupport.LOG2_ARRAY_BYTE_INDEX_SCALE); |
|
if (i >= 0) |
|
return i; |
|
i = SIZEOF_SOCKETADDRESS - ~i; |
|
for (; i < SIZEOF_SOCKETADDRESS; i++) { |
|
if (UNSAFE.getByte(this.address + i) != UNSAFE.getByte(other.address + i)) { |
|
return i; |
|
} |
|
} |
|
return -1; |
|
} |
|
|
|
@Override |
|
public boolean equals(Object other) { |
|
if (other instanceof NativeSocketAddress) { |
|
return mismatch((NativeSocketAddress) other) < 0; |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
@Override |
|
public int hashCode() { |
|
int h = 0; |
|
for (int offset = 0; offset < SIZEOF_SOCKETADDRESS; offset++) { |
|
h = 31 * h + UNSAFE.getByte(address + offset); |
|
} |
|
return h; |
|
} |
|
|
|
@Override |
|
public String toString() { |
|
int family = family(); |
|
if (family == AF_INET || family == AF_INET6) { |
|
return ((family == AF_INET) ? "AF_INET" : "AF_INET6") |
|
+ ", address=" + address(family) + ", port=" + port(family); |
|
} else { |
|
return "<unknown>"; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private int family() { |
|
if (SIZEOF_FAMILY == 1) { |
|
return UNSAFE.getByte(address + OFFSET_FAMILY); |
|
} else if (SIZEOF_FAMILY == 2) { |
|
return UNSAFE.getShort(address + OFFSET_FAMILY); |
|
} else { |
|
throw new InternalError(); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private void putFamily(int family) { |
|
if (SIZEOF_FAMILY == 1) { |
|
UNSAFE.putByte(address + OFFSET_FAMILY, (byte) family); |
|
} else if (SIZEOF_FAMILY == 2) { |
|
UNSAFE.putShort(address + OFFSET_FAMILY, (short) family); |
|
} else { |
|
throw new InternalError(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private int port(int family) { |
|
byte b1, b2; |
|
if (family == AF_INET) { |
|
b1 = UNSAFE.getByte(address + OFFSET_SIN4_PORT); |
|
b2 = UNSAFE.getByte(address + OFFSET_SIN4_PORT + 1); |
|
} else { |
|
b1 = UNSAFE.getByte(address + OFFSET_SIN6_PORT); |
|
b2 = UNSAFE.getByte(address + OFFSET_SIN6_PORT + 1); |
|
} |
|
return (Byte.toUnsignedInt(b1) << 8) + Byte.toUnsignedInt(b2); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private void putPort(int family, int port) { |
|
byte b1 = (byte) ((port >> 8) & 0xff); |
|
byte b2 = (byte) ((port >> 0) & 0xff); |
|
if (family == AF_INET) { |
|
UNSAFE.putByte(address + OFFSET_SIN4_PORT, b1); |
|
UNSAFE.putByte(address + OFFSET_SIN4_PORT + 1, b2); |
|
} else { |
|
UNSAFE.putByte(address + OFFSET_SIN6_PORT, b1); |
|
UNSAFE.putByte(address + OFFSET_SIN6_PORT + 1, b2); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private InetAddress address(int family) { |
|
int len; |
|
int offset; |
|
int scope_id; |
|
if (family == AF_INET) { |
|
len = 4; |
|
offset = OFFSET_SIN4_ADDR; |
|
scope_id = 0; |
|
} else { |
|
len = 16; |
|
offset = OFFSET_SIN6_ADDR; |
|
scope_id = UNSAFE.getInt(address + OFFSET_SIN6_SCOPE_ID); |
|
} |
|
byte[] bytes = new byte[len]; |
|
UNSAFE.copyMemory(null, address + offset, bytes, ARRAY_BASE_OFFSET, len); |
|
try { |
|
if (scope_id == 0) { |
|
return InetAddress.getByAddress(bytes); |
|
} else { |
|
return Inet6Address.getByAddress(null, bytes, scope_id); |
|
} |
|
} catch (UnknownHostException e) { |
|
throw new InternalError(e); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void putAddress(int family, InetAddress ia) { |
|
if (family == AF_INET) { |
|
|
|
putAddress(address + OFFSET_SIN4_ADDR, (Inet4Address) ia); |
|
} else { |
|
int scope_id; |
|
if (ia instanceof Inet4Address) { |
|
|
|
UNSAFE.setMemory(address + OFFSET_SIN6_ADDR, 10, (byte) 0); |
|
UNSAFE.putByte(address + OFFSET_SIN6_ADDR + 10, (byte) 0xff); |
|
UNSAFE.putByte(address + OFFSET_SIN6_ADDR + 11, (byte) 0xff); |
|
putAddress(address + OFFSET_SIN6_ADDR + 12, (Inet4Address) ia); |
|
scope_id = 0; |
|
} else { |
|
|
|
var inet6Address = (Inet6Address) ia; |
|
putAddress(address + OFFSET_SIN6_ADDR, inet6Address); |
|
scope_id = inet6Address.getScopeId(); |
|
} |
|
UNSAFE.putInt(address + OFFSET_SIN6_SCOPE_ID, scope_id); |
|
} |
|
} |
|
|
|
private static void putAddress(long address, Inet4Address ia) { |
|
int ipAddress = JNINA.addressValue(ia); |
|
|
|
UNSAFE.putByte(address + 0, (byte) ((ipAddress >>> 24) & 0xFF)); |
|
UNSAFE.putByte(address + 1, (byte) ((ipAddress >>> 16) & 0xFF)); |
|
UNSAFE.putByte(address + 2, (byte) ((ipAddress >>> 8) & 0xFF)); |
|
UNSAFE.putByte(address + 3, (byte) (ipAddress & 0xFF)); |
|
} |
|
|
|
private static void putAddress(long address, Inet6Address ia) { |
|
byte[] bytes = JNINA.addressBytes(ia); |
|
UNSAFE.copyMemory(bytes, ARRAY_BASE_OFFSET, null, address, 16); |
|
} |
|
|
|
private static native int AFINET(); |
|
private static native int AFINET6(); |
|
private static native int sizeofSockAddr4(); |
|
private static native int sizeofSockAddr6(); |
|
private static native int sizeofFamily(); |
|
private static native int offsetFamily(); |
|
private static native int offsetSin4Port(); |
|
private static native int offsetSin4Addr(); |
|
private static native int offsetSin6Port(); |
|
private static native int offsetSin6Addr(); |
|
private static native int offsetSin6ScopeId(); |
|
private static native int offsetSin6FlowInfo(); |
|
|
|
static { |
|
IOUtil.load(); |
|
} |
|
} |