< prev index next >

src/java.base/share/classes/sun/nio/ch/NativeSocketAddress.java

Print this page
M NativeSocketAddress.java

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2020, 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

@@ -23,35 +23,42 @@
  * questions.
  */
 
 package sun.nio.ch;
 
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+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.ByteOrder;
 import java.nio.channels.UnsupportedAddressTypeException;
-
+import jdk.incubator.foreign.MemoryAddress;
+import jdk.incubator.foreign.MemoryHandles;
+import jdk.incubator.foreign.MemoryLayout;
+import jdk.incubator.foreign.MemoryLayout.PathElement;
+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 static jdk.incubator.foreign.MemoryLayout.PathElement.*;
 
 /**
  * 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();

@@ -64,21 +71,175 @@
     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;
+    private static final ByteOrder NETWORK_BYTE_ORDER = ByteOrder.BIG_ENDIAN;
+    private static final ByteOrder HOST_BYTE_ORDER = ByteOrder.nativeOrder();
+
+    private static final MemoryLayout SOCKADDR;
+
+    private static final int SOCKADDR_IN_SIZE;
+    private static final int SOCKADDR_IN6_SIZE;
+
+    private static final VarHandle SA_FAMILY_HANDLE;
+    private static final VarHandle SIN_PORT_HANDLE;
+    private static final VarHandle SIN_ADDR_HANDLE;
+    private static final VarHandle SIN6_PORT_HANDLE;
+    private static final VarHandle SIN6_FLOWINFO_HANDLE;
+    private static final VarHandle SIN6_ADDR_HANDLE;
+    private static final VarHandle SIN6_SCOPE_HANDLE;
+    private static final VarHandle BYTEWISE_HANDLE;
+
+    // byte/short to/from int adapter handles
+    private static final MethodHandle INT_TO_SHORT;
+    private static final MethodHandle SHORT_TO_UNSIGNED_INT;
+    private static final MethodHandle INT_TO_BYTE;
+    private static final MethodHandle BYTE_TO_UNSIGNED_INT;
+
+    private static final boolean VERIFY = true;
+    private static final boolean DEBUG = true;
+
+    static {
+        try {
+            var lookup = MethodHandles.lookup();
+            BYTE_TO_UNSIGNED_INT = lookup.findStatic(Byte.class, "toUnsignedInt", MethodType.methodType(int.class, byte.class));
+            INT_TO_BYTE = lookup.findStatic(NativeSocketAddress.class, "byteValue", MethodType.methodType(byte.class, int.class));
+            SHORT_TO_UNSIGNED_INT = lookup.findStatic(Short.class, "toUnsignedInt", MethodType.methodType(int.class, short.class));
+            INT_TO_SHORT = lookup.findStatic(NativeSocketAddress.class, "shortValue", MethodType.methodType(short.class, int.class));
+        } catch (Throwable throwable) {
+            throw new AssertionError(throwable);
+        }
+
+        MemoryLayout familyLayout;
+        if (OFFSET_FAMILY == 1 && SIZEOF_FAMILY == 1) {
+            familyLayout = MemoryLayout.ofStruct(MemoryLayout.ofPaddingBits(8), MemoryLayouts.JAVA_BYTE.withName("sa_family"));
+            SA_FAMILY_HANDLE = MemoryHandles.filterValue(
+                    familyLayout.varHandle(byte.class, groupElement("sa_family")),
+                    INT_TO_BYTE,
+                    BYTE_TO_UNSIGNED_INT);
+        } else if (OFFSET_FAMILY == 0 && SIZEOF_FAMILY == 2) {
+            familyLayout = MemoryLayouts.JAVA_SHORT.withName("sa_family");
+            SA_FAMILY_HANDLE = MemoryHandles.filterValue(
+                    familyLayout.varHandle(short.class),
+                    INT_TO_SHORT,
+                    SHORT_TO_UNSIGNED_INT);
+        } else {
+            throw new InternalError("unknown family [offset:%d, size:%d]".formatted(OFFSET_FAMILY, SIZEOF_FAMILY));
+        }
+
+        SOCKADDR = MemoryLayout.ofUnion(
+                    MemoryLayout.ofStruct(familyLayout,
+                                          MemoryLayout.ofValueBits(16, NETWORK_BYTE_ORDER).withName("sin_port"),
+                                          //MemoryLayouts.BITS_32_BE.withName("sin_addr"))    // #### treat as bits rather than bytes?
+                                          MemoryLayout.ofSequence(4, MemoryLayouts.JAVA_BYTE).withName("sin_addr"),
+                                          MemoryLayout.ofPaddingBits(64)) // pad to size of struct sockaddr
+                                .withName("sockaddr_in"),
+                    MemoryLayout.ofStruct(familyLayout,
+                                          MemoryLayout.ofValueBits(16, NETWORK_BYTE_ORDER).withName("sin6_port"),
+                                          MemoryLayout.ofValueBits(32, HOST_BYTE_ORDER).withName("sin6_flowinfo"),
+                                          //MemoryLayout.ofValueBits(128, NETWORK_BYTE_ORDER).withName("sin6_addr"),  // #### treat as bits rather than bytes?
+                                          MemoryLayout.ofSequence(16, MemoryLayouts.JAVA_BYTE).withName("sin6_addr"),
+                                          MemoryLayout.ofValueBits(32, HOST_BYTE_ORDER).withName("sin6_scope_id"))
+                                .withName("sockaddr_in6"))
+                         .withName("sockaddr");
+
+        PathElement sockaddr_in = groupElement("sockaddr_in");
+        SIN_PORT_HANDLE      = MemoryHandles.filterValue(
+                                    SOCKADDR.varHandle(short.class, sockaddr_in, groupElement("sin_port")),
+                                    INT_TO_SHORT,
+                                    SHORT_TO_UNSIGNED_INT);
+        SIN_ADDR_HANDLE      = SOCKADDR.varHandle(byte.class, sockaddr_in, groupElement("sin_addr"), sequenceElement());
+        PathElement sockaddr_in6 = groupElement("sockaddr_in6");
+        SIN6_PORT_HANDLE     = MemoryHandles.filterValue(
+                                    SOCKADDR.varHandle(short.class, sockaddr_in6, groupElement("sin6_port")),
+                                    INT_TO_SHORT,
+                                    SHORT_TO_UNSIGNED_INT);
+        SIN6_FLOWINFO_HANDLE = SOCKADDR.varHandle(int.class,  sockaddr_in6, groupElement("sin6_flowinfo"));
+        SIN6_ADDR_HANDLE     = SOCKADDR.varHandle(byte.class, sockaddr_in6, groupElement("sin6_addr"), sequenceElement());
+        SIN6_SCOPE_HANDLE    = SOCKADDR.varHandle(int.class,  sockaddr_in6, groupElement("sin6_scope_id"));
+
+        // byte-wise handle for equality comparison
+        MemoryLayout layout = MemoryLayout.ofSequence(SOCKADDR.byteSize(), MemoryLayouts.JAVA_BYTE);
+        BYTEWISE_HANDLE = layout.varHandle(byte.class, sequenceElement());
+
+        SOCKADDR_IN_SIZE = (int) SOCKADDR.select(sockaddr_in).byteSize();
+        SOCKADDR_IN6_SIZE = (int) SOCKADDR.select(sockaddr_in6).byteSize();
+
+        debug();
+        // Verifies the handcrafted layout against the natively derived sizes and offsets
+        if (VERIFY)
+            verify();
+    }
+
+    private static void verify() {
+        // sockaddr_in
+        PathElement sockaddr_in = groupElement("sockaddr_in");
+        assert SIZEOF_SOCKADDR4 == SOCKADDR_IN_SIZE : "SIZEOF_SOCKADDR [%d] != SOCKADDR_IN_SIZE [%d]".formatted(SIZEOF_SOCKADDR4, SOCKADDR_IN_SIZE);
+        var offset = bitsToBytes(SOCKADDR.offset(sockaddr_in , groupElement("sin_port")));
+        assert offset == OFFSET_SIN4_PORT : "OFFSET_SIN4_PORT [%d] != layout offset [%d]".formatted(OFFSET_SIN4_PORT, offset);
+        offset = bitsToBytes(SOCKADDR.offset(sockaddr_in , groupElement("sin_addr")));
+        assert offset == OFFSET_SIN4_ADDR : "OFFSET_SIN4_ADDR [%d] != layout offset [%d]".formatted(OFFSET_SIN4_ADDR, offset);
+
+        //sockaddr_in6
+        PathElement sockaddr_in6 = groupElement("sockaddr_in6");
+        assert SIZEOF_SOCKADDR6 == SOCKADDR_IN6_SIZE : "SIZEOF_SOCKADDR6 [%d] != SOCKADDR_IN6_SIZE [%d]".formatted(SIZEOF_SOCKADDR6, SOCKADDR_IN6_SIZE);
+        offset = bitsToBytes(SOCKADDR.offset(sockaddr_in6 , groupElement("sin6_port")));
+        assert offset == OFFSET_SIN6_PORT : "OFFSET_SIN6_PORT [%d] != layout offset [%d]".formatted(OFFSET_SIN6_PORT, offset);
+        offset = bitsToBytes(SOCKADDR.offset(sockaddr_in6 , groupElement("sin6_addr")));
+        assert offset == OFFSET_SIN6_ADDR : "OFFSET_SIN6_ADDR [%d] != layout offset [%d]".formatted(OFFSET_SIN6_ADDR, offset);
+        offset = bitsToBytes(SOCKADDR.offset(sockaddr_in6 , groupElement("sin6_flowinfo")));
+        assert offset == OFFSET_SIN6_FLOWINFO : "OFFSET_SIN6_FLOWINFO [%d] != layout offset [%d]".formatted(OFFSET_SIN6_FLOWINFO, offset);
+        offset = bitsToBytes(SOCKADDR.offset(sockaddr_in6 , groupElement("sin6_scope_id")));
+        assert offset == OFFSET_SIN6_SCOPE_ID : "OFFSET_SIN6_SCOPE_ID [%d] != layout offset [%d]".formatted(OFFSET_SIN6_SCOPE_ID, offset);
+    }
+
+    private static void debug() {
+        if (DEBUG) {
+            System.out.println("SIZEOF_SOCKADDR4:" + SIZEOF_SOCKADDR4);
+            System.out.println("SIZEOF_SOCKADDR6:" + SIZEOF_SOCKADDR6);
+            System.out.println("SIZEOF_SOCKETADDRESS:" + SIZEOF_SOCKETADDRESS);
+            System.out.println("SIZEOF_FAMILY:" + SIZEOF_FAMILY);
+            System.out.println("OFFSET_FAMILY:" + OFFSET_FAMILY);
+            System.out.println("OFFSET_SIN4_PORT:" + OFFSET_SIN4_PORT);
+            System.out.println("OFFSET_SIN4_ADDR:" + OFFSET_SIN4_ADDR);
+            System.out.println("OFFSET_SIN6_PORT:" + OFFSET_SIN6_PORT);
+            System.out.println("OFFSET_SIN6_ADDR:" + OFFSET_SIN6_ADDR);
+            System.out.println("OFFSET_SIN6_SCOPE_ID:" + OFFSET_SIN6_SCOPE_ID);
+            System.out.println("OFFSET_SIN6_FLOWINFO:" + OFFSET_SIN6_FLOWINFO);
+            System.out.println("SOCKADDR layout:" + SOCKADDR);
+            System.out.println("SOCKADDR layout byteSize:" + SOCKADDR.byteSize());
+            System.out.println("SOCKADDR layout byteAlignment:" + SOCKADDR.byteAlignment());
+        }
+    }
+
+    private static long bitsToBytes(long value) {
+        return value / 8;
+    }
+
+    private static byte byteValue(int value) {
+        return (byte)value;
+    }
+
+    private static short shortValue(int value) {
+        return (short)value;
+    }
+
+    private final MemorySegment segment;
+    private final MemoryAddress memoryAddress;
+    private final long rawAddress;
 
     long address() {
-        return address;
+        return rawAddress;
     }
 
     NativeSocketAddress() {
-        long base = UNSAFE.allocateMemory(SIZEOF_SOCKETADDRESS);
-        UNSAFE.setMemory(base, SIZEOF_SOCKETADDRESS, (byte) 0);
-        this.address = base;
+        var initialSegment = MemorySegment.allocateNative(SOCKADDR);
+        //segment = MemorySegment.ofNativeRestricted(initialSegment.baseAddress(), initialSegment.byteSize(), null, () -> initialSegment.close(), null);  // TODO: cannot close from another thread!
+        segment = MemorySegment.ofNativeRestricted(initialSegment.baseAddress(), initialSegment.byteSize(), null, null, null);
+        memoryAddress = segment.baseAddress();
+        rawAddress = memoryAddress.toRawLongValue();
     }
 
     /**
      * Allocate an array of native socket addresses.
      */

