8036979: Support java.net.SocketOption<> in java.net socket types
authormichaelm
Sat, 12 Apr 2014 20:21:09 +0100
changeset 23879 284802a2d355
parent 23816 b47e02119575
child 23880 7d6b060131d3
8036979: Support java.net.SocketOption<> in java.net socket types Reviewed-by: alanb, chegar
jdk/make/mapfiles/libnet/mapfile-vers
jdk/src/share/classes/java/net/DatagramSocket.java
jdk/src/share/classes/java/net/DatagramSocketImpl.java
jdk/src/share/classes/java/net/ServerSocket.java
jdk/src/share/classes/java/net/Socket.java
jdk/src/share/classes/java/net/SocketImpl.java
jdk/src/share/classes/jdk/net/ExtendedSocketOptions.java
jdk/src/share/classes/jdk/net/NetworkPermission.java
jdk/src/share/classes/jdk/net/SocketFlow.java
jdk/src/share/classes/jdk/net/Sockets.java
jdk/src/share/classes/jdk/net/package-info.java
jdk/src/share/classes/sun/net/ExtendedOptionsImpl.java
jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java
jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java
jdk/src/share/classes/sun/nio/ch/Net.java
jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java
jdk/src/share/native/java/net/net_util.h
jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java
jdk/src/solaris/classes/java/net/PlainSocketImpl.java
jdk/src/solaris/native/java/net/ExtendedOptionsImpl.c
jdk/src/solaris/native/java/net/net_util_md.h
jdk/src/windows/native/java/net/ExtendedOptionsImpl.c
jdk/test/TEST.groups
jdk/test/java/net/SocketOption/OptionsTest.java
jdk/test/jdk/net/Sockets/Test.java
jdk/test/jdk/net/Sockets/policy.fail
jdk/test/jdk/net/Sockets/policy.success
--- a/jdk/make/mapfiles/libnet/mapfile-vers	Wed Jul 05 19:36:17 2017 +0200
+++ b/jdk/make/mapfiles/libnet/mapfile-vers	Sat Apr 12 20:21:09 2014 +0100
@@ -94,6 +94,10 @@
 		Java_sun_net_sdp_SdpSupport_create0;
 		Java_sun_net_spi_DefaultProxySelector_init;
 		Java_sun_net_spi_DefaultProxySelector_getSystemProxy;
+		Java_sun_net_ExtendedOptionsImpl_init;
+		Java_sun_net_ExtendedOptionsImpl_setFlowOption;
+		Java_sun_net_ExtendedOptionsImpl_getFlowOption;
+		Java_sun_net_ExtendedOptionsImpl_flowSupported;
 		NET_AllocSockaddr;
 		NET_SockaddrToInetAddress;
                 NET_SockaddrEqualsInetAddress;
--- a/jdk/src/share/classes/java/net/DatagramSocket.java	Wed Jul 05 19:36:17 2017 +0200
+++ b/jdk/src/share/classes/java/net/DatagramSocket.java	Sat Apr 12 20:21:09 2014 +0100
@@ -29,6 +29,8 @@
 import java.nio.channels.DatagramChannel;
 import java.security.AccessController;
 import java.security.PrivilegedExceptionAction;
+import java.util.Set;
+import java.util.Collections;
 
 /**
  * This class represents a socket for sending and receiving datagram packets.
@@ -315,6 +317,7 @@
         }
         // creates a udp socket
         impl.create();
+        impl.setDatagramSocket(this);
         created = true;
     }
 
@@ -1258,4 +1261,94 @@
         }
         factory = fac;
     }
+
+    /**
+     * Sets the value of a socket option.
+     *
+     * @param name The socket option
+     * @param value The value of the socket option. A value of {@code null}
+     *              may be valid for some options.
+     *
+     * @return this DatagramSocket
+     *
+     * @throws UnsupportedOperationException if the datagram socket
+     *         does not support the option.
+     *
+     * @throws IllegalArgumentException if the value is not valid for
+     *         the option.
+     *
+     * @throws IOException if an I/O error occurs, or if the socket is closed.
+     *
+     * @throws SecurityException if a security manager is set and if the socket
+     *         option requires a security permission and if the caller does
+     *         not have the required permission.
+     *         {@link java.net.StandardSocketOptions StandardSocketOptions}
+     *         do not require any security permission.
+     *
+     * @throws NullPointerException if name is {@code null}
+     *
+     * @since 1.9
+     */
+    public <T> DatagramSocket setOption(SocketOption<T> name, T value)
+        throws IOException
+    {
+        getImpl().setOption(name, value);
+        return this;
+    }
+
+    /**
+     * Returns the value of a socket option.
+     *
+     * @param name The socket option
+     *
+     * @return The value of the socket option.
+     *
+     * @throws UnsupportedOperationException if the datagram socket
+     *         does not support the option.
+     *
+     * @throws IOException if an I/O error occurs, or if the socket is closed.
+     *
+     * @throws NullPointerException if name is {@code null}
+     *
+     * @throws SecurityException if a security manager is set and if the socket
+     *         option requires a security permission and if the caller does
+     *         not have the required permission.
+     *         {@link java.net.StandardSocketOptions StandardSocketOptions}
+     *         do not require any security permission.
+     *
+     * @since 1.9
+     */
+    public <T> T getOption(SocketOption<T> name) throws IOException {
+        return getImpl().getOption(name);
+    }
+
+    private static Set<SocketOption<?>> options;
+    private static boolean optionsSet = false;
+
+    /**
+     * Returns a set of the socket options supported by this socket.
+     *
+     * This method will continue to return the set of options even after
+     * the socket has been closed.
+     *
+     * @return A set of the socket options supported by this socket. This set
+     *        may be empty if the socket's DatagramSocketImpl cannot be created.
+     *
+     * @since 1.9
+     */
+    public Set<SocketOption<?>> supportedOptions() {
+        synchronized(DatagramSocket.class) {
+            if (optionsSet) {
+                return options;
+            }
+            try {
+                DatagramSocketImpl impl = getImpl();
+                options = Collections.unmodifiableSet(impl.supportedOptions());
+            } catch (IOException e) {
+                options = Collections.emptySet();
+            }
+            optionsSet = true;
+            return options;
+        }
+    }
 }
--- a/jdk/src/share/classes/java/net/DatagramSocketImpl.java	Wed Jul 05 19:36:17 2017 +0200
+++ b/jdk/src/share/classes/java/net/DatagramSocketImpl.java	Sat Apr 12 20:21:09 2014 +0100
@@ -28,6 +28,8 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.InterruptedIOException;
+import java.util.Set;
+import java.util.HashSet;
 
 /**
  * Abstract datagram and multicast socket implementation base class.
@@ -48,6 +50,20 @@
     protected FileDescriptor fd;
 
     /**
+     * The DatagramSocket or MulticastSocket
+     * that owns this impl
+     */
+    DatagramSocket socket;
+
+    void setDatagramSocket(DatagramSocket socket) {
+        this.socket = socket;
+    }
+
+    DatagramSocket getDatagramSocket() {
+        return socket;
+    }
+
+    /**
      * Creates a datagram socket.
      * @exception SocketException if there is an error in the
      * underlying protocol, such as a TCP error.
@@ -241,4 +257,116 @@
     protected FileDescriptor getFileDescriptor() {
         return fd;
     }
+
+    /**
+     * Called to set a socket option.
+     *
+     * @param name The socket option
+     *
+     * @param value The value of the socket option. A value of {@code null}
+     *              may be valid for some options.
+     *
+     * @throws UnsupportedOperationException if the DatagramSocketImpl does not
+     *         support the option
+     *
+     * @throws NullPointerException if name is {@code null}
+     *
+     * @since 1.9
+     */
+    protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
+        if (name == StandardSocketOptions.SO_SNDBUF) {
+            setOption(SocketOptions.SO_SNDBUF, value);
+        } else if (name == StandardSocketOptions.SO_RCVBUF) {
+            setOption(SocketOptions.SO_RCVBUF, value);
+        } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+            setOption(SocketOptions.SO_REUSEADDR, value);
+        } else if (name == StandardSocketOptions.IP_TOS) {
+            setOption(SocketOptions.IP_TOS, value);
+        } else if (name == StandardSocketOptions.IP_MULTICAST_IF &&
+            (getDatagramSocket() instanceof MulticastSocket)) {
+            setOption(SocketOptions.IP_MULTICAST_IF2, value);
+        } else if (name == StandardSocketOptions.IP_MULTICAST_TTL &&
+            (getDatagramSocket() instanceof MulticastSocket)) {
+            if (! (value instanceof Integer)) {
+                throw new IllegalArgumentException("not an integer");
+            }
+            setTimeToLive((Integer)value);
+        } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP &&
+            (getDatagramSocket() instanceof MulticastSocket)) {
+            setOption(SocketOptions.IP_MULTICAST_LOOP, value);
+        } else {
+            throw new UnsupportedOperationException("unsupported option");
+        }
+    }
+
+    /**
+     * Called to get a socket option.
+     *
+     * @param name The socket option
+     *
+     * @throws UnsupportedOperationException if the DatagramSocketImpl does not
+     *         support the option
+     *
+     * @throws NullPointerException if name is {@code null}
+     *
+     * @since 1.9
+     */
+    protected <T> T getOption(SocketOption<T> name) throws IOException {
+        if (name == StandardSocketOptions.SO_SNDBUF) {
+            return (T) getOption(SocketOptions.SO_SNDBUF);
+        } else if (name == StandardSocketOptions.SO_RCVBUF) {
+            return (T) getOption(SocketOptions.SO_RCVBUF);
+        } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+            return (T) getOption(SocketOptions.SO_REUSEADDR);
+        } else if (name == StandardSocketOptions.IP_TOS) {
+            return (T) getOption(SocketOptions.IP_TOS);
+        } else if (name == StandardSocketOptions.IP_MULTICAST_IF &&
+            (getDatagramSocket() instanceof MulticastSocket)) {
+            return (T) getOption(SocketOptions.IP_MULTICAST_IF2);
+        } else if (name == StandardSocketOptions.IP_MULTICAST_TTL &&
+            (getDatagramSocket() instanceof MulticastSocket)) {
+            Integer ttl = getTimeToLive();
+            return (T)ttl;
+        } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP &&
+            (getDatagramSocket() instanceof MulticastSocket)) {
+            return (T) getOption(SocketOptions.IP_MULTICAST_LOOP);
+        } else {
+            throw new UnsupportedOperationException("unsupported option");
+        }
+    }
+
+    private static final  Set<SocketOption<?>> dgSocketOptions =
+        new HashSet<>();
+
+    private static final  Set<SocketOption<?>> mcSocketOptions =
+        new HashSet<>();
+
+    static {
+        dgSocketOptions.add(StandardSocketOptions.SO_SNDBUF);
+        dgSocketOptions.add(StandardSocketOptions.SO_RCVBUF);
+        dgSocketOptions.add(StandardSocketOptions.SO_REUSEADDR);
+        dgSocketOptions.add(StandardSocketOptions.IP_TOS);
+
+        mcSocketOptions.add(StandardSocketOptions.SO_SNDBUF);
+        mcSocketOptions.add(StandardSocketOptions.SO_RCVBUF);
+        mcSocketOptions.add(StandardSocketOptions.SO_REUSEADDR);
+        mcSocketOptions.add(StandardSocketOptions.IP_TOS);
+        mcSocketOptions.add(StandardSocketOptions.IP_MULTICAST_IF);
+        mcSocketOptions.add(StandardSocketOptions.IP_MULTICAST_TTL);
+        mcSocketOptions.add(StandardSocketOptions.IP_MULTICAST_LOOP);
+    };
+
+    /**
+     * Returns a set of SocketOptions supported by this impl
+     * and by this impl's socket (DatagramSocket or MulticastSocket)
+     *
+     * @return a Set of SocketOptions
+     */
+    protected Set<SocketOption<?>> supportedOptions() {
+        if (getDatagramSocket() instanceof MulticastSocket) {
+            return mcSocketOptions;
+        } else {
+            return dgSocketOptions;
+        }
+    }
 }
