src/java.base/unix/native/libnet/NetworkInterface.c
branchdatagramsocketimpl-branch
changeset 58678 9cf78a70fa4f
parent 54889 53d51822f287
child 58679 9c3209ff7550
--- a/src/java.base/unix/native/libnet/NetworkInterface.c	Thu Oct 17 20:27:44 2019 +0100
+++ b/src/java.base/unix/native/libnet/NetworkInterface.c	Thu Oct 17 20:53:35 2019 +0100
@@ -34,6 +34,7 @@
 #include <netinet/in6_var.h>
 #include <sys/ndd_var.h>
 #include <sys/kinfo.h>
+#include <strings.h>
 #endif
 
 #if defined(__solaris__)
@@ -238,6 +239,7 @@
 
     ifs = enumInterfaces(env);
     if (ifs == NULL) {
+        (*env)->ReleaseStringUTFChars(env, name, name_utf);
         return NULL;
     }
 
@@ -320,33 +322,9 @@
     return obj;
 }
 
-/*
- * Class:     java_net_NetworkInterface
- * Method:    getByInetAddress0
- * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
- */
-JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
-  (JNIEnv *env, jclass cls, jobject iaObj)
-{
-    netif *ifs, *curr;
-    jobject obj = NULL;
-    jboolean match = JNI_FALSE;
-    int family = getInetAddress_family(env, iaObj);
-    JNU_CHECK_EXCEPTION_RETURN(env, NULL);
-
-    if (family == java_net_InetAddress_IPv4) {
-        family = AF_INET;
-    } else if (family == java_net_InetAddress_IPv6) {
-        family = AF_INET6;
-    } else {
-        return NULL; // Invalid family
-    }
-    ifs = enumInterfaces(env);
-    if (ifs == NULL) {
-        return NULL;
-    }
-
-    curr = ifs;
+// Return the interface in ifs that iaObj is bound to, if any - otherwise NULL
+static netif* find_bound_interface(JNIEnv *env, netif* ifs, jobject iaObj, int family) {
+    netif* curr = ifs;
     while (curr != NULL) {
         netaddr *addrP = curr->addr;
 
@@ -359,11 +337,10 @@
                         ((struct sockaddr_in *)addrP->addr)->sin_addr.s_addr);
                     int address2 = getInetAddress_addr(env, iaObj);
                     if ((*env)->ExceptionCheck(env)) {
-                        goto cleanup;
+                        return NULL;
                     }
                     if (address1 == address2) {
-                        match = JNI_TRUE;
-                        break;
+                        return curr;
                     }
                 } else if (family == AF_INET6) {
                     jbyte *bytes = (jbyte *)&(
@@ -383,30 +360,117 @@
                         i++;
                     }
                     if (i >= 16) {
-                        match = JNI_TRUE;
-                        break;
+                        return curr;
                     }
                 }
             }
 
-            if (match) {
-                break;
-            }
             addrP = addrP->next;
         }
-
-        if (match) {
-            break;
-        }
         curr = curr->next;
     }
 
+    return NULL;
+}
+
+/*
+ * Class:     java_net_NetworkInterface
+ * Method:    boundInetAddress0
+ * Signature: (Ljava/net/InetAddress;)boundInetAddress;
+ */
+JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_boundInetAddress0
+    (JNIEnv *env, jclass cls, jobject iaObj)
+{
+    netif *ifs = NULL;
+    jboolean bound = JNI_FALSE;
+    int sock;
+
+    int family = getInetAddress_family(env, iaObj);
+    JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);
+
+    if (family == java_net_InetAddress_IPv4) {
+        family = AF_INET;
+    } else if (family == java_net_InetAddress_IPv6) {
+        family = AF_INET6;
+    } else {
+        return JNI_FALSE; // Invalid family
+    }
+
+    if (family == AF_INET) {
+        sock = openSocket(env, AF_INET);
+        if (sock < 0 && (*env)->ExceptionOccurred(env)) {
+            return JNI_FALSE;
+        }
+
+        // enumerate IPv4 addresses
+        if (sock >= 0) {
+            ifs = enumIPv4Interfaces(env, sock, ifs);
+            close(sock);
+
+            if ((*env)->ExceptionOccurred(env)) {
+                goto cleanup;
+            }
+        }
+        if (find_bound_interface(env, ifs, iaObj, family) != NULL)
+            bound = JNI_TRUE;
+    } else if (ipv6_available()) {
+        // If IPv6 is available then enumerate IPv6 addresses.
+        // User can disable ipv6 explicitly by -Djava.net.preferIPv4Stack=true,
+        // so we have to call ipv6_available()
+        sock = openSocket(env, AF_INET6);
+        if (sock < 0) {
+            return JNI_FALSE;
+        }
+
+        ifs = enumIPv6Interfaces(env, sock, ifs);
+        close(sock);
+
+        if ((*env)->ExceptionOccurred(env)) {
+            goto cleanup;
+        }
+
+        if (find_bound_interface(env, ifs, iaObj, family) != NULL)
+            bound = JNI_TRUE;
+    }
+
+cleanup:
+    freeif(ifs);
+
+    return bound;
+}
+
+/*
+ * Class:     java_net_NetworkInterface
+ * Method:    getByInetAddress0
+ * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
+ */
+JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
+  (JNIEnv *env, jclass cls, jobject iaObj)
+{
+    netif *ifs, *curr;
+    jobject obj = NULL;
+    int family = getInetAddress_family(env, iaObj);
+    JNU_CHECK_EXCEPTION_RETURN(env, NULL);
+
+    if (family == java_net_InetAddress_IPv4) {
+        family = AF_INET;
+    } else if (family == java_net_InetAddress_IPv6) {
+        family = AF_INET6;
+    } else {
+        return NULL; // Invalid family
+    }
+    ifs = enumInterfaces(env);
+    if (ifs == NULL) {
+        return NULL;
+    }
+
+    curr = find_bound_interface(env, ifs, iaObj, family);
+
     // if found create a NetworkInterface
-    if (match) {
+    if (curr != NULL) {
         obj = createNetworkInterface(env, curr);
     }
 
-cleanup:
     // release the interface list
     freeif(ifs);
 
@@ -1330,6 +1394,10 @@
 /** AIX **/
 #if defined(_AIX)
 
+/* seems getkerninfo is guarded by _KERNEL in the system headers */
+/* see net/proto_uipc.h */
+int getkerninfo(int, char *, int *, int32long64_t);
+
 /*
  * Opens a socket for further ioctl calls. Tries AF_INET socket first and
  * if it fails return AF_INET6 socket.
@@ -1549,7 +1617,7 @@
         return -1;
     }
 
-    if (getkerninfo(KINFO_NDD, nddp, &size, 0) < 0) {
+    if (getkerninfo(KINFO_NDD, (char*) nddp, &size, 0) < 0) {
         perror("getkerninfo 2");
         free(nddp);
         return -1;