Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 
     27 #include <errno.h>
     28 #include <strings.h>
     29 #if defined(_ALLBSD_SOURCE) && defined(__OpenBSD__)
     30 #include <sys/types.h>
     31 #endif
     32 #include <netinet/in.h>
     33 #include <stdlib.h>
     34 #include <string.h>
     35 #include <sys/types.h>
     36 #include <sys/socket.h>
     37 #include <arpa/inet.h>
     38 #include <net/if.h>
     39 #include <net/if_arp.h>
     40 #include <linux/if_packet.h>
     41 
     42 #include <sys/ioctl.h>
     43 //#include <bits/ioctls.h>
     44 #include <sys/utsname.h>
     45 #include <stdio.h>
     46 #include <ifaddrs.h>
     47 
     48 #include "jvm.h"
     49 #include "jni_util.h"
     50 #include "net_util.h"
     51 #include "JNIHelp.h"
     52 
     53 #define NATIVE_METHOD(className, functionName, signature) \
     54 { #functionName, signature, (void*)(className ## _ ## functionName) }
     55 
     56 typedef struct _netaddr  {
     57     struct sockaddr *addr;
     58     struct sockaddr *brdcast;
     59     short mask;
     60     int family; /* to make searches simple */
     61     struct _netaddr *next;
     62 } netaddr;
     63 
     64 typedef struct _netif {
     65     char *name;
     66     int index;
     67     char virtual;
     68 
     69     uint8_t hwAddrLen;
     70     uint8_t *hwAddr;
     71     netaddr *addr;
     72     struct _netif *childs;
     73     struct _netif *next;
     74 } netif;
     75 
     76 /************************************************************************
     77  * NetworkInterface
     78  */
     79 
     80 
     81 /************************************************************************
     82  * NetworkInterface
     83  */
     84 jclass ni_class;
     85 jfieldID ni_nameID;
     86 jfieldID ni_indexID;
     87 jfieldID ni_descID;
     88 jfieldID ni_addrsID;
     89 jfieldID ni_bindsID;
     90 jfieldID ni_virutalID;
     91 jfieldID ni_childsID;
     92 jfieldID ni_parentID;
     93 jfieldID ni_defaultIndexID;
     94 jfieldID ni_hardwareAddrID;
     95 jmethodID ni_ctrID;
     96 
     97 static jclass ni_iacls;
     98 static jclass ni_ia4cls;
     99 static jclass ni_ia6cls;
    100 static jclass ni_ibcls;
    101 static jmethodID ni_ia4ctrID;
    102 static jmethodID ni_ia6ctrID;
    103 static jmethodID ni_ibctrID;
    104 static jfieldID ni_ia6ipaddressID;
    105 static jfieldID ni_ibaddressID;
    106 static jfieldID ni_ib4broadcastID;
    107 static jfieldID ni_ib4maskID;
    108 
    109 /** Private methods declarations **/
    110 static jobject createNetworkInterface(JNIEnv *env, netif *ifs);
    111 static int     getFlags0(JNIEnv *env, jstring  ifname);
    112 
    113 static netif  *enumInterfaces(JNIEnv *env);
    114 
    115 static netif  *addif(JNIEnv *env, int sock, struct ifaddrs *ifa, netif *ifs);
    116 static void    freeif(netif *ifs);
    117 
    118 static int     openSocket(JNIEnv *env, int proto);
    119 static int     openSocketWithFallback(JNIEnv *env, const char *ifname);
    120 
    121 static int     getIndex(int sock, const char *ifname);
    122 
    123 static int     getFlags(int sock, const char *ifname, int *flags);
    124 static int     getMTU(JNIEnv *env, int sock, const char *ifname);
    125 
    126 /******************* Java entry points *****************************/
    127 
    128 static void NetworkInterface_init(JNIEnv *env) {
    129     ni_class = (*env)->FindClass(env,"java/net/NetworkInterface");
    130     ni_class = (*env)->NewGlobalRef(env, ni_class);
    131     ni_nameID = (*env)->GetFieldID(env, ni_class,"name", "Ljava/lang/String;");
    132     ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I");
    133     ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs", "[Ljava/net/InetAddress;");
    134     ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings", "[Ljava/net/InterfaceAddress;");
    135     ni_descID = (*env)->GetFieldID(env, ni_class, "displayName", "Ljava/lang/String;");
    136     ni_virutalID = (*env)->GetFieldID(env, ni_class, "virtual", "Z");
    137     ni_childsID = (*env)->GetFieldID(env, ni_class, "childs", "[Ljava/net/NetworkInterface;");
    138     ni_parentID = (*env)->GetFieldID(env, ni_class, "parent", "Ljava/net/NetworkInterface;");
    139     ni_hardwareAddrID = (*env)->GetFieldID(env, ni_class, "hardwareAddr", "[B");
    140     ni_ctrID = (*env)->GetMethodID(env, ni_class, "<init>", "()V");
    141 
    142     ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
    143     ni_iacls = (*env)->NewGlobalRef(env, ni_iacls);
    144     ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address");
    145     ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls);
    146     ni_ia6cls = (*env)->FindClass(env, "java/net/Inet6Address");
    147     ni_ia6cls = (*env)->NewGlobalRef(env, ni_ia6cls);
    148     ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress");
    149     ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls);
    150     ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V");
    151     ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "<init>", "()V");
    152     ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V");
    153     ni_ia6ipaddressID = (*env)->GetFieldID(env, ni_ia6cls, "ipaddress", "[B");
    154     ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address", "Ljava/net/InetAddress;");
    155     ni_ib4broadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast", "Ljava/net/Inet4Address;");
    156     ni_ib4maskID = (*env)->GetFieldID(env, ni_ibcls, "maskLength", "S");
    157     ni_defaultIndexID = (*env)->GetStaticFieldID(env, ni_class, "defaultIndex", "I");
    158 }
    159 
    160 
    161 /*
    162  * Class:     java_net_NetworkInterface
    163  * Method:    getByName0
    164  * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
    165  */
    166 JNIEXPORT jobject JNICALL NetworkInterface_getByName0
    167     (JNIEnv *env, jclass cls, jstring name) {
    168 
    169     netif *ifs, *curr;
    170     jboolean isCopy;
    171     const char* name_utf;
    172     jobject obj = NULL;
    173 
    174     ifs = enumInterfaces(env);
    175     if (ifs == NULL) {
    176         return NULL;
    177     }
    178 
    179     name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
    180 
    181     /*
    182      * Search the list of interface based on name
    183      */
    184     curr = ifs;
    185     while (curr != NULL) {
    186         if (strcmp(name_utf, curr->name) == 0) {
    187             break;
    188         }
    189         curr = curr->next;
    190     }
    191 
    192     /* if found create a NetworkInterface */
    193     if (curr != NULL) {;
    194         obj = createNetworkInterface(env, curr);
    195     }
    196 
    197     /* release the UTF string and interface list */
    198     (*env)->ReleaseStringUTFChars(env, name, name_utf);
    199     freeif(ifs);
    200 
    201     return obj;
    202 }
    203 
    204 
    205 /*
    206  * Class:     java_net_NetworkInterface
    207  * Method:    getByIndex0
    208  * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
    209  */
    210 JNIEXPORT jobject JNICALL NetworkInterface_getByIndex0
    211     (JNIEnv *env, jclass cls, jint index) {
    212 
    213     netif *ifs, *curr;
    214     jobject obj = NULL;
    215 
    216     if (index <= 0) {
    217         return NULL;
    218     }
    219 
    220     ifs = enumInterfaces(env);
    221     if (ifs == NULL) {
    222         return NULL;
    223     }
    224 
    225     /*
    226      * Search the list of interface based on index
    227      */
    228     curr = ifs;
    229     while (curr != NULL) {
    230         if (index == curr->index) {
    231             break;
    232         }
    233         curr = curr->next;
    234     }
    235 
    236     /* if found create a NetworkInterface */
    237     if (curr != NULL) {;
    238         obj = createNetworkInterface(env, curr);
    239     }
    240 
    241     freeif(ifs);
    242     return obj;
    243 }
    244 
    245 /*
    246  * Class:     java_net_NetworkInterface
    247  * Method:    getByInetAddress0
    248  * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
    249  */
    250 JNIEXPORT jobject JNICALL NetworkInterface_getByInetAddress0
    251     (JNIEnv *env, jclass cls, jobject iaObj) {
    252 
    253     netif *ifs, *curr;
    254 
    255     int family = (getInetAddress_family(env, iaObj) == IPv4) ? AF_INET : AF_INET6;
    256 
    257     jobject obj = NULL;
    258     jboolean match = JNI_FALSE;
    259 
    260     ifs = enumInterfaces(env);
    261     if (ifs == NULL) {
    262         return NULL;
    263     }
    264 
    265     curr = ifs;
    266     while (curr != NULL) {
    267         netaddr *addrP = curr->addr;
    268 
    269         /*
    270          * Iterate through each address on the interface
    271          */
    272         while (addrP != NULL) {
    273 
    274             if (family == addrP->family) {
    275                 if (family == AF_INET) {
    276                     int address1 = htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr);
    277                     int address2 = getInetAddress_addr(env, iaObj);
    278 
    279                     if (address1 == address2) {
    280                         match = JNI_TRUE;
    281                         break;
    282                     }
    283                 }
    284 
    285                 if (family == AF_INET6) {
    286                     jbyte *bytes = (jbyte *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr);
    287                     jbyteArray ipaddress = (*env)->GetObjectField(env, iaObj, ni_ia6ipaddressID);
    288                     jbyte caddr[16];
    289                     int i;
    290 
    291                     (*env)->GetByteArrayRegion(env, ipaddress, 0, 16, caddr);
    292                     i = 0;
    293                     while (i < 16) {
    294                         if (caddr[i] != bytes[i]) {
    295                             break;
    296                         }
    297                         i++;
    298                     }
    299                     if (i >= 16) {
    300                         match = JNI_TRUE;
    301                         break;
    302                     }
    303                 }
    304             }
    305 
    306             if (match) {
    307                 break;
    308             }
    309             addrP = addrP->next;
    310         }
    311 
    312         if (match) {
    313             break;
    314         }
    315         curr = curr->next;
    316     }
    317 
    318     /* if found create a NetworkInterface */
    319     if (match) {;
    320         obj = createNetworkInterface(env, curr);
    321     }
    322 
    323     freeif(ifs);
    324     return obj;
    325 }
    326 
    327 
    328 /*
    329  * Class:     java_net_NetworkInterface
    330  * Method:    getAll
    331  * Signature: ()[Ljava/net/NetworkInterface;
    332  */
    333 JNIEXPORT jobjectArray JNICALL NetworkInterface_getAll
    334     (JNIEnv *env, jclass cls) {
    335 
    336     netif *ifs, *curr;
    337     jobjectArray netIFArr;
    338     jint arr_index, ifCount;
    339 
    340     ifs = enumInterfaces(env);
    341     if (ifs == NULL) {
    342         return NULL;
    343     }
    344 
    345     /* count the interface */
    346     ifCount = 0;
    347     curr = ifs;
    348     while (curr != NULL) {
    349         ifCount++;
    350         curr = curr->next;
    351     }
    352 
    353     /* allocate a NetworkInterface array */
    354     netIFArr = (*env)->NewObjectArray(env, ifCount, cls, NULL);
    355     if (netIFArr == NULL) {
    356         freeif(ifs);
    357         return NULL;
    358     }
    359 
    360     /*
    361      * Iterate through the interfaces, create a NetworkInterface instance
    362      * for each array element and populate the object.
    363      */
    364     curr = ifs;
    365     arr_index = 0;
    366     while (curr != NULL) {
    367         jobject netifObj;
    368 
    369         netifObj = createNetworkInterface(env, curr);
    370         if (netifObj == NULL) {
    371             freeif(ifs);
    372             return NULL;
    373         }
    374 
    375         /* put the NetworkInterface into the array */
    376         (*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj);
    377 
    378         curr = curr->next;
    379     }
    380 
    381     freeif(ifs);
    382     return netIFArr;
    383 }
    384 
    385 
    386 /*
    387  * Class:     java_net_NetworkInterface
    388  * Method:    isUp0
    389  * Signature: (Ljava/lang/String;I)Z
    390  */
    391 JNIEXPORT jboolean JNICALL NetworkInterface_isUp0(JNIEnv *env, jclass cls, jstring name, jint index) {
    392     int ret = getFlags0(env, name);
    393     return ((ret & IFF_UP) && (ret & IFF_RUNNING)) ? JNI_TRUE :  JNI_FALSE;
    394 }
    395 
    396 /*
    397  * Class:     java_net_NetworkInterface
    398  * Method:    isP2P0
    399  * Signature: (Ljava/lang/String;I)Z
    400  */
    401 JNIEXPORT jboolean JNICALL NetworkInterface_isP2P0(JNIEnv *env, jclass cls, jstring name, jint index) {
    402     int ret = getFlags0(env, name);
    403     return (ret & IFF_POINTOPOINT) ? JNI_TRUE :  JNI_FALSE;
    404 }
    405 
    406 /*
    407  * Class:     java_net_NetworkInterface
    408  * Method:    isLoopback0
    409  * Signature: (Ljava/lang/String;I)Z
    410  */
    411 JNIEXPORT jboolean JNICALL NetworkInterface_isLoopback0(JNIEnv *env, jclass cls, jstring name, jint index) {
    412   int ret = getFlags0(env, name);
    413   return (ret & IFF_LOOPBACK) ? JNI_TRUE :  JNI_FALSE;
    414 }
    415 
    416 /*
    417  * Class:     java_net_NetworkInterface
    418  * Method:    supportsMulticast0
    419  * Signature: (Ljava/lang/String;I)Z
    420  */
    421 JNIEXPORT jboolean JNICALL NetworkInterface_supportsMulticast0(JNIEnv *env, jclass cls, jstring name, jint index) {
    422   int ret = getFlags0(env, name);
    423   return (ret & IFF_MULTICAST) ? JNI_TRUE :  JNI_FALSE;
    424 }
    425 
    426 /*
    427  * Class:       java_net_NetworkInterface
    428  * Method:      getMTU0
    429  * Signature:   ([bLjava/lang/String;I)I
    430  */
    431 
    432 JNIEXPORT jint JNICALL NetworkInterface_getMTU0(JNIEnv *env, jclass class, jstring name, jint index) {
    433   jboolean isCopy;
    434   int ret = -1;
    435   int sock;
    436   const char* name_utf;
    437 
    438   name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
    439 
    440   if ((sock =openSocketWithFallback(env, name_utf)) < 0) {
    441     (*env)->ReleaseStringUTFChars(env, name, name_utf);
    442     return JNI_FALSE;
    443   }
    444 
    445   ret = getMTU(env, sock, name_utf);
    446 
    447   (*env)->ReleaseStringUTFChars(env, name, name_utf);
    448 
    449   untagSocket(env, sock);
    450   close(sock);
    451   return ret;
    452 }
    453 
    454 /*** Private methods definitions ****/
    455 
    456 static int getFlags0(JNIEnv *env, jstring name) {
    457   jboolean isCopy;
    458   int ret, sock;
    459   const char* name_utf;
    460   int flags = 0;
    461 
    462   name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
    463 
    464   if ((sock = openSocketWithFallback(env, name_utf)) < 0) {
    465     (*env)->ReleaseStringUTFChars(env, name, name_utf);
    466     return -1;
    467   }
    468 
    469   ret = getFlags(sock, name_utf, &flags);
    470 
    471   untagSocket(env, sock);
    472   close(sock);
    473   (*env)->ReleaseStringUTFChars(env, name, name_utf);
    474 
    475   if (ret < 0) {
    476     NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL  SIOCGLIFFLAGS failed");
    477     return -1;
    478   }
    479 
    480   return flags;
    481 }
    482 
    483 
    484 
    485 
    486 /*
    487  * Create a NetworkInterface object, populate the name and index, and
    488  * populate the InetAddress array based on the IP addresses for this
    489  * interface.
    490  */
    491 jobject createNetworkInterface(JNIEnv *env, netif *ifs) {
    492   jobject netifObj;
    493   jobject name;
    494   jobjectArray addrArr;
    495   jobjectArray bindArr;
    496   jobjectArray childArr;
    497   netaddr *addrs;
    498   jint addr_index, addr_count, bind_index;
    499   jint child_count, child_index;
    500   netaddr *addrP;
    501   netif *childP;
    502   jobject tmp;
    503 
    504   /*
    505    * Create a NetworkInterface object and populate it
    506    */
    507   netifObj = (*env)->NewObject(env, ni_class, ni_ctrID);
    508   name = (*env)->NewStringUTF(env, ifs->name);
    509   if (netifObj == NULL || name == NULL) {
    510     return NULL;
    511   }
    512   (*env)->SetObjectField(env, netifObj, ni_nameID, name);
    513   (*env)->SetObjectField(env, netifObj, ni_descID, name);
    514   (*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);
    515   (*env)->SetBooleanField(env, netifObj, ni_virutalID, ifs->virtual ? JNI_TRUE : JNI_FALSE);
    516 
    517   /*
    518    * Set the hardware address
    519    */
    520   if (ifs->hwAddrLen > 0 && ifs->hwAddr != NULL) {
    521     jbyteArray hardwareAddr = (*env)->NewByteArray(env, ifs->hwAddrLen);
    522     if (hardwareAddr == NULL) {
    523       return NULL;
    524     }
    525     (*env)->SetByteArrayRegion(env, hardwareAddr, 0, ifs->hwAddrLen, (jbyte *)ifs->hwAddr);
    526     (*env)->SetObjectField(env, netifObj, ni_hardwareAddrID, hardwareAddr);
    527   }
    528 
    529   /*
    530    * Count the number of address on this interface
    531    */
    532   addr_count = 0;
    533   addrP = ifs->addr;
    534   while (addrP != NULL) {
    535     addr_count++;
    536     addrP = addrP->next;
    537   }
    538 
    539   /*
    540    * Create the array of InetAddresses
    541    */
    542   addrArr = (*env)->NewObjectArray(env, addr_count,  ni_iacls, NULL);
    543   if (addrArr == NULL) {
    544     return NULL;
    545   }
    546 
    547   bindArr = (*env)->NewObjectArray(env, addr_count, ni_ibcls, NULL);
    548   if (bindArr == NULL) {
    549     return NULL;
    550   }
    551   addrP = ifs->addr;
    552   addr_index = 0;
    553   bind_index = 0;
    554   while (addrP != NULL) {
    555     jobject iaObj = NULL;
    556     jobject ibObj = NULL;
    557 
    558     if (addrP->family == AF_INET) {
    559       iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
    560       if (iaObj) {
    561         setInetAddress_addr(env, iaObj, htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr));
    562       }
    563       ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
    564       if (ibObj) {
    565         (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
    566         if (addrP->brdcast) {
    567           jobject ia2Obj = NULL;
    568           ia2Obj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
    569           if (ia2Obj) {
    570             setInetAddress_addr(env, ia2Obj, htonl(((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr));
    571             (*env)->SetObjectField(env, ibObj, ni_ib4broadcastID, ia2Obj);
    572           }
    573         }
    574         (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);
    575         (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);
    576       }
    577     }
    578 
    579     if (addrP->family == AF_INET6) {
    580       int scope=0;
    581       iaObj = (*env)->NewObject(env, ni_ia6cls, ni_ia6ctrID);
    582       if (iaObj) {
    583         jbyteArray ipaddress = (*env)->NewByteArray(env, 16);
    584         if (ipaddress == NULL) {
    585           return NULL;
    586         }
    587         (*env)->SetByteArrayRegion(env, ipaddress, 0, 16,
    588                                    (jbyte *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr));
    589 
    590         scope = ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id;
    591 
    592         if (scope != 0) { /* zero is default value, no need to set */
    593           (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
    594           (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
    595           (*env)->SetObjectField(env, iaObj, ia6_scopeifnameID, netifObj);
    596         }
    597         (*env)->SetObjectField(env, iaObj, ni_ia6ipaddressID, ipaddress);
    598       }
    599       ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
    600       if (ibObj) {
    601         (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
    602         (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);
    603         (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);
    604       }
    605     }
    606 
    607     if (iaObj == NULL) {
    608       return NULL;
    609     }
    610 
    611     (*env)->SetObjectArrayElement(env, addrArr, addr_index++, iaObj);
    612     addrP = addrP->next;
    613   }
    614 
    615   /*
    616    * See if there is any virtual interface attached to this one.
    617    */
    618   child_count = 0;
    619   childP = ifs->childs;
    620   while (childP) {
    621     child_count++;
    622     childP = childP->next;
    623   }
    624 
    625   childArr = (*env)->NewObjectArray(env, child_count, ni_class, NULL);
    626   if (childArr == NULL) {
    627     return NULL;
    628   }
    629 
    630   /*
    631    * Create the NetworkInterface instances for the sub-interfaces as
    632    * well.
    633    */
    634   child_index = 0;
    635   childP = ifs->childs;
    636   while(childP) {
    637     tmp = createNetworkInterface(env, childP);
    638     if (tmp == NULL) {
    639       return NULL;
    640     }
    641     (*env)->SetObjectField(env, tmp, ni_parentID, netifObj);
    642     (*env)->SetObjectArrayElement(env, childArr, child_index++, tmp);
    643     childP = childP->next;
    644   }
    645   (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr);
    646   (*env)->SetObjectField(env, netifObj, ni_bindsID, bindArr);
    647   (*env)->SetObjectField(env, netifObj, ni_childsID, childArr);
    648 
    649   /* return the NetworkInterface */
    650   return netifObj;
    651 }
    652 
    653 /*
    654  * Determines the mask length for IPV4/v6 addresses.
    655  */
    656 static
    657 int mask_address_to_mask_length(uint8_t *val, int size) {
    658   int byte, bit, plen = 0;
    659 
    660   for (byte = 0; byte < size && val[byte] == 0xff; byte++) {
    661     plen += 8;
    662   }
    663   if (byte < size) {
    664     for (bit = 7; bit > 0; bit--) {
    665       if (val[byte] & (1 << bit)) plen++;
    666     }
    667   }
    668   return plen;
    669 }
    670 
    671 /*
    672  * Enumerates all interfaces
    673  */
    674 static netif *enumInterfaces(JNIEnv *env) {
    675   netif *ifs = NULL;
    676   struct ifaddrs *ifa, *origifa;
    677 
    678   int sock = openSocket(env, AF_INET);
    679   if (sock < 0 && (*env)->ExceptionOccurred(env)) {
    680     return NULL;
    681   }
    682 
    683   if (getifaddrs(&origifa) != 0) {
    684     NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException",
    685                                  "getifaddrs() function failed");
    686     return NULL;
    687   }
    688 
    689   for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {
    690     if (ifa->ifa_addr != NULL) {
    691       switch (ifa->ifa_addr->sa_family) {
    692         case AF_PACKET:
    693         case AF_INET:
    694         case AF_INET6:
    695           ifs = addif(env, sock, ifa, ifs);
    696           break;
    697       }
    698     }
    699   }
    700 
    701   freeifaddrs(origifa);
    702   untagSocket(env, sock);
    703   close(sock);
    704 
    705   return ifs;
    706 }
    707 
    708 #define CHECKED_MALLOC3(_pointer,_type,_size) \
    709     do{ \
    710       _pointer = (_type)malloc( _size ); \
    711       if (_pointer == NULL) { \
    712         JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); \
    713         return ifs; /* return untouched list */ \
    714       } \
    715     } while(0)
    716 
    717 
    718 /*
    719  * Free an interface list (including any attached addresses)
    720  */
    721 void freeif(netif *ifs) {
    722   netif *currif = ifs;
    723   netif *child = NULL;
    724 
    725   while (currif != NULL) {
    726     netaddr *addrP = currif->addr;
    727     while (addrP != NULL) {
    728       netaddr *next = addrP->next;
    729       free(addrP);
    730       addrP = next;
    731     }
    732 
    733     /*
    734      * Don't forget to free the sub-interfaces.
    735      */
    736     if (currif->childs != NULL) {
    737       freeif(currif->childs);
    738     }
    739 
    740     /*
    741      * Remove mac address
    742      */
    743     if (currif->hwAddr != NULL) {
    744       free(currif->hwAddr);
    745     }
    746 
    747     ifs = currif->next;
    748     free(currif);
    749     currif = ifs;
    750   }
    751 }
    752 
    753 netif *addif(JNIEnv *env, int sock, struct ifaddrs *ifa, netif *ifs)
    754 {
    755   netif *currif = ifs, *parent;
    756   netaddr *addrP = NULL;
    757 
    758   char name[IFNAMSIZ], vname[IFNAMSIZ];
    759 
    760   char  *name_colonP;
    761   int mask;
    762   int isVirtual = 0;
    763   int addr_size;
    764   int flags = 0;
    765 
    766   /*
    767    * If the interface name is a logical interface then we
    768    * remove the unit number so that we have the physical
    769    * interface (eg: hme0:1 -> hme0). NetworkInterface
    770    * currently doesn't have any concept of physical vs.
    771    * logical interfaces.
    772    */
    773   strncpy(name, ifa->ifa_name, sizeof(name));
    774   name[sizeof(name) - 1] = '\0';
    775   *vname = 0;
    776 
    777   /*
    778    * Create and populate the netaddr node. If allocation fails
    779    * return an un-updated list.
    780    */
    781   switch(ifa->ifa_addr->sa_family) {
    782     case AF_INET:
    783       addr_size = sizeof(struct sockaddr_in);
    784       break;
    785     case AF_INET6:
    786       addr_size = sizeof(struct sockaddr_in6);
    787       break;
    788     case AF_PACKET:
    789       // Don't add an address entry, will extract data to netif struct
    790       addr_size = 0;
    791       break;
    792     default:
    793       return NULL;
    794   }
    795 
    796   if (addr_size > 0) {
    797     /*Allocate for addr and brdcast at once*/
    798     CHECKED_MALLOC3(addrP, netaddr *, sizeof(netaddr)+2*addr_size);
    799     addrP->addr = (struct sockaddr *)( (char *) addrP+sizeof(netaddr) );
    800     memcpy(addrP->addr, ifa->ifa_addr, addr_size);
    801 
    802     addrP->family = ifa->ifa_addr->sa_family;
    803     addrP->next = 0;
    804 
    805     if (ifa->ifa_broadaddr && (ifa->ifa_flags & IFF_BROADCAST)) {
    806       struct sockaddr * brdcast_to = (struct sockaddr *) ((char *) addrP + sizeof(netaddr) + addr_size);
    807       addrP->brdcast = brdcast_to;
    808       memcpy(brdcast_to, ifa->ifa_broadaddr, sizeof(struct sockaddr));
    809     } else {
    810       addrP->brdcast = NULL;
    811     }
    812 
    813     if (ifa->ifa_netmask) {
    814       if (ifa->ifa_netmask->sa_family == AF_INET) {
    815         addrP->mask = mask_address_to_mask_length(
    816             (uint8_t*)&(((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr),
    817             sizeof(struct in_addr));
    818       } else if (ifa->ifa_netmask->sa_family == AF_INET6) {
    819         addrP->mask = mask_address_to_mask_length(
    820             (uint8_t*)&((struct sockaddr_in6*)ifa->ifa_netmask)->sin6_addr,
    821             sizeof(struct in6_addr));
    822       }
    823     } else {
    824       addrP->mask = 0;
    825     }
    826   }
    827 
    828   /**
    829    * Deal with virtual interface with colon notaion e.g. eth0:1
    830    */
    831   name_colonP = strchr(name, ':');
    832   if (name_colonP != NULL) {
    833     /**
    834      * This is a virtual interface. If we are able to access the parent
    835      * we need to create a new entry if it doesn't exist yet *and* update
    836      * the 'parent' interface with the new records.
    837      */
    838     *name_colonP = 0;
    839     if (getFlags(sock, name, &flags) < 0 || flags < 0) {
    840       // failed to access parent interface do not create parent.
    841       // We are a virtual interface with no parent.
    842       isVirtual = 1;
    843       *name_colonP = ':';
    844     }
    845     else{
    846       // Got access to parent, so create it if necessary.
    847       // Save original name to vname and truncate name by ':'
    848       memcpy(vname, name, sizeof(vname) );
    849       vname[name_colonP - name] = ':';
    850     }
    851   }
    852 
    853   /*
    854    * Check if this is a "new" interface. Use the interface
    855    * name for matching because index isn't supported on
    856    * Solaris 2.6 & 7.
    857    */
    858   while (currif != NULL) {
    859     if (strcmp(name, currif->name) == 0) {
    860       break;
    861     }
    862     currif = currif->next;
    863   }
    864 
    865   /*
    866    * If "new" then create an netif structure and
    867    * insert it onto the list.
    868    */
    869   if (currif == NULL) {
    870     CHECKED_MALLOC3(currif, netif *, sizeof(netif) + sizeof(name));
    871     currif->name = (char *) currif+sizeof(netif);
    872     strncpy(currif->name, name, sizeof(name));
    873     currif->name[sizeof(name) - 1] = '\0';
    874     currif->index = getIndex(sock, name);
    875     currif->addr = NULL;
    876     currif->childs = NULL;
    877     currif->virtual = isVirtual;
    878     currif->hwAddrLen = 0;
    879     currif->hwAddr = NULL;
    880     currif->next = ifs;
    881     ifs = currif;
    882   }
    883 
    884   /*
    885    * Insert the mac address on the interface
    886    */
    887   if (ifa->ifa_addr->sa_family == AF_PACKET) {
    888     struct sockaddr_ll *s = (struct sockaddr_ll*)ifa->ifa_addr;
    889 
    890     if (s->sll_halen > 0) {
    891       /*
    892        * All bytes to 0 means no hardware address.
    893        */
    894       int i;
    895       for (i = 0;i < s->sll_halen; ++i) {
    896         if (s->sll_addr[i] != 0) {
    897           break;
    898         }
    899       }
    900       if (i != s->sll_halen && currif->hwAddr == NULL) {
    901         CHECKED_MALLOC3(currif->hwAddr, uint8_t *, s->sll_halen);
    902         memcpy(currif->hwAddr, s->sll_addr, s->sll_halen);
    903         currif->hwAddrLen = s->sll_halen;
    904       }
    905     }
    906   }
    907 
    908   /*
    909    * Finally insert the address on the interface
    910    */
    911   if (addrP != NULL) {
    912     addrP->next = currif->addr;
    913     currif->addr = addrP;
    914   }
    915 
    916   parent = currif;
    917 
    918   /**
    919    * Let's deal with the virtual interface now.
    920    */
    921   if (vname[0]) {
    922     netaddr *tmpaddr;
    923 
    924     currif = parent->childs;
    925 
    926     while (currif != NULL) {
    927       if (strcmp(vname, currif->name) == 0) {
    928         break;
    929       }
    930       currif = currif->next;
    931     }
    932 
    933     if (currif == NULL) {
    934       CHECKED_MALLOC3(currif, netif *, sizeof(netif) + sizeof(name));
    935       currif->name = (char *) currif + sizeof(netif);
    936       strncpy(currif->name, vname, sizeof(name));
    937       currif->name[sizeof(name) - 1] = '\0';
    938       currif->index = getIndex(sock, vname);
    939       currif->addr = NULL;
    940       /* Need to duplicate the addr entry? */
    941       currif->virtual = 1;
    942       currif->childs = NULL;
    943       currif->next = parent->childs;
    944       parent->childs = currif;
    945     }
    946 
    947     CHECKED_MALLOC3(tmpaddr, netaddr *, sizeof(netaddr)+2*addr_size);
    948     memcpy(tmpaddr, addrP, sizeof(netaddr));
    949     if (addrP->addr != NULL) {
    950       tmpaddr->addr = (struct sockaddr *) ( (char*)tmpaddr + sizeof(netaddr) ) ;
    951       memcpy(tmpaddr->addr, addrP->addr, addr_size);
    952     }
    953 
    954     if (addrP->brdcast != NULL) {
    955       tmpaddr->brdcast = (struct sockaddr *) ((char *) tmpaddr + sizeof(netaddr)+addr_size);
    956       memcpy(tmpaddr->brdcast, addrP->brdcast, addr_size);
    957     }
    958 
    959     tmpaddr->next = currif->addr;
    960     currif->addr = tmpaddr;
    961   }
    962 
    963   return ifs;
    964 }
    965 
    966 /* Open socket for further ioct calls
    967  * proto is AF_INET/AF_INET6
    968  */
    969 static int  openSocket(JNIEnv *env, int proto){
    970   int sock;
    971 
    972   if ((sock = JVM_Socket(proto, SOCK_DGRAM, 0)) < 0) {
    973     /*
    974      * If EPROTONOSUPPORT is returned it means we don't have
    975      * support  for this proto so don't throw an exception.
    976      */
    977     if (errno != EPROTONOSUPPORT) {
    978       NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "Socket creation failed");
    979     }
    980     return -1;
    981   }
    982 
    983   tagSocket(env, sock);
    984   return sock;
    985 }
    986 
    987 
    988 /** Linux **/
    989 
    990 /* Open socket for further ioct calls, try v4 socket first and
    991  * if it falls return v6 socket
    992  */
    993 
    994 static int openSocketWithFallback(JNIEnv *env, const char *ifname){
    995   int sock;
    996   struct ifreq if2;
    997 
    998   if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    999     if (errno == EPROTONOSUPPORT){
   1000       if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){
   1001         NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
   1002         return -1;
   1003       }
   1004     }
   1005     else{ // errno is not NOSUPPORT
   1006       NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
   1007       return -1;
   1008     }
   1009   }
   1010 
   1011   /* Linux starting from 2.6.? kernel allows ioctl call with either IPv4 or IPv6 socket regardless of type
   1012      of address of an interface */
   1013 
   1014   tagSocket(env, sock);
   1015   return sock;
   1016 }
   1017 
   1018 static int getIndex(int sock, const char *name){
   1019   /*
   1020    * Try to get the interface index
   1021    * (Not supported on Solaris 2.6 or 7)
   1022    */
   1023   struct ifreq if2;
   1024   strcpy(if2.ifr_name, name);
   1025 
   1026   if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {
   1027     return -1;
   1028   }
   1029 
   1030   return if2.ifr_ifindex;
   1031 }
   1032 
   1033 static int getMTU(JNIEnv *env, int sock,  const char *ifname) {
   1034   struct ifreq if2;
   1035 
   1036   memset((char *) &if2, 0, sizeof(if2));
   1037   strcpy(if2.ifr_name, ifname);
   1038 
   1039   if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
   1040     NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFMTU failed");
   1041     return -1;
   1042   }
   1043 
   1044   return  if2.ifr_mtu;
   1045 }
   1046 
   1047 static int getFlags(int sock, const char *ifname, int *flags) {
   1048   struct ifreq if2;
   1049 
   1050   memset((char *) &if2, 0, sizeof(if2));
   1051   strcpy(if2.ifr_name, ifname);
   1052 
   1053   if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0){
   1054     return -1;
   1055   }
   1056 
   1057   if (sizeof(if2.ifr_flags) == sizeof(short)) {
   1058     *flags = (if2.ifr_flags & 0xffff);
   1059   } else {
   1060     *flags = if2.ifr_flags;
   1061   }
   1062   return 0;
   1063 }
   1064 
   1065 static JNINativeMethod gMethods[] = {
   1066   NATIVE_METHOD(NetworkInterface, getMTU0, "(Ljava/lang/String;I)I"),
   1067   NATIVE_METHOD(NetworkInterface, supportsMulticast0, "(Ljava/lang/String;I)Z"),
   1068   NATIVE_METHOD(NetworkInterface, isLoopback0, "(Ljava/lang/String;I)Z"),
   1069   NATIVE_METHOD(NetworkInterface, isP2P0, "(Ljava/lang/String;I)Z"),
   1070   NATIVE_METHOD(NetworkInterface, isUp0, "(Ljava/lang/String;I)Z"),
   1071   NATIVE_METHOD(NetworkInterface, getAll, "()[Ljava/net/NetworkInterface;"),
   1072   NATIVE_METHOD(NetworkInterface, getByInetAddress0, "(Ljava/net/InetAddress;)Ljava/net/NetworkInterface;"),
   1073   NATIVE_METHOD(NetworkInterface, getByIndex0, "(I)Ljava/net/NetworkInterface;"),
   1074   NATIVE_METHOD(NetworkInterface, getByName0, "(Ljava/lang/String;)Ljava/net/NetworkInterface;"),
   1075 };
   1076 
   1077 void register_java_net_NetworkInterface(JNIEnv* env) {
   1078   jniRegisterNativeMethods(env, "java/net/NetworkInterface", gMethods, NELEM(gMethods));
   1079   NetworkInterface_init(env);
   1080 }
   1081