/
githubmirror
/
jdk22
Обзор
Документация
Войти
/
githubmirror
/
jdk22
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/java.base/share/classes/sun/nio/ch/NativeSocketAddress.java
346 строк
12 KB
Alan Bateman
8235193: (dc) Remove JNI overhead from DatagramChannel.send implementation
04 дек 2019, 19:37
04 дек 2019, 19:37
e7d68cd
Код
Авторство
О чём код?
/* * 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.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.internal.access.JavaNetInetAddressAccess; import jdk.internal.access.SharedSecrets; 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 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; } NativeSocketAddress() { long base = UNSAFE.allocateMemory(SIZEOF_SOCKETADDRESS); UNSAFE.setMemory(base, SIZEOF_SOCKETADDRESS, (byte) 0); this.address = base; } /** * Allocate an array of native socket addresses. */ static NativeSocketAddress[] allocate(int count) { NativeSocketAddress[] array = new NativeSocketAddress[count]; for (int i = 0; i < count; i++) { try { array[i] = new NativeSocketAddress(); } catch (OutOfMemoryError e) { freeAll(array); throw e; } } return array; } /** * Free all non-null native socket addresses in the given array. */ static void freeAll(NativeSocketAddress[] array) { for (int i = 0; i < array.length; i++) { NativeSocketAddress sa = array[i]; if (sa != null) { UNSAFE.freeMemory(sa.address); } } } /** * 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) { 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; } 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; } } /** * 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(); 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 { return false; } } @Override public int hashCode() { int h = 0; for (int offset = 0; offset < SIZEOF_SOCKETADDRESS; offset++) { h = 31 * h + UNSAFE.getByte(address + offset); } return h; } @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(); } } /** * 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(); } } /** * 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); 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); } } /** * 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); try { if (scope_id == 0) { return InetAddress.getByAddress(bytes); } else { return Inet6Address.getByAddress(null, bytes, scope_id); } } catch (UnknownHostException e) { throw new InternalError(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 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 void putAddress(long address, Inet6Address ia) { byte[] bytes = JNINA.addressBytes(ia); UNSAFE.copyMemory(bytes, ARRAY_BASE_OFFSET, null, address, 16); } 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(); } }