diff a/src/java.base/share/classes/sun/nio/ch/NativeSocketAddress.java b/src/java.base/share/classes/sun/nio/ch/NativeSocketAddress.java --- a/src/java.base/share/classes/sun/nio/ch/NativeSocketAddress.java +++ b/src/java.base/share/classes/sun/nio/ch/NativeSocketAddress.java @@ -23,68 +23,59 @@ * 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.misc.Unsafe; -import jdk.internal.util.ArraysSupport; +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. */ -class NativeSocketAddress { +final 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; + final long address() { + return address.toRawLongValue(); } - NativeSocketAddress() { - long base = UNSAFE.allocateMemory(SIZEOF_SOCKETADDRESS); - UNSAFE.setMemory(base, SIZEOF_SOCKETADDRESS, (byte) 0); - this.address = base; + 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 NativeSocketAddress[] allocate(int count) { + 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) { @@ -96,251 +87,172 @@ } /** * Free all non-null native socket addresses in the given array. */ - static void freeAll(NativeSocketAddress[] array) { + static final void freeAll(NativeSocketAddress[] array) { for (int i = 0; i < array.length; i++) { NativeSocketAddress sa = array[i]; if (sa != null) { - UNSAFE.freeMemory(sa.address); + 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 */ - int encode(ProtocolFamily protocolFamily, InetSocketAddress isa) { + final 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; + 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 - putFamily(AF_INET6); - putAddress(AF_INET6, isa.getAddress()); - putPort(AF_INET6, isa.getPort()); - UNSAFE.putInt(address + OFFSET_SIN6_FLOWINFO, 0); - return SIZEOF_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); + in6_h.Csockaddr_in6.sin6_addr$addr(address).segment().copyFrom(addressAsSegment(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 */ - InetSocketAddress decode() throws SocketException { - int family = family(); + 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)); } - /** - * 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 { + 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; - for (int offset = 0; offset < SIZEOF_SOCKETADDRESS; offset++) { - h = 31 * h + UNSAFE.getByte(address + offset); + 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 = family(); + 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 ""; } } - /** - * 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(); - } - } + 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 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); + private final int port(int family) { if (family == AF_INET) { - UNSAFE.putByte(address + OFFSET_SIN4_PORT, b1); - UNSAFE.putByte(address + OFFSET_SIN4_PORT + 1, b2); + return (int) sin_port.get(address); } else { - UNSAFE.putByte(address + OFFSET_SIN6_PORT, b1); - UNSAFE.putByte(address + OFFSET_SIN6_PORT + 1, b2); + 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 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); + private final InetAddress address(int family) { try { - if (scope_id == 0) { - return InetAddress.getByAddress(bytes); + if (family == AF_INET) { + return InetAddress.getByAddress(intToByteArray(in_h.Cin_addr.s_addr$get(in_h.Csockaddr_in.sin_addr$addr(address)))); } else { - return Inet6Address.getByAddress(null, bytes, scope_id); + int scope = in6_h.Csockaddr_in6.sin6_scope_id$get(address); + byte[] ba = in6_h.Cin6_addr.__u6_addr$addr(in6_h.Csockaddr_in6.sin6_addr$addr(address)).segment().toByteArray(); + if (scope == 0) { + return InetAddress.getByAddress(ba); + } else { + return Inet6Address.getByAddress(null, ba, scope); + } } } catch (UnknownHostException e) { - throw new InternalError(e); + throw new InternalError("should not reach here", 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 final byte[] intToByteArray(int value) { + return new byte[] { (byte) (value >>> 24), + (byte) (value >>> 16), + (byte) (value >>> 8), + (byte) value}; + } + + private static final MemorySegment addressAsSegment(InetAddress ia) { + return MemorySegment.ofArray(ipv6AddressBytes(ia)); + } + + private static final byte[] ipv6AddressBytes(InetAddress ia) { + if (ia instanceof Inet4Address) { + byte[] ba = new byte[16]; + ba[10] = (byte) 0xFF; + ba[11] = (byte) 0xFF; + int ipAddress = JNINA.addressValue((Inet4Address) ia); + // network order + ba[12] = (byte) ((ipAddress >>> 24) & 0xFF); + ba[13] = (byte) ((ipAddress >>> 16) & 0xFF); + ba[14] = (byte) ((ipAddress >>> 8) & 0xFF); + ba[15] = (byte) (ipAddress & 0xFF); + return ba; } + return JNINA.addressBytes((Inet6Address) ia); } - 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 final int scopeidFromAddress(InetAddress ia) { + if (ia instanceof Inet4Address) + return 0; + return ((Inet6Address) ia).getScopeId(); } - private static void putAddress(long address, Inet6Address ia) { - byte[] bytes = JNINA.addressBytes(ia); - UNSAFE.copyMemory(bytes, ARRAY_BASE_OFFSET, null, address, 16); + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + private static final MemorySegment allocateNative(long byteSize) { + long base = UNSAFE.allocateMemory(byteSize); + return MemorySegment.ofNativeRestricted(MemoryAddress.ofLong(base), byteSize, null, () -> UNSAFE.freeMemory(base), null); } 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(); } }