--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/nio/ch/NativeSocketAddress.java Sat Nov 30 16:21:19 2019 +0000
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.ch;
+
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+
+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 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_SOCKETADDRESS = sizeofSOCKETADDRESS();
+ 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();
+
+ // SOCKETADDRESS
+ private final long address;
+
+ // cached copy of SOCKETADDRESS and the corresponding InetSocketAddress
+ private final long cachedSocketAddress;
+ private InetSocketAddress cachedInetSocketAddress;
+
+ NativeSocketAddress() {
+ // allocate 2 * SOCKETADDRESS
+ int size = SIZEOF_SOCKETADDRESS << 1;
+ long base = UNSAFE.allocateMemory(size);
+ UNSAFE.setMemory(base, size, (byte) 0);
+
+ this.address = base;
+ this.cachedSocketAddress = base + SIZEOF_SOCKETADDRESS;
+ }
+
+ long address() {
+ return address;
+ }
+
+ void free() {
+ UNSAFE.freeMemory(address);
+ }
+
+ /**
+ * 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 toInetSocketAddress() throws SocketException {
+ // return cached InetSocketAddress if the SOCKETADDRESS bytes match
+ if (cachedInetSocketAddress != null && mismatch() < 0) {
+ return cachedInetSocketAddress;
+ }
+
+ // decode SOCKETADDRESS to InetSocketAddress
+ int family = family();
+ if (family != AF_INET && family != AF_INET6)
+ throw new SocketException("Socket family not recognized");
+ var isa = new InetSocketAddress(address(family), port(family));
+
+ // copy SOCKETADDRESS and InetSocketAddress
+ UNSAFE.copyMemory(null, address, null, cachedSocketAddress, SIZEOF_SOCKETADDRESS);
+ this.cachedInetSocketAddress = isa;
+ return isa;
+ }
+
+ /**
+ * Find a mismatch between the SOCKETADDRESS structures stored at address
+ * and cachedSocketAddress.
+ * @return the byte offset of the first mismatch or -1 if no mismatch
+ */
+ private int mismatch() {
+ int i = ArraysSupport.vectorizedMismatch(null,
+ address,
+ null,
+ cachedSocketAddress,
+ 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(address + i) != UNSAFE.getByte(cachedSocketAddress + i)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @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();
+ }
+ }
+
+ /**
+ * Return the value of the sin4_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);
+ }
+
+ /**
+ * Return an InetAddress to represent the value of the address in the
+ * sin4_addr or sin6_addr fields.
+ */
+ 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 static native int AFINET();
+ private static native int AFINET6();
+ private static native int sizeofSOCKETADDRESS();
+ 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();
+
+ static {
+ IOUtil.load();
+ }
+}