Import upstream change: Support Solaris SO_FLOW_SLA socket option

Upstream Change:

    8032808: Support Solaris SO_FLOW_SLA socket option
    Reviewed-by: alanb, chegar

    http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/7f04532ee859

The change has no effect for Linux/Android, however we keep it to
minimize local diff.

Bug: 29067535
Change-Id: I3748377ef382545424a6af720fc97d204f677d09
diff --git a/ojluni/src/main/java/java/net/DatagramSocket.java b/ojluni/src/main/java/java/net/DatagramSocket.java
index 6d43ad0..84d2a06 100755
--- a/ojluni/src/main/java/java/net/DatagramSocket.java
+++ b/ojluni/src/main/java/java/net/DatagramSocket.java
@@ -354,6 +354,7 @@
         }
         // creates a udp socket
         impl.create();
+        impl.setDatagramSocket(this);
         created = true;
     }
 
diff --git a/ojluni/src/main/java/java/net/DatagramSocketImpl.java b/ojluni/src/main/java/java/net/DatagramSocketImpl.java
index bbabc03..bdee48c 100755
--- a/ojluni/src/main/java/java/net/DatagramSocketImpl.java
+++ b/ojluni/src/main/java/java/net/DatagramSocketImpl.java
@@ -54,6 +54,20 @@
     }
 
     /**
+     * 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.
@@ -239,6 +253,56 @@
         return localPort;
     }
 
+    <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");
+        }
+    }
+
+    <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");
+        }
+    }
+
     /**
      * Gets the datagram socket file descriptor.
      * @return a {@code FileDescriptor} object representing the datagram socket
diff --git a/ojluni/src/main/java/java/net/SocketImpl.java b/ojluni/src/main/java/java/net/SocketImpl.java
index eeacd64..688ba60 100755
--- a/ojluni/src/main/java/java/net/SocketImpl.java
+++ b/ojluni/src/main/java/java/net/SocketImpl.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2013, 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
@@ -362,4 +362,44 @@
     {
         /* Not implemented yet */
     }
+
+    <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");
+        }
+    }
+
+    <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");
+        }
+    }
 }
