1 /* 2 * Copyright (c) 2009, 2013, 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.nio.ch.IOUtil; 38 import sun.nio.ch.Net; 39 import com.sun.nio.sctp.SctpSocketOption; 40 import static com.sun.nio.sctp.SctpStandardSocketOptions.*; 41 42 public class SctpNet { 43 private static final String osName = AccessController.doPrivileged( 44 (PrivilegedAction<String>) () -> System.getProperty("os.name")); 45 46 /* -- Miscellaneous SCTP utilities -- */ 47 IPv4MappedAddresses()48 private static boolean IPv4MappedAddresses() { 49 if ("SunOS".equals(osName)) { 50 /* Solaris supports IPv4Mapped Addresses with bindx */ 51 return true; 52 } /* else { //other OS/implementations */ 53 54 /* lksctp/linux requires Ipv4 addresses */ 55 return false; 56 } 57 throwAlreadyBoundException()58 static boolean throwAlreadyBoundException() throws IOException { 59 throw new AlreadyBoundException(); 60 } 61 listen(int fd, int backlog)62 static void listen(int fd, int backlog) throws IOException { 63 listen0(fd, backlog); 64 } 65 connect(int fd, InetAddress remote, int remotePort)66 static int connect(int fd, InetAddress remote, int remotePort) 67 throws IOException { 68 return connect0(fd, remote, remotePort); 69 } 70 close(int fd)71 static void close(int fd) throws IOException { 72 close0(fd); 73 } 74 preClose(int fd)75 static void preClose(int fd) throws IOException { 76 preClose0(fd); 77 } 78 79 /** 80 * @param oneToOne 81 * if {@code true} returns a one-to-one sctp socket, otherwise 82 * returns a one-to-many sctp socket 83 */ socket(boolean oneToOne)84 static FileDescriptor socket(boolean oneToOne) throws IOException { 85 int nativefd = socket0(oneToOne); 86 return IOUtil.newFD(nativefd); 87 } 88 bindx(int fd, InetAddress[] addrs, int port, boolean add)89 static void bindx(int fd, InetAddress[] addrs, int port, boolean add) 90 throws IOException { 91 bindx(fd, addrs, port, addrs.length, add, 92 IPv4MappedAddresses()); 93 } 94 getLocalAddresses(int fd)95 static Set<SocketAddress> getLocalAddresses(int fd) 96 throws IOException { 97 Set<SocketAddress> set = null; 98 SocketAddress[] saa = getLocalAddresses0(fd); 99 100 if (saa != null) { 101 set = getRevealedLocalAddressSet(saa); 102 } 103 104 return set; 105 } 106 getRevealedLocalAddressSet( SocketAddress[] saa)107 private static Set<SocketAddress> getRevealedLocalAddressSet( 108 SocketAddress[] saa) 109 { 110 SecurityManager sm = System.getSecurityManager(); 111 Set<SocketAddress> set = new HashSet<>(saa.length); 112 for (SocketAddress sa : saa) { 113 set.add(getRevealedLocalAddress(sa, sm)); 114 } 115 return set; 116 } 117 getRevealedLocalAddress(SocketAddress sa, SecurityManager sm)118 private static SocketAddress getRevealedLocalAddress(SocketAddress sa, 119 SecurityManager sm) 120 { 121 if (sm == null || sa == null) 122 return sa; 123 InetSocketAddress ia = (InetSocketAddress)sa; 124 try{ 125 sm.checkConnect(ia.getAddress().getHostAddress(), -1); 126 // Security check passed 127 } catch (SecurityException e) { 128 // Return loopback address 129 return new InetSocketAddress(InetAddress.getLoopbackAddress(), 130 ia.getPort()); 131 } 132 return sa; 133 } 134 getRemoteAddresses(int fd, int assocId)135 static Set<SocketAddress> getRemoteAddresses(int fd, int assocId) 136 throws IOException { 137 HashSet<SocketAddress> set = null; 138 SocketAddress[] saa = getRemoteAddresses0(fd, assocId); 139 140 if (saa != null) { 141 set = new HashSet<SocketAddress>(saa.length); 142 for (SocketAddress sa : saa) 143 set.add(sa); 144 } 145 146 return set; 147 } 148 setSocketOption(int fd, SctpSocketOption<T> name, T value, int assocId)149 static <T> void setSocketOption(int fd, 150 SctpSocketOption<T> name, 151 T value, 152 int assocId) 153 throws IOException { 154 if (value == null) 155 throw new IllegalArgumentException("Invalid option value"); 156 157 if (name.equals(SCTP_INIT_MAXSTREAMS)) { 158 InitMaxStreams maxStreamValue = (InitMaxStreams)value; 159 SctpNet.setInitMsgOption0(fd, 160 maxStreamValue.maxInStreams(), maxStreamValue.maxOutStreams()); 161 } else if (name.equals(SCTP_PRIMARY_ADDR) || 162 name.equals(SCTP_SET_PEER_PRIMARY_ADDR)) { 163 164 SocketAddress addr = (SocketAddress) value; 165 if (addr == null) 166 throw new IllegalArgumentException("Invalid option value"); 167 168 Net.checkAddress(addr); 169 InetSocketAddress netAddr = (InetSocketAddress)addr; 170 171 if (name.equals(SCTP_PRIMARY_ADDR)) { 172 setPrimAddrOption0(fd, 173 assocId, 174 netAddr.getAddress(), 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 getSocketOption(int fd, SctpSocketOption<?> name, int assocId)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 setIntOption(int fd, SctpSocketOption<?> name, Object value)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 getIntOption(int fd, SctpSocketOption<?> name)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 shutdown(int fd, int assocId)281 static void shutdown(int fd, int assocId) 282 throws IOException { 283 shutdown0(fd, assocId); 284 } 285 branch(int fd, int assocId)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 */ socket0(boolean oneToOne)292 static native int socket0(boolean oneToOne) throws IOException; 293 listen0(int fd, int backlog)294 static native void listen0(int fd, int backlog) throws IOException; 295 connect0(int fd, InetAddress remote, int remotePort)296 static native int connect0(int fd, InetAddress remote, int remotePort) 297 throws IOException; 298 close0(int fd)299 static native void close0(int fd) throws IOException; 300 preClose0(int fd)301 static native void preClose0(int fd) throws IOException; 302 bindx(int fd, InetAddress[] addrs, int port, int length, boolean add, boolean preferIPv6)303 static native void bindx(int fd, InetAddress[] addrs, int port, int length, 304 boolean add, boolean preferIPv6) throws IOException; 305 getIntOption0(int fd, int opt)306 static native int getIntOption0(int fd, int opt) throws IOException; 307 setIntOption0(int fd, int opt, int arg)308 static native void setIntOption0(int fd, int opt, int arg) 309 throws IOException; 310 getLocalAddresses0(int fd)311 static native SocketAddress[] getLocalAddresses0(int fd) throws IOException; 312 getRemoteAddresses0(int fd, int assocId)313 static native SocketAddress[] getRemoteAddresses0(int fd, int assocId) 314 throws IOException; 315 branch0(int fd, int assocId)316 static native int branch0(int fd, int assocId) throws IOException; 317 setPrimAddrOption0(int fd, int assocId, InetAddress ia, int port)318 static native void setPrimAddrOption0(int fd, int assocId, InetAddress ia, 319 int port) throws IOException; 320 setPeerPrimAddrOption0(int fd, int assocId, InetAddress ia, int port, boolean preferIPv6)321 static native void setPeerPrimAddrOption0(int fd, int assocId, 322 InetAddress ia, int port, boolean preferIPv6) throws IOException; 323 getPrimAddrOption0(int fd, int assocId)324 static native SocketAddress getPrimAddrOption0(int fd, int assocId) 325 throws IOException; 326 327 /* retVals [0] maxInStreams, [1] maxOutStreams */ getInitMsgOption0(int fd, int[] retVals)328 static native void getInitMsgOption0(int fd, int[] retVals) throws IOException; 329 setInitMsgOption0(int fd, int arg1, int arg2)330 static native void setInitMsgOption0(int fd, int arg1, int arg2) 331 throws IOException; 332 shutdown0(int fd, int assocId)333 static native void shutdown0(int fd, int assocId); 334 init()335 static native void init(); 336 337 static { init()338 init(); 339 } 340 } 341 342