@@ -100,11 +261,12 @@
      */
     static 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();
+                // #### underlying segment is not closed
             }
         }
     }
 
     /**

@@ -114,25 +276,25 @@
      * @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
+            // struct sockaddr_in
             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;
+            return SOCKADDR_IN_SIZE;
         } else {
-            // struct sockaddr6
+            // struct sockaddr_in6
             putFamily(AF_INET6);
             putAddress(AF_INET6, isa.getAddress());
             putPort(AF_INET6, isa.getPort());
-            UNSAFE.putInt(address + OFFSET_SIN6_FLOWINFO, 0);
-            return SIZEOF_SOCKADDR6;
+            SIN6_FLOWINFO_HANDLE.set(memoryAddress, 0);
+            return SOCKADDR_IN6_SIZE;
         }
     }
 
     /**
      * Return an InetSocketAddress to represent the socket address in this buffer.

@@ -143,46 +305,36 @@
         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;
+        }
+        var that = (NativeSocketAddress)other;
+
+        // #### this is byte-at-a-time, do we need to compare with a larger stride?
+
+        final MemoryAddress thisAddress = this.memoryAddress;
+        final MemoryAddress thatAddress = that.memoryAddress;
+        for (int i = 0; i < SOCKADDR.byteSize(); i++) {
+            byte b1 = (byte) BYTEWISE_HANDLE.get(thisAddress, i);
+            byte b2 = (byte) BYTEWISE_HANDLE.get(thatAddress, i);
+            if (b1 != b2)
             return false;
         }
+        return true;
     }
 
     @Override
     public int hashCode() {
         int h = 0;
-        for (int offset = 0; offset < SIZEOF_SOCKETADDRESS; offset++) {
-            h = 31 * h + UNSAFE.getByte(address + offset);
+        final MemoryAddress address = memoryAddress;
+        for (int i = 0; i < SOCKADDR.byteSize(); i++) {
+            h = 31 * h + (byte) BYTEWISE_HANDLE.get(address, i);
         }
         return h;
     }
 
     @Override

@@ -198,84 +350,63 @@
 
     /**
      * 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 (int) SA_FAMILY_HANDLE.get(memoryAddress);
     }
 
     /**
      * 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();
-        }
+        SA_FAMILY_HANDLE.set(memoryAddress, family);
     }
 
     /**
      * 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);
+        if (family == AF_INET)
+            return (int) SIN_PORT_HANDLE.get(memoryAddress);
+        else
+            return (int) SIN6_PORT_HANDLE.get(memoryAddress);
     }
 
     /**
      * 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);
-        }
+        if (family == AF_INET)
+            SIN_PORT_HANDLE.set(memoryAddress, port);
+        else
+            SIN6_PORT_HANDLE.set(memoryAddress, port);
     }
 
     /**
      * 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;
+        final MemoryAddress address = memoryAddress;
         int scope_id;
+        byte[] bytes;
+
         if (family == AF_INET) {
-            len = 4;
-            offset = OFFSET_SIN4_ADDR;
+            bytes = new byte[4];
+            for (int i = 0; i < 4; i++)
+                bytes[i] = (byte) SIN_ADDR_HANDLE.get(address, i);
             scope_id = 0;
         } else {
-            len = 16;
-            offset = OFFSET_SIN6_ADDR;
-            scope_id = UNSAFE.getInt(address + OFFSET_SIN6_SCOPE_ID);
+            bytes = new byte[16];
+            for (int i = 0; i < 16; i++)
+                bytes[i] = (byte) SIN6_ADDR_HANDLE.get(address, i);
+            scope_id = (int) SIN6_SCOPE_HANDLE.get(address);
         }
-        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);

@@ -289,44 +420,55 @@
      * 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) {
+        final MemoryAddress address = memoryAddress;
         if (family == AF_INET) {
             // IPv4 address
-            putAddress(address + OFFSET_SIN4_ADDR, (Inet4Address) ia);
+            putIPv4Address(address, (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);
+                putMappedAddress(address, (Inet4Address)ia);
                 scope_id = 0;
             } else {
                 // IPv6 address
                 var inet6Address = (Inet6Address) ia;
-                putAddress(address + OFFSET_SIN6_ADDR, inet6Address);
+                putIPv6Address(address, inet6Address);
                 scope_id = inet6Address.getScopeId();
             }
-            UNSAFE.putInt(address + OFFSET_SIN6_SCOPE_ID, scope_id);
+            SIN6_SCOPE_HANDLE.set(address, scope_id);
         }
     }
 
-    private static void putAddress(long address, Inet4Address ia) {
+    private static void putIPv4Address(MemoryAddress 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));
+        SIN_ADDR_HANDLE.set(address, 0, (byte) ((ipAddress >>> 24) & 0xFF));
+        SIN_ADDR_HANDLE.set(address, 1, (byte) ((ipAddress >>> 16) & 0xFF));
+        SIN_ADDR_HANDLE.set(address, 2, (byte) ((ipAddress >>>  8) & 0xFF));
+        SIN_ADDR_HANDLE.set(address, 3, (byte) ((ipAddress >>>  0) & 0xFF));
+    }
+
+    private static void putMappedAddress(MemoryAddress address, Inet4Address ia) {
+        int ipAddress = JNINA.addressValue(ia);
+        for (int i=0; i< 10; i++)
+            SIN6_ADDR_HANDLE.set(address, i, (byte) 0x00);
+
+        SIN6_ADDR_HANDLE.set(address, 10, (byte) 0xFF);
+        SIN6_ADDR_HANDLE.set(address, 11, (byte) 0xFF);
+        SIN6_ADDR_HANDLE.set(address, 12, (byte) ((ipAddress >>> 24) & 0xFF));
+        SIN6_ADDR_HANDLE.set(address, 13, (byte) ((ipAddress >>> 16) & 0xFF));
+        SIN6_ADDR_HANDLE.set(address, 14, (byte) ((ipAddress >>>  8) & 0xFF));
+        SIN6_ADDR_HANDLE.set(address, 15, (byte) ((ipAddress >>>  0) & 0xFF));
     }
 
-    private static void putAddress(long address, Inet6Address ia) {
+    private static void putIPv6Address(MemoryAddress address, Inet6Address ia) {
         byte[] bytes = JNINA.addressBytes(ia);
-        UNSAFE.copyMemory(bytes, ARRAY_BASE_OFFSET, null, address, 16);
+        for (int i = 0; i < 16; i++)
+            SIN6_ADDR_HANDLE.set(address, i, bytes[i]);
     }
 
     private static native int AFINET();
     private static native int AFINET6();
     private static native int sizeofSockAddr4();
< prev index next >