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.lang.invoke.VarHandle;
 29 import java.net.Inet4Address;
 30 import java.net.Inet6Address;
 31 import java.net.InetAddress;
 32 import java.net.InetSocketAddress;
 33 import java.net.ProtocolFamily;
 34 import java.net.SocketException;
 35 import java.net.StandardProtocolFamily;
 36 import java.net.UnknownHostException;
 37 import java.nio.channels.UnsupportedAddressTypeException;
 38 import jdk.incubator.foreign.MemoryAddress;
 39 import jdk.incubator.foreign.MemoryHandles;
 40 import jdk.incubator.foreign.MemoryLayouts;
 41 import jdk.incubator.foreign.MemorySegment;
 42 import jdk.internal.access.JavaNetInetAddressAccess;
 43 import jdk.internal.access.SharedSecrets;
 44 import jdk.internal.sys.in6_h;
 45 import jdk.internal.sys.in_h;
 46 
 47 /**
 48  * A native socket address that is the union of struct sockaddr, struct sockaddr_in,
 49  * and struct sockaddr_in6.
 50  *
 51  * This class is not thread safe.
 52  */
 53 final class NativeSocketAddress {
 54     private static final JavaNetInetAddressAccess JNINA = SharedSecrets.getJavaNetInetAddressAccess();
 55 
 56     private static final int AF_INET  = AFINET();
 57     private static final int AF_INET6 = AFINET6();
 58 
 59     final long address() {
 60         return address.toRawLongValue();
 61     }
 62 
 63     private final MemorySegment segment;
 64     private final MemoryAddress address;
 65 
 66     private NativeSocketAddress() {
 67         segment = allocateNative(in6_h.Csockaddr_in6.sizeof());
 68         segment.fill((byte) 0x00);
 69         address = segment.baseAddress();
 70     }
 71 
 72     /**
 73      * Allocate an array of native socket addresses.
 74      */
 75     static final NativeSocketAddress[] allocate(int count) {
 76         NativeSocketAddress[] array = new NativeSocketAddress[count];
 77         for (int i = 0; i < count; i++) {
 78             try {
 79                 array[i] = new NativeSocketAddress();
 80             } catch (OutOfMemoryError e) {
 81                 freeAll(array);
 82                 throw e;
 83             }
 84         }
 85         return array;
 86     }
 87 
 88     /**
 89      * Free all non-null native socket addresses in the given array.
 90      */
 91     static final void freeAll(NativeSocketAddress[] array) {
 92         for (int i = 0; i < array.length; i++) {
 93             NativeSocketAddress sa = array[i];
 94             if (sa != null) {
 95                 sa.segment.close();
 96             }
 97         }
 98     }
 99 
100     private static final VarHandle sin_family = MemoryHandles.asUnsigned(in_h.Csockaddr_in.sin_family$VH(), int.class);
101     private static final VarHandle sin6_family = MemoryHandles.asUnsigned(in6_h.Csockaddr_in6.sin6_family$VH(), int.class);
102 
103     /**
104      * Encodes the given InetSocketAddress into this socket address.
105      * @param protocolFamily protocol family
106      * @param isa the InetSocketAddress to encode
107      * @return the size of the socket address (sizeof sockaddr or sockaddr6)
108      * @throws UnsupportedAddressTypeException if the address type is not supported
109      */
110     final int encode(ProtocolFamily protocolFamily, InetSocketAddress isa) {
111         if (protocolFamily == StandardProtocolFamily.INET) {
112             // struct sockaddr
113             InetAddress ia = isa.getAddress();
114             if (!(ia instanceof Inet4Address))
115                 throw new UnsupportedAddressTypeException();
116             sin_family.set(address, AF_INET);
117             in_h.Csockaddr_in.sin_port$set(address, (short) isa.getPort());
118             in_h.Cin_addr.s_addr$set(in_h.Csockaddr_in.sin_addr$addr(address),
119                                      JNINA.addressValue((Inet4Address) ia));
120             return (int) in_h.Csockaddr_in.sizeof();
121         } else {
122             // struct sockaddr6
123             sin6_family.set(address, AF_INET6);
124             in6_h.Csockaddr_in6.sin6_port$set(address, (short) isa.getPort());
125             in6_h.Csockaddr_in6.sin6_flowinfo$set(address, 0);
126             setSin6Address(in6_h.Csockaddr_in6.sin6_addr$addr(address).segment(), isa.getAddress());
127             in6_h.Csockaddr_in6.sin6_scope_id$set(address, scopeidFromAddress(isa.getAddress()));
128             return (int) in6_h.Csockaddr_in6.sizeof();
129         }
130     }
131 
132     /**
133      * Return an InetSocketAddress to represent the socket address in this buffer.
134      * @throws SocketException if the socket address is not AF_INET or AF_INET6
135      */
136     final InetSocketAddress decode() throws SocketException {
137         int family = (int) sin_family.get(address);
138         if (family != AF_INET && family != AF_INET6)
139             throw new SocketException("Socket family not recognized");
140         return new InetSocketAddress(address(family), port(family));
141     }
142 
143     @Override
144     public boolean equals(Object other) {
145         if (!(other instanceof NativeSocketAddress))
146             return false;
147         NativeSocketAddress that = (NativeSocketAddress) other;
148         return this.segment.mismatch(that.segment) == -1;
149     }
150 
151     private static final VarHandle BYTE_HANDLE = MemoryLayouts.JAVA_BYTE.varHandle(byte.class);
152 
153     @Override
154     public int hashCode() {
155         int h = 0;
156         final MemoryAddress addr = segment.baseAddress();
157         for (int i = 0 ; i < segment.byteSize() ; i++) {
158             h = 31 * h + (byte) BYTE_HANDLE.get(addr.addOffset(i));
159         }
160         return h;
161     }
162 
163     @Override
164     public String toString() {
165         int family = in_h.Csockaddr_in.sin_family$get(address);
166         if (family == AF_INET || family == AF_INET6) {
167             return ((family == AF_INET) ? "AF_INET" : "AF_INET6")
168                     + ", address=" + address(family) + ", port=" + port(family);
169         } else {
170             return "<unknown>";
171         }
172     }
173 
174     private static final VarHandle sin_port = MemoryHandles.asUnsigned(in_h.Csockaddr_in.sin_port$VH(), int.class);
175     private static final VarHandle sin6_port = MemoryHandles.asUnsigned(in6_h.Csockaddr_in6.sin6_port$VH(), int.class);
176 
177     /**
178      * Return the value of the sin_port or sin6_port field. These fields are
179      * stored in network order.
180      */
181     private final int port(int family) {
182         if (family == AF_INET) {
183             return (int) sin_port.get(address);
184         } else {
185             return (int) sin6_port.get(address);
186         }
187     }
188 
189     /**
190      * Return an InetAddress to represent the value of the address in the
191      * sin4_addr or sin6_addr fields. For IPv6 addresses, the Inet6Address is
192      * created with the sin6_scope_id in the sockaddr_in6 structure.
193      */
194     private final InetAddress address(int family) {
195         if (family == AF_INET) {
196             return JNINA.getByAddress(
197                     in_h.Cin_addr.s_addr$get(in_h.Csockaddr_in.sin_addr$addr(address)));
198         } else {
199             return JNINA.getByAddress(
200                     in6_h.Cin6_addr.__u6_addr$addr(in6_h.Csockaddr_in6.sin6_addr$addr(address)).segment().toByteArray(),
201                     in6_h.Csockaddr_in6.sin6_scope_id$get(address)
202             );
203         }
204     }
205 
206     private static final VarHandle ADDR_HANDLE = MemoryHandles.withOffset(MemoryLayouts.BITS_32_BE.varHandle(int.class), 12);
207     private static final void setSin6Address(MemorySegment seg, InetAddress ia) {
208         if (ia instanceof Inet4Address) { // IPv4-mapped IPv6 address
209             seg.fill((byte) 0x00).asSlice(10, 2).fill((byte) 0xFF);
210             ADDR_HANDLE.set(seg.baseAddress(), JNINA.addressValue((Inet4Address) ia));
211         } else {
212             seg.copyFrom(MemorySegment.ofArray(JNINA.addressBytes((Inet6Address) ia)));
213         }
214     }
215 
216     private static final int scopeidFromAddress(InetAddress ia) {
217         if (ia instanceof Inet4Address)
218             return 0;
219         return ((Inet6Address) ia).getScopeId();
220     }
221 
222     private static final jdk.internal.misc.Unsafe UNSAFE = jdk.internal.misc.Unsafe.getUnsafe();
223     private static final MemorySegment allocateNative(long byteSize) {
224         long base = UNSAFE.allocateMemory(byteSize);
225         return jdk.internal.foreign.NativeMemorySegmentImpl.makeNativeSegmentUnchecked(
226                 MemoryAddress.ofLong(base),
227                 byteSize,
228                 null,
229                 () -> UNSAFE.freeMemory(base),
230                 null);
231     }
232 
233     private static native int AFINET();
234     private static native int AFINET6();
235 
236     static {
237         IOUtil.load();
238     }
239 }