1 /*
   2  * Copyright (c) 2019, 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.net.Inet4Address;
  29 import java.net.Inet6Address;
  30 import java.net.InetAddress;
  31 import java.net.InetSocketAddress;
  32 import java.net.ProtocolFamily;
  33 import java.net.SocketException;
  34 import java.net.StandardProtocolFamily;
  35 import java.net.UnknownHostException;
  36 import java.nio.channels.UnsupportedAddressTypeException;
  37 
  38 import jdk.internal.access.JavaNetInetAddressAccess;
  39 import jdk.internal.access.SharedSecrets;
  40 import jdk.internal.misc.Unsafe;
  41 import jdk.internal.util.ArraysSupport;
  42 
  43 /**
  44  * A native socket address that is the union of struct sockaddr, struct sockaddr_in,
  45  * and struct sockaddr_in6.
  46  *
  47  * This class is not thread safe.
  48  */
  49 class NativeSocketAddress {
  50     private static final JavaNetInetAddressAccess JNINA = SharedSecrets.getJavaNetInetAddressAccess();
  51     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
  52     private static final long ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
  53 
  54     private static final int AF_INET  = AFINET();
  55     private static final int AF_INET6 = AFINET6();
  56 
  57     private static final int SIZEOF_SOCKADDR4     = sizeofSockAddr4();
  58     private static final int SIZEOF_SOCKADDR6     = sizeofSockAddr6();
  59     private static final int SIZEOF_SOCKETADDRESS = Math.max(SIZEOF_SOCKADDR4, SIZEOF_SOCKADDR6);
  60     private static final int SIZEOF_FAMILY        = sizeofFamily();
  61     private static final int OFFSET_FAMILY        = offsetFamily();
  62     private static final int OFFSET_SIN4_PORT     = offsetSin4Port();
  63     private static final int OFFSET_SIN4_ADDR     = offsetSin4Addr();
  64     private static final int OFFSET_SIN6_PORT     = offsetSin6Port();
  65     private static final int OFFSET_SIN6_ADDR     = offsetSin6Addr();
  66     private static final int OFFSET_SIN6_SCOPE_ID = offsetSin6ScopeId();
  67     private static final int OFFSET_SIN6_FLOWINFO = offsetSin6FlowInfo();
  68 
  69     // SOCKETADDRESS
  70     private final long address;
  71 
  72     long address() {
  73         return address;
  74     }
  75 
  76     NativeSocketAddress() {
  77         long base = UNSAFE.allocateMemory(SIZEOF_SOCKETADDRESS);
  78         UNSAFE.setMemory(base, SIZEOF_SOCKETADDRESS, (byte) 0);
  79         this.address = base;
  80     }
  81 
  82     /**
  83      * Allocate an array of native socket addresses.
  84      */
  85     static NativeSocketAddress[] allocate(int count) {
  86         NativeSocketAddress[] array = new NativeSocketAddress[count];
  87         for (int i = 0; i < count; i++) {
  88             try {
  89                 array[i] = new NativeSocketAddress();
  90             } catch (OutOfMemoryError e) {
  91                 freeAll(array);
  92                 throw e;
  93             }
  94         }
  95         return array;
  96     }
  97 
  98     /**
  99      * Free all non-null native socket addresses in the given array.
 100      */
 101     static void freeAll(NativeSocketAddress[] array) {
 102         for (int i = 0; i < array.length; i++) {
 103             NativeSocketAddress sa = array[i];
 104             if (sa != null) {
 105                 UNSAFE.freeMemory(sa.address);
 106             }
 107         }
 108     }
 109 
 110     /**
 111      * Encodes the given InetSocketAddress into this socket address.
 112      * @param protocolFamily protocol family
 113      * @param isa the InetSocketAddress to encode
 114      * @return the size of the socket address (sizeof sockaddr or sockaddr6)
 115      * @throws UnsupportedAddressTypeException if the address type is not supported
 116      */
 117     int encode(ProtocolFamily protocolFamily, InetSocketAddress isa) {
 118         if (protocolFamily == StandardProtocolFamily.INET) {
 119             // struct sockaddr
 120             InetAddress ia = isa.getAddress();
 121             if (!(ia instanceof Inet4Address))
 122                 throw new UnsupportedAddressTypeException();
 123             putFamily(AF_INET);
 124             putAddress(AF_INET, ia);
 125             putPort(AF_INET, isa.getPort());
 126             return SIZEOF_SOCKADDR4;
 127         } else {
 128             // struct sockaddr6
 129             putFamily(AF_INET6);
 130             putAddress(AF_INET6, isa.getAddress());
 131             putPort(AF_INET6, isa.getPort());
 132             UNSAFE.putInt(address + OFFSET_SIN6_FLOWINFO, 0);
 133             return SIZEOF_SOCKADDR6;
 134         }
 135     }
 136 
 137     /**
 138      * Return an InetSocketAddress to represent the socket address in this buffer.
 139      * @throws SocketException if the socket address is not AF_INET or AF_INET6
 140      */
 141     InetSocketAddress decode() throws SocketException {
 142         int family = family();
 143         if (family != AF_INET && family != AF_INET6)
 144             throw new SocketException("Socket family not recognized");
 145         return new InetSocketAddress(address(family), port(family));
 146     }
 147 
 148     /**
 149      * Find a mismatch between this and another socket address
 150      * @return the byte offset of the first mismatch or -1 if no mismatch
 151      */
 152     private int mismatch(NativeSocketAddress other) {
 153         int i = ArraysSupport.vectorizedMismatch(null,
 154                 this.address,
 155                 null,
 156                 other.address,
 157                 SIZEOF_SOCKETADDRESS,
 158                 ArraysSupport.LOG2_ARRAY_BYTE_INDEX_SCALE);
 159         if (i >= 0)
 160             return i;
 161         i = SIZEOF_SOCKETADDRESS - ~i;
 162         for (; i < SIZEOF_SOCKETADDRESS; i++) {
 163             if (UNSAFE.getByte(this.address + i) != UNSAFE.getByte(other.address + i)) {
 164                 return i;
 165             }
 166         }
 167         return -1;
 168     }
 169 
 170     @Override
 171     public boolean equals(Object other) {
 172         if (other instanceof NativeSocketAddress) {
 173             return mismatch((NativeSocketAddress) other) < 0;
 174         } else {
 175             return false;
 176         }
 177     }
 178 
 179     @Override
 180     public int hashCode() {
 181         int h = 0;
 182         for (int offset = 0; offset < SIZEOF_SOCKETADDRESS; offset++) {
 183             h = 31 * h + UNSAFE.getByte(address + offset);
 184         }
 185         return h;
 186     }
 187 
 188     @Override
 189     public String toString() {
 190         int family = family();
 191         if (family == AF_INET || family == AF_INET6) {
 192             return ((family == AF_INET) ? "AF_INET" : "AF_INET6")
 193                     + ", address=" + address(family) + ", port=" + port(family);
 194         } else {
 195             return "<unknown>";
 196         }
 197     }
 198 
 199     /**
 200      * Return the value of the sa_family field.
 201      */
 202     private int family() {
 203         if (SIZEOF_FAMILY == 1) {
 204             return UNSAFE.getByte(address + OFFSET_FAMILY);
 205         } else if (SIZEOF_FAMILY == 2) {
 206             return UNSAFE.getShort(address + OFFSET_FAMILY);
 207         } else {
 208             throw new InternalError();
 209         }
 210     }
 211 
 212     /**
 213      * Stores the given family in the sa_family field.
 214      */
 215     private void putFamily(int family) {
 216         if (SIZEOF_FAMILY == 1) {
 217             UNSAFE.putByte(address + OFFSET_FAMILY, (byte) family);
 218         } else if (SIZEOF_FAMILY == 2) {
 219             UNSAFE.putShort(address + OFFSET_FAMILY, (short) family);
 220         } else {
 221             throw new InternalError();
 222         }
 223     }
 224 
 225     /**
 226      * Return the value of the sin_port or sin6_port field. These fields are
 227      * stored in network order.
 228      */
 229     private int port(int family) {
 230         byte b1, b2;
 231         if (family == AF_INET) {
 232             b1 = UNSAFE.getByte(address + OFFSET_SIN4_PORT);
 233             b2 = UNSAFE.getByte(address + OFFSET_SIN4_PORT + 1);
 234         } else {
 235             b1 = UNSAFE.getByte(address + OFFSET_SIN6_PORT);
 236             b2 = UNSAFE.getByte(address + OFFSET_SIN6_PORT + 1);
 237         }
 238         return (Byte.toUnsignedInt(b1) << 8) + Byte.toUnsignedInt(b2);
 239     }
 240 
 241     /**
 242      * Stores the given port number in the sin_port or sin6_port field. The
 243      * port is stored in network order.
 244      */
 245     private void putPort(int family, int port) {
 246         byte b1 = (byte) ((port >> 8) & 0xff);
 247         byte b2 = (byte) ((port >> 0) & 0xff);
 248         if (family == AF_INET) {
 249             UNSAFE.putByte(address + OFFSET_SIN4_PORT, b1);
 250             UNSAFE.putByte(address + OFFSET_SIN4_PORT + 1, b2);
 251         } else {
 252             UNSAFE.putByte(address + OFFSET_SIN6_PORT, b1);
 253             UNSAFE.putByte(address + OFFSET_SIN6_PORT + 1, b2);
 254         }
 255     }
 256 
 257     /**
 258      * Return an InetAddress to represent the value of the address in the
 259      * sin4_addr or sin6_addr fields. For IPv6 addresses, the Inet6Address is
 260      * created with the sin6_scope_id in the sockaddr_in6 structure.
 261      */
 262     private InetAddress address(int family) {
 263         int len;
 264         int offset;
 265         int scope_id;
 266         if (family == AF_INET) {
 267             len = 4;
 268             offset = OFFSET_SIN4_ADDR;
 269             scope_id = 0;
 270         } else {
 271             len = 16;
 272             offset = OFFSET_SIN6_ADDR;
 273             scope_id = UNSAFE.getInt(address + OFFSET_SIN6_SCOPE_ID);
 274         }
 275         byte[] bytes = new byte[len];
 276         UNSAFE.copyMemory(null, address + offset, bytes, ARRAY_BASE_OFFSET, len);
 277         try {
 278             if (scope_id == 0) {
 279                 return InetAddress.getByAddress(bytes);
 280             } else {
 281                 return Inet6Address.getByAddress(null, bytes, scope_id);
 282             }
 283         } catch (UnknownHostException e) {
 284             throw new InternalError(e);
 285         }
 286     }
 287 
 288     /**
 289      * Stores the given InetAddress in the sin_addr or sin6_addr/sin6_scope_id
 290      * fields. For IPv6 addresses, the sin6_addr will be popluated with an
 291      * IPv4-mapped IPv6 address when the given InetAddress is an IPv4 address.
 292      */
 293     private void putAddress(int family, InetAddress ia) {
 294         if (family == AF_INET) {
 295             // IPv4 address
 296             putAddress(address + OFFSET_SIN4_ADDR, (Inet4Address) ia);
 297         } else {
 298             int scope_id;
 299             if (ia instanceof Inet4Address) {
 300                 // IPv4-mapped IPv6 address
 301                 UNSAFE.setMemory(address + OFFSET_SIN6_ADDR, 10, (byte) 0);
 302                 UNSAFE.putByte(address + OFFSET_SIN6_ADDR + 10, (byte) 0xff);
 303                 UNSAFE.putByte(address + OFFSET_SIN6_ADDR + 11, (byte) 0xff);
 304                 putAddress(address + OFFSET_SIN6_ADDR + 12, (Inet4Address) ia);
 305                 scope_id = 0;
 306             } else {
 307                 // IPv6 address
 308                 var inet6Address = (Inet6Address) ia;
 309                 putAddress(address + OFFSET_SIN6_ADDR, inet6Address);
 310                 scope_id = inet6Address.getScopeId();
 311             }
 312             UNSAFE.putInt(address + OFFSET_SIN6_SCOPE_ID, scope_id);
 313         }
 314     }
 315 
 316     private static void putAddress(long address, Inet4Address ia) {
 317         int ipAddress = JNINA.addressValue(ia);
 318         // network order
 319         UNSAFE.putByte(address + 0, (byte) ((ipAddress >>> 24) & 0xFF));
 320         UNSAFE.putByte(address + 1, (byte) ((ipAddress >>> 16) & 0xFF));
 321         UNSAFE.putByte(address + 2, (byte) ((ipAddress >>> 8) & 0xFF));
 322         UNSAFE.putByte(address + 3, (byte) (ipAddress & 0xFF));
 323     }
 324 
 325     private static void putAddress(long address, Inet6Address ia) {
 326         byte[] bytes = JNINA.addressBytes(ia);
 327         UNSAFE.copyMemory(bytes, ARRAY_BASE_OFFSET, null, address, 16);
 328     }
 329 
 330     private static native int AFINET();
 331     private static native int AFINET6();
 332     private static native int sizeofSockAddr4();
 333     private static native int sizeofSockAddr6();
 334     private static native int sizeofFamily();
 335     private static native int offsetFamily();
 336     private static native int offsetSin4Port();
 337     private static native int offsetSin4Addr();
 338     private static native int offsetSin6Port();
 339     private static native int offsetSin6Addr();
 340     private static native int offsetSin6ScopeId();
 341     private static native int offsetSin6FlowInfo();
 342 
 343     static {
 344         IOUtil.load();
 345     }
 346 }