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