jdk/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java
changeset 36115 0676e37a0b9c
parent 32649 2ee9017c7597
child 38477 f462865d453d
--- a/jdk/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java	Tue Feb 23 09:49:04 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java	Tue Feb 23 17:41:00 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2016, 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
@@ -33,6 +33,9 @@
 import sun.net.ConnectionResetException;
 import sun.net.NetHooks;
 import sun.net.ResourceManager;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
 
 /**
  * Default Socket Implementation. This implementation does
@@ -87,6 +90,45 @@
             });
     }
 
+    private static volatile boolean checkedReusePort;
+    private static volatile boolean isReusePortAvailable;
+
+    /**
+     * Tells whether SO_REUSEPORT is supported.
+     */
+    static boolean isReusePortAvailable() {
+        if (!checkedReusePort) {
+            isReusePortAvailable = isReusePortAvailable0();
+            checkedReusePort = true;
+        }
+        return isReusePortAvailable;
+    }
+
+    private static volatile Set<SocketOption<?>> socketOptions;
+
+   /**
+    * Returns a set of SocketOptions supported by this impl
+    * and by this impl's socket (Socket or ServerSocket)
+    *
+    * @return a Set of SocketOptions
+    */
+    @Override
+    protected Set<SocketOption<?>> supportedOptions() {
+        Set<SocketOption<?>> options = socketOptions;
+        if (options == null) {
+            if (isReusePortAvailable()) {
+                options = new HashSet<>();
+                options.addAll(super.supportedOptions());
+                options.add(StandardSocketOptions.SO_REUSEPORT);
+                options = Collections.unmodifiableSet(options);
+            } else {
+                options = super.supportedOptions();
+            }
+            socketOptions = options;
+        }
+        return options;
+    }
+
     /**
      * Creates a socket with a boolean that specifies whether this
      * is a stream socket (true) or an unconnected UDP socket (false).
@@ -269,6 +311,13 @@
                 throw new SocketException("bad parameter for SO_REUSEADDR");
             on = ((Boolean)val).booleanValue();
             break;
+        case SO_REUSEPORT:
+            if (val == null || !(val instanceof Boolean))
+                throw new SocketException("bad parameter for SO_REUSEPORT");
+            if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT))
+                throw new UnsupportedOperationException("unsupported option");
+            on = ((Boolean)val).booleanValue();
+            break;
         default:
             throw new SocketException("unrecognized TCP option: " + opt);
         }
@@ -326,6 +375,12 @@
         case SO_KEEPALIVE:
             ret = socketGetOption(opt, null);
             return Boolean.valueOf(ret != -1);
+        case SO_REUSEPORT:
+            if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
+                throw new UnsupportedOperationException("unsupported option");
+            }
+            ret = socketGetOption(opt, null);
+            return Boolean.valueOf(ret != -1);
         // should never get here
         default:
             return null;
@@ -723,4 +778,6 @@
 
     public static final int SHUT_RD = 0;
     public static final int SHUT_WR = 1;
+
+    private static native boolean isReusePortAvailable0();
 }