1 /*
   2  * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.nio.ch;
  27 
  28 import java.lang.invoke.MethodHandle;
  29 import java.lang.invoke.MethodHandles;
  30 import java.lang.invoke.MethodType;
  31 import java.lang.invoke.VarHandle;
  32 import java.net.Inet4Address;
  33 import java.net.Inet6Address;
  34 import java.net.InetAddress;
  35 import java.net.InetSocketAddress;
  36 import java.net.ProtocolFamily;
  37 import java.net.SocketException;
  38 import java.net.StandardProtocolFamily;
  39 import java.net.UnknownHostException;
  40 import java.nio.ByteOrder;
  41 import java.nio.channels.UnsupportedAddressTypeException;
  42 import jdk.incubator.foreign.MemoryAddress;
  43 import jdk.incubator.foreign.MemoryHandles;
  44 import jdk.incubator.foreign.MemoryLayout;
  45 import jdk.incubator.foreign.MemoryLayout.PathElement;
  46 import jdk.incubator.foreign.MemoryLayouts;
  47 import jdk.incubator.foreign.MemorySegment;
  48 import jdk.internal.access.JavaNetInetAddressAccess;
  49 import jdk.internal.access.SharedSecrets;
  50 import static jdk.incubator.foreign.MemoryLayout.PathElement.*;
  51 
  52 /**
  53  * A native socket address that is the union of struct sockaddr, struct sockaddr_in,
  54  * and struct sockaddr_in6.
  55  *
  56  * This class is not thread safe.
  57  */
  58 class NativeSocketAddress {
  59     private static final JavaNetInetAddressAccess JNINA = SharedSecrets.getJavaNetInetAddressAccess();
  60 
  61     private static final int AF_INET  = AFINET();
  62     private static final int AF_INET6 = AFINET6();
  63 
  64     private static final int SIZEOF_SOCKADDR4     = sizeofSockAddr4();
  65     private static final int SIZEOF_SOCKADDR6     = sizeofSockAddr6();
  66     private static final int SIZEOF_SOCKETADDRESS = Math.max(SIZEOF_SOCKADDR4, SIZEOF_SOCKADDR6);
  67     private static final int SIZEOF_FAMILY        = sizeofFamily();
  68     private static final int OFFSET_FAMILY        = offsetFamily();
  69     private static final int OFFSET_SIN4_PORT     = offsetSin4Port();
  70     private static final int OFFSET_SIN4_ADDR     = offsetSin4Addr();
  71     private static final int OFFSET_SIN6_PORT     = offsetSin6Port();
  72     private static final int OFFSET_SIN6_ADDR     = offsetSin6Addr();
  73     private static final int OFFSET_SIN6_SCOPE_ID = offsetSin6ScopeId();
  74     private static final int OFFSET_SIN6_FLOWINFO = offsetSin6FlowInfo();
  75 
  76     private static final ByteOrder NETWORK_BYTE_ORDER = ByteOrder.BIG_ENDIAN;
  77     private static final ByteOrder HOST_BYTE_ORDER = ByteOrder.nativeOrder();
  78 
  79     private static final MemoryLayout SOCKADDR;
  80 
  81     private static final int SOCKADDR_IN_SIZE;
  82     private static final int SOCKADDR_IN6_SIZE;
  83 
  84     private static final VarHandle SA_FAMILY_HANDLE;
  85     private static final VarHandle SIN_PORT_HANDLE;
  86     private static final VarHandle SIN_ADDR_HANDLE;
  87     private static final VarHandle SIN6_PORT_HANDLE;
  88     private static final VarHandle SIN6_FLOWINFO_HANDLE;
  89     private static final VarHandle SIN6_ADDR_HANDLE;
  90     private static final VarHandle SIN6_SCOPE_HANDLE;
  91     private static final VarHandle BYTEWISE_HANDLE;
  92 
  93     // byte/short to/from int adapter handles
  94     private static final MethodHandle INT_TO_SHORT;
  95     private static final MethodHandle SHORT_TO_UNSIGNED_INT;
  96     private static final MethodHandle INT_TO_BYTE;
  97     private static final MethodHandle BYTE_TO_UNSIGNED_INT;
  98 
  99     private static final boolean VERIFY = true;
 100     private static final boolean DEBUG = true;
 101 
 102     static {
 103         try {
 104             var lookup = MethodHandles.lookup();
 105             BYTE_TO_UNSIGNED_INT = lookup.findStatic(Byte.class, "toUnsignedInt", MethodType.methodType(int.class, byte.class));
 106             INT_TO_BYTE = lookup.findStatic(NativeSocketAddress.class, "byteValue", MethodType.methodType(byte.class, int.class));
 107             SHORT_TO_UNSIGNED_INT = lookup.findStatic(Short.class, "toUnsignedInt", MethodType.methodType(int.class, short.class));
 108             INT_TO_SHORT = lookup.findStatic(NativeSocketAddress.class, "shortValue", MethodType.methodType(short.class, int.class));
 109         } catch (Throwable throwable) {
 110             throw new AssertionError(throwable);
 111         }
 112 
 113         MemoryLayout familyLayout;
 114         if (OFFSET_FAMILY == 1 && SIZEOF_FAMILY == 1) {
 115             familyLayout = MemoryLayout.ofStruct(MemoryLayout.ofPaddingBits(8), MemoryLayouts.JAVA_BYTE.withName("sa_family"));
 116             SA_FAMILY_HANDLE = MemoryHandles.filterValue(
 117                     familyLayout.varHandle(byte.class, groupElement("sa_family")),
 118                     INT_TO_BYTE,
 119                     BYTE_TO_UNSIGNED_INT);
 120         } else if (OFFSET_FAMILY == 0 && SIZEOF_FAMILY == 2) {
 121             familyLayout = MemoryLayouts.JAVA_SHORT.withName("sa_family");
 122             SA_FAMILY_HANDLE = MemoryHandles.filterValue(
 123                     familyLayout.varHandle(short.class),
 124                     INT_TO_SHORT,
 125                     SHORT_TO_UNSIGNED_INT);
 126         } else {
 127             throw new InternalError("unknown family [offset:%d, size:%d]".formatted(OFFSET_FAMILY, SIZEOF_FAMILY));
 128         }
 129 
 130         SOCKADDR = MemoryLayout.ofUnion(
 131                     MemoryLayout.ofStruct(familyLayout,
 132                                           MemoryLayout.ofValueBits(16, NETWORK_BYTE_ORDER).withName("sin_port"),
 133                                           //MemoryLayouts.BITS_32_BE.withName("sin_addr"))    // #### treat as bits rather than bytes?
 134                                           MemoryLayout.ofSequence(4, MemoryLayouts.JAVA_BYTE).withName("sin_addr"),
 135                                           MemoryLayout.ofPaddingBits(64)) // pad to size of struct sockaddr
 136                                 .withName("sockaddr_in"),
 137                     MemoryLayout.ofStruct(familyLayout,
 138                                           MemoryLayout.ofValueBits(16, NETWORK_BYTE_ORDER).withName("sin6_port"),
 139                                           MemoryLayout.ofValueBits(32, HOST_BYTE_ORDER).withName("sin6_flowinfo"),
 140                                           //MemoryLayout.ofValueBits(128, NETWORK_BYTE_ORDER).withName("sin6_addr"),  // #### treat as bits rather than bytes?
 141                                           MemoryLayout.ofSequence(16, MemoryLayouts.JAVA_BYTE).withName("sin6_addr"),
 142                                           MemoryLayout.ofValueBits(32, HOST_BYTE_ORDER).withName("sin6_scope_id"))
 143                                 .withName("sockaddr_in6"))
 144                          .withName("sockaddr");
 145 
 146         PathElement sockaddr_in = groupElement("sockaddr_in");
 147         SIN_PORT_HANDLE      = MemoryHandles.filterValue(
 148                                     SOCKADDR.varHandle(short.class, sockaddr_in, groupElement("sin_port")),
 149                                     INT_TO_SHORT,
 150                                     SHORT_TO_UNSIGNED_INT);
 151         SIN_ADDR_HANDLE      = SOCKADDR.varHandle(byte.class, sockaddr_in, groupElement("sin_addr"), sequenceElement());
 152         PathElement sockaddr_in6 = groupElement("sockaddr_in6");
 153         SIN6_PORT_HANDLE     = MemoryHandles.filterValue(
 154                                     SOCKADDR.varHandle(short.class, sockaddr_in6, groupElement("sin6_port")),
 155                                     INT_TO_SHORT,
 156                                     SHORT_TO_UNSIGNED_INT);
 157         SIN6_FLOWINFO_HANDLE = SOCKADDR.varHandle(int.class,  sockaddr_in6, groupElement("sin6_flowinfo"));
 158         SIN6_ADDR_HANDLE     = SOCKADDR.varHandle(byte.class, sockaddr_in6, groupElement("sin6_addr"), sequenceElement());
 159         SIN6_SCOPE_HANDLE    = SOCKADDR.varHandle(int.class,  sockaddr_in6, groupElement("sin6_scope_id"));
 160 
 161         // byte-wise handle for equality comparison
 162         MemoryLayout layout = MemoryLayout.ofSequence(SOCKADDR.byteSize(), MemoryLayouts.JAVA_BYTE);
 163         BYTEWISE_HANDLE = layout.varHandle(byte.class, sequenceElement());
 164 
 165         SOCKADDR_IN_SIZE = (int) SOCKADDR.select(sockaddr_in).byteSize();
 166         SOCKADDR_IN6_SIZE = (int) SOCKADDR.select(sockaddr_in6).byteSize();
 167 
 168         debug();
 169         // Verifies the handcrafted layout against the natively derived sizes and offsets
 170         if (VERIFY)
 171             verify();
 172     }
 173 
 174     private static void verify() {
 175         // sockaddr_in
 176         PathElement sockaddr_in = groupElement("sockaddr_in");
 177         assert SIZEOF_SOCKADDR4 == SOCKADDR_IN_SIZE : "SIZEOF_SOCKADDR [%d] != SOCKADDR_IN_SIZE [%d]".formatted(SIZEOF_SOCKADDR4, SOCKADDR_IN_SIZE);
 178         var offset = bitsToBytes(SOCKADDR.offset(sockaddr_in , groupElement("sin_port")));
 179         assert offset == OFFSET_SIN4_PORT : "OFFSET_SIN4_PORT [%d] != layout offset [%d]".formatted(OFFSET_SIN4_PORT, offset);
 180         offset = bitsToBytes(SOCKADDR.offset(sockaddr_in , groupElement("sin_addr")));
 181         assert offset == OFFSET_SIN4_ADDR : "OFFSET_SIN4_ADDR [%d] != layout offset [%d]".formatted(OFFSET_SIN4_ADDR, offset);
 182 
 183         //sockaddr_in6
 184         PathElement sockaddr_in6 = groupElement("sockaddr_in6");
 185         assert SIZEOF_SOCKADDR6 == SOCKADDR_IN6_SIZE : "SIZEOF_SOCKADDR6 [%d] != SOCKADDR_IN6_SIZE [%d]".formatted(SIZEOF_SOCKADDR6, SOCKADDR_IN6_SIZE);
 186         offset = bitsToBytes(SOCKADDR.offset(sockaddr_in6 , groupElement("sin6_port")));
 187         assert offset == OFFSET_SIN6_PORT : "OFFSET_SIN6_PORT [%d] != layout offset [%d]".formatted(OFFSET_SIN6_PORT, offset);
 188         offset = bitsToBytes(SOCKADDR.offset(sockaddr_in6 , groupElement("sin6_addr")));
 189         assert offset == OFFSET_SIN6_ADDR : "OFFSET_SIN6_ADDR [%d] != layout offset [%d]".formatted(OFFSET_SIN6_ADDR, offset);
 190         offset = bitsToBytes(SOCKADDR.offset(sockaddr_in6 , groupElement("sin6_flowinfo")));
 191         assert offset == OFFSET_SIN6_FLOWINFO : "OFFSET_SIN6_FLOWINFO [%d] != layout offset [%d]".formatted(OFFSET_SIN6_FLOWINFO, offset);
 192         offset = bitsToBytes(SOCKADDR.offset(sockaddr_in6 , groupElement("sin6_scope_id")));
 193         assert offset == OFFSET_SIN6_SCOPE_ID : "OFFSET_SIN6_SCOPE_ID [%d] != layout offset [%d]".formatted(OFFSET_SIN6_SCOPE_ID, offset);
 194     }
 195 
 196     private static void debug() {
 197         if (DEBUG) {
 198             System.out.println("SIZEOF_SOCKADDR4:" + SIZEOF_SOCKADDR4);
 199             System.out.println("SIZEOF_SOCKADDR6:" + SIZEOF_SOCKADDR6);
 200             System.out.println("SIZEOF_SOCKETADDRESS:" + SIZEOF_SOCKETADDRESS);
 201             System.out.println("SIZEOF_FAMILY:" + SIZEOF_FAMILY);
 202             System.out.println("OFFSET_FAMILY:" + OFFSET_FAMILY);
 203             System.out.println("OFFSET_SIN4_PORT:" + OFFSET_SIN4_PORT);
 204             System.out.println("OFFSET_SIN4_ADDR:" + OFFSET_SIN4_ADDR);
 205             System.out.println("OFFSET_SIN6_PORT:" + OFFSET_SIN6_PORT);
 206             System.out.println("OFFSET_SIN6_ADDR:" + OFFSET_SIN6_ADDR);
 207             System.out.println("OFFSET_SIN6_SCOPE_ID:" + OFFSET_SIN6_SCOPE_ID);
 208             System.out.println("OFFSET_SIN6_FLOWINFO:" + OFFSET_SIN6_FLOWINFO);
 209             System.out.println("SOCKADDR layout:" + SOCKADDR);
 210             System.out.println("SOCKADDR layout byteSize:" + SOCKADDR.byteSize());
 211             System.out.println("SOCKADDR layout byteAlignment:" + SOCKADDR.byteAlignment());
 212         }
 213     }
 214 
 215     private static long bitsToBytes(long value) {
 216         return value / 8;
 217     }
 218 
 219     private static byte byteValue(int value) {
 220         return (byte)value;
 221     }
 222 
 223     private static short shortValue(int value) {
 224         return (short)value;
 225     }
 226 
 227     private final MemorySegment segment;
 228     private final MemoryAddress memoryAddress;
 229     private final long rawAddress;
 230 
 231     long address() {
 232         return rawAddress;
 233     }
 234 
 235     NativeSocketAddress() {
 236         var initialSegment = MemorySegment.allocateNative(SOCKADDR);
 237         //segment = MemorySegment.ofNativeRestricted(initialSegment.baseAddress(), initialSegment.byteSize(), null, () -> initialSegment.close(), null);  // TODO: cannot close from another thread!
 238         segment = MemorySegment.ofNativeRestricted(initialSegment.baseAddress(), initialSegment.byteSize(), null, null, null);
 239         memoryAddress = segment.baseAddress();
 240         rawAddress = memoryAddress.toRawLongValue();
 241     }
 242 
 243     /**
 244      * Allocate an array of native socket addresses.
 245      */
 246     static NativeSocketAddress[] allocate(int count) {
 247         NativeSocketAddress[] array = new NativeSocketAddress[count];
 248         for (int i = 0; i < count; i++) {
 249             try {
 250                 array[i] = new NativeSocketAddress();
 251             } catch (OutOfMemoryError e) {
 252                 freeAll(array);
 253                 throw e;
 254             }
 255         }
 256         return array;
 257     }
 258 
 259     /**
 260      * Free all non-null native socket addresses in the given array.
 261      */
 262     static void freeAll(NativeSocketAddress[] array) {
 263         for (int i = 0; i < array.length; i++) {
 264             NativeSocketAddress sa = array[i];
 265             if (sa != null) {
 266                 sa.segment.close();
 267                 // #### underlying segment is not closed
 268             }
 269         }
 270     }
 271 
 272     /**
 273      * Encodes the given InetSocketAddress into this socket address.
 274      * @param protocolFamily protocol family
 275      * @param isa the InetSocketAddress to encode
 276      * @return the size of the socket address (sizeof sockaddr or sockaddr6)
 277      * @throws UnsupportedAddressTypeException if the address type is not supported
 278      */
 279     int encode(ProtocolFamily protocolFamily, InetSocketAddress isa) {
 280         if (protocolFamily == StandardProtocolFamily.INET) {
 281             // struct sockaddr_in
 282             InetAddress ia = isa.getAddress();
 283             if (!(ia instanceof Inet4Address))
 284                 throw new UnsupportedAddressTypeException();
 285             putFamily(AF_INET);
 286             putAddress(AF_INET, ia);
 287             putPort(AF_INET, isa.getPort());
 288             return SOCKADDR_IN_SIZE;
 289         } else {
 290             // struct sockaddr_in6
 291             putFamily(AF_INET6);
 292             putAddress(AF_INET6, isa.getAddress());
 293             putPort(AF_INET6, isa.getPort());
 294             SIN6_FLOWINFO_HANDLE.set(memoryAddress, 0);
 295             return SOCKADDR_IN6_SIZE;
 296         }
 297     }
 298 
 299     /**
 300      * Return an InetSocketAddress to represent the socket address in this buffer.
 301      * @throws SocketException if the socket address is not AF_INET or AF_INET6
 302      */
 303     InetSocketAddress decode() throws SocketException {
 304         int family = family();
 305         if (family != AF_INET && family != AF_INET6)
 306             throw new SocketException("Socket family not recognized");
 307         return new InetSocketAddress(address(family), port(family));
 308     }
 309 
 310     @Override
 311     public boolean equals(Object other) {
 312         if (!(other instanceof NativeSocketAddress)) {
 313             return false;
 314         }
 315         var that = (NativeSocketAddress)other;
 316 
 317         // #### this is byte-at-a-time, do we need to compare with a larger stride?
 318 
 319         final MemoryAddress thisAddress = this.memoryAddress;
 320         final MemoryAddress thatAddress = that.memoryAddress;
 321         for (int i = 0; i < SOCKADDR.byteSize(); i++) {
 322             byte b1 = (byte) BYTEWISE_HANDLE.get(thisAddress, i);
 323             byte b2 = (byte) BYTEWISE_HANDLE.get(thatAddress, i);
 324             if (b1 != b2)
 325                 return false;
 326         }
 327         return true;
 328     }
 329 
 330     @Override
 331     public int hashCode() {
 332         int h = 0;
 333         final MemoryAddress address = memoryAddress;
 334         for (int i = 0; i < SOCKADDR.byteSize(); i++) {
 335             h = 31 * h + (byte) BYTEWISE_HANDLE.get(address, i);
 336         }
 337         return h;
 338     }
 339 
 340     @Override
 341     public String toString() {
 342         int family = family();
 343         if (family == AF_INET || family == AF_INET6) {
 344             return ((family == AF_INET) ? "AF_INET" : "AF_INET6")
 345                     + ", address=" + address(family) + ", port=" + port(family);
 346         } else {
 347             return "<unknown>";
 348         }
 349     }
 350 
 351     /**
 352      * Return the value of the sa_family field.
 353      */
 354     private int family() {
 355         return (int) SA_FAMILY_HANDLE.get(memoryAddress);
 356     }
 357 
 358     /**
 359      * Stores the given family in the sa_family field.
 360      */
 361     private void putFamily(int family) {
 362         SA_FAMILY_HANDLE.set(memoryAddress, family);
 363     }
 364 
 365     /**
 366      * Return the value of the sin_port or sin6_port field. These fields are
 367      * stored in network order.
 368      */
 369     private int port(int family) {
 370         if (family == AF_INET)
 371             return (int) SIN_PORT_HANDLE.get(memoryAddress);
 372         else
 373             return (int) SIN6_PORT_HANDLE.get(memoryAddress);
 374     }
 375 
 376     /**
 377      * Stores the given port number in the sin_port or sin6_port field. The
 378      * port is stored in network order.
 379      */
 380     private void putPort(int family, int port) {
 381         if (family == AF_INET)
 382             SIN_PORT_HANDLE.set(memoryAddress, port);
 383         else
 384             SIN6_PORT_HANDLE.set(memoryAddress, port);
 385     }
 386 
 387     /**
 388      * Return an InetAddress to represent the value of the address in the
 389      * sin4_addr or sin6_addr fields. For IPv6 addresses, the Inet6Address is
 390      * created with the sin6_scope_id in the sockaddr_in6 structure.
 391      */
 392     private InetAddress address(int family) {
 393         final MemoryAddress address = memoryAddress;
 394         int scope_id;
 395         byte[] bytes;
 396 
 397         if (family == AF_INET) {
 398             bytes = new byte[4];
 399             for (int i = 0; i < 4; i++)
 400                 bytes[i] = (byte) SIN_ADDR_HANDLE.get(address, i);
 401             scope_id = 0;
 402         } else {
 403             bytes = new byte[16];
 404             for (int i = 0; i < 16; i++)
 405                 bytes[i] = (byte) SIN6_ADDR_HANDLE.get(address, i);
 406             scope_id = (int) SIN6_SCOPE_HANDLE.get(address);
 407         }
 408         try {
 409             if (scope_id == 0) {
 410                 return InetAddress.getByAddress(bytes);
 411             } else {
 412                 return Inet6Address.getByAddress(null, bytes, scope_id);
 413             }
 414         } catch (UnknownHostException e) {
 415             throw new InternalError(e);
 416         }
 417     }
 418 
 419     /**
 420      * Stores the given InetAddress in the sin_addr or sin6_addr/sin6_scope_id
 421      * fields. For IPv6 addresses, the sin6_addr will be popluated with an
 422      * IPv4-mapped IPv6 address when the given InetAddress is an IPv4 address.
 423      */
 424     private void putAddress(int family, InetAddress ia) {
 425         final MemoryAddress address = memoryAddress;
 426         if (family == AF_INET) {
 427             // IPv4 address
 428             putIPv4Address(address, (Inet4Address)ia);
 429         } else {
 430             int scope_id;
 431             if (ia instanceof Inet4Address) {
 432                 // IPv4-mapped IPv6 address
 433                 putMappedAddress(address, (Inet4Address)ia);
 434                 scope_id = 0;
 435             } else {
 436                 // IPv6 address
 437                 var inet6Address = (Inet6Address) ia;
 438                 putIPv6Address(address, inet6Address);
 439                 scope_id = inet6Address.getScopeId();
 440             }
 441             SIN6_SCOPE_HANDLE.set(address, scope_id);
 442         }
 443     }
 444 
 445     private static void putIPv4Address(MemoryAddress address, Inet4Address ia) {
 446         int ipAddress = JNINA.addressValue(ia);
 447         SIN_ADDR_HANDLE.set(address, 0, (byte) ((ipAddress >>> 24) & 0xFF));
 448         SIN_ADDR_HANDLE.set(address, 1, (byte) ((ipAddress >>> 16) & 0xFF));
 449         SIN_ADDR_HANDLE.set(address, 2, (byte) ((ipAddress >>>  8) & 0xFF));
 450         SIN_ADDR_HANDLE.set(address, 3, (byte) ((ipAddress >>>  0) & 0xFF));
 451     }
 452 
 453     private static void putMappedAddress(MemoryAddress address, Inet4Address ia) {
 454         int ipAddress = JNINA.addressValue(ia);
 455         for (int i=0; i< 10; i++)
 456             SIN6_ADDR_HANDLE.set(address, i, (byte) 0x00);
 457 
 458         SIN6_ADDR_HANDLE.set(address, 10, (byte) 0xFF);
 459         SIN6_ADDR_HANDLE.set(address, 11, (byte) 0xFF);
 460         SIN6_ADDR_HANDLE.set(address, 12, (byte) ((ipAddress >>> 24) & 0xFF));
 461         SIN6_ADDR_HANDLE.set(address, 13, (byte) ((ipAddress >>> 16) & 0xFF));
 462         SIN6_ADDR_HANDLE.set(address, 14, (byte) ((ipAddress >>>  8) & 0xFF));
 463         SIN6_ADDR_HANDLE.set(address, 15, (byte) ((ipAddress >>>  0) & 0xFF));
 464     }
 465 
 466     private static void putIPv6Address(MemoryAddress address, Inet6Address ia) {
 467         byte[] bytes = JNINA.addressBytes(ia);
 468         for (int i = 0; i < 16; i++)
 469             SIN6_ADDR_HANDLE.set(address, i, bytes[i]);
 470     }
 471 
 472     private static native int AFINET();
 473     private static native int AFINET6();
 474     private static native int sizeofSockAddr4();
 475     private static native int sizeofSockAddr6();
 476     private static native int sizeofFamily();
 477     private static native int offsetFamily();
 478     private static native int offsetSin4Port();
 479     private static native int offsetSin4Addr();
 480     private static native int offsetSin6Port();
 481     private static native int offsetSin6Addr();
 482     private static native int offsetSin6ScopeId();
 483     private static native int offsetSin6FlowInfo();
 484 
 485     static {
 486         IOUtil.load();
 487     }
 488 }