< prev index next > src/java.base/share/classes/sun/nio/ch/NativeSocketAddress.java
Print this page
* questions.
*/
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;
/**
* A native socket address that is the union of struct sockaddr, struct sockaddr_in,
* and struct sockaddr_in6.
*
* This class is not thread safe.
*/
! 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();
-
- // SOCKETADDRESS
- 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;
}
/**
* Allocate an array of native socket addresses.
*/
! 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) {
* questions.
*/
package sun.nio.ch;
+ import java.lang.invoke.VarHandle;
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.incubator.foreign.MemoryAddress;
+ import jdk.incubator.foreign.MemoryHandles;
+ import jdk.incubator.foreign.MemoryLayouts;
+ import jdk.incubator.foreign.MemorySegment;
import jdk.internal.access.JavaNetInetAddressAccess;
import jdk.internal.access.SharedSecrets;
! import jdk.internal.sys.in6_h;
! import jdk.internal.sys.in_h;
/**
* A native socket address that is the union of struct sockaddr, struct sockaddr_in,
* and struct sockaddr_in6.
*
* This class is not thread safe.
*/
! final class NativeSocketAddress {
private static final JavaNetInetAddressAccess JNINA = SharedSecrets.getJavaNetInetAddressAccess();
private static final int AF_INET = AFINET();
private static final int AF_INET6 = AFINET6();
! final long address() {
! return address.toRawLongValue();
}
! private final MemorySegment segment;
! private final MemoryAddress address;
!
! private NativeSocketAddress() {
+ segment = allocateNative(in6_h.Csockaddr_in6.sizeof());
+ segment.fill((byte) 0x00);
+ address = segment.baseAddress();
}
/**
* Allocate an array of native socket addresses.
*/
! static final NativeSocketAddress[] allocate(int count) {
NativeSocketAddress[] array = new NativeSocketAddress[count];
for (int i = 0; i < count; i++) {
try {
array[i] = new NativeSocketAddress();
} catch (OutOfMemoryError e) {
}
/**
* Free all non-null native socket addresses in the given 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);
}
}
}
/**
* Encodes the given InetSocketAddress into this socket address.
* @param protocolFamily protocol family
* @param isa the InetSocketAddress to encode
* @return the size of the socket address (sizeof sockaddr or sockaddr6)
* @throws UnsupportedAddressTypeException if the address type is not supported
*/
! int encode(ProtocolFamily protocolFamily, InetSocketAddress isa) {
if (protocolFamily == StandardProtocolFamily.INET) {
// struct sockaddr
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 {
// struct sockaddr6
! putFamily(AF_INET6);
! putAddress(AF_INET6, isa.getAddress());
! putPort(AF_INET6, isa.getPort());
! UNSAFE.putInt(address + OFFSET_SIN6_FLOWINFO, 0);
! return SIZEOF_SOCKADDR6;
}
}
/**
* Return an InetSocketAddress to represent the socket address in this buffer.
* @throws SocketException if the socket address is not AF_INET or AF_INET6
*/
! 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));
}
- /**
- * Find a mismatch between this and another socket address
- * @return the byte offset of the first mismatch or -1 if no mismatch
- */
- 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>";
}
}
! /**
! * Return the value of the sa_family field.
- */
- 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();
- }
- }
-
- /**
- * Stores the given family in the sa_family field.
- */
- 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();
- }
- }
/**
* Return the value of the sin_port or sin6_port field. These fields are
* stored in network order.
*/
! 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);
- }
-
- /**
- * Stores the given port number in the sin_port or sin6_port field. The
- * port is stored in network order.
- */
- 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);
}
}
/**
* Return an InetAddress to represent the value of the address in the
* sin4_addr or sin6_addr fields. For IPv6 addresses, the Inet6Address is
* created with the sin6_scope_id in the sockaddr_in6 structure.
*/
! 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);
}
}
! /**
! * Stores the given InetAddress in the sin_addr or sin6_addr/sin6_scope_id
! * fields. For IPv6 addresses, the sin6_addr will be popluated with an
! * IPv4-mapped IPv6 address when the given InetAddress is an IPv4 address.
! */
- private void putAddress(int family, InetAddress ia) {
- if (family == AF_INET) {
- // IPv4 address
- putAddress(address + OFFSET_SIN4_ADDR, (Inet4Address) ia);
} else {
! int scope_id;
- if (ia instanceof Inet4Address) {
- // IPv4-mapped IPv6 address
- 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 {
- // IPv6 address
- 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);
! // network order
! 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();
}
}
}
/**
* Free all non-null native socket addresses in the given array.
*/
! static final void freeAll(NativeSocketAddress[] array) {
for (int i = 0; i < array.length; i++) {
NativeSocketAddress sa = array[i];
if (sa != null) {
! sa.segment.close();
}
}
}
+ private static final VarHandle sin_family = MemoryHandles.asUnsigned(in_h.Csockaddr_in.sin_family$VH(), int.class);
+ private static final VarHandle sin6_family = MemoryHandles.asUnsigned(in6_h.Csockaddr_in6.sin6_family$VH(), int.class);
+
/**
* Encodes the given InetSocketAddress into this socket address.
* @param protocolFamily protocol family
* @param isa the InetSocketAddress to encode
* @return the size of the socket address (sizeof sockaddr or sockaddr6)
* @throws UnsupportedAddressTypeException if the address type is not supported
*/
! final int encode(ProtocolFamily protocolFamily, InetSocketAddress isa) {
if (protocolFamily == StandardProtocolFamily.INET) {
// struct sockaddr
InetAddress ia = isa.getAddress();
if (!(ia instanceof Inet4Address))
throw new UnsupportedAddressTypeException();
! sin_family.set(address, AF_INET);
! in_h.Csockaddr_in.sin_port$set(address, (short) isa.getPort());
! in_h.Cin_addr.s_addr$set(in_h.Csockaddr_in.sin_addr$addr(address),
! JNINA.addressValue((Inet4Address) ia));
+ return (int) in_h.Csockaddr_in.sizeof();
} else {
// struct sockaddr6
! sin6_family.set(address, AF_INET6);
! in6_h.Csockaddr_in6.sin6_port$set(address, (short) isa.getPort());
! in6_h.Csockaddr_in6.sin6_flowinfo$set(address, 0);
! setSin6Address(in6_h.Csockaddr_in6.sin6_addr$addr(address).segment(), isa.getAddress());
! in6_h.Csockaddr_in6.sin6_scope_id$set(address, scopeidFromAddress(isa.getAddress()));
+ return (int) in6_h.Csockaddr_in6.sizeof();
}
}
/**
* Return an InetSocketAddress to represent the socket address in this buffer.
* @throws SocketException if the socket address is not AF_INET or AF_INET6
*/
! final InetSocketAddress decode() throws SocketException {
! int family = (int) sin_family.get(address);
if (family != AF_INET && family != AF_INET6)
throw new SocketException("Socket family not recognized");
return new InetSocketAddress(address(family), port(family));
}
@Override
public boolean equals(Object other) {
! if (!(other instanceof NativeSocketAddress))
return false;
! NativeSocketAddress that = (NativeSocketAddress) other;
+ return this.segment.mismatch(that.segment) == -1;
}
+ private static final VarHandle BYTE_HANDLE = MemoryLayouts.JAVA_BYTE.varHandle(byte.class);
+
@Override
public int hashCode() {
int h = 0;
! final MemoryAddress addr = segment.baseAddress();
! for (int i = 0 ; i < segment.byteSize() ; i++) {
+ h = 31 * h + (byte) BYTE_HANDLE.get(addr.addOffset(i));
}
return h;
}
@Override
public String toString() {
! int family = in_h.Csockaddr_in.sin_family$get(address);
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 static final VarHandle sin_port = MemoryHandles.asUnsigned(in_h.Csockaddr_in.sin_port$VH(), int.class);
! private static final VarHandle sin6_port = MemoryHandles.asUnsigned(in6_h.Csockaddr_in6.sin6_port$VH(), int.class);
/**
* Return the value of the sin_port or sin6_port field. These fields are
* stored in network order.
*/
! private final int port(int family) {
if (family == AF_INET) {
! return (int) sin_port.get(address);
} else {
! return (int) sin6_port.get(address);
}
}
/**
* Return an InetAddress to represent the value of the address in the
* sin4_addr or sin6_addr fields. For IPv6 addresses, the Inet6Address is
* created with the sin6_scope_id in the sockaddr_in6 structure.
*/
! private final InetAddress address(int family) {
if (family == AF_INET) {
! return JNINA.getByAddress(
! in_h.Cin_addr.s_addr$get(in_h.Csockaddr_in.sin_addr$addr(address)));
} else {
! return JNINA.getByAddress(
! in6_h.Cin6_addr.__u6_addr$addr(in6_h.Csockaddr_in6.sin6_addr$addr(address)).segment().toByteArray(),
! in6_h.Csockaddr_in6.sin6_scope_id$get(address)
! );
}
}
! private static final VarHandle ADDR_HANDLE = MemoryHandles.withOffset(MemoryLayouts.BITS_32_BE.varHandle(int.class), 12);
! private static final void setSin6Address(MemorySegment seg, InetAddress ia) {
! if (ia instanceof Inet4Address) { // IPv4-mapped IPv6 address
! seg.fill((byte) 0x00).asSlice(10, 2).fill((byte) 0xFF);
! ADDR_HANDLE.set(seg.baseAddress(), JNINA.addressValue((Inet4Address) ia));
} else {
! seg.copyFrom(MemorySegment.ofArray(JNINA.addressBytes((Inet6Address) ia)));
}
}
! private static final int scopeidFromAddress(InetAddress ia) {
! if (ia instanceof Inet4Address)
! return 0;
! return ((Inet6Address) ia).getScopeId();
}
! private static final jdk.internal.misc.Unsafe UNSAFE = jdk.internal.misc.Unsafe.getUnsafe();
! private static final MemorySegment allocateNative(long byteSize) {
! long base = UNSAFE.allocateMemory(byteSize);
+ return jdk.internal.foreign.NativeMemorySegmentImpl.makeNativeSegmentUnchecked(
+ MemoryAddress.ofLong(base),
+ byteSize,
+ null,
+ () -> UNSAFE.freeMemory(base),
+ null);
}
private static native int AFINET();
private static native int AFINET6();
static {
IOUtil.load();
}
}
< prev index next >