1 /* 2 * Copyright (c) 2009, 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 package sun.nio.ch.sctp; 26 27 import java.io.FileDescriptor; 28 import java.io.IOException; 29 import java.net.InetAddress; 30 import java.net.InetSocketAddress; 31 import java.net.SocketAddress; 32 import java.nio.channels.AlreadyBoundException; 33 import java.util.Set; 34 import java.util.HashSet; 35 import java.security.AccessController; 36 import java.security.PrivilegedAction; 37 import sun.net.util.IPAddressUtil; 38 import sun.nio.ch.IOUtil; 39 import sun.nio.ch.Net; 40 import com.sun.nio.sctp.SctpSocketOption; 41 import static com.sun.nio.sctp.SctpStandardSocketOptions.*; 42 43 public class SctpNet { 44 private static final String osName = AccessController.doPrivileged( 45 (PrivilegedAction<String>) () -> System.getProperty("os.name")); 46 47 /* -- Miscellaneous SCTP utilities -- */ 48 49 private static boolean IPv4MappedAddresses() { 50 /* lksctp/linux requires Ipv4 addresses */ 51 return false; 52 } 53 54 static boolean throwAlreadyBoundException() throws IOException { 55 throw new AlreadyBoundException(); 56 } 57 58 static void listen(int fd, int backlog) throws IOException { 59 listen0(fd, backlog); 60 } 61 62 static int connect(int fd, InetAddress remote, int remotePort) 63 throws IOException { 64 return connect0(fd, remote, remotePort); 65 } 66 67 static void close(int fd) throws IOException { 68 close0(fd); 69 } 70 71 static void preClose(int fd) throws IOException { 72 preClose0(fd); 73 } 74 75 /** 76 * @param oneToOne 77 * if {@code true} returns a one-to-one sctp socket, otherwise 78 * returns a one-to-many sctp socket 79 */ 80 static FileDescriptor socket(boolean oneToOne) throws IOException { 81 int nativefd = socket0(oneToOne); 82 return IOUtil.newFD(nativefd); 83 } 84 85 static void bindx(int fd, InetAddress[] addrs, int port, boolean add) 86 throws IOException { 87 bindx(fd, addrs, port, addrs.length, add, 88 IPv4MappedAddresses()); 89 } 90 91 static Set<SocketAddress> getLocalAddresses(int fd) 92 throws IOException { 93 Set<SocketAddress> set = null; 94 SocketAddress[] saa = getLocalAddresses0(fd); 95 96 if (saa != null) { 97 set = getRevealedLocalAddressSet(saa); 98 } 99 100 return set; 101 } 102 103 private static Set<SocketAddress> getRevealedLocalAddressSet( 104 SocketAddress[] saa) 105 { 106 SecurityManager sm = System.getSecurityManager(); 107 Set<SocketAddress> set = new HashSet<>(saa.length); 108 for (SocketAddress sa : saa) { 109 set.add(getRevealedLocalAddress(sa, sm)); 110 } 111 return set; 112 } 113 114 private static SocketAddress getRevealedLocalAddress(SocketAddress sa, 115 SecurityManager sm) 116 { 117 if (sm == null || sa == null) 118 return sa; 119 InetSocketAddress ia = (InetSocketAddress)sa; 120 try{ 121 sm.checkConnect(ia.getAddress().getHostAddress(), -1); 122 // Security check passed 123 } catch (SecurityException e) { 124 // Return loopback address 125 return new InetSocketAddress(InetAddress.getLoopbackAddress(), 126 ia.getPort()); 127 } 128 return sa; 129 } 130 131 static Set<SocketAddress> getRemoteAddresses(int fd, int assocId) 132 throws IOException { 133 HashSet<SocketAddress> set = null; 134 SocketAddress[] saa = getRemoteAddresses0(fd, assocId); 135 136 if (saa != null) { 137 set = new HashSet<SocketAddress>(saa.length); 138 for (SocketAddress sa : saa) 139 set.add(sa); 140 } 141 142 return set; 143 } 144 145 static <T> void setSocketOption(int fd, 146 SctpSocketOption<T> name, 147 T value, 148 int assocId) 149 throws IOException { 150 if (value == null) 151 throw new IllegalArgumentException("Invalid option value"); 152 153 if (name.equals(SCTP_INIT_MAXSTREAMS)) { 154 InitMaxStreams maxStreamValue = (InitMaxStreams)value; 155 SctpNet.setInitMsgOption0(fd, 156 maxStreamValue.maxInStreams(), maxStreamValue.maxOutStreams()); 157 } else if (name.equals(SCTP_PRIMARY_ADDR) || 158 name.equals(SCTP_SET_PEER_PRIMARY_ADDR)) { 159 160 SocketAddress addr = (SocketAddress) value; 161 if (addr == null) 162 throw new IllegalArgumentException("Invalid option value"); 163 164 Net.checkAddress(addr); 165 InetSocketAddress netAddr = (InetSocketAddress)addr; 166 167 if (name.equals(SCTP_PRIMARY_ADDR)) { 168 InetAddress inetAddress = netAddr.getAddress(); 169 if (inetAddress.isLinkLocalAddress()) { 170 inetAddress = IPAddressUtil.toScopedAddress(inetAddress); 171 } 172 setPrimAddrOption0(fd, 173 assocId, 174 inetAddress, 175 netAddr.getPort()); 176 } else { 177 setPeerPrimAddrOption0(fd, 178 assocId, 179 netAddr.getAddress(), 180 netAddr.getPort(), 181 IPv4MappedAddresses()); 182 } 183 } else if (name.equals(SCTP_DISABLE_FRAGMENTS) || 184 name.equals(SCTP_EXPLICIT_COMPLETE) || 185 name.equals(SCTP_FRAGMENT_INTERLEAVE) || 186 name.equals(SCTP_NODELAY) || 187 name.equals(SO_SNDBUF) || 188 name.equals(SO_RCVBUF) || 189 name.equals(SO_LINGER)) { 190 setIntOption(fd, name, value); 191 } else { 192 throw new AssertionError("Unknown socket option"); 193 } 194 } 195 196 static Object getSocketOption(int fd, SctpSocketOption<?> name, int assocId) 197 throws IOException { 198 if (name.equals(SCTP_SET_PEER_PRIMARY_ADDR)) { 199 throw new IllegalArgumentException( 200 "SCTP_SET_PEER_PRIMARY_ADDR cannot be retrieved"); 201 } else if (name.equals(SCTP_INIT_MAXSTREAMS)) { 202 /* container for holding maxIn/Out streams */ 203 int[] values = new int[2]; 204 SctpNet.getInitMsgOption0(fd, values); 205 return InitMaxStreams.create(values[0], values[1]); 206 } else if (name.equals(SCTP_PRIMARY_ADDR)) { 207 return getPrimAddrOption0(fd, assocId); 208 } else if (name.equals(SCTP_DISABLE_FRAGMENTS) || 209 name.equals(SCTP_EXPLICIT_COMPLETE) || 210 name.equals(SCTP_FRAGMENT_INTERLEAVE) || 211 name.equals(SCTP_NODELAY) || 212 name.equals(SO_SNDBUF) || 213 name.equals(SO_RCVBUF) || 214 name.equals(SO_LINGER)) { 215 return getIntOption(fd, name); 216 } else { 217 throw new AssertionError("Unknown socket option"); 218 } 219 } 220 221 static void setIntOption(int fd, SctpSocketOption<?> name, Object value) 222 throws IOException { 223 if (value == null) 224 throw new IllegalArgumentException("Invalid option value"); 225 226 Class<?> type = name.type(); 227 if (type != Integer.class && type != Boolean.class) 228 throw new AssertionError("Should not reach here"); 229 230 if (name == SO_RCVBUF || 231 name == SO_SNDBUF) 232 { 233 int i = ((Integer)value).intValue(); 234 if (i < 0) 235 throw new IllegalArgumentException( 236 "Invalid send/receive buffer size"); 237 } else if (name == SO_LINGER) { 238 int i = ((Integer)value).intValue(); 239 if (i < 0) 240 value = Integer.valueOf(-1); 241 if (i > 65535) 242 value = Integer.valueOf(65535); 243 } else if (name.equals(SCTP_FRAGMENT_INTERLEAVE)) { 244 int i = ((Integer)value).intValue(); 245 if (i < 0 || i > 2) 246 throw new IllegalArgumentException( 247 "Invalid value for SCTP_FRAGMENT_INTERLEAVE"); 248 } 249 250 int arg; 251 if (type == Integer.class) { 252 arg = ((Integer)value).intValue(); 253 } else { 254 boolean b = ((Boolean)value).booleanValue(); 255 arg = (b) ? 1 : 0; 256 } 257 258 setIntOption0(fd, ((SctpStdSocketOption)name).constValue(), arg); 259 } 260 261 static Object getIntOption(int fd, SctpSocketOption<?> name) 262 throws IOException { 263 Class<?> type = name.type(); 264 265 if (type != Integer.class && type != Boolean.class) 266 throw new AssertionError("Should not reach here"); 267 268 if (!(name instanceof SctpStdSocketOption)) 269 throw new AssertionError("Should not reach here"); 270 271 int value = getIntOption0(fd, 272 ((SctpStdSocketOption)name).constValue()); 273 274 if (type == Integer.class) { 275 return Integer.valueOf(value); 276 } else { 277 return (value == 0) ? Boolean.FALSE : Boolean.TRUE; 278 } 279 } 280 281 static void shutdown(int fd, int assocId) 282 throws IOException { 283 shutdown0(fd, assocId); 284 } 285 286 static FileDescriptor branch(int fd, int assocId) throws IOException { 287 int nativefd = branch0(fd, assocId); 288 return IOUtil.newFD(nativefd); 289 } 290 291 /* Native Methods */ 292 static native int socket0(boolean oneToOne) throws IOException; 293 294 static native void listen0(int fd, int backlog) throws IOException; 295 296 static native int connect0(int fd, InetAddress remote, int remotePort) 297 throws IOException; 298 299 static native void close0(int fd) throws IOException; 300 301 static native void preClose0(int fd) throws IOException; 302 303 static native void bindx(int fd, InetAddress[] addrs, int port, int length, 304 boolean add, boolean preferIPv6) throws IOException; 305 306 static native int getIntOption0(int fd, int opt) throws IOException; 307 308 static native void setIntOption0(int fd, int opt, int arg) 309 throws IOException; 310 311 static native SocketAddress[] getLocalAddresses0(int fd) throws IOException; 312 313 static native SocketAddress[] getRemoteAddresses0(int fd, int assocId) 314 throws IOException; 315 316 static native int branch0(int fd, int assocId) throws IOException; 317 318 static native void setPrimAddrOption0(int fd, int assocId, InetAddress ia, 319 int port) throws IOException; 320 321 static native void setPeerPrimAddrOption0(int fd, int assocId, 322 InetAddress ia, int port, boolean preferIPv6) throws IOException; 323 324 static native SocketAddress getPrimAddrOption0(int fd, int assocId) 325 throws IOException; 326 327 /* retVals [0] maxInStreams, [1] maxOutStreams */ 328 static native void getInitMsgOption0(int fd, int[] retVals) throws IOException; 329 330 static native void setInitMsgOption0(int fd, int arg1, int arg2) 331 throws IOException; 332 333 static native void shutdown0(int fd, int assocId); 334 335 static native void init(); 336 337 static { 338 IOUtil.load(); // loads nio & net native libraries 339 java.security.AccessController.doPrivileged( 340 new java.security.PrivilegedAction<Void>() { 341 public Void run() { 342 System.loadLibrary("sctp"); 343 return null; 344 } 345 }); 346 init(); 347 } 348 } 349