[PATCH] SOCK_CLOEXEC for opening sockets

Andrew Luo andrewluotechnologies at outlook.com
Thu Jul 12 04:55:41 UTC 2018


Ok, fixed a few more places (and a bug where fcntl was being run on a -1 fd).  Patch is below, let me know if there's any other suggestions/etc.

By the way, is anyone willing to sponsor this change?  I'm not a committer/author, this is my first OpenJDK contribution.

Thanks,

-Andrew

diff --git a/src/java.base/linux/native/libnio/fs/LinuxWatchService.c b/src/java.base/linux/native/libnio/fs/LinuxWatchService.c
--- a/src/java.base/linux/native/libnio/fs/LinuxWatchService.c
+++ b/src/java.base/linux/native/libnio/fs/LinuxWatchService.c
@@ -119,7 +119,7 @@
     (JNIEnv* env, jclass clazz, jintArray sv)
{
     int sp[2];
-    if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) {
+    if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) {
         throwUnixException(env, errno);
     } else {
         jint res[2];
diff --git a/src/java.base/unix/native/libnet/Inet4AddressImpl.c b/src/java.base/unix/native/libnet/Inet4AddressImpl.c
--- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c
+++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c
@@ -264,7 +264,7 @@
     int connect_rv = -1;
     // open a TCP socket
-    fd = socket(AF_INET, SOCK_STREAM, 0);
+    fd = NET_Socket(AF_INET, SOCK_STREAM, 0);
     if (fd == -1) {
         // note: if you run out of fds, you may not be able to load
         // the exception class, and get a NoClassDefFoundError instead.
@@ -503,7 +503,7 @@
     // Let's try to create a RAW socket to send ICMP packets.
     // This usually requires "root" privileges, so it's likely to fail.
-    fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+    fd = NET_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
     if (fd == -1) {
         return tcp_ping4(env, &sa, netif, timeout, ttl);
     } else {
diff --git a/src/java.base/unix/native/libnet/Inet6AddressImpl.c b/src/java.base/unix/native/libnet/Inet6AddressImpl.c
--- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c
+++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c
@@ -461,7 +461,7 @@
     int connect_rv = -1;
     // open a TCP socket
-    fd = socket(AF_INET6, SOCK_STREAM, 0);
+    fd = NET_Socket(AF_INET6, SOCK_STREAM, 0);
     if (fd == -1) {
         // note: if you run out of fds, you may not be able to load
         // the exception class, and get a NoClassDefFoundError instead.
@@ -711,7 +711,7 @@
     // Let's try to create a RAW socket to send ICMP packets.
     // This usually requires "root" privileges, so it's likely to fail.
-    fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+    fd = NET_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
     if (fd == -1) {
         return tcp_ping6(env, &sa, netif, timeout, ttl);
     } else {
diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c
--- a/src/java.base/unix/native/libnet/NetworkInterface.c
+++ b/src/java.base/unix/native/libnet/NetworkInterface.c
@@ -1055,7 +1055,7 @@
static int openSocket(JNIEnv *env, int proto) {
     int sock;
-    if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) {
+    if ((sock = NET_Socket(proto, SOCK_DGRAM, 0)) < 0) {
         // If EPROTONOSUPPORT is returned it means we don't have
         // support for this proto so don't throw an exception.
         if (errno != EPROTONOSUPPORT) {
@@ -1078,9 +1078,9 @@
static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
     int sock;
-    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+    if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
         if (errno == EPROTONOSUPPORT) {
-            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+            if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
                 JNU_ThrowByNameWithMessageAndLastError
                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
                 return -1;
@@ -1315,9 +1315,9 @@
static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
     int sock;
-    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+    if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
         if (errno == EPROTONOSUPPORT) {
-            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+            if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
                 JNU_ThrowByNameWithMessageAndLastError
                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
                 return -1;
@@ -1590,9 +1590,9 @@
     int sock, alreadyV6 = 0;
     struct lifreq if2;
-    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+    if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
         if (errno == EPROTONOSUPPORT) {
-            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+            if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
                 JNU_ThrowByNameWithMessageAndLastError
                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
                 return -1;
@@ -1616,7 +1616,7 @@
         strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
         if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) {
             close(sock);
-            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+            if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
                 JNU_ThrowByNameWithMessageAndLastError
                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
                 return -1;
@@ -1941,9 +1941,9 @@
static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
     int sock;
-    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+    if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
         if (errno == EPROTONOSUPPORT) {
-            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+            if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
                 JNU_ThrowByNameWithMessageAndLastError
                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
                 return -1;
diff --git a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c
--- a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c
+++ b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c
@@ -904,7 +904,7 @@
         return;
     }
-    if ((fd = socket(domain, SOCK_DGRAM, 0)) == -1) {
+    if ((fd = NET_Socket(domain, SOCK_DGRAM, 0)) == -1) {
         JNU_ThrowByNameWithMessageAndLastError
             (env, JNU_JAVANETPKG "SocketException", "Error creating socket");
         return;
diff --git a/src/java.base/unix/native/libnet/PlainSocketImpl.c b/src/java.base/unix/native/libnet/PlainSocketImpl.c
--- a/src/java.base/unix/native/libnet/PlainSocketImpl.c
+++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c
@@ -77,7 +77,7 @@
     int sv[2];
 #ifdef AF_UNIX
-    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
+    if (NET_SocketPair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
         return -1;
     }
#else
@@ -178,7 +178,7 @@
         return;
     }
-    if ((fd = socket(domain, type, 0)) == -1) {
+    if ((fd = NET_Socket(domain, type, 0)) == -1) {
         /* note: if you run out of fds, you may not be able to load
          * the exception class, and get a NoClassDefFoundError
          * instead.
diff --git a/src/java.base/unix/native/libnet/SdpSupport.c b/src/java.base/unix/native/libnet/SdpSupport.c
--- a/src/java.base/unix/native/libnet/SdpSupport.c
+++ b/src/java.base/unix/native/libnet/SdpSupport.c
@@ -57,7 +57,7 @@
 #if defined(__solaris__)
     int domain = ipv6_available() ? AF_INET6 : AF_INET;
-    s = socket(domain, SOCK_STREAM, PROTO_SDP);
+    s = NET_Socket(domain, SOCK_STREAM, PROTO_SDP);
#elif defined(__linux__)
     /**
      * IPv6 not supported by SDP on Linux
@@ -66,7 +66,7 @@
         JNU_ThrowIOException(env, "IPv6 not supported");
         return -1;
     }
-    s = socket(AF_INET_SDP, SOCK_STREAM, 0);
+    s = NET_Socket(AF_INET_SDP, SOCK_STREAM, 0);
#else
     /* not supported on other platforms at this time */
     s = -1;
diff --git a/src/java.base/unix/native/libnet/net_util_md.c b/src/java.base/unix/native/libnet/net_util_md.c
--- a/src/java.base/unix/native/libnet/net_util_md.c
+++ b/src/java.base/unix/native/libnet/net_util_md.c
@@ -117,6 +117,64 @@
     return defaultIndex;
}
+/*
+ * Opens a socket
+ * On systems where supported, uses SOCK_CLOEXEC where possible
+ */
+JNIEXPORT int JNICALL
+NET_Socket(int domain, int type, int protocol) {
+#if defined(SOCK_CLOEXEC)
+    int typeToUse = type | SOCK_CLOEXEC;
+#else
+    int typeToUse = type;
+#endif
+
+    int socketFileDescriptor = socket(domain, typeToUse, protocol);
+#if defined(SOCK_CLOEXEC)
+    if ((socketFileDescriptor == -1) && (errno = EINVAL)) {
+        // Attempt to open the socket without SOCK_CLOEXEC
+        // May have been compiled on an OS with SOCK_CLOEXEC supported
+        // But runtime system might not have SOCK_CLOEXEC support
+        socketFileDescriptor = socket(domain, type, protocol);
+    }
+#else
+    if (socketFileDescriptor != -1) {
+        // Best effort
+        // Return value is intentionally ignored since socket was successfully opened anyways
+        fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC);
+    }
+#endif
+
+    return socketFileDescriptor;
+}
+
+JNIEXPORT int JNICALL
+NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]) {
+#if defined(SOCK_CLOEXEC)
+    int typeToUse = type | SOCK_CLOEXEC;
+#else
+    int typeToUse = type;
+#endif
+
+    int socketFileDescriptor = socketpair(domain, typeToUse, protocol, socket_vector);
+#if defined(SOCK_CLOEXEC)
+    if ((socketFileDescriptor == -1) && (errno = EINVAL)) {
+        // Attempt to open the socket without SOCK_CLOEXEC
+        // May have been compiled on an OS with SOCK_CLOEXEC supported
+        // But runtime system might not have SOCK_CLOEXEC support
+        socketFileDescriptor = socketpair(domain, type, protocol, socket_vector);
+    }
+#else
+    if (socketFileDescriptor != -1) {
+        // Best effort
+        // Return value is intentionally ignored since socket was successfully opened anyways
+        fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC);
+    }
+#endif
+
+    return socketFileDescriptor;
+}
+
#define RESTARTABLE(_cmd, _result) do { \
     do { \
         _result = _cmd; \
@@ -295,7 +353,7 @@
     SOCKETADDRESS sa;
     socklen_t sa_len = sizeof(SOCKETADDRESS);
-    fd = socket(AF_INET6, SOCK_STREAM, 0) ;
+    fd = NET_Socket(AF_INET6, SOCK_STREAM, 0) ;
     if (fd < 0) {
         /*
          *  TODO: We really cant tell since it may be an unrelated error
@@ -402,7 +460,7 @@
     /* Do a simple dummy call, and try to figure out from that */
     int one = 1;
     int rv, s;
-    s = socket(PF_INET, SOCK_STREAM, 0);
+    s = NET_Socket(PF_INET, SOCK_STREAM, 0);
     if (s < 0) {
         return JNI_FALSE;
     }
diff --git a/src/java.base/unix/native/libnet/net_util_md.h b/src/java.base/unix/native/libnet/net_util_md.h
--- a/src/java.base/unix/native/libnet/net_util_md.h
+++ b/src/java.base/unix/native/libnet/net_util_md.h
@@ -89,6 +89,8 @@
int NET_Writev(int s, const struct iovec * vector, int count);
int NET_Connect(int s, struct sockaddr *addr, int addrlen);
int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen);
+JNIEXPORT int JNICALL NET_Socket(int domain, int type, int protocol);
+JNIEXPORT int JNICALL NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]);
int NET_SocketClose(int s);
int NET_Dup2(int oldfd, int newfd);
int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout);
diff --git a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c
--- a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c
+++ b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c
@@ -67,7 +67,7 @@
Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl)
{
     int sp[2];
-    if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) {
+    if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) {
         JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");
         return;
     }
diff --git a/src/java.base/unix/native/libnio/ch/Net.c b/src/java.base/unix/native/libnio/ch/Net.c
--- a/src/java.base/unix/native/libnio/ch/Net.c
+++ b/src/java.base/unix/native/libnio/ch/Net.c
@@ -198,7 +198,7 @@
     int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
     int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET;
-    fd = socket(domain, type, 0);
+    fd = NET_Socket(domain, type, 0);
     if (fd < 0) {
         return handleSocketError(env, errno);
     }
diff --git a/src/jdk.sctp/unix/native/libsctp/SctpNet.c b/src/jdk.sctp/unix/native/libsctp/SctpNet.c
--- a/src/jdk.sctp/unix/native/libsctp/SctpNet.c
+++ b/src/jdk.sctp/unix/native/libsctp/SctpNet.c
@@ -151,7 +151,7 @@
Java_sun_nio_ch_sctp_SctpNet_init
   (JNIEnv *env, jclass cl) {
     int sp[2];
-    if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) {
+    if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) {
         JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");
         return;
     }
@@ -180,7 +180,7 @@
         return 0;
     }
-    fd = socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP);
+    fd = NET_Socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP);
     if (fd < 0) {
         return handleSocketError(env, errno);

From: Andrew Luo
Sent: Wednesday, July 11, 2018 1:47 AM
To: 'Alan Bateman' <Alan.Bateman at oracle.com>; Norman Maurer <norman.maurer at googlemail.com>
Cc: Martin Buchholz <martinrb at google.com>; net-dev at openjdk.java.net
Subject: RE: [PATCH] SOCK_CLOEXEC for opening sockets

Sounds good.  I've updated my patch:

diff -r 95c0644a1c47 src/java.base/linux/native/libnio/fs/LinuxWatchService.c
--- a/src/java.base/linux/native/libnio/fs/LinuxWatchService.c    Fri Jun 15 17:34:01 2018 -0700
+++ b/src/java.base/linux/native/libnio/fs/LinuxWatchService.c Wed Jul 11 01:46:03 2018 -0700
@@ -119,7 +119,7 @@
     (JNIEnv* env, jclass clazz, jintArray sv)
{
     int sp[2];
-    if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) {
+    if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) {
         throwUnixException(env, errno);
     } else {
         jint res[2];
diff -r 95c0644a1c47 src/java.base/unix/native/libnet/Inet4AddressImpl.c
--- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c             Fri Jun 15 17:34:01 2018 -0700
+++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c          Wed Jul 11 01:46:03 2018 -0700
@@ -264,7 +264,7 @@
     int connect_rv = -1;

     // open a TCP socket
-    fd = socket(AF_INET, SOCK_STREAM, 0);
+    fd = NET_Socket(AF_INET, SOCK_STREAM, 0);
     if (fd == -1) {
         // note: if you run out of fds, you may not be able to load
         // the exception class, and get a NoClassDefFoundError instead.
@@ -503,7 +503,7 @@

     // Let's try to create a RAW socket to send ICMP packets.
     // This usually requires "root" privileges, so it's likely to fail.
-    fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+    fd = NET_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
     if (fd == -1) {
         return tcp_ping4(env, &sa, netif, timeout, ttl);
     } else {
diff -r 95c0644a1c47 src/java.base/unix/native/libnet/Inet6AddressImpl.c
--- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c             Fri Jun 15 17:34:01 2018 -0700
+++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c          Wed Jul 11 01:46:03 2018 -0700
@@ -461,7 +461,7 @@
     int connect_rv = -1;

     // open a TCP socket
-    fd = socket(AF_INET6, SOCK_STREAM, 0);
+    fd = NET_Socket(AF_INET6, SOCK_STREAM, 0);
     if (fd == -1) {
         // note: if you run out of fds, you may not be able to load
         // the exception class, and get a NoClassDefFoundError instead.
@@ -711,7 +711,7 @@

     // Let's try to create a RAW socket to send ICMP packets.
     // This usually requires "root" privileges, so it's likely to fail.
-    fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+    fd = NET_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
     if (fd == -1) {
         return tcp_ping6(env, &sa, netif, timeout, ttl);
     } else {
diff -r 95c0644a1c47 src/java.base/unix/native/libnet/NetworkInterface.c
--- a/src/java.base/unix/native/libnet/NetworkInterface.c             Fri Jun 15 17:34:01 2018 -0700
+++ b/src/java.base/unix/native/libnet/NetworkInterface.c          Wed Jul 11 01:46:03 2018 -0700
@@ -1055,7 +1055,7 @@
static int openSocket(JNIEnv *env, int proto) {
     int sock;

-    if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) {
+    if ((sock = NET_Socket(proto, SOCK_DGRAM, 0)) < 0) {
         // If EPROTONOSUPPORT is returned it means we don't have
         // support for this proto so don't throw an exception.
         if (errno != EPROTONOSUPPORT) {
@@ -1078,9 +1078,9 @@
static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
     int sock;

-    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+    if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
         if (errno == EPROTONOSUPPORT) {
-            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+            if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
                 JNU_ThrowByNameWithMessageAndLastError
                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
                 return -1;
@@ -1315,9 +1315,9 @@
static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
     int sock;

-    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+    if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
         if (errno == EPROTONOSUPPORT) {
-            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+            if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
                 JNU_ThrowByNameWithMessageAndLastError
                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
                 return -1;
@@ -1590,9 +1590,9 @@
     int sock, alreadyV6 = 0;
     struct lifreq if2;

-    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+    if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
         if (errno == EPROTONOSUPPORT) {
-            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+            if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
                 JNU_ThrowByNameWithMessageAndLastError
                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
                 return -1;
@@ -1616,7 +1616,7 @@
         strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
         if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) {
             close(sock);
-            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+            if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
                 JNU_ThrowByNameWithMessageAndLastError
                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
                 return -1;
@@ -1941,9 +1941,9 @@
static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
     int sock;

-    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+    if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
         if (errno == EPROTONOSUPPORT) {
-            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+            if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
                 JNU_ThrowByNameWithMessageAndLastError
                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
                 return -1;
diff -r 95c0644a1c47 src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c
--- a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c             Fri Jun 15 17:34:01 2018 -0700
+++ b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c          Wed Jul 11 01:46:03 2018 -0700
@@ -904,7 +904,7 @@
         return;
     }

-    if ((fd = socket(domain, SOCK_DGRAM, 0)) == -1) {
+    if ((fd = NET_Socket(domain, SOCK_DGRAM, 0)) == -1) {
         JNU_ThrowByNameWithMessageAndLastError
             (env, JNU_JAVANETPKG "SocketException", "Error creating socket");
         return;
diff -r 95c0644a1c47 src/java.base/unix/native/libnet/PlainSocketImpl.c
--- a/src/java.base/unix/native/libnet/PlainSocketImpl.c Fri Jun 15 17:34:01 2018 -0700
+++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c             Wed Jul 11 01:46:03 2018 -0700
@@ -178,7 +178,7 @@
         return;
     }

-    if ((fd = socket(domain, type, 0)) == -1) {
+    if ((fd = NET_Socket(domain, type, 0)) == -1) {
         /* note: if you run out of fds, you may not be able to load
          * the exception class, and get a NoClassDefFoundError
          * instead.
diff -r 95c0644a1c47 src/java.base/unix/native/libnet/SdpSupport.c
--- a/src/java.base/unix/native/libnet/SdpSupport.c         Fri Jun 15 17:34:01 2018 -0700
+++ b/src/java.base/unix/native/libnet/SdpSupport.c      Wed Jul 11 01:46:03 2018 -0700
@@ -57,7 +57,7 @@

 #if defined(__solaris__)
     int domain = ipv6_available() ? AF_INET6 : AF_INET;
-    s = socket(domain, SOCK_STREAM, PROTO_SDP);
+    s = NET_Socket(domain, SOCK_STREAM, PROTO_SDP);
#elif defined(__linux__)
     /**
      * IPv6 not supported by SDP on Linux
@@ -66,7 +66,7 @@
         JNU_ThrowIOException(env, "IPv6 not supported");
         return -1;
     }
-    s = socket(AF_INET_SDP, SOCK_STREAM, 0);
+    s = NET_Socket(AF_INET_SDP, SOCK_STREAM, 0);
#else
     /* not supported on other platforms at this time */
     s = -1;
diff -r 95c0644a1c47 src/java.base/unix/native/libnet/net_util_md.c
--- a/src/java.base/unix/native/libnet/net_util_md.c       Fri Jun 15 17:34:01 2018 -0700
+++ b/src/java.base/unix/native/libnet/net_util_md.c    Wed Jul 11 01:46:03 2018 -0700
@@ -117,6 +117,60 @@
     return defaultIndex;
}

+/*
+ * Opens a socket
+ * On systems where supported, uses SOCK_CLOEXEC where possible
+ */
+JNIEXPORT int JNICALL
+NET_Socket(int domain, int type, int protocol) {
+#if defined(SOCK_CLOEXEC)
+    int typeToUse = type | SOCK_CLOEXEC;
+#else
+    int typeToUse = type;
+#endif
+
+    int socketFileDescriptor = socket(domain, typeToUse, protocol);
+#if defined(SOCK_CLOEXEC)
+    if ((socketFileDescriptor == -1) && (errno = EINVAL)) {
+        // Attempt to open the socket without SOCK_CLOEXEC
+        // May have been compiled on an OS with SOCK_CLOEXEC supported
+        // But runtime system might not have SOCK_CLOEXEC support
+        socketFileDescriptor = socket(domain, type, protocol);
+    }
+#else
+    // Best effort
+    // Return value is intentionally ignored since socket was successfully opened anyways
+    fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC);
+#endif
+
+    return socketFileDescriptor;
+}
+
+JNIEXPORT int JNICALL
+NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]) {
+#if defined(SOCK_CLOEXEC)
+    int typeToUse = type | SOCK_CLOEXEC;
+#else
+    int typeToUse = type;
+#endif
+
+    int socketFileDescriptor = socketpair(domain, typeToUse, protocol, socket_vector);
+#if defined(SOCK_CLOEXEC)
+    if ((socketFileDescriptor == -1) && (errno = EINVAL)) {
+        // Attempt to open the socket without SOCK_CLOEXEC
+        // May have been compiled on an OS with SOCK_CLOEXEC supported
+        // But runtime system might not have SOCK_CLOEXEC support
+        socketFileDescriptor = socketpair(domain, type, protocol, socket_vector);
+    }
+#else
+    // Best effort
+    // Return value is intentionally ignored since socket was successfully opened anyways
+    fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC);
+#endif
+
+    return socketFileDescriptor;
+}
+
#define RESTARTABLE(_cmd, _result) do { \
     do { \
         _result = _cmd; \
@@ -295,7 +349,7 @@
     SOCKETADDRESS sa;
     socklen_t sa_len = sizeof(SOCKETADDRESS);

-    fd = socket(AF_INET6, SOCK_STREAM, 0) ;
+    fd = NET_Socket(AF_INET6, SOCK_STREAM, 0) ;
     if (fd < 0) {
         /*
          *  TODO: We really cant tell since it may be an unrelated error
@@ -402,7 +456,7 @@
     /* Do a simple dummy call, and try to figure out from that */
     int one = 1;
     int rv, s;
-    s = socket(PF_INET, SOCK_STREAM, 0);
+    s = NET_Socket(PF_INET, SOCK_STREAM, 0);
     if (s < 0) {
         return JNI_FALSE;
     }
diff -r 95c0644a1c47 src/java.base/unix/native/libnet/net_util_md.h
--- a/src/java.base/unix/native/libnet/net_util_md.h       Fri Jun 15 17:34:01 2018 -0700
+++ b/src/java.base/unix/native/libnet/net_util_md.h    Wed Jul 11 01:46:03 2018 -0700
@@ -89,6 +89,8 @@
int NET_Writev(int s, const struct iovec * vector, int count);
int NET_Connect(int s, struct sockaddr *addr, int addrlen);
int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen);
+JNIEXPORT int JNICALL NET_Socket(int domain, int type, int protocol);
+JNIEXPORT int JNICALL NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]);
int NET_SocketClose(int s);
int NET_Dup2(int oldfd, int newfd);
int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout);
diff -r 95c0644a1c47 src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c
--- a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c     Fri Jun 15 17:34:01 2018 -0700
+++ b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c  Wed Jul 11 01:46:03 2018 -0700
@@ -67,7 +67,7 @@
Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl)
{
     int sp[2];
-    if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) {
+    if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) {
         JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");
         return;
     }
diff -r 95c0644a1c47 src/java.base/unix/native/libnio/ch/Net.c
--- a/src/java.base/unix/native/libnio/ch/Net.c   Fri Jun 15 17:34:01 2018 -0700
+++ b/src/java.base/unix/native/libnio/ch/Net.c Wed Jul 11 01:46:03 2018 -0700
@@ -198,7 +198,7 @@
     int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
     int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET;

-    fd = socket(domain, type, 0);
+    fd = NET_Socket(domain, type, 0);
     if (fd < 0) {
         return handleSocketError(env, errno);
     }

From: Alan Bateman <Alan.Bateman at oracle.com<mailto:Alan.Bateman at oracle.com>>
Sent: Wednesday, July 11, 2018 12:12 AM
To: Andrew Luo <andrewluotechnologies at outlook.com<mailto:andrewluotechnologies at outlook.com>>; Norman Maurer <norman.maurer at googlemail.com<mailto:norman.maurer at googlemail.com>>
Cc: Martin Buchholz <martinrb at google.com<mailto:martinrb at google.com>>; net-dev at openjdk.java.net<mailto:net-dev at openjdk.java.net>
Subject: Re: [PATCH] SOCK_CLOEXEC for opening sockets

This seems to cover the sockets created in libnet but there is also a usage in libnio that will need update. It might be cleaner to name it NET_Socket to be consistent with the other wrappers (NET_Bind, NET_SetSocketOpt, etc.).

There are a lot of other file descriptors that you may run into. We use socketpair in a few places, we have file descriptors for epoll and more. It makes me wonder if it would be better to use FD_CLOEXEC consistently. In the Windows port then you'll see that we change the inheritance flag on all newly created SOCKETs, that is because is because we don't have the same opportunity to close inherited handles in the child process that we do on Unix platforms.

-Alan
On 11/07/2018 07:35, Andrew Luo wrote:
I agree, I wasn't aware of the other uses of ::socket in the libnet codebase.  Thus, I've added a new common function, NET_SocketOpen that can be used by all the source files in libnet and revised my patch:

diff -r 95c0644a1c47 src/java.base/unix/native/libnet/Inet4AddressImpl.c
--- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c             Fri Jun 15 17:34:01 2018 -0700
+++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c          Tue Jul 10 23:32:21 2018 -0700
@@ -264,7 +264,7 @@
     int connect_rv = -1;
     // open a TCP socket
-    fd = socket(AF_INET, SOCK_STREAM, 0);
+    fd = NET_SocketOpen(AF_INET, SOCK_STREAM, 0);
     if (fd == -1) {
         // note: if you run out of fds, you may not be able to load
         // the exception class, and get a NoClassDefFoundError instead.
@@ -503,7 +503,7 @@
     // Let's try to create a RAW socket to send ICMP packets.
     // This usually requires "root" privileges, so it's likely to fail.
-    fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+    fd = NET_SocketOpen(AF_INET, SOCK_RAW, IPPROTO_ICMP);
     if (fd == -1) {
         return tcp_ping4(env, &sa, netif, timeout, ttl);
     } else {
diff -r 95c0644a1c47 src/java.base/unix/native/libnet/Inet6AddressImpl.c
--- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c             Fri Jun 15 17:34:01 2018 -0700
+++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c          Tue Jul 10 23:32:21 2018 -0700
@@ -461,7 +461,7 @@
     int connect_rv = -1;
     // open a TCP socket
-    fd = socket(AF_INET6, SOCK_STREAM, 0);
+    fd = NET_SocketOpen(AF_INET6, SOCK_STREAM, 0);
     if (fd == -1) {
         // note: if you run out of fds, you may not be able to load
         // the exception class, and get a NoClassDefFoundError instead.
@@ -711,7 +711,7 @@
     // Let's try to create a RAW socket to send ICMP packets.
     // This usually requires "root" privileges, so it's likely to fail.
-    fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+    fd = NET_SocketOpen(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
     if (fd == -1) {
         return tcp_ping6(env, &sa, netif, timeout, ttl);
     } else {
diff -r 95c0644a1c47 src/java.base/unix/native/libnet/NetworkInterface.c
--- a/src/java.base/unix/native/libnet/NetworkInterface.c             Fri Jun 15 17:34:01 2018 -0700
+++ b/src/java.base/unix/native/libnet/NetworkInterface.c          Tue Jul 10 23:32:21 2018 -0700
@@ -1055,7 +1055,7 @@
static int openSocket(JNIEnv *env, int proto) {
     int sock;
-    if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) {
+    if ((sock = NET_SocketOpen(proto, SOCK_DGRAM, 0)) < 0) {
         // If EPROTONOSUPPORT is returned it means we don't have
         // support for this proto so don't throw an exception.
         if (errno != EPROTONOSUPPORT) {
@@ -1078,9 +1078,9 @@
static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
     int sock;
-    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+    if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) {
         if (errno == EPROTONOSUPPORT) {
-            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+            if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) {
                 JNU_ThrowByNameWithMessageAndLastError
                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
                 return -1;
@@ -1315,9 +1315,9 @@
static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
     int sock;
-    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+    if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) {
         if (errno == EPROTONOSUPPORT) {
-            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+            if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) {
                 JNU_ThrowByNameWithMessageAndLastError
                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
                 return -1;
@@ -1590,9 +1590,9 @@
     int sock, alreadyV6 = 0;
     struct lifreq if2;
-    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+    if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) {
         if (errno == EPROTONOSUPPORT) {
-            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+            if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) {
                 JNU_ThrowByNameWithMessageAndLastError
                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
                 return -1;
@@ -1616,7 +1616,7 @@
         strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
         if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) {
             close(sock);
-            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+            if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) {
                 JNU_ThrowByNameWithMessageAndLastError
                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
                 return -1;
@@ -1941,9 +1941,9 @@
static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
     int sock;
-    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+    if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) {
         if (errno == EPROTONOSUPPORT) {
-            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+            if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) {
                 JNU_ThrowByNameWithMessageAndLastError
                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
                 return -1;
diff -r 95c0644a1c47 src/java.base/unix/native/libnet/PlainSocketImpl.c
--- a/src/java.base/unix/native/libnet/PlainSocketImpl.c Fri Jun 15 17:34:01 2018 -0700
+++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c             Tue Jul 10 23:32:21 2018 -0700
@@ -178,7 +178,7 @@
         return;
     }
-    if ((fd = socket(domain, type, 0)) == -1) {
+    if ((fd = NET_SocketOpen(domain, type, 0)) == -1) {
         /* note: if you run out of fds, you may not be able to load
          * the exception class, and get a NoClassDefFoundError
          * instead.
diff -r 95c0644a1c47 src/java.base/unix/native/libnet/SdpSupport.c
--- a/src/java.base/unix/native/libnet/SdpSupport.c         Fri Jun 15 17:34:01 2018 -0700
+++ b/src/java.base/unix/native/libnet/SdpSupport.c      Tue Jul 10 23:32:21 2018 -0700
@@ -57,7 +57,7 @@
 #if defined(__solaris__)
     int domain = ipv6_available() ? AF_INET6 : AF_INET;
-    s = socket(domain, SOCK_STREAM, PROTO_SDP);
+    s = NET_SocketOpen(domain, SOCK_STREAM, PROTO_SDP);
#elif defined(__linux__)
     /**
      * IPv6 not supported by SDP on Linux
@@ -66,7 +66,7 @@
         JNU_ThrowIOException(env, "IPv6 not supported");
         return -1;
     }
-    s = socket(AF_INET_SDP, SOCK_STREAM, 0);
+    s = NET_SocketOpen(AF_INET_SDP, SOCK_STREAM, 0);
#else
     /* not supported on other platforms at this time */
     s = -1;
diff -r 95c0644a1c47 src/java.base/unix/native/libnet/net_util_md.c
--- a/src/java.base/unix/native/libnet/net_util_md.c       Fri Jun 15 17:34:01 2018 -0700
+++ b/src/java.base/unix/native/libnet/net_util_md.c    Tue Jul 10 23:32:21 2018 -0700
@@ -117,6 +117,34 @@
     return defaultIndex;
}
+/*
+ * Opens a socket
+ * On systems where supported, uses SOCK_CLOEXEC where possible
+ */
+int NET_SocketOpen(int domain, int type, int protocol) {
+#if defined(SOCK_CLOEXEC)
+    int typeToUse = type | SOCK_CLOEXEC;
+#else
+    int typeToUse = type;
+#endif
+
+    int socketFileDescriptor = socket(domain, typeToUse, protocol);
+#if defined(SOCK_CLOEXEC)
+    if ((socketFileDescriptor == -1) && (errno = EINVAL)) {
+        // Attempt to open the socket without SOCK_CLOEXEC
+        // May have been compiled on an OS with SOCK_CLOEXEC supported
+        // But runtime system might not have SOCK_CLOEXEC support
+        socketFileDescriptor = socket(domain, type, protocol);
+    }
+#else
+    // Best effort
+    // Return value is intentionally ignored since socket was successfully opened anyways
+    fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC);
+#endif
+
+    return socketFileDescriptor;
+}
+
#define RESTARTABLE(_cmd, _result) do { \
     do { \
         _result = _cmd; \
@@ -295,7 +323,7 @@
     SOCKETADDRESS sa;
     socklen_t sa_len = sizeof(SOCKETADDRESS);
-    fd = socket(AF_INET6, SOCK_STREAM, 0) ;
+    fd = NET_SocketOpen(AF_INET6, SOCK_STREAM, 0) ;
     if (fd < 0) {
         /*
          *  TODO: We really cant tell since it may be an unrelated error
@@ -402,7 +430,7 @@
     /* Do a simple dummy call, and try to figure out from that */
     int one = 1;
     int rv, s;
-    s = socket(PF_INET, SOCK_STREAM, 0);
+    s = NET_SocketOpen(PF_INET, SOCK_STREAM, 0);
     if (s < 0) {
         return JNI_FALSE;
     }
diff -r 95c0644a1c47 src/java.base/unix/native/libnet/net_util_md.h
--- a/src/java.base/unix/native/libnet/net_util_md.h       Fri Jun 15 17:34:01 2018 -0700
+++ b/src/java.base/unix/native/libnet/net_util_md.h    Tue Jul 10 23:32:21 2018 -0700
@@ -89,6 +89,7 @@
int NET_Writev(int s, const struct iovec * vector, int count);
int NET_Connect(int s, struct sockaddr *addr, int addrlen);
int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen);
+int NET_SocketOpen(int domain, int type, int protocol);
int NET_SocketClose(int s);
int NET_Dup2(int oldfd, int newfd);
int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout);

From: Norman Maurer <norman.maurer at googlemail.com><mailto:norman.maurer at googlemail.com>
Sent: Tuesday, July 10, 2018 9:55 AM
To: Alan Bateman <Alan.Bateman at oracle.com><mailto:Alan.Bateman at oracle.com>
Cc: Martin Buchholz <martinrb at google.com><mailto:martinrb at google.com>; Andrew Luo <andrewluotechnologies at outlook.com><mailto:andrewluotechnologies at outlook.com>; net-dev at openjdk.java.net<mailto:net-dev at openjdk.java.net>
Subject: Re: [PATCH] SOCK_CLOEXEC for opening sockets

+1 I think this makes a lot of sense



On 10. Jul 2018, at 17:54, Alan Bateman <Alan.Bateman at oracle.com<mailto:Alan.Bateman at oracle.com>> wrote:

On 10/07/2018 17:40, Martin Buchholz wrote:

I agree with this approach - it parallels the efforts made with O_CLOEXEC in past years.


According to
https://www.freebsd.org/cgi/man.cgi?query=socket&sektion=2

SOCK_CLOEXEC is also available on freebsd.

This is something that doesn't come up too often, I assume because most developers using ProcessBuilder/Process rather than invoking fork from native code.

If we are going to tackle this issue then it will require changes in several places, changing PlainSocketImpl.c is just one of several.

-Alan


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/net-dev/attachments/20180712/5703b439/attachment-0001.html>


More information about the net-dev mailing list