< prev index next >

src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c

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

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2018, 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

@@ -58,25 +58,31 @@
  * Class:     java_net_DualStackPlainSocketImpl
  * Method:    socket0
  * Signature: (ZZ)I
  */
 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket0
-  (JNIEnv *env, jclass clazz, jboolean stream, jboolean v6Only /*unused*/) {
+  (JNIEnv *env, jclass clazz, jboolean stream) {
     int fd, rv, opt=0;
+    int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
+    int domain = ipv6_available() ? AF_INET6 : AF_INET;
+
+    fd = NET_Socket(domain, type, 0);
 
-    fd = NET_Socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);
     if (fd == INVALID_SOCKET) {
         NET_ThrowNew(env, WSAGetLastError(), "create");
         return -1;
     }
 
-    rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt, sizeof(opt));
+    if (domain == AF_INET6) {
+        rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt,
+                        sizeof(opt));
     if (rv == SOCKET_ERROR) {
         NET_ThrowNew(env, WSAGetLastError(), "create");
+            closesocket(fd);
+            return -1;
+        }
     }
-
-    SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
 
     return fd;
 }
 
 /*

@@ -88,13 +94,14 @@
   (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port,
    jboolean exclBind)
 {
     SOCKETADDRESS sa;
     int rv, sa_len = 0;
+    jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
 
     if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
-                                  &sa_len, JNI_TRUE) != 0) {
+                                  &sa_len, v4MappedAddress) != 0) {
       return;
     }
 
     rv = NET_WinBind(fd, &sa, sa_len, exclBind);
 

@@ -109,24 +116,26 @@
  */
 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_connect0
   (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
     SOCKETADDRESS sa;
     int rv, sa_len = 0;
+    jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
 
     if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
-                                  &sa_len, JNI_TRUE) != 0) {
+                                  &sa_len, v4MappedAddress) != 0) {
       return -1;
     }
 
     rv = connect(fd, &sa.sa, sa_len);
     if (rv == SOCKET_ERROR) {
         int err = WSAGetLastError();
         if (err == WSAEWOULDBLOCK) {
             return java_net_DualStackPlainSocketImpl_WOULDBLOCK;
         } else if (err == WSAEADDRNOTAVAIL) {
             JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
-                "connect: Address is invalid on local machine, or port is not valid on remote machine");
+                "connect: Address is invalid on local machine,"
+                " or port is not valid on remote machine");
         } else {
             NET_ThrowNew(env, err, "connect");
         }
         return -1;  // return value not important.
     }

@@ -198,10 +207,14 @@
     }
 
     if (rv == 0) {
         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
                         "Unable to establish connection");
+    } else if (!ipv6_available() && rv == WSAEADDRNOTAVAIL) {
+        JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
+                        "connect: Address is invalid on local machine,"
+                        " or port is not valid on remote machine");
     } else {
         NET_ThrowNew(env, rv, "connect");
     }
 }
 

@@ -282,24 +295,22 @@
 
     memset((char *)&sa, 0, len);
     newfd = accept(fd, &sa.sa, &len);
 
     if (newfd == INVALID_SOCKET) {
-        if (WSAGetLastError() == -2) {
-            JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
-                            "operation interrupted");
-        } else {
-            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
-                            "socket closed");
-        }
+        NET_ThrowNew(env, WSAGetLastError(), "accept failed");
         return -1;
     }
 
     SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
 
     ia = NET_SockaddrToInetAddress(env, &sa, &port);
     isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
+    if (isa == NULL) {
+        closesocket(newfd);
+        return -1;
+    }
     (*env)->SetObjectArrayElement(env, isaa, 0, isa);
 
     return newfd;
 }
 

@@ -400,10 +411,55 @@
     }
 }
 
 /*
  * Class:     java_net_DualStackPlainSocketImpl
+ * Method:    setSoTimeout0
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_java_net_DualStackPlainSocketImpl_setSoTimeout0
+  (JNIEnv *env, jclass clazz, jint fd, jint timeout)
+{
+    /*
+     * SO_TIMEOUT is the socket option used to specify the timeout
+     * for ServerSocket.accept and Socket.getInputStream().read.
+     * It does not typically map to a native level socket option.
+     * For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO
+     * socket option to specify a receive timeout on the socket. This
+     * receive timeout is applicable to Socket only and the socket
+     * option should not be set on ServerSocket.
+     */
+
+    /*
+     * SO_RCVTIMEO is only supported on Microsoft's implementation
+     * of Windows Sockets so if WSAENOPROTOOPT returned then
+     * reset flag and timeout will be implemented using
+     * select() -- see SocketInputStream.socketRead.
+     */
+    if (isRcvTimeoutSupported) {
+        /*
+         * Disable SO_RCVTIMEO if timeout is <= 5 second.
+         */
+        if (timeout <= 5000) {
+            timeout = 0;
+        }
+
+        if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
+            sizeof(timeout)) < 0) {
+            int err = WSAGetLastError();
+            if (err == WSAENOPROTOOPT) {
+                isRcvTimeoutSupported = JNI_FALSE;
+            } else {
+                NET_ThrowNew(env, err, "setsockopt SO_RCVTIMEO");
+            }
+        }
+    }
+}
+
+/*
+ * Class:     java_net_DualStackPlainSocketImpl
  * Method:    getIntOption
  * Signature: (II)I
  */
 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_getIntOption
   (JNIEnv *env, jclass clazz, jint fd, jint cmd)
< prev index next >