--- a/jdk/src/share/classes/java/net/ServerSocket.java	Wed Jul 05 19:36:17 2017 +0200
+++ b/jdk/src/share/classes/java/net/ServerSocket.java	Sat Apr 12 20:21:09 2014 +0100
@@ -30,6 +30,8 @@
 import java.nio.channels.ServerSocketChannel;
 import java.security.AccessController;
 import java.security.PrivilegedExceptionAction;
+import java.util.Set;
+import java.util.Collections;
 
 /**
  * This class implements server sockets. A server socket waits for
@@ -919,4 +921,92 @@
         /* Not implemented yet */
     }
 
+    /**
+     * Sets the value of a socket option.
+     *
+     * @param name The socket option
+     * @param value The value of the socket option. A value of {@code null}
+     *              may be valid for some options.
+     * @return this ServerSocket
+     *
+     * @throws UnsupportedOperationException if the server socket does not
+     *         support the option.
+     *
+     * @throws IllegalArgumentException if the value is not valid for
+     *         the option.
+     *
+     * @throws IOException if an I/O error occurs, or if the socket is closed.
+     *
+     * @throws NullPointerException if name is {@code null}
+     *
+     * @throws SecurityException if a security manager is set and if the socket
+     *         option requires a security permission and if the caller does
+     *         not have the required permission.
+     *         {@link java.net.StandardSocketOptions StandardSocketOptions}
+     *         do not require any security permission.
+     *
+     * @since 1.9
+     */
+    public <T> ServerSocket setOption(SocketOption<T> name, T value)
+        throws IOException
+    {
+        getImpl().setOption(name, value);
+        return this;
+    }
+
+    /**
+     * Returns the value of a socket option.
+     *
+     * @param name The socket option
+     *
+     * @return The value of the socket option.
+     *
+     * @throws UnsupportedOperationException if the server socket does not
+     *         support the option.
+     *
+     * @throws IOException if an I/O error occurs, or if the socket is closed.
+     *
+     * @throws NullPointerException if name is {@code null}
+     *
+     * @throws SecurityException if a security manager is set and if the socket
+     *         option requires a security permission and if the caller does
+     *         not have the required permission.
+     *         {@link java.net.StandardSocketOptions StandardSocketOptions}
+     *         do not require any security permission.
+     *
+     * @since 1.9
+     */
+    public <T> T getOption(SocketOption<T> name) throws IOException {
+        return getImpl().getOption(name);
+    }
+
+    private static Set<SocketOption<?>> options;
+    private static boolean optionsSet = false;
+
+    /**
+     * Returns a set of the socket options supported by this server socket.
+     *
+     * This method will continue to return the set of options even after
+     * the socket has been closed.
+     *
+     * @return A set of the socket options supported by this socket. This set
+     *         may be empty if the socket's SocketImpl cannot be created.
+     *
+     * @since 1.9
+     */
+    public Set<SocketOption<?>> supportedOptions() {
+        synchronized (ServerSocket.class) {
+            if (optionsSet) {
+                return options;
+            }
+            try {
+                SocketImpl impl = getImpl();
+                options = Collections.unmodifiableSet(impl.supportedOptions());
+            } catch (IOException e) {
+                options = Collections.emptySet();
+            }
+            optionsSet = true;
+            return options;
+        }
+    }
 }
--- a/jdk/src/share/classes/java/net/Socket.java	Wed Jul 05 19:36:17 2017 +0200
+++ b/jdk/src/share/classes/java/net/Socket.java	Sat Apr 12 20:21:09 2014 +0100
@@ -32,6 +32,8 @@
 import java.security.AccessController;
 import java.security.PrivilegedExceptionAction;
 import java.security.PrivilegedAction;
+import java.util.Set;
+import java.util.Collections;
 
 /**
  * This class implements client sockets (also called just
@@ -1720,4 +1722,93 @@
     {
         /* Not implemented yet */
     }
+
+
+    /**
+     * Sets the value of a socket option.
+     *
+     * @param name The socket option
+     * @param value The value of the socket option. A value of {@code null}
+     *              may be valid for some options.
+     * @return this Socket
+     *
+     * @throws UnsupportedOperationException if the socket does not support
+     *         the option.
+     *
+     * @throws IllegalArgumentException if the value is not valid for
+     *         the option.
+     *
+     * @throws IOException if an I/O error occurs, or if the socket is closed.
+     *
+     * @throws NullPointerException if name is {@code null}
+     *
+     * @throws SecurityException if a security manager is set and if the socket
+     *         option requires a security permission and if the caller does
+     *         not have the required permission.
+     *         {@link java.net.StandardSocketOptions StandardSocketOptions}
+     *         do not require any security permission.
+     *
+     * @since 1.9
+     */
+    public <T> Socket setOption(SocketOption<T> name, T value) throws IOException {
+        getImpl().setOption(name, value);
+        return this;
+    }
+
+    /**
+     * Returns the value of a socket option.
+     *
+     * @param name The socket option
+     *
+     * @return The value of the socket option.
+     *
+     * @throws UnsupportedOperationException if the socket does not support
+     *         the option.
+     *
+     * @throws IOException if an I/O error occurs, or if the socket is closed.
+     *
+     * @throws NullPointerException if name is {@code null}
+     *
+     * @throws SecurityException if a security manager is set and if the socket
+     *         option requires a security permission and if the caller does
+     *         not have the required permission.
+     *         {@link java.net.StandardSocketOptions StandardSocketOptions}
+     *         do not require any security permission.
+     *
+     * @since 1.9
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T getOption(SocketOption<T> name) throws IOException {
+        return getImpl().getOption(name);
+    }
+
+    private static Set<SocketOption<?>> options;
+    private static boolean optionsSet = false;
+
+    /**
+     * Returns a set of the socket options supported by this socket.
+     *
+     * This method will continue to return the set of options even after
+     * the socket has been closed.
+     *
+     * @return A set of the socket options supported by this socket. This set
+     *         may be empty if the socket's SocketImpl cannot be created.
+     *
+     * @since 1.9
+     */
+    public Set<SocketOption<?>> supportedOptions() {
+        synchronized (Socket.class) {
+            if (optionsSet) {
+                return options;
+            }
+            try {
+                SocketImpl impl = getImpl();
+                options = Collections.unmodifiableSet(impl.supportedOptions());
+            } catch (IOException e) {
+                options = Collections.emptySet();
+            }
+            optionsSet = true;
+            return options;
+        }
+    }
 }
--- a/jdk/src/share/classes/java/net/SocketImpl.java	Wed Jul 05 19:36:17 2017 +0200
+++ b/jdk/src/share/classes/java/net/SocketImpl.java	Sat Apr 12 20:21:09 2014 +0100
@@ -29,6 +29,9 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.FileDescriptor;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
 
 /**
  * The abstract class {@code SocketImpl} is a common superclass
@@ -355,4 +358,106 @@
     {
         /* Not implemented yet */
     }
