1096N/A/*
3261N/A * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
1096N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1096N/A *
1096N/A * This code is free software; you can redistribute it and/or modify it
1096N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
1096N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
1096N/A *
1096N/A * This code is distributed in the hope that it will be useful, but WITHOUT
1096N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1096N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1096N/A * version 2 for more details (a copy is included in the LICENSE file that
1096N/A * accompanied this code).
1096N/A *
1096N/A * You should have received a copy of the GNU General Public License version
1096N/A * 2 along with this work; if not, write to the Free Software Foundation,
1096N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1096N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
1096N/A */
1096N/Apackage sun.nio.ch;
1096N/A
1096N/Aimport java.io.FileDescriptor;
1096N/Aimport java.io.IOException;
1096N/Aimport java.net.InetAddress;
1096N/Aimport java.net.InetSocketAddress;
1096N/Aimport java.net.SocketAddress;
2084N/Aimport java.nio.channels.AlreadyBoundException;
1096N/Aimport java.util.Set;
1096N/Aimport java.util.HashSet;
1096N/Aimport java.security.AccessController;
1096N/Aimport sun.security.action.GetPropertyAction;
1096N/Aimport com.sun.nio.sctp.SctpSocketOption;
4216N/Aimport static com.sun.nio.sctp.SctpStandardSocketOptions.*;
6319N/Aimport java.security.PrivilegedExceptionAction;
1096N/A
1096N/Apublic class SctpNet {
1096N/A static final String osName = AccessController.doPrivileged(
1096N/A new GetPropertyAction("os.name"));
1096N/A
6319N/A // Value of jdk.net.revealLocalAddress
6319N/A private static boolean revealLocalAddress;
6319N/A
6319N/A // True if jdk.net.revealLocalAddress had been read
6319N/A private static volatile boolean propRevealLocalAddr;
6319N/A
1096N/A /* -- Miscellaneous SCTP utilities -- */
1096N/A
3230N/A private static boolean IPv4MappedAddresses() {
1096N/A if ("SunOS".equals(osName)) {
1096N/A /* Solaris supports IPv4Mapped Addresses with bindx */
1096N/A return true;
1096N/A } /* else { //other OS/implementations */
1096N/A
1096N/A /* lksctp/linux requires Ipv4 addresses */
1096N/A return false;
1096N/A }
1096N/A
2084N/A static boolean throwAlreadyBoundException() throws IOException {
2084N/A throw new AlreadyBoundException();
2084N/A }
2084N/A
2084N/A static void listen(int fd, int backlog) throws IOException {
2084N/A listen0(fd, backlog);
2084N/A }
2084N/A
2084N/A static int connect(int fd, InetAddress remote, int remotePort)
2084N/A throws IOException {
2084N/A return connect0(fd, remote, remotePort);
2084N/A }
2084N/A
2084N/A static void close(int fd) throws IOException {
2084N/A close0(fd);
2084N/A }
2084N/A
2084N/A static void preClose(int fd) throws IOException {
2084N/A preClose0(fd);
2084N/A }
2084N/A
1096N/A /**
2084N/A * @param oneToOne
1096N/A * if {@code true} returns a one-to-one sctp socket, otherwise
1096N/A * returns a one-to-many sctp socket
1096N/A */
1096N/A static FileDescriptor socket(boolean oneToOne) throws IOException {
1096N/A int nativefd = socket0(oneToOne);
1096N/A return IOUtil.newFD(nativefd);
1096N/A }
1096N/A
1096N/A static void bindx(int fd, InetAddress[] addrs, int port, boolean add)
1096N/A throws IOException {
1096N/A bindx(fd, addrs, port, addrs.length, add,
3230N/A IPv4MappedAddresses());
1096N/A }
1096N/A
1096N/A static Set<SocketAddress> getLocalAddresses(int fd)
1096N/A throws IOException {
6319N/A Set<SocketAddress> set = null;
1096N/A SocketAddress[] saa = getLocalAddresses0(fd);
1096N/A
1096N/A if (saa != null) {
6319N/A set = getRevealedLocalAddressSet(saa);
1096N/A }
1096N/A
1096N/A return set;
1096N/A }
1096N/A
6319N/A private static Set<SocketAddress> getRevealedLocalAddressSet(
6319N/A SocketAddress[] saa)
6319N/A {
6319N/A SecurityManager sm = System.getSecurityManager();
6319N/A Set<SocketAddress> set = new HashSet<>(saa.length);
6319N/A for (SocketAddress sa : saa) {
6319N/A set.add(getRevealedLocalAddress(sa, sm));
6319N/A }
6319N/A return set;
6319N/A }
6319N/A
6319N/A private static SocketAddress getRevealedLocalAddress(SocketAddress sa,
6319N/A SecurityManager sm)
6319N/A {
6319N/A if (sm == null || sa == null)
6319N/A return sa;
6319N/A InetSocketAddress ia = (InetSocketAddress)sa;
6319N/A if (!propRevealLocalAddr) {
6319N/A try {
6319N/A revealLocalAddress = Boolean.parseBoolean(
6319N/A AccessController.doPrivileged(
6319N/A new PrivilegedExceptionAction<String>() {
6319N/A public String run() {
6319N/A return System.getProperty(
6319N/A "jdk.net.revealLocalAddress");
6319N/A }
6319N/A }));
6319N/A
6319N/A } catch (Exception e) {
6319N/A // revealLocalAddress is false
6319N/A }
6319N/A propRevealLocalAddr = true;
6319N/A }
6319N/A if (!revealLocalAddress) {
6319N/A try{
6319N/A sm.checkConnect(ia.getAddress().getHostAddress(), -1);
6319N/A //Security check passed
6319N/A } catch (SecurityException e) {
6319N/A //Return loopback address
6319N/A return new InetSocketAddress(
6319N/A InetAddress.getLoopbackAddress(), ia.getPort());
6319N/A }
6319N/A }
6319N/A
6319N/A // Security check passed or jdk.net.revealLocalAddress set to true
6319N/A return sa;
6319N/A
6319N/A }
6319N/A
1096N/A static Set<SocketAddress> getRemoteAddresses(int fd, int assocId)
1096N/A throws IOException {
1096N/A HashSet<SocketAddress> set = null;
1096N/A SocketAddress[] saa = getRemoteAddresses0(fd, assocId);
1096N/A
1096N/A if (saa != null) {
1096N/A set = new HashSet<SocketAddress>(saa.length);
1096N/A for (SocketAddress sa : saa)
1096N/A set.add(sa);
1096N/A }
1096N/A
1096N/A return set;
1096N/A }
1096N/A
1096N/A static void setSocketOption(int fd,
1096N/A SctpSocketOption name,
1096N/A Object value,
1096N/A int assocId)
1096N/A throws IOException {
1096N/A if (value == null)
1096N/A throw new IllegalArgumentException("Invalid option value");
1096N/A
1096N/A Class<?> type = name.type();
1096N/A if (!type.isInstance(value))
1096N/A throw new IllegalArgumentException("Invalid option value");
1096N/A
1096N/A if (name.equals(SCTP_INIT_MAXSTREAMS)) {
1096N/A InitMaxStreams maxStreamValue = (InitMaxStreams)value;
1096N/A SctpNet.setInitMsgOption0(fd,
1096N/A maxStreamValue.maxInStreams(), maxStreamValue.maxOutStreams());
1096N/A } else if (name.equals(SCTP_PRIMARY_ADDR) ||
1096N/A name.equals(SCTP_SET_PEER_PRIMARY_ADDR)) {
1096N/A
1096N/A SocketAddress addr = (SocketAddress) value;
1096N/A if (addr == null)
1096N/A throw new IllegalArgumentException("Invalid option value");
1096N/A
1096N/A Net.checkAddress(addr);
1096N/A InetSocketAddress netAddr = (InetSocketAddress)addr;
1096N/A
1096N/A if (name.equals(SCTP_PRIMARY_ADDR)) {
3230N/A setPrimAddrOption0(fd,
3230N/A assocId,
3230N/A netAddr.getAddress(),
3230N/A netAddr.getPort());
1096N/A } else {
3230N/A setPeerPrimAddrOption0(fd,
3230N/A assocId,
3230N/A netAddr.getAddress(),
3230N/A netAddr.getPort(),
3230N/A IPv4MappedAddresses());
1096N/A }
1096N/A } else if (name.equals(SCTP_DISABLE_FRAGMENTS) ||
1096N/A name.equals(SCTP_EXPLICIT_COMPLETE) ||
1096N/A name.equals(SCTP_FRAGMENT_INTERLEAVE) ||
1096N/A name.equals(SCTP_NODELAY) ||
1096N/A name.equals(SO_SNDBUF) ||
1096N/A name.equals(SO_RCVBUF) ||
1096N/A name.equals(SO_LINGER)) {
1096N/A setIntOption(fd, name, value);
1096N/A } else {
1096N/A throw new AssertionError("Unknown socket option");
1096N/A }
1096N/A }
1096N/A
1096N/A static Object getSocketOption(int fd, SctpSocketOption name, int assocId)
1096N/A throws IOException {
1096N/A if (name.equals(SCTP_SET_PEER_PRIMARY_ADDR)) {
1096N/A throw new IllegalArgumentException(
1096N/A "SCTP_SET_PEER_PRIMARY_ADDR cannot be retrieved");
1096N/A } else if (name.equals(SCTP_INIT_MAXSTREAMS)) {
1096N/A /* container for holding maxIn/Out streams */
1096N/A int[] values = new int[2];
1096N/A SctpNet.getInitMsgOption0(fd, values);
1096N/A return InitMaxStreams.create(values[0], values[1]);
1096N/A } else if (name.equals(SCTP_PRIMARY_ADDR)) {
1096N/A return getPrimAddrOption0(fd, assocId);
1096N/A } else if (name.equals(SCTP_DISABLE_FRAGMENTS) ||
1096N/A name.equals(SCTP_EXPLICIT_COMPLETE) ||
1096N/A name.equals(SCTP_FRAGMENT_INTERLEAVE) ||
1096N/A name.equals(SCTP_NODELAY) ||
1096N/A name.equals(SO_SNDBUF) ||
1096N/A name.equals(SO_RCVBUF) ||
1096N/A name.equals(SO_LINGER)) {
1096N/A return getIntOption(fd, name);
1096N/A } else {
1096N/A throw new AssertionError("Unknown socket option");
1096N/A }
1096N/A }
1096N/A
1096N/A static void setIntOption(int fd, SctpSocketOption name, Object value)
1096N/A throws IOException {
1096N/A if (value == null)
1096N/A throw new IllegalArgumentException("Invalid option value");
1096N/A
1096N/A Class<?> type = name.type();
1096N/A if (type != Integer.class && type != Boolean.class)
1096N/A throw new AssertionError("Should not reach here");
1096N/A
1096N/A if (name == SO_RCVBUF ||
1096N/A name == SO_SNDBUF)
1096N/A {
1096N/A int i = ((Integer)value).intValue();
1096N/A if (i < 0)
1096N/A throw new IllegalArgumentException(
1096N/A "Invalid send/receive buffer size");
1096N/A } else if (name == SO_LINGER) {
1096N/A int i = ((Integer)value).intValue();
1096N/A if (i < 0)
1096N/A value = Integer.valueOf(-1);
1096N/A if (i > 65535)
1096N/A value = Integer.valueOf(65535);
1096N/A } else if (name.equals(SCTP_FRAGMENT_INTERLEAVE)) {
1096N/A int i = ((Integer)value).intValue();
1096N/A if (i < 0 || i > 2)
1096N/A throw new IllegalArgumentException(
1096N/A "Invalid value for SCTP_FRAGMENT_INTERLEAVE");
1096N/A }
1096N/A
1096N/A int arg;
1096N/A if (type == Integer.class) {
1096N/A arg = ((Integer)value).intValue();
1096N/A } else {
1096N/A boolean b = ((Boolean)value).booleanValue();
1096N/A arg = (b) ? 1 : 0;
1096N/A }
1096N/A
1096N/A setIntOption0(fd, ((SctpStdSocketOption)name).constValue(), arg);
1096N/A }
1096N/A
1096N/A static Object getIntOption(int fd, SctpSocketOption name)
1096N/A throws IOException {
1096N/A Class<?> type = name.type();
1096N/A
1096N/A if (type != Integer.class && type != Boolean.class)
1096N/A throw new AssertionError("Should not reach here");
1096N/A
1096N/A if (!(name instanceof SctpStdSocketOption))
1096N/A throw new AssertionError("Should not reach here");
1096N/A
1096N/A int value = getIntOption0(fd,
1096N/A ((SctpStdSocketOption)name).constValue());
1096N/A
1096N/A if (type == Integer.class) {
1096N/A return Integer.valueOf(value);
1096N/A } else {
1096N/A return (value == 0) ? Boolean.FALSE : Boolean.TRUE;
1096N/A }
1096N/A }
1096N/A
1096N/A static void shutdown(int fd, int assocId)
1096N/A throws IOException {
1096N/A shutdown0(fd, assocId);
1096N/A }
1096N/A
1326N/A static FileDescriptor branch(int fd, int assocId) throws IOException {
1326N/A int nativefd = branch0(fd, assocId);
1326N/A return IOUtil.newFD(nativefd);
1326N/A }
1326N/A
1096N/A /* Native Methods */
1096N/A static native int socket0(boolean oneToOne) throws IOException;
1096N/A
2084N/A static native void listen0(int fd, int backlog) throws IOException;
2084N/A
2084N/A static native int connect0(int fd, InetAddress remote, int remotePort)
2084N/A throws IOException;
2084N/A
2084N/A static native void close0(int fd) throws IOException;
2084N/A
2084N/A static native void preClose0(int fd) throws IOException;
2084N/A
1096N/A static native void bindx(int fd, InetAddress[] addrs, int port, int length,
1096N/A boolean add, boolean preferIPv6) throws IOException;
1096N/A
1096N/A static native int getIntOption0(int fd, int opt) throws IOException;
1096N/A
1096N/A static native void setIntOption0(int fd, int opt, int arg)
1096N/A throws IOException;
1096N/A
1096N/A static native SocketAddress[] getLocalAddresses0(int fd) throws IOException;
1096N/A
1096N/A static native SocketAddress[] getRemoteAddresses0(int fd, int assocId)
1096N/A throws IOException;
1096N/A
1326N/A static native int branch0(int fd, int assocId) throws IOException;
1326N/A
1096N/A static native void setPrimAddrOption0(int fd, int assocId, InetAddress ia,
1096N/A int port) throws IOException;
1096N/A
1096N/A static native void setPeerPrimAddrOption0(int fd, int assocId,
3230N/A InetAddress ia, int port, boolean preferIPv6) throws IOException;
1096N/A
1096N/A static native SocketAddress getPrimAddrOption0(int fd, int assocId)
1096N/A throws IOException;
1096N/A
1096N/A /* retVals [0] maxInStreams, [1] maxOutStreams */
1096N/A static native void getInitMsgOption0(int fd, int[] retVals) throws IOException;
1096N/A
1096N/A static native void setInitMsgOption0(int fd, int arg1, int arg2)
1096N/A throws IOException;
1096N/A
1096N/A static native void shutdown0(int fd, int assocId);
2084N/A
2084N/A static native void init();
2084N/A
2084N/A static {
2084N/A init();
2084N/A }
1096N/A}
1096N/A