| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
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;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
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();  | 
 | 
 | 
 | 
      | 
 | 
    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;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    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;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    static void freeAll(NativeSocketAddress[] array) { | 
 | 
        for (int i = 0; i < array.length; i++) { | 
 | 
            NativeSocketAddress sa = array[i];  | 
 | 
            if (sa != null) { | 
 | 
                UNSAFE.freeMemory(sa.address);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    int encode(ProtocolFamily protocolFamily, InetSocketAddress isa) { | 
 | 
        if (protocolFamily == StandardProtocolFamily.INET) { | 
 | 
              | 
 | 
            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 { | 
 | 
              | 
 | 
            putFamily(AF_INET6);  | 
 | 
            putAddress(AF_INET6, isa.getAddress());  | 
 | 
            putPort(AF_INET6, isa.getPort());  | 
 | 
            UNSAFE.putInt(address + OFFSET_SIN6_FLOWINFO, 0);  | 
 | 
            return SIZEOF_SOCKADDR6;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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));  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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>";  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    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();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    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();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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 void putAddress(int family, InetAddress ia) { | 
 | 
        if (family == AF_INET) { | 
 | 
              | 
 | 
            putAddress(address + OFFSET_SIN4_ADDR, (Inet4Address) ia);  | 
 | 
        } else { | 
 | 
            int scope_id;  | 
 | 
            if (ia instanceof Inet4Address) { | 
 | 
                  | 
 | 
                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 { | 
 | 
                  | 
 | 
                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);  | 
 | 
          | 
 | 
        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();  | 
 | 
    }  | 
 | 
}  |