+
+    /**
+     * Called to set a socket option.
+     *
+     * @param name The socket option
+     *
+     * @param value The value of the socket option. A value of {@code null}
+     *              may be valid for some options.
+     *
+     * @throws UnsupportedOperationException if the SocketImpl does not
+     *         support the option
+     *
+     * @throws IOException if an I/O error occurs, or if the socket is closed.
+     *
+     * @since 1.9
+     */
+    protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
+        if (name == StandardSocketOptions.SO_KEEPALIVE) {
+            setOption(SocketOptions.SO_KEEPALIVE, value);
+        } else if (name == StandardSocketOptions.SO_SNDBUF) {
+            setOption(SocketOptions.SO_SNDBUF, value);
+        } else if (name == StandardSocketOptions.SO_RCVBUF) {
+            setOption(SocketOptions.SO_RCVBUF, value);
+        } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+            setOption(SocketOptions.SO_REUSEADDR, value);
+        } else if (name == StandardSocketOptions.SO_LINGER) {
+            setOption(SocketOptions.SO_LINGER, value);
+        } else if (name == StandardSocketOptions.IP_TOS) {
+            setOption(SocketOptions.IP_TOS, value);
+        } else if (name == StandardSocketOptions.TCP_NODELAY) {
+            setOption(SocketOptions.TCP_NODELAY, value);
+        } else {
+            throw new UnsupportedOperationException("unsupported option");
+        }
+    }
+
+    /**
+     * Called to get a socket option.
+     *
+     * @param name The socket option
+     *
+     * @return the value of the named option
+     *
+     * @throws UnsupportedOperationException if the SocketImpl does not
+     *         support the option.
+     *
+     * @throws IOException if an I/O error occurs, or if the socket is closed.
+     *
+     * @since 1.9
+     */
+    protected <T> T getOption(SocketOption<T> name) throws IOException {
+        if (name == StandardSocketOptions.SO_KEEPALIVE) {
+            return (T)getOption(SocketOptions.SO_KEEPALIVE);
+        } else if (name == StandardSocketOptions.SO_SNDBUF) {
+            return (T)getOption(SocketOptions.SO_SNDBUF);
+        } else if (name == StandardSocketOptions.SO_RCVBUF) {
+            return (T)getOption(SocketOptions.SO_RCVBUF);
+        } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+            return (T)getOption(SocketOptions.SO_REUSEADDR);
+        } else if (name == StandardSocketOptions.SO_LINGER) {
+            return (T)getOption(SocketOptions.SO_LINGER);
+        } else if (name == StandardSocketOptions.IP_TOS) {
+            return (T)getOption(SocketOptions.IP_TOS);
+        } else if (name == StandardSocketOptions.TCP_NODELAY) {
+            return (T)getOption(SocketOptions.TCP_NODELAY);
+        } else {
+            throw new UnsupportedOperationException("unsupported option");
+        }
+    }
+
+    private static final  Set<SocketOption<?>> socketOptions =
+        new HashSet<>();
+
+    private static final  Set<SocketOption<?>> serverSocketOptions =
+        new HashSet<>();
+
+    static {
+        socketOptions.add(StandardSocketOptions.SO_KEEPALIVE);
+        socketOptions.add(StandardSocketOptions.SO_SNDBUF);
+        socketOptions.add(StandardSocketOptions.SO_RCVBUF);
+        socketOptions.add(StandardSocketOptions.SO_REUSEADDR);
+        socketOptions.add(StandardSocketOptions.SO_LINGER);
+        socketOptions.add(StandardSocketOptions.IP_TOS);
+        socketOptions.add(StandardSocketOptions.TCP_NODELAY);
+
+        serverSocketOptions.add(StandardSocketOptions.SO_RCVBUF);
+        serverSocketOptions.add(StandardSocketOptions.SO_REUSEADDR);
+    };
+
+    /**
+     * Returns a set of SocketOptions supported by this impl
+     * and by this impl's socket (Socket or ServerSocket)
+     *
+     * @return a Set of SocketOptions
+     */
+    protected Set<SocketOption<?>> supportedOptions() {
+        if (getSocket() != null) {
+            return socketOptions;
+        } else {
+            return serverSocketOptions;
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/net/ExtendedSocketOptions.java	Sat Apr 12 20:21:09 2014 +0100
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.net;
+
+import java.net.SocketOption;
+
+/**
+ * Defines extended socket options, beyond those defined in
+ * {@link java.net.StandardSocketOptions}. These options may be platform
+ * specific.
+ *
+ * @since 1.9
+ */
+@jdk.Exported
+public final class ExtendedSocketOptions {
+
+    private static class ExtSocketOption<T> implements SocketOption<T> {
+        private final String name;
+        private final Class<T> type;
+        ExtSocketOption(String name, Class<T> type) {
+            this.name = name;
+            this.type = type;
+        }
+        @Override public String name() { return name; }
+        @Override public Class<T> type() { return type; }
+        @Override public String toString() { return name; }
+    }
+
+    private ExtendedSocketOptions() {}
+
+    /**
+     * Service level properties. When a security manager is installed,
+     * setting or getting this option requires a {@link NetworkPermission}
+     * {@code ("setOption.SO_FLOW_SLA")} or {@code "getOption.SO_FLOW_SLA"}
+     * respectively.
+     */
+    public static final SocketOption<SocketFlow> SO_FLOW_SLA = new
+        ExtSocketOption<SocketFlow>("SO_FLOW_SLA", SocketFlow.class);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/net/NetworkPermission.java	Sat Apr 12 20:21:09 2014 +0100
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.net;
+
+import java.security.BasicPermission;
+
+/**
+ * Represents permission to access the extended networking capabilities
+ * defined in the jdk.net package. These permissions contain a target
+ * name, but no actions list. Callers either possess the permission or not.
+ * <p>
+ * The following targets are defined:
+ * <p>
+ * <table border=1 cellpadding=5 summary="permission target name,
+ *  what the target allows,and associated risks">
+ * <tr>
+ *   <th>Permission Target Name</th>
+ *   <th>What the Permission Allows</th>
+ *   <th>Risks of Allowing this Permission</th>
+ * </tr>
+ * <tr>
+ *   <td>setOption.SO_FLOW_SLA</td>
+ *   <td>set the {@link ExtendedSocketOptions#SO_FLOW_SLA SO_FLOW_SLA} option
+ *       on any socket that supports it</td>
+ *   <td>allows caller to set a higher priority or bandwidth allocation
+ *       to sockets it creates, than they might otherwise be allowed.</td>
+ * </tr>
+ * <tr>
+ *   <td>getOption.SO_FLOW_SLA</td>
+ *   <td>retrieve the {@link ExtendedSocketOptions#SO_FLOW_SLA SO_FLOW_SLA}
+ *       setting from any socket that supports the option</td>
+ *   <td>allows caller access to SLA information that it might not
+ *       otherwise have</td>
+ * </tr></table>
+ *
+ * @see jdk.net.ExtendedSocketOptions
+ *
+ * @since 1.9
+ */
+
+@jdk.Exported
+public final class NetworkPermission extends BasicPermission {
+
+    private static final long serialVersionUID = -2012939586906722291L;
+
+    /**
+     * Creates a NetworkPermission with the given target name.
+     *
+     * @param name the permission target name
+     * @throws NullPointerException if {@code name} is {@code null}.
+     * @throws IllegalArgumentException if {@code name} is empty.
+     */
+    public NetworkPermission(String name)
+    {
+        super(name);
+    }
+
+    /**
+     * Creates a NetworkPermission with the given target name.
+     *
+     * @param name the permission target name
+     * @param actions should be {@code null}. Is ignored if not.
+     * @throws NullPointerException if {@code name} is {@code null}.
+     * @throws IllegalArgumentException if {@code name} is empty.
+     */
+    public NetworkPermission(String name, String actions)
+    {
+        super(name, actions);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/net/SocketFlow.java	Sat Apr 12 20:21:09 2014 +0100
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.net;
+
+import java.lang.annotation.Native;
+
+/**
+ * Represents the service level properties for the platform specific socket
+ * option {@link ExtendedSocketOptions#SO_FLOW_SLA}.
+ * <p>
+ * The priority and bandwidth parameters must be set before
+ * setting the socket option.
+ * <p>
+ * When the {@code SO_FLOW_SLA} option is set then it may not take effect
+ * immediately. If the value of the socket option is obtained with
+ * {@code getOption()} then the status may be returned as {@code INPROGRESS}
+ * until it takes effect. The priority and bandwidth values are only valid when
+ * the status is returned as OK.
+ * <p>
+ * When a security manager is installed, a {@link NetworkPermission}
+ * is required to set or get this option.
+ *
+ * @since 1.9
+ */
+@jdk.Exported
+public class SocketFlow {
+
+    private static final int UNSET = -1;
+    @Native public static final int NORMAL_PRIORITY = 1;
+    @Native public static final int HIGH_PRIORITY = 2;
+
+    private int priority = NORMAL_PRIORITY;
+
+    private long bandwidth = UNSET;
+
+    private Status status = Status.NO_STATUS;
+
+    private SocketFlow() {}
+
+    /**
+     * Enumeration of the return values from the SO_FLOW_SLA
+     * socket option. Both setting and getting the option return
+     * one of these statuses, which reflect the state of socket's
+     * flow.
+     *
+     * @since 1.9
+     */
+    @jdk.Exported
+    public enum Status {
+        /**
+         * Set or get socket option has not been called yet. Status
+         * values can only be retrieved after calling set or get.
+         */
+        NO_STATUS,
+        /**
+         * Flow successfully created.
+         */
+        OK,
+        /**
+         * Caller has no permission to create flow.
+         */
+        NO_PERMISSION,
+        /**
+         * Flow can not be created because socket is not connected.
+         */
+        NOT_CONNECTED,
+        /**
+         * Flow creation not supported for this socket.
+         */
+        NOT_SUPPORTED,
+        /**
+         * A flow already exists with identical attributes.
+         */
+        ALREADY_CREATED,
+        /**
+         * A flow is being created.
+         */
+        IN_PROGRESS,
+        /**
+         * Some other unspecified error.
+         */
+        OTHER
+    }
+
+    /**
+     * Creates a new SocketFlow that can be used to set the SO_FLOW_SLA
+     * socket option and create a socket flow.
+     */
+    public static SocketFlow create() {
+        return new SocketFlow();
+    }
+
+    /**
+     * Sets this SocketFlow's priority. Must be either NORMAL_PRIORITY
+     * HIGH_PRIORITY. If not set, a flow's priority is normal.
+     *
+     * @throws IllegalArgumentException if priority is not NORMAL_PRIORITY or
+     *         HIGH_PRIORITY.
+     */
+    public SocketFlow priority(int priority) {
+        if (priority != NORMAL_PRIORITY && priority != HIGH_PRIORITY) {
+            throw new IllegalArgumentException("invalid priority");
+        }
+        this.priority = priority;
+        return this;
+    }
+
+    /**
+     * Sets this SocketFlow's bandwidth. Must be greater than or equal to zero.
+     * A value of zero drops all packets for the socket.
+     *
+     * @throws IllegalArgumentException if bandwidth is less than zero.
+     */
+    public SocketFlow bandwidth(long bandwidth) {
+        if (bandwidth < 0) {
+            throw new IllegalArgumentException("invalid bandwidth");
+        } else {
+            this.bandwidth = bandwidth;
+        }
+        return this;
+    }
+
+    /**
+     * Returns this SocketFlow's priority.
+     */
+    public int priority() {
+        return priority;
+    }
+
+    /**
+     * Returns this SocketFlow's bandwidth.
+     *
+     * @return this SocketFlow's bandwidth, or {@code -1} if status is not OK.
+     */
+    public long bandwidth() {
+        return bandwidth;
+    }
+
+    /**
+     * Returns the Status value of this SocketFlow. NO_STATUS is returned
+     * if the object was not used in a call to set or get the option.
+     */
+    public Status status() {
+        return status;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/net/Sockets.java	Sat Apr 12 20:21:09 2014 +0100
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.net;
+
+import java.net.*;
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.security.PrivilegedAction;
+import java.security.AccessController;
+import java.lang.reflect.Field;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.Collections;
+import sun.net.ExtendedOptionsImpl;
+
+/**
+ * Defines static methods to set and get socket options defined by the
+ * {@link java.net.SocketOption} interface. All of the standard options defined
+ * by {@link java.net.Socket}, {@link java.net.ServerSocket}, and
+ * {@link java.net.DatagramSocket} can be set this way, as well as additional
+ * or platform specific options supported by each socket type.
+ * <p>
+ * The {@link #supportedOptions(Class)} method can be called to determine
+ * the complete set of options available (per socket type) on the
+ * current system.
+ * <p>
+ * When a security manager is installed, some non-standard socket options
+ * may require a security permission before being set or get.
+ * The details are specified in {@link ExtendedSocketOptions}. No permission
+ * is required for {@link java.net.StandardSocketOption}s.
+ *
+ * @see java.nio.channels.NetworkChannel
+ */
+@jdk.Exported
+public class Sockets {
+
+    private final static HashMap<Class<?>,Set<SocketOption<?>>>
+        options = new HashMap<>();
+
+    static {
+        initOptionSets();
+    }
+
+    private Sockets() {}
+
+    /**
+     * Sets the value of a socket option on a {@link java.net.Socket}
+     *
+     * @param s the socket
+     * @param name The socket option
+     * @param value The value of the socket option. May be null for some
+     *              options.
+     *
+     * @throws UnsupportedOperationException if the socket does not support
+     *         the option.
+     *
+     * @throws IllegalArgumentException if the value is not valid for
+     *         the option.
+     *
+     * @throws IOException if an I/O error occurs, or socket is closed.
+     *
+     * @throws SecurityException if a security manager is set and the
+     *         caller does not have any required permission.
+     *
+     * @throws NullPointerException if name is null
+     *
+     * @see java.net.StandardSocketOptions
+     */
+    public static <T> void setOption(Socket s, SocketOption<T> name, T value) throws IOException
+    {
+        s.setOption(name, value);
+    }
+
+    /**
+     * Returns the value of a socket option from a {@link java.net.Socket}
+     *
+     * @param s the socket
+     * @param name The socket option
+     *
+     * @return The value of the socket option.
+     *
+     * @throws UnsupportedOperationException if the socket does not support
+     *         the option.
+     *
+     * @throws IOException if an I/O error occurs
+     *
+     * @throws SecurityException if a security manager is set and the
+     *         caller does not have any required permission.
+     *
+     * @throws NullPointerException if name is null
+     *
+     * @see java.net.StandardSocketOptions
+     */
+    public static <T> T getOption(Socket s, SocketOption<T> name) throws IOException
+    {
+        return s.getOption(name);
+    }
+
+    /**
+     * Sets the value of a socket option on a {@link java.net.ServerSocket}
+     *
+     * @param s the socket
+     * @param name The socket option
+     * @param value The value of the socket option.
+     *
+     * @throws UnsupportedOperationException if the socket does not support
+     *         the option.
+     *
+     * @throws IllegalArgumentException if the value is not valid for
+     *         the option.
+     *
+     * @throws IOException if an I/O error occurs
+     *
+     * @throws NullPointerException if name is null
+     *
+     * @throws SecurityException if a security manager is set and the
+     *         caller does not have any required permission.
+     *
+     * @see java.net.StandardSocketOptions
+     */
+    public static <T> void setOption(ServerSocket s, SocketOption<T> name, T value) throws IOException
+    {
+        s.setOption(name, value);
+    }
+
+    /**
+     * Returns the value of a socket option from a {@link java.net.ServerSocket}
+     *
+     * @param s the socket
+     * @param name The socket option
+     *
+     * @return The value of the socket option.
+     *
+     * @throws UnsupportedOperationException if the socket does not support
+     *         the option.
+     *
+     * @throws IOException if an I/O error occurs
+     *
+     * @throws NullPointerException if name is null
+     *
+     * @throws SecurityException if a security manager is set and the
+     *         caller does not have any required permission.
+     *
+     * @see java.net.StandardSocketOptions
+     */
+    public static <T> T getOption(ServerSocket s, SocketOption<T> name) throws IOException
+    {
+        return s.getOption(name);
+    }
+
+    /**
+     * Sets the value of a socket option on a {@link java.net.DatagramSocket}
+     * or {@link java.net.MulticastSocket}
+     *
+     * @param s the socket
+     * @param name The socket option
+     * @param value The value of the socket option.
+     *
+     * @throws UnsupportedOperationException if the socket does not support
+     *         the option.
+     *
+     * @throws IllegalArgumentException if the value is not valid for
+     *         the option.
+     *
+     * @throws IOException if an I/O error occurs
+     *
+     * @throws NullPointerException if name is null
+     *
+     * @throws SecurityException if a security manager is set and the
+     *         caller does not have any required permission.
+     *
+     * @see java.net.StandardSocketOptions
+     */
+    public static <T> void setOption(DatagramSocket s, SocketOption<T> name, T value) throws IOException
+    {
+        s.setOption(name, value);
+    }
+
+    /**
+     * Returns the value of a socket option from a
+     * {@link java.net.DatagramSocket} or {@link java.net.MulticastSocket}
+     *
+     * @param s the socket
+     * @param name The socket option
+     *
+     * @return The value of the socket option.
+     *
+     * @throws UnsupportedOperationException if the socket does not support
+     *         the option.
+     *
+     * @throws IOException if an I/O error occurs
+     *
+     * @throws NullPointerException if name is null
+     *
+     * @throws SecurityException if a security manager is set and the
+     *         caller does not have any required permission.
+     *
+     * @see java.net.StandardSocketOptions
+     */
+    public static <T> T getOption(DatagramSocket s, SocketOption<T> name) throws IOException
+    {
+        return s.getOption(name);
+    }
+
+    /**
+     * Returns a set of {@link java.net.SocketOption}s supported by the
+     * given socket type. This set may include standard options and also
+     * non standard extended options.
+     *
+     * @param socketType the type of java.net socket
+     *
+     * @throws IllegalArgumentException if socketType is not a valid
+     *         socket type from the java.net package.
+     */
+    public static Set<SocketOption<?>> supportedOptions(Class<?> socketType) {
+        Set<SocketOption<?>> set = options.get(socketType);
+        if (set == null) {
+            throw new IllegalArgumentException("unknown socket type");
+        }
+        return set;
+    }
+
+    private static void checkValueType(Object value, Class<?> type) {
+        if (!type.isAssignableFrom(value.getClass())) {
+            String s = "Found: " + value.getClass().toString() + " Expected: "
+                        + type.toString();
+            throw new IllegalArgumentException(s);
+        }
+    }
+
+    private static void initOptionSets() {
+        boolean flowsupported = ExtendedOptionsImpl.flowSupported();
+
+        // Socket
+
+        Set<SocketOption<?>> set = new HashSet<>();
+        set.add(StandardSocketOptions.SO_KEEPALIVE);
+        set.add(StandardSocketOptions.SO_SNDBUF);
+        set.add(StandardSocketOptions.SO_RCVBUF);
+        set.add(StandardSocketOptions.SO_REUSEADDR);
+        set.add(StandardSocketOptions.SO_LINGER);
+        set.add(StandardSocketOptions.IP_TOS);
+        set.add(StandardSocketOptions.TCP_NODELAY);
+        if (flowsupported) {
+            set.add(ExtendedSocketOptions.SO_FLOW_SLA);
+        }
+        set = Collections.unmodifiableSet(set);
+        options.put(Socket.class, set);
+
+        // ServerSocket
+
+        set = new HashSet<>();
+        set.add(StandardSocketOptions.SO_RCVBUF);
+        set.add(StandardSocketOptions.SO_REUSEADDR);
+        set = Collections.unmodifiableSet(set);
+        options.put(ServerSocket.class, set);
+
+        // DatagramSocket
+
+        set = new HashSet<>();
+        set.add(StandardSocketOptions.SO_SNDBUF);
+        set.add(StandardSocketOptions.SO_RCVBUF);
+        set.add(StandardSocketOptions.SO_REUSEADDR);
+        set.add(StandardSocketOptions.IP_TOS);
+        if (flowsupported) {
+            set.add(ExtendedSocketOptions.SO_FLOW_SLA);
+        }
+        set = Collections.unmodifiableSet(set);
+        options.put(DatagramSocket.class, set);
+
+        // MulticastSocket
+
+        set = new HashSet<>();
+        set.add(StandardSocketOptions.SO_SNDBUF);
+        set.add(StandardSocketOptions.SO_RCVBUF);
+        set.add(StandardSocketOptions.SO_REUSEADDR);
+        set.add(StandardSocketOptions.IP_TOS);
+        set.add(StandardSocketOptions.IP_MULTICAST_IF);
+        set.add(StandardSocketOptions.IP_MULTICAST_TTL);
+        set.add(StandardSocketOptions.IP_MULTICAST_LOOP);
+        if (flowsupported) {
+            set.add(ExtendedSocketOptions.SO_FLOW_SLA);
+        }
+        set = Collections.unmodifiableSet(set);
+        options.put(MulticastSocket.class, set);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/jdk/net/package-info.java	Sat Apr 12 20:21:09 2014 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Platform specific socket options for the {@code java.net} and {@code java.nio.channels}
+ * socket classes.
+ *
+ * @since 1.9
+ */
+
+@jdk.Exported
+package jdk.net;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/net/ExtendedOptionsImpl.java	Sat Apr 12 20:21:09 2014 +0100
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.net;
+
+import java.net.*;
+import jdk.net.*;
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.security.PrivilegedAction;
+import java.security.AccessController;
+import java.lang.reflect.Field;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.Collections;
+
+/**
+ * Contains the native implementation for extended socket options
+ * together with some other static utilities
+ */
+public class ExtendedOptionsImpl {
+
+    static {
+        AccessController.doPrivileged((PrivilegedAction<Void>)() -> {
+            System.loadLibrary("net");
+            return null;
+        });
+        init();
+    }
+
+    private ExtendedOptionsImpl() {}
+
+    public static void checkSetOptionPermission(SocketOption<?> option) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm == null) {
+            return;
+        }
+        String check = "setOption." + option.name();
+        sm.checkPermission(new NetworkPermission(check));
+    }
+
+    public static void checkGetOptionPermission(SocketOption<?> option) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm == null) {
+            return;
+        }
+        String check = "getOption." + option.name();
+        sm.checkPermission(new NetworkPermission(check));
+    }
+
+    public static void checkValueType(Object value, Class<?> type) {
+        if (!type.isAssignableFrom(value.getClass())) {
+            String s = "Found: " + value.getClass().toString() + " Expected: "
+                        + type.toString();
+            throw new IllegalArgumentException(s);
+        }
+    }
+
+    private static native void init();
+
+    /*
+     * Extension native implementations
+     *
+     * SO_FLOW_SLA
+     */
+    public static native void setFlowOption(FileDescriptor fd, SocketFlow f);
+    public static native void getFlowOption(FileDescriptor fd, SocketFlow f);
+    public static native boolean flowSupported();
+}
--- a/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java	Wed Jul 05 19:36:17 2017 +0200
+++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java	Sat Apr 12 20:21:09 2014 +0100
@@ -39,6 +39,7 @@
 import java.util.concurrent.*;
 import java.util.concurrent.locks.*;
 import sun.net.NetHooks;
+import sun.net.ExtendedOptionsImpl;
 
 /**
  * Base implementation of AsynchronousSocketChannel
@@ -508,6 +509,9 @@
             set.add(StandardSocketOptions.SO_KEEPALIVE);
             set.add(StandardSocketOptions.SO_REUSEADDR);
             set.add(StandardSocketOptions.TCP_NODELAY);
+            if (ExtendedOptionsImpl.flowSupported()) {
+                set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA);
+            }
             return Collections.unmodifiableSet(set);
         }
     }
--- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java	Wed Jul 05 19:36:17 2017 +0200
+++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java	Sat Apr 12 20:21:09 2014 +0100
@@ -33,6 +33,7 @@
 import java.nio.channels.spi.*;
 import java.util.*;
 import sun.net.ResourceManager;
+import sun.net.ExtendedOptionsImpl;
 
 /**
  * An implementation of DatagramChannels.
@@ -317,6 +318,9 @@
             set.add(StandardSocketOptions.IP_MULTICAST_IF);
             set.add(StandardSocketOptions.IP_MULTICAST_TTL);
             set.add(StandardSocketOptions.IP_MULTICAST_LOOP);
+            if (ExtendedOptionsImpl.flowSupported()) {
+                set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA);
+            }
             return Collections.unmodifiableSet(set);
         }
     }
--- a/jdk/src/share/classes/sun/nio/ch/Net.java	Wed Jul 05 19:36:17 2017 +0200
+++ b/jdk/src/share/classes/sun/nio/ch/Net.java	Sat Apr 12 20:21:09 2014 +0100
@@ -27,11 +27,13 @@
 
 import java.io.*;
 import java.net.*;
+import jdk.net.*;
 import java.nio.channels.*;
 import java.util.*;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.security.PrivilegedExceptionAction;
+import sun.net.ExtendedOptionsImpl;
 
 
 public class Net {
@@ -297,6 +299,16 @@
 
         // only simple values supported by this method
         Class<?> type = name.type();
+
+        if (type == SocketFlow.class) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                sm.checkPermission(new NetworkPermission("setOption.SO_FLOW_SLA"));
+            }
+            ExtendedOptionsImpl.setFlowOption(fd, (SocketFlow)value);
+            return;
+        }
+
         if (type != Integer.class && type != Boolean.class)
             throw new AssertionError("Should not reach here");
 
@@ -349,6 +361,16 @@
     {
         Class<?> type = name.type();
 
+        if (type == SocketFlow.class) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                sm.checkPermission(new NetworkPermission("getOption.SO_FLOW_SLA"));
+            }
+            SocketFlow flow = SocketFlow.create();
+            ExtendedOptionsImpl.getFlowOption(fd, flow);
+            return flow;
+        }
+
         // only simple values supported by this method
         if (type != Integer.class && type != Boolean.class)
             throw new AssertionError("Should not reach here");
--- a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java	Wed Jul 05 19:36:17 2017 +0200
+++ b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java	Sat Apr 12 20:21:09 2014 +0100
@@ -33,6 +33,7 @@
 import java.nio.channels.spi.*;
 import java.util.*;
 import sun.net.NetHooks;
+import sun.net.ExtendedOptionsImpl;
 
 
 /**
@@ -237,6 +238,9 @@
             // additional options required by socket adaptor
             set.add(StandardSocketOptions.IP_TOS);
             set.add(ExtendedSocketOption.SO_OOBINLINE);
+            if (ExtendedOptionsImpl.flowSupported()) {
+                set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA);
+            }
             return Collections.unmodifiableSet(set);
         }
     }
--- a/jdk/src/share/native/java/net/net_util.h	Wed Jul 05 19:36:17 2017 +0200
+++ b/jdk/src/share/native/java/net/net_util.h	Sat Apr 12 20:21:09 2014 +0100
@@ -40,7 +40,7 @@
 #define IPv6 2
 
 #define NET_ERROR(env, ex, msg) \
-{ if (!(*env)->ExceptionOccurred(env)) JNU_ThrowByName(env, ex, msg) }
+{ if (!(*env)->ExceptionOccurred(env)) JNU_ThrowByName(env, ex, msg); }
 
 /************************************************************************
  * Cached field IDs
--- a/jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java	Wed Jul 05 19:36:17 2017 +0200
+++ b/jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java	Sat Apr 12 20:21:09 2014 +0100
@@ -25,6 +25,11 @@
 package java.net;
 
 import java.io.IOException;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
+import jdk.net.*;
+import static sun.net.ExtendedOptionsImpl.*;
 
 /*
  * On Unix systems we simply delegate to native methods.
@@ -38,6 +43,42 @@
         init();
     }
 
+    protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
+        if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
+            super.setOption(name, value);
+        } else {
+            if (isClosed()) {
+                throw new SocketException("Socket closed");
+            }
+            checkSetOptionPermission(name);
+            checkValueType(value, SocketFlow.class);
+            setFlowOption(getFileDescriptor(), (SocketFlow)value);
+        }
+    }
+
+    protected <T> T getOption(SocketOption<T> name) throws IOException {
+        if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
+            return super.getOption(name);
+        }
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+        checkGetOptionPermission(name);
+        SocketFlow flow = SocketFlow.create();
+        getFlowOption(getFileDescriptor(), flow);
+        return (T)flow;
+    }
+
+    protected Set<SocketOption<?>> supportedOptions() {
+        HashSet<SocketOption<?>> options = new HashSet(
+            super.supportedOptions());
+
+        if (flowSupported()) {
+            options.add(ExtendedSocketOptions.SO_FLOW_SLA);
+        }
+        return options;
+    }
+
     protected synchronized native void bind0(int lport, InetAddress laddr)
         throws SocketException;
 
--- a/jdk/src/solaris/classes/java/net/PlainSocketImpl.java	Wed Jul 05 19:36:17 2017 +0200
+++ b/jdk/src/solaris/classes/java/net/PlainSocketImpl.java	Sat Apr 12 20:21:09 2014 +0100
@@ -26,6 +26,12 @@
 
 import java.io.IOException;
 import java.io.FileDescriptor;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
+import jdk.net.*;
+
+import static sun.net.ExtendedOptionsImpl.*;
 
 /*
  * On Unix systems we simply delegate to native methods.
@@ -51,6 +57,42 @@
         this.fd = fd;
     }
 
+    protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
+        if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
+            super.setOption(name, value);
+        } else {
+            if (isClosedOrPending()) {
+                throw new SocketException("Socket closed");
+            }
+            checkSetOptionPermission(name);
+            checkValueType(value, SocketFlow.class);
+            setFlowOption(getFileDescriptor(), (SocketFlow)value);
+        }
+    }
+
+    protected <T> T getOption(SocketOption<T> name) throws IOException {
+        if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
+            return super.getOption(name);
+        }
+        if (isClosedOrPending()) {
+            throw new SocketException("Socket closed");
+        }
+        checkGetOptionPermission(name);
+        SocketFlow flow = SocketFlow.create();
+        getFlowOption(getFileDescriptor(), flow);
+        return (T)flow;
+    }
+
+    protected Set<SocketOption<?>> supportedOptions() {
+        HashSet<SocketOption<?>> options = new HashSet(
+            super.supportedOptions());
+
+        if (getSocket() != null && flowSupported()) {
+            options.add(ExtendedSocketOptions.SO_FLOW_SLA);
+        }
+        return options;
+    }
+
     native void socketCreate(boolean isServer) throws IOException;
 
     native void socketConnect(InetAddress address, int port, int timeout)
@@ -77,5 +119,4 @@
     native int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
 
     native void socketSendUrgentData(int data) throws IOException;
-
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/java/net/ExtendedOptionsImpl.c	Sat Apr 12 20:21:09 2014 +0100
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <jni.h>
+#include <string.h>
+
+#include "net_util.h"
+#include "jdk_net_SocketFlow.h"
+
+static jclass sf_status_class;          /* Status enum type */
+
+static jfieldID sf_status;
+static jfieldID sf_priority;
+static jfieldID sf_bandwidth;
+
+static jfieldID sf_fd_fdID;             /* FileDescriptor.fd */
+
+/* References to the literal enum values */
+
+static jobject sfs_NOSTATUS;
+static jobject sfs_OK;
+static jobject sfs_NOPERMISSION;
+static jobject sfs_NOTCONNECTED;
+static jobject sfs_NOTSUPPORTED;
+static jobject sfs_ALREADYCREATED;
+static jobject sfs_INPROGRESS;
+static jobject sfs_OTHER;
+
+static jobject getEnumField(JNIEnv *env, char *name);
+static void setStatus(JNIEnv *env, jobject obj, int errval);
+
+/* OS specific code is implemented in these three functions */
+
+static jboolean flowSupported0() ;
+
+/*
+ * Class:     sun_net_ExtendedOptionsImpl
+ * Method:    init
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_init
+  (JNIEnv *env, jclass UNUSED)
+{
+    static int initialized = 0;
+    jclass c;
+
+    /* Global class references */
+
+    if (initialized) {
+        return;
+    }
+
+    c = (*env)->FindClass(env, "jdk/net/SocketFlow$Status");
+    CHECK_NULL(c);
+    sf_status_class = (*env)->NewGlobalRef(env, c);
+    CHECK_NULL(sf_status_class);
+
+    /* int "fd" field of java.io.FileDescriptor  */
+
+    c = (*env)->FindClass(env, "java/io/FileDescriptor");
+    CHECK_NULL(c);
+    sf_fd_fdID = (*env)->GetFieldID(env, c, "fd", "I");
+    CHECK_NULL(sf_fd_fdID);
+
+
+    /* SocketFlow fields */
+
+    c = (*env)->FindClass(env, "jdk/net/SocketFlow");
+
+    /* status */
+
+    sf_status = (*env)->GetFieldID(env, c, "status",
+                                        "Ljdk/net/SocketFlow$Status;");
+    CHECK_NULL(sf_status);
+
+    /* priority */
+
+    sf_priority = (*env)->GetFieldID(env, c, "priority", "I");
+    CHECK_NULL(sf_priority);
+
+    /* bandwidth */
+
+    sf_bandwidth = (*env)->GetFieldID(env, c, "bandwidth", "J");
+    CHECK_NULL(sf_bandwidth);
+
+    /* Initialize the static enum values */
+
+    sfs_NOSTATUS = getEnumField(env, "NO_STATUS");
+    CHECK_NULL(sfs_NOSTATUS);
+    sfs_OK = getEnumField(env, "OK");
+    CHECK_NULL(sfs_OK);
+    sfs_NOPERMISSION = getEnumField(env, "NO_PERMISSION");
+    CHECK_NULL(sfs_NOPERMISSION);
+    sfs_NOTCONNECTED = getEnumField(env, "NOT_CONNECTED");
+    CHECK_NULL(sfs_NOTCONNECTED);
+    sfs_NOTSUPPORTED = getEnumField(env, "NOT_SUPPORTED");
+    CHECK_NULL(sfs_NOTSUPPORTED);
+    sfs_ALREADYCREATED = getEnumField(env, "ALREADY_CREATED");
+    CHECK_NULL(sfs_ALREADYCREATED);
+    sfs_INPROGRESS = getEnumField(env, "IN_PROGRESS");
+    CHECK_NULL(sfs_INPROGRESS);
+    sfs_OTHER = getEnumField(env, "OTHER");
+    CHECK_NULL(sfs_OTHER);
+    initialized = JNI_TRUE;
+}
+
+static jobject getEnumField(JNIEnv *env, char *name)
+{
+    jobject f;
+    jfieldID fID = (*env)->GetStaticFieldID(env, sf_status_class, name,
+        "Ljdk/net/SocketFlow$Status;");
+    CHECK_NULL_RETURN(fID, NULL);
+
+    f = (*env)->GetStaticObjectField(env, sf_status_class, fID);
+    CHECK_NULL_RETURN(f, NULL);
+    f  = (*env)->NewGlobalRef(env, f);
+    CHECK_NULL_RETURN(f, NULL);
+    return f;
+}
+
+/*
+ * Retrieve the int file-descriptor from a public socket type object.
+ * Gets impl, then the FileDescriptor from the impl, and then the fd
+ * from that.
+ */
+static int getFD(JNIEnv *env, jobject fileDesc) {
+    return (*env)->GetIntField(env, fileDesc, sf_fd_fdID);
+}
+
+/**
+ * Sets the status field of a SocketFlow to one of the
+ * canned enum values
+ */
+static void setStatus (JNIEnv *env, jobject obj, int errval)
+{
+    switch (errval) {
+      case 0: /* OK */
+        (*env)->SetObjectField(env, obj, sf_status, sfs_OK);
+        break;
+      case EPERM:
+        (*env)->SetObjectField(env, obj, sf_status, sfs_NOPERMISSION);
+        break;
+      case ENOTCONN:
+        (*env)->SetObjectField(env, obj, sf_status, sfs_NOTCONNECTED);
+        break;
+      case EOPNOTSUPP:
+        (*env)->SetObjectField(env, obj, sf_status, sfs_NOTSUPPORTED);
+        break;
+      case EALREADY:
+        (*env)->SetObjectField(env, obj, sf_status, sfs_ALREADYCREATED);
+        break;
+      case EINPROGRESS:
+        (*env)->SetObjectField(env, obj, sf_status, sfs_INPROGRESS);
+        break;
+      default:
+        (*env)->SetObjectField(env, obj, sf_status, sfs_OTHER);
+        break;
+    }
+}
+
+#ifdef __solaris__
+
+/*
+ * Class:     sun_net_ExtendedOptionsImpl
+ * Method:    setFlowOption
+ * Signature: (Ljava/io/FileDescriptor;Ljdk/net/SocketFlow;)V
+ */
+JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption
+  (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow)
+{
+    int fd = getFD(env, fileDesc);
+
+    if (fd < 0) {
+        NET_ERROR(env, JNU_JAVANETPKG "SocketException", "socket closed");
+        return;
+    } else {
+        sock_flow_props_t props;
+        jlong bandwidth;
+        int rv;
+
+        jint priority = (*env)->GetIntField(env, flow, sf_priority);
+        memset(&props, 0, sizeof(props));
+        props.sfp_version = SOCK_FLOW_PROP_VERSION1;
+
+        if (priority != jdk_net_SocketFlow_UNSET) {
+            props.sfp_mask |= SFP_PRIORITY;
+            props.sfp_priority = priority;
+        }
+        bandwidth = (*env)->GetLongField(env, flow, sf_bandwidth);
+        if (bandwidth > -1)  {
+            props.sfp_mask |= SFP_MAXBW;
+            props.sfp_maxbw = (uint64_t) bandwidth;
+        }
+        rv = setsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props));
+        if (rv < 0) {
+            if (errno == ENOPROTOOPT) {
+                JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+                        "unsupported socket option");
+            } else {
+                NET_ERROR(env, JNU_JAVANETPKG "SocketException",
+                                "set option SO_FLOW_SLA failed");
+            }
+            return;
+        }
+        setStatus(env, flow, props.sfp_status);
+    }
+}
+
+/*
+ * Class:     sun_net_ExtendedOptionsImpl
+ * Method:    getFlowOption
+ * Signature: (Ljava/io/FileDescriptor;Ljdk/net/SocketFlow;)V
+ */
+JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption
+  (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow)
+{
+    int fd = getFD(env, fileDesc);
+
+    if (fd < 0) {
+        NET_ERROR(env, JNU_JAVANETPKG "SocketException", "socket closed");
+        return;
+    } else {
+        sock_flow_props_t props;
+        int status;
+        socklen_t sz = sizeof(props);
+
+        int rv = getsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, &sz);
+        if (rv < 0) {
+            if (errno == ENOPROTOOPT) {
+                JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+                        "unsupported socket option");
+            } else {
+                NET_ERROR(env, JNU_JAVANETPKG "SocketException",
+                                "set option SO_FLOW_SLA failed");
+            }
+            return;
+        }
+        /* first check status to see if flow exists */
+        status = props.sfp_status;
+        setStatus(env, flow, status);
+        if (status == 0) { /* OK */
+            /* can set the other fields now */
+            if (props.sfp_mask & SFP_PRIORITY) {
+                (*env)->SetIntField(env, flow, sf_priority, props.sfp_priority);
+            }
+            if (props.sfp_mask & SFP_MAXBW) {
+                (*env)->SetLongField(env, flow, sf_bandwidth,
+                                        (jlong)props.sfp_maxbw);
+            }
+        }
+    }
+}
+
+static jboolean flowsupported;
+static jboolean flowsupported_set = JNI_FALSE;
+
+static jboolean flowSupported0()
+{
+    /* Do a simple dummy call, and try to figure out from that */
+    sock_flow_props_t props;
+    int rv, s;
+    if (flowsupported_set) {
+        return flowsupported;
+    }
+    s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (s < 0) {
+        flowsupported = JNI_FALSE;
+        flowsupported_set = JNI_TRUE;
+        return JNI_FALSE;
+    }
+    memset(&props, 0, sizeof(props));
+    props.sfp_version = SOCK_FLOW_PROP_VERSION1;
+    props.sfp_mask |= SFP_PRIORITY;
+    props.sfp_priority = SFP_PRIO_NORMAL;
+    rv = setsockopt(s, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props));
+    if (rv != 0 && errno == ENOPROTOOPT) {
+        rv = JNI_FALSE;
+    } else {
+        rv = JNI_TRUE;
+    }
+    close(s);
+    flowsupported = rv;
+    flowsupported_set = JNI_TRUE;
+    return flowsupported;
+}
+
+#else /* __solaris__ */
+
+/* Non Solaris. Functionality is not supported. So, throw UnsupportedOpExc */
+
+JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption
+  (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow)
+{
+    JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+        "unsupported socket option");
+}
+
+JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption
+  (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow)
+{
+    JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+        "unsupported socket option");
+}
+
+static jboolean flowSupported0()  {
+    return JNI_FALSE;
+}
+
+#endif /* __solaris__ */
+
+JNIEXPORT jboolean JNICALL Java_sun_net_ExtendedOptionsImpl_flowSupported
+  (JNIEnv *env, jclass UNUSED)
+{
+    return flowSupported0();
+}
--- a/jdk/src/solaris/native/java/net/net_util_md.h	Wed Jul 05 19:36:17 2017 +0200
+++ b/jdk/src/solaris/native/java/net/net_util_md.h	Sat Apr 12 20:21:09 2014 +0100
@@ -107,6 +107,47 @@
 
 #ifdef __solaris__
 int net_getParam(char *driver, char *param);
+
+#ifndef SO_FLOW_SLA
+#define SO_FLOW_SLA 0x1018
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack(4)
 #endif
 
+/*
+ * Used with the setsockopt(SO_FLOW_SLA, ...) call to set
+ * per socket service level properties.
+ * When the application uses per-socket API, we will enforce the properties
+ * on both outbound and inbound packets.
+ *
+ * For now, only priority and maxbw are supported in SOCK_FLOW_PROP_VERSION1.
+ */
+typedef struct sock_flow_props_s {
+        int             sfp_version;
+        uint32_t        sfp_mask;
+        int             sfp_priority;   /* flow priority */
+        uint64_t        sfp_maxbw;      /* bandwidth limit in bps */
+        int             sfp_status;     /* flow create status for getsockopt */
+} sock_flow_props_t;
+
+#define SOCK_FLOW_PROP_VERSION1 1
+
+/* bit mask values for sfp_mask */
+#define SFP_MAXBW       0x00000001      /* Flow Bandwidth Limit */
+#define SFP_PRIORITY    0x00000008      /* Flow priority */
+
+/* possible values for sfp_priority */
+#define SFP_PRIO_NORMAL 1
+#define SFP_PRIO_HIGH   2
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack()
+#endif /* _LONG_LONG_ALIGNMENT */
+
+#endif /* SO_FLOW_SLA */
+#endif /* __solaris__ */
+
+JNIEXPORT jboolean JNICALL NET_IsFlowSupported();
+
 #endif /* NET_UTILS_MD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/native/java/net/ExtendedOptionsImpl.c	Sat Apr 12 20:21:09 2014 +0100
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <jni.h>
+#include <string.h>
+
+#include "net_util.h"
+
+/*
+ * Class:     sun_net_ExtendedOptionsImpl
+ * Method:    init
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_init
+  (JNIEnv *env, jclass UNUSED)
+{
+}
+
+/* Non Solaris. Functionality is not supported. So, throw UnsupportedOpExc */
+
+JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption
+  (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow)
+{
+    JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+        "unsupported socket option");
+}
+
+JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption
+  (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow)
+{
+    JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+        "unsupported socket option");
+}
+
+static jboolean flowSupported0()  {
+    return JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL Java_sun_net_ExtendedOptionsImpl_flowSupported
+  (JNIEnv *env, jclass UNUSED)
+{
+    return JNI_FALSE;
+}
--- a/jdk/test/TEST.groups	Wed Jul 05 19:36:17 2017 +0200
+++ b/jdk/test/TEST.groups	Sat Apr 12 20:21:09 2014 +0100
@@ -102,7 +102,8 @@
 jdk_net = \
     java/net \
     com/sun/net/httpserver \
-    sun/net
+    sun/net \
+    jdk/net
 
 jdk_time = \
     java/time
@@ -284,7 +285,7 @@
     javax/accessibility \
     com/sun/java/swing \
     sun/pisces \
-    com/sun/awt  
+    com/sun/awt
 
 
 ###############################################################################
@@ -294,7 +295,7 @@
 # - compact1, compact2, compact3, full JRE, JDK
 #
 # In addition they support testing of the minimal VM on compact1 and compact2.
-# Essentially this defines groups based around the specified API's and VM 
+# Essentially this defines groups based around the specified API's and VM
 # services available in the runtime.
 #
 # The groups are defined hierarchically in two forms:
@@ -506,7 +507,7 @@
  -:needs_jdk
 
 # Tests that require compact2 API's and a full VM
-#  
+#
 needs_full_vm_compact2 =
 
 # Minimal VM on Compact 2 adds in some compact2 tests
@@ -590,7 +591,7 @@
   javax/crypto/Cipher/CipherStreamClose.java \
   sun/misc/URLClassPath/ClassnameCharTest.java \
   sun/net/www/protocol/https/HttpsURLConnection/HttpsCreateSockTest.java \
-  sun/net/www/protocol/https/HttpsURLConnection/HttpsSocketFacTest.java 
+  sun/net/www/protocol/https/HttpsURLConnection/HttpsSocketFacTest.java
 
 # Compact 1 adds full VM tests
 #
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/SocketOption/OptionsTest.java	Sat Apr 12 20:21:09 2014 +0100
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8036979
+ * @run main/othervm -Xcheck:jni OptionsTest
+ */
+
+import java.net.*;
+import java.util.*;
+
+public class OptionsTest {
+
+    static class Test {
+        Test(SocketOption<?> option, Object testValue) {
+            this.option = option;
+            this.testValue = testValue;
+        }
+        static Test create (SocketOption<?> option, Object testValue) {
+            return new Test(option, testValue);
+        }
+        Object option;
+        Object testValue;
+    };
+
+    // The tests set the option using the new API, read back the set value
+    // which could be diferent, and then use the legacy get API to check
+    // these values are the same
+
+    static Test[] socketTests = new Test[] {
+        Test.create(StandardSocketOptions.SO_KEEPALIVE, Boolean.TRUE),
+        Test.create(StandardSocketOptions.SO_SNDBUF, Integer.valueOf(10 * 100)),
+        Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)),
+        Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE),
+        Test.create(StandardSocketOptions.SO_LINGER, Integer.valueOf(80)),
+        Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100))
+    };
+
+    static Test[] serverSocketTests = new Test[] {
+        Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)),
+        Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE)
+    };
+
+    static Test[] dgSocketTests = new Test[] {
+        Test.create(StandardSocketOptions.SO_SNDBUF, Integer.valueOf(10 * 100)),
+        Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)),
+        Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE),
+        Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100))
+    };
+
+    static Test[] mcSocketTests = new Test[] {
+        Test.create(StandardSocketOptions.IP_MULTICAST_IF, getNetworkInterface()),
+        Test.create(StandardSocketOptions.IP_MULTICAST_TTL, Integer.valueOf(10)),
+        Test.create(StandardSocketOptions.IP_MULTICAST_LOOP, Boolean.TRUE)
+    };
+
+    static NetworkInterface getNetworkInterface() {
+        try {
+            Enumeration<NetworkInterface> nifs = NetworkInterface.getNetworkInterfaces();
+            if (nifs.hasMoreElements()) {
+                return (NetworkInterface)nifs.nextElement();
+            }
+        } catch (Exception e) {
+        }
+        return null;
+    }
+
+    static void doSocketTests() throws Exception {
+        try (
+            ServerSocket srv = new ServerSocket(0);
+            Socket c = new Socket("127.0.0.1", srv.getLocalPort());
+            Socket s = srv.accept();
+        ) {
+            for (int i=0; i<socketTests.length; i++) {
+                Test test = socketTests[i];
+                c.setOption((SocketOption)test.option, test.testValue);
+                Object getval = c.getOption((SocketOption)test.option);
+                Object legacyget = legacyGetOption(Socket.class, c,test.option);
+                if (!getval.equals(legacyget)) {
+                    Formatter f = new Formatter();
+                    f.format("S Err %d: %s/%s", i, getval, legacyget);
+                    throw new RuntimeException(f.toString());
+                }
+            }
+        }
+    }
+
+    static void doDgSocketTests() throws Exception {
+        try (
+            DatagramSocket c = new DatagramSocket(0);
+        ) {
+            for (int i=0; i<dgSocketTests.length; i++) {
+                Test test = dgSocketTests[i];
+                c.setOption((SocketOption)test.option, test.testValue);
+                Object getval = c.getOption((SocketOption)test.option);
+                Object legacyget = legacyGetOption(DatagramSocket.class, c,test.option);
+                if (!getval.equals(legacyget)) {
+                    Formatter f = new Formatter();
+                    f.format("DG Err %d: %s/%s", i, getval, legacyget);
+                    throw new RuntimeException(f.toString());
+                }
+            }
+        }
+    }
+
+    static void doMcSocketTests() throws Exception {
+        try (
+            MulticastSocket c = new MulticastSocket(0);
+        ) {
+            for (int i=0; i<mcSocketTests.length; i++) {
+                Test test = mcSocketTests[i];
+                c.setOption((SocketOption)test.option, test.testValue);
+                Object getval = c.getOption((SocketOption)test.option);
+                Object legacyget = legacyGetOption(MulticastSocket.class, c,test.option);
+                if (!getval.equals(legacyget)) {
+                    Formatter f = new Formatter();
+                    f.format("MC Err %d: %s/%s", i, getval, legacyget);
+                    throw new RuntimeException(f.toString());
+                }
+            }
+        }
+    }
+
+    static void doServerSocketTests() throws Exception {
+        try (
+            ServerSocket c = new ServerSocket(0);
+        ) {
+            for (int i=0; i<serverSocketTests.length; i++) {
+                Test test = serverSocketTests[i];
+                c.setOption((SocketOption)test.option, test.testValue);
+                Object getval = c.getOption((SocketOption)test.option);
+                Object legacyget = legacyGetOption(
+                    ServerSocket.class, c, test.option
+                );
+                if (!getval.equals(legacyget)) {
+                    Formatter f = new Formatter();
+                    f.format("SS Err %d: %s/%s", i, getval, legacyget);
+                    throw new RuntimeException(f.toString());
+                }
+            }
+        }
+    }
+
+    static Object legacyGetOption(
+        Class<?> type, Object s, Object option)
+
+        throws Exception
+    {
+        if (type.equals(Socket.class)) {
+            Socket socket = (Socket)s;
+
+            if (option.equals(StandardSocketOptions.SO_KEEPALIVE)) {
+                return Boolean.valueOf(socket.getKeepAlive());
+            } else if (option.equals(StandardSocketOptions.SO_SNDBUF)) {
+                return Integer.valueOf(socket.getSendBufferSize());
+            } else if (option.equals(StandardSocketOptions.SO_RCVBUF)) {
+                return Integer.valueOf(socket.getReceiveBufferSize());
+            } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
+                return Boolean.valueOf(socket.getReuseAddress());
+            } else if (option.equals(StandardSocketOptions.SO_LINGER)) {
+                return Integer.valueOf(socket.getSoLinger());
+            } else if (option.equals(StandardSocketOptions.IP_TOS)) {
+                return Integer.valueOf(socket.getTrafficClass());
+            } else if (option.equals(StandardSocketOptions.TCP_NODELAY)) {
+                return Boolean.valueOf(socket.getTcpNoDelay());
+            } else {
+                throw new RuntimeException("unexecpted socket option");
+            }
+        } else if  (type.equals(ServerSocket.class)) {
+            ServerSocket socket = (ServerSocket)s;
+            if (option.equals(StandardSocketOptions.SO_RCVBUF)) {
+                return Integer.valueOf(socket.getReceiveBufferSize());
+            } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
+                return Boolean.valueOf(socket.getReuseAddress());
+            } else {
+                throw new RuntimeException("unexecpted socket option");
+            }
+        } else if  (type.equals(DatagramSocket.class)) {
+            DatagramSocket socket = (DatagramSocket)s;
+
+            if (option.equals(StandardSocketOptions.SO_SNDBUF)) {
+                return Integer.valueOf(socket.getSendBufferSize());
+            } else if (option.equals(StandardSocketOptions.SO_RCVBUF)) {
+                return Integer.valueOf(socket.getReceiveBufferSize());
+            } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
+                return Boolean.valueOf(socket.getReuseAddress());
+            } else if (option.equals(StandardSocketOptions.IP_TOS)) {
+                return Integer.valueOf(socket.getTrafficClass());
+            } else {
+                throw new RuntimeException("unexecpted socket option");
+            }
+
+        } else if  (type.equals(MulticastSocket.class)) {
+            MulticastSocket socket = (MulticastSocket)s;
+
+            if (option.equals(StandardSocketOptions.SO_SNDBUF)) {
+                return Integer.valueOf(socket.getSendBufferSize());
+            } else if (option.equals(StandardSocketOptions.SO_RCVBUF)) {
+                return Integer.valueOf(socket.getReceiveBufferSize());
+            } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
+                return Boolean.valueOf(socket.getReuseAddress());
+            } else if (option.equals(StandardSocketOptions.IP_TOS)) {
+                return Integer.valueOf(socket.getTrafficClass());
+            } else if (option.equals(StandardSocketOptions.IP_MULTICAST_IF)) {
+                return socket.getNetworkInterface();
+            } else if (option.equals(StandardSocketOptions.IP_MULTICAST_TTL)) {
+                return Integer.valueOf(socket.getTimeToLive());
+            } else if (option.equals(StandardSocketOptions.IP_MULTICAST_LOOP)) {
+                return Boolean.valueOf(socket.getLoopbackMode());
+            } else {
+                throw new RuntimeException("unexecpted socket option");
+            }
+        }
+        throw new RuntimeException("unexecpted socket type");
+    }
+
+    public static void main(String args[]) throws Exception {
+        doSocketTests();
+        doServerSocketTests();
+        doDgSocketTests();
+        doMcSocketTests();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/net/Sockets/Test.java	Sat Apr 12 20:21:09 2014 +0100
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8032808
+ * @run main/othervm -Xcheck:jni Test
+ * @run main/othervm/policy=policy.fail -Xcheck:jni Test fail
+ * @run main/othervm/policy=policy.success -Xcheck:jni Test success
+ */
+
+import java.net.*;
+import java.nio.channels.*;
+import java.util.concurrent.*;
+import jdk.net.*;
+
+public class Test {
+
+    static boolean security;
+    static boolean success;
+
+    interface Runner {
+        public void run() throws Exception;
+    }
+
+    public static void main(String[] args) throws Exception {
+
+        // quick check to see if supportedOptions() working before
+        // creating any sockets and libnet loaded
+
+        Sockets.supportedOptions(Socket.class);
+
+        security = System.getSecurityManager() != null;
+        success = security && args[0].equals("success");
+
+        // Main thing is to check for JNI problems
+        // Doesn't matter if current system does not support the option
+        // and currently setting the option with the loopback interface
+        // doesn't work either
+
+        System.out.println ("Security Manager enabled: " + security);
+        if (security) {
+            System.out.println ("Success expected: " + success);
+        }
+
+        final SocketFlow flowIn = SocketFlow.create()
+            .bandwidth(1000)
+            .priority(SocketFlow.HIGH_PRIORITY);
+
+        ServerSocket ss = new ServerSocket(0);
+        int tcp_port = ss.getLocalPort();
+        final InetAddress loop = InetAddress.getByName("127.0.0.1");
+        final InetSocketAddress loopad = new InetSocketAddress(loop, tcp_port);
+
+        DatagramSocket dg = new DatagramSocket(0);
+        final int udp_port = dg.getLocalPort();
+
+        final Socket s = new Socket("127.0.0.1", tcp_port);
+        final SocketChannel sc = SocketChannel.open();
+        sc.connect (new InetSocketAddress("127.0.0.1", tcp_port));
+
+        doTest(()->{
+            Sockets.setOption(s, ExtendedSocketOptions.SO_FLOW_SLA, flowIn);
+        });
+        doTest(()->{
+            Sockets.getOption(s, ExtendedSocketOptions.SO_FLOW_SLA);
+        });
+        doTest(()->{
+            sc.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn);
+        });
+        doTest(()->{
+            sc.getOption(ExtendedSocketOptions.SO_FLOW_SLA);
+        });
+        doTest(()->{
+            DatagramSocket dg1 = new DatagramSocket(0);
+            dg1.connect(loop, udp_port);
+            Sockets.setOption(dg1, ExtendedSocketOptions.SO_FLOW_SLA, flowIn);
+        });
+        doTest(()->{
+            DatagramChannel dg2 = DatagramChannel.open();
+            dg2.bind(new InetSocketAddress(loop, 0));
+            dg2.connect(new InetSocketAddress(loop, udp_port));
+            dg2.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn);
+        });
+        doTest(()->{
+            MulticastSocket mc1 = new MulticastSocket(0);
+            mc1.connect(loop, udp_port);
+            Sockets.setOption(mc1, ExtendedSocketOptions.SO_FLOW_SLA, flowIn);
+        });
+        doTest(()->{
+            AsynchronousSocketChannel asc = AsynchronousSocketChannel.open();
+            Future<Void> f = asc.connect(loopad);
+            f.get();
+            asc.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn);
+        });
+    }
+
+    static void doTest(Runner func) throws Exception {
+        try {
+            func.run();
+            if (security && !success) {
+                throw new RuntimeException("Test failed");
+            }
+        } catch (SecurityException e) {
+            if (success) {
+                throw new RuntimeException("Test failed");
+            }
+        } catch (UnsupportedOperationException e) {}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/net/Sockets/policy.fail	Sat Apr 12 20:21:09 2014 +0100
@@ -0,0 +1,4 @@
+grant {
+    permission java.net.SocketPermission "127.0.0.1", "connect,accept" ;
+    permission java.net.SocketPermission "localhost", "listen" ;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/net/Sockets/policy.success	Sat Apr 12 20:21:09 2014 +0100
@@ -0,0 +1,6 @@
+grant {
+    permission java.net.SocketPermission "127.0.0.1", "connect,accept" ;
+    permission java.net.SocketPermission "localhost", "listen" ;
+    permission jdk.net.NetworkPermission "setOption.SO_FLOW_SLA";
+    permission jdk.net.NetworkPermission "getOption.SO_FLOW_SLA";
+};