< prev index next >

src/java.base/windows/classes/java/net/DualStackPlainSocketImpl.java

Print this page
rev 49701 : [mq]: 8201510-Merge-TwoStacksPlainSocketImpl-into-DualStackPlainSocketImpl

@@ -24,58 +24,70 @@
  */
 package java.net;
 
 import java.io.IOException;
 import java.io.FileDescriptor;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import sun.security.action.GetPropertyAction;
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.JavaIOFileDescriptorAccess;
 
 /**
- * This class defines the plain SocketImpl that is used on Windows platforms
- * greater or equal to Windows Vista. These platforms have a dual
- * layer TCP/IP stack and can handle both IPv4 and IPV6 through a
- * single file descriptor.
+ * This class defines the plain SocketImpl.
+ * When java.net.preferIPv4Stack system property is set to true, it uses
+ * IPv4-only socket.
+ * When java.net.preferIPv4Stack is set to false, it handles both IPv4
+ * and IPv6 through a single file descriptor.
  *
  * @author Chris Hegarty
  */
 
 class DualStackPlainSocketImpl extends AbstractPlainSocketImpl {
 
     private static final JavaIOFileDescriptorAccess fdAccess =
         SharedSecrets.getJavaIOFileDescriptorAccess();
 
-    // true if this socket is exclusively bound
-    private final boolean exclusiveBind;
+    private static final boolean preferIPv4Stack =
+            Boolean.parseBoolean(AccessController.doPrivileged(
+                new GetPropertyAction("java.net.preferIPv4Stack", "false")));
+
+    private static final boolean useExclusiveBind =
+            Boolean.parseBoolean(AccessController.doPrivileged(
+                new GetPropertyAction("sun.net.useExclusiveBind", "true")));
 
-    // emulates SO_REUSEADDR when exclusiveBind is true
+    // emulates SO_REUSEADDR when useExclusiveBind is true
     private boolean isReuseAddress;
 
-    public DualStackPlainSocketImpl(boolean exclBind) {
-        exclusiveBind = exclBind;
+    public DualStackPlainSocketImpl() {
     }
 
-    public DualStackPlainSocketImpl(FileDescriptor fd, boolean exclBind) {
+    public DualStackPlainSocketImpl(FileDescriptor fd) {
         this.fd = fd;
-        exclusiveBind = exclBind;
     }
 
+    @Override
     void socketCreate(boolean stream) throws IOException {
         if (fd == null)
             throw new SocketException("Socket closed");
 
-        int newfd = socket0(stream, false /*v6 Only*/);
+        int newfd = socket0(stream);
 
         fdAccess.set(fd, newfd);
     }
 
+    @Override
     void socketConnect(InetAddress address, int port, int timeout)
         throws IOException {
         int nativefd = checkAndReturnNativeFD();
 
         if (address == null)
             throw new NullPointerException("inet address argument is null.");
 
+        if (preferIPv4Stack && !(address instanceof Inet4Address))
+            throw new SocketException("Protocol family not supported");
+
         int connectResult;
         if (timeout <= 0) {
             connectResult = connect0(nativefd, address, port);
         } else {
             configureBlocking(nativefd, false);

@@ -95,32 +107,38 @@
          */
         if (localport == 0)
             localport = localPort0(nativefd);
     }
 
+    @Override
     void socketBind(InetAddress address, int port) throws IOException {
         int nativefd = checkAndReturnNativeFD();
 
         if (address == null)
             throw new NullPointerException("inet address argument is null.");
 
-        bind0(nativefd, address, port, exclusiveBind);
+        if (preferIPv4Stack && !(address instanceof Inet4Address))
+            throw new SocketException("Protocol family not supported");
+
+        bind0(nativefd, address, port, useExclusiveBind);
         if (port == 0) {
             localport = localPort0(nativefd);
         } else {
             localport = port;
         }
 
         this.address = address;
     }
 
+    @Override
     void socketListen(int backlog) throws IOException {
         int nativefd = checkAndReturnNativeFD();
 
         listen0(nativefd, backlog);
     }
 
+    @Override
     void socketAccept(SocketImpl s) throws IOException {
         int nativefd = checkAndReturnNativeFD();
 
         if (s == null)
             throw new NullPointerException("socket is null");

@@ -146,17 +164,21 @@
         /* Update socketImpls remote port, address and localport */
         InetSocketAddress isa = isaa[0];
         s.port = isa.getPort();
         s.address = isa.getAddress();
         s.localport = localport;
+        if (preferIPv4Stack && !(s.address instanceof Inet4Address))
+            throw new SocketException("Protocol family not supported");
     }
 
+    @Override
     int socketAvailable() throws IOException {
         int nativefd = checkAndReturnNativeFD();
         return available0(nativefd);
     }
 
+    @Override
     void socketClose0(boolean useDeferredClose/*unused*/) throws IOException {
         if (fd == null)
             throw new SocketException("Socket closed");
 
         if (!fd.valid())

@@ -165,50 +187,61 @@
         final int nativefd = fdAccess.get(fd);
         fdAccess.set(fd, -1);
         close0(nativefd);
     }
 
+    @Override
     void socketShutdown(int howto) throws IOException {
         int nativefd = checkAndReturnNativeFD();
         shutdown0(nativefd, howto);
     }
 
     // Intentional fallthrough after SO_REUSEADDR
     @SuppressWarnings("fallthrough")
+    @Override
     void socketSetOption(int opt, boolean on, Object value)
         throws SocketException {
-        int nativefd = checkAndReturnNativeFD();
 
-        if (opt == SO_TIMEOUT) {  // timeout implemented through select.
-            return;
-        }
         // SO_REUSEPORT is not supported on Windows.
         if (opt == SO_REUSEPORT) {
             throw new UnsupportedOperationException("unsupported option");
         }
 
+        int nativefd = checkAndReturnNativeFD();
+
+        if (opt == SO_TIMEOUT) {
+            if (preferIPv4Stack) {
+                // Don't enable the socket option on ServerSocket as it's
+                // meaningless (we don't receive on a ServerSocket).
+                if (serverSocket == null) {
+                    setSoTimeout0(nativefd, ((Integer)value).intValue());
+                }
+            } // else timeout is implemented through select.
+            return;
+        }
+
         int optionValue = 0;
 
         switch(opt) {
-            case SO_REUSEADDR :
-                if (exclusiveBind) {
+            case SO_REUSEADDR:
+                if (useExclusiveBind) {
                     // SO_REUSEADDR emulated when using exclusive bind
                     isReuseAddress = on;
                     return;
                 }
                 // intentional fallthrough
-            case TCP_NODELAY :
-            case SO_OOBINLINE :
-            case SO_KEEPALIVE :
+            case TCP_NODELAY:
+            case SO_OOBINLINE:
+            case SO_KEEPALIVE:
                 optionValue = on ? 1 : 0;
                 break;
-            case SO_SNDBUF :
-            case SO_RCVBUF :
-            case IP_TOS :
+            case SO_SNDBUF:
+            case SO_RCVBUF:
+            case IP_TOS:
                 optionValue = ((Integer)value).intValue();
                 break;
-            case SO_LINGER :
+            case SO_LINGER:
                 if (on) {
                     optionValue =  ((Integer)value).intValue();
                 } else {
                     optionValue = -1;
                 }

@@ -218,39 +251,44 @@
         }
 
         setIntOption(nativefd, opt, optionValue);
     }
 
-    int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
+    @Override
+    int socketGetOption(int opt, Object iaContainerObj)
+        throws SocketException {
+
+        // SO_REUSEPORT is not supported on Windows.
+        if (opt == SO_REUSEPORT) {
+            throw new UnsupportedOperationException("unsupported option");
+        }
+
         int nativefd = checkAndReturnNativeFD();
 
         // SO_BINDADDR is not a socket option.
         if (opt == SO_BINDADDR) {
             localAddress(nativefd, (InetAddressContainer)iaContainerObj);
             return 0;  // return value doesn't matter.
         }
-        // SO_REUSEPORT is not supported on Windows.
-        if (opt == SO_REUSEPORT) {
-            throw new UnsupportedOperationException("unsupported option");
-        }
 
         // SO_REUSEADDR emulated when using exclusive bind
-        if (opt == SO_REUSEADDR && exclusiveBind)
-            return isReuseAddress? 1 : -1;
+        if (opt == SO_REUSEADDR && useExclusiveBind)
+            return isReuseAddress ? 1 : -1;
 
         int value = getIntOption(nativefd, opt);
 
         switch (opt) {
-            case TCP_NODELAY :
-            case SO_OOBINLINE :
-            case SO_KEEPALIVE :
-            case SO_REUSEADDR :
+            case TCP_NODELAY:
+            case SO_OOBINLINE:
+            case SO_KEEPALIVE:
+            case SO_REUSEADDR:
                 return (value == 0) ? -1 : 1;
         }
         return value;
     }
 
+    @Override
     void socketSendUrgentData(int data) throws IOException {
         int nativefd = checkAndReturnNativeFD();
         sendOOB(nativefd, data);
     }
 

@@ -269,11 +307,11 @@
 
     /* Native methods */
 
     static native void initIDs();
 
-    static native int socket0(boolean stream, boolean v6Only) throws IOException;
+    static native int socket0(boolean stream) throws IOException;
 
     static native void bind0(int fd, InetAddress localAddress, int localport,
                              boolean exclBind)
         throws IOException;
 

@@ -298,10 +336,12 @@
 
     static native void shutdown0(int fd, int howto) throws IOException;
 
     static native void setIntOption(int fd, int cmd, int optionValue) throws SocketException;
 
+    static native void setSoTimeout0(int fd, int timeout) throws SocketException;
+
     static native int getIntOption(int fd, int cmd) throws SocketException;
 
     static native void sendOOB(int fd, int data) throws IOException;
 
     static native void configureBlocking(int fd, boolean blocking) throws IOException;
< prev index next >