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