diff --git a/ojluni/src/main/java/java/net/SocketSecrets.java b/ojluni/src/main/java/java/net/SocketSecrets.java
new file mode 100644
index 0000000..9772906
--- /dev/null
+++ b/ojluni/src/main/java/java/net/SocketSecrets.java
@@ -0,0 +1,70 @@
+/*
+ * 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 java.net;
+
+import java.io.IOException;
+
+class SocketSecrets {
+
+    /* accessed by reflection from jdk.net.Sockets */
+
+    /* obj must be a Socket or ServerSocket */
+
+    private static <T> void setOption(Object obj, SocketOption<T> name, T value) throws IOException {
+        SocketImpl impl;
+
+        if (obj instanceof Socket) {
+            impl = ((Socket)obj).getImpl();
+        } else if (obj instanceof ServerSocket) {
+            impl = ((ServerSocket)obj).getImpl();
+        } else {
+            throw new IllegalArgumentException();
+        }
+        impl.setOption(name, value);
+    }
+
+    private static <T> T getOption(Object obj, SocketOption<T> name) throws IOException {
+        SocketImpl impl;
+
+        if (obj instanceof Socket) {
+            impl = ((Socket)obj).getImpl();
+        } else if (obj instanceof ServerSocket) {
+            impl = ((ServerSocket)obj).getImpl();
+        } else {
+            throw new IllegalArgumentException();
+        }
+        return impl.getOption(name);
+    }
+
+    private static <T> void setOption(DatagramSocket s, SocketOption<T> name, T value) throws IOException {
+        s.getImpl().setOption(name, value);
+    }
+
+    private static <T> T getOption(DatagramSocket s, SocketOption<T> name) throws IOException {
+        return s.getImpl().getOption(name);
+    }
+
+}
diff --git a/ojluni/src/main/java/jdk/net/ExtendedSocketOptions.java b/ojluni/src/main/java/jdk/net/ExtendedSocketOptions.java
new file mode 100644
index 0000000..73c67d8
--- /dev/null
+++ b/ojluni/src/main/java/jdk/net/ExtendedSocketOptions.java
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+//@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);
+}
diff --git a/ojluni/src/main/java/jdk/net/NetworkPermission.java b/ojluni/src/main/java/jdk/net/NetworkPermission.java
new file mode 100644
index 0000000..420c74f
--- /dev/null
+++ b/ojluni/src/main/java/jdk/net/NetworkPermission.java
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+/**
+ * Legacy security code; do not use.
+ */
+
+//@jdk.Exported
+public final class NetworkPermission extends BasicPermission {
+
+    public NetworkPermission(String name) {
+        super("");
+    }
+
+    public NetworkPermission(String name, String actions) {
+        super("", "");
+    }
+}
diff --git a/ojluni/src/main/java/jdk/net/SocketFlow.java b/ojluni/src/main/java/jdk/net/SocketFlow.java
new file mode 100644
index 0000000..a8ca749
--- /dev/null
+++ b/ojluni/src/main/java/jdk/net/SocketFlow.java
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+//@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.
+     */
+//    @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;
+    }
+}
diff --git a/ojluni/src/main/java/jdk/net/Sockets.java b/ojluni/src/main/java/jdk/net/Sockets.java
new file mode 100644
index 0000000..1187eb3
--- /dev/null
+++ b/ojluni/src/main/java/jdk/net/Sockets.java
@@ -0,0 +1,407 @@
+/*
+ * 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.*;
+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.StandardSocketOptions}.
+ *
+ * @see java.nio.channels.NetworkChannel
+ */
+//@jdk.Exported
+public class Sockets {
+
+    private final static HashMap<Class<?>,Set<SocketOption<?>>>
+        options = new HashMap<>();
+
+    static {
+        initOptionSets();
+        AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Void>() {
+                public Void run() {
+                    initMethods();
+                    return null;
+                }
+            }
+        );
+    }
+
+    private static Method siSetOption;
+    private static Method siGetOption;
+    private static Method dsiSetOption;
+    private static Method dsiGetOption;
+
+    private static void initMethods() {
+        try {
+            Class<?> clazz = Class.forName("java.net.SocketSecrets");
+
+            siSetOption = clazz.getDeclaredMethod(
+                "setOption", Object.class,
+                SocketOption.class, Object.class
+            );
+            siSetOption.setAccessible(true);
+
+            siGetOption = clazz.getDeclaredMethod(
+                "getOption", Object.class, SocketOption.class
+            );
+            siGetOption.setAccessible(true);
+
+            dsiSetOption = clazz.getDeclaredMethod(
+                "setOption", DatagramSocket.class,
+                SocketOption.class, Object.class
+            );
+            dsiSetOption.setAccessible(true);
+
+            dsiGetOption = clazz.getDeclaredMethod(
+                "getOption", DatagramSocket.class, SocketOption.class
+            );
+            dsiGetOption.setAccessible(true);
+        } catch (ReflectiveOperationException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    private static <T> void invokeSet(
+        Method method, Object socket,
+        SocketOption<T> option, T value) throws IOException
+    {
+        try {
+            method.invoke(null, socket, option, value);
+        } catch (Exception e) {
+            if (e instanceof InvocationTargetException) {
+                Throwable t = ((InvocationTargetException)e).getTargetException();
+                if (t instanceof IOException) {
+                    throw (IOException)t;
+                } else if (t instanceof RuntimeException) {
+                    throw (RuntimeException)t;
+                }
+            }
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static <T> T invokeGet(
+        Method method, Object socket, SocketOption<T> option) throws IOException
+    {
+        try {
+            return (T)method.invoke(null, socket, option);
+        } catch (Exception e) {
+            if (e instanceof InvocationTargetException) {
+                Throwable t = ((InvocationTargetException)e).getTargetException();
+                if (t instanceof IOException) {
+                    throw (IOException)t;
+                } else if (t instanceof RuntimeException) {
+                    throw (RuntimeException)t;
+                }
+            }
+            throw new RuntimeException(e);
+        }
+    }
+
+    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
+    {
+        if (!isSupported(Socket.class, name)) {
+            throw new UnsupportedOperationException(name.name());
+        }
+        invokeSet(siSetOption, s, 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
+    {
+        if (!isSupported(Socket.class, name)) {
+            throw new UnsupportedOperationException(name.name());
+        }
+        return invokeGet(siGetOption, s, 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
+    {
+        if (!isSupported(ServerSocket.class, name)) {
+            throw new UnsupportedOperationException(name.name());
+        }
+        invokeSet(siSetOption, s, 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
+    {
+        if (!isSupported(ServerSocket.class, name)) {
+            throw new UnsupportedOperationException(name.name());
+        }
+        return invokeGet(siGetOption, s, 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
+    {
+        if (!isSupported(s.getClass(), name)) {
+            throw new UnsupportedOperationException(name.name());
+        }
+        invokeSet(dsiSetOption, s, 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
+    {
+        if (!isSupported(s.getClass(), name)) {
+            throw new UnsupportedOperationException(name.name());
+        }
+        return invokeGet(dsiGetOption, s, 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 boolean isSupported(Class<?> type, SocketOption<?> option) {
+        Set<SocketOption<?>> options = supportedOptions(type);
+        return options.contains(option);
+    }
+
+    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.add(StandardSocketOptions.IP_TOS);
+        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);
+    }
+}
diff --git a/ojluni/src/main/java/jdk/net/package-info.java b/ojluni/src/main/java/jdk/net/package-info.java
new file mode 100644
index 0000000..b05d543
--- /dev/null
+++ b/ojluni/src/main/java/jdk/net/package-info.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+@jdk.Exported
+package jdk.net;
diff --git a/ojluni/src/main/java/sun/net/ExtendedOptionsImpl.java b/ojluni/src/main/java/sun/net/ExtendedOptionsImpl.java
new file mode 100644
index 0000000..240f705
--- /dev/null
+++ b/ojluni/src/main/java/sun/net/ExtendedOptionsImpl.java
@@ -0,0 +1,101 @@
+/*
+ * 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
+     */
+    // Android-changed: Linux does not support flow operations.
+    public static void setFlowOption(FileDescriptor fd, SocketFlow f) {
+        throw new UnsupportedOperationException("unsupported socket option");
+    }
+
+    public static void getFlowOption(FileDescriptor fd, SocketFlow f) {
+        throw new UnsupportedOperationException("unsupported socket option");
+    }
+
+    public static boolean flowSupported() {
+        return false;
+    }
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/AsynchronousSocketChannelImpl.java b/ojluni/src/main/java/sun/nio/ch/AsynchronousSocketChannelImpl.java
index af20709..a106d41 100755
--- a/ojluni/src/main/java/sun/nio/ch/AsynchronousSocketChannelImpl.java
+++ b/ojluni/src/main/java/sun/nio/ch/AsynchronousSocketChannelImpl.java
@@ -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
@@ -504,6 +505,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);
         }
     }
diff --git a/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java b/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java
index d1b398fa..c93e82d 100755
--- a/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java
+++ b/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java
@@ -33,6 +33,7 @@
 import java.nio.channels.*;
 import java.nio.channels.spi.*;
 import java.util.*;
+import sun.net.ExtendedOptionsImpl;
 
 import dalvik.system.BlockGuard;
 import sun.net.ResourceManager;
@@ -321,6 +322,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);
         }
     }
diff --git a/ojluni/src/main/java/sun/nio/ch/Net.java b/ojluni/src/main/java/sun/nio/ch/Net.java
index 99d2629..24ea94c 100755
--- a/ojluni/src/main/java/sun/nio/ch/Net.java
+++ b/ojluni/src/main/java/sun/nio/ch/Net.java
@@ -30,11 +30,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;
 
 
 class Net {                                             // package-private
@@ -337,6 +339,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");
 
@@ -389,6 +401,16 @@
     {
         Class<?> type = name.type();
 
+        if (type == SocketFlow.class) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                sm.checkPermission(new NetworkPermission("setOption.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");
diff --git a/ojluni/src/main/java/sun/nio/ch/SocketChannelImpl.java b/ojluni/src/main/java/sun/nio/ch/SocketChannelImpl.java
index 453b15b..c73eec5 100755
--- a/ojluni/src/main/java/sun/nio/ch/SocketChannelImpl.java
+++ b/ojluni/src/main/java/sun/nio/ch/SocketChannelImpl.java
@@ -37,6 +37,7 @@
 import dalvik.system.BlockGuard;
 import sun.net.NetHooks;
 import sun.misc.IoTrace;
+import sun.net.ExtendedOptionsImpl;
 
 /**
  * An implementation of SocketChannels
@@ -240,6 +241,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);
         }
     }
diff --git a/ojluni/src/main/native/net_util.h b/ojluni/src/main/native/net_util.h
index 74e8089..2f5cffd 100755
--- a/ojluni/src/main/native/net_util.h
+++ b/ojluni/src/main/native/net_util.h
@@ -40,7 +40,7 @@
 #define IPv6 AF_INET6
 
 #define NET_ERROR(env, ex, msg) \
-{ if (!(*env)->ExceptionOccurred(env)) JNU_ThrowByName(env, ex, msg) }
+{ if (!(*env)->ExceptionOccurred(env)) JNU_ThrowByName(env, ex, msg); }
 
 #define CHECK_NULL(x) if ((x) == NULL) return;
 #define CHECK_NULL_RETURN(x, y) if ((x) == NULL) return y;
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index 9fa9afa..a0ba44f 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -1156,6 +1156,10 @@
     ojluni/src/main/java/java/util/spi/LocaleNameProvider.java \
     ojluni/src/main/java/java/util/spi/LocaleServiceProvider.java \
     ojluni/src/main/java/java/util/spi/TimeZoneNameProvider.java \
+    ojluni/src/main/java/jdk/net/ExtendedSocketOptions.java \
+    ojluni/src/main/java/jdk/net/NetworkPermission.java \
+    ojluni/src/main/java/jdk/net/SocketFlow.java \
+    ojluni/src/main/java/jdk/net/Sockets.java \
     ojluni/src/main/java/sun/misc/ASCIICaseInsensitiveComparator.java \
     ojluni/src/main/java/sun/misc/BASE64Decoder.java \
     ojluni/src/main/java/sun/misc/BASE64Encoder.java \
@@ -1195,6 +1199,7 @@
     ojluni/src/main/java/sun/misc/VM.java \
     ojluni/src/main/java/sun/net/ApplicationProxy.java \
     ojluni/src/main/java/sun/net/ConnectionResetException.java \
+    ojluni/src/main/java/sun/net/ExtendedOptionsImpl.java \
     ojluni/src/main/java/sun/net/ftp/FtpClient.java \
     ojluni/src/main/java/sun/net/ftp/FtpClientProvider.java \
     ojluni/src/main/java/sun/net/ftp/FtpDirEntry.java \