diff -r 4ebc2e2fb97c -r 71c04702a3d5 src/java.base/windows/native/libnet/NetworkInterface.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/windows/native/libnet/NetworkInterface.c Tue Sep 12 19:03:39 2017 +0200 @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 2000, 2016, 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 + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include "net_util.h" +#include "NetworkInterface.h" + +#include "java_net_NetworkInterface.h" + +/* + * Windows implementation of the java.net.NetworkInterface native methods. + * This module provides the implementations of getAll, getByName, getByIndex, + * and getByAddress. + * + * Interfaces and addresses are enumerated using the IP helper routines + * GetIfTable, GetIfAddrTable resp. These routines are available on Windows + * 98, NT SP+4, 2000, and XP. They are also available on Windows 95 if + * IE is upgraded to 5.x. + * + * Windows does not have any standard for device names so we are forced + * to use our own convention which is based on the normal Unix naming + * convention ("lo" for the loopback, eth0, eth1, .. for ethernet devices, + * tr0, tr1, .. for token ring, and so on). This convention gives us + * consistency across multiple Windows editions and also consistency with + * Solaris/Linux device names. Note that we always enumerate in index + * order and this ensures consistent device number across invocations. + */ + +/* various JNI ids */ + +jclass ni_class; /* NetworkInterface */ + +jmethodID ni_ctor; /* NetworkInterface() */ + +jfieldID ni_indexID; /* NetworkInterface.index */ +jfieldID ni_addrsID; /* NetworkInterface.addrs */ +jfieldID ni_bindsID; /* NetworkInterface.bindings */ +jfieldID ni_nameID; /* NetworkInterface.name */ +jfieldID ni_displayNameID; /* NetworkInterface.displayName */ +jfieldID ni_childsID; /* NetworkInterface.childs */ + +jclass ni_ibcls; /* InterfaceAddress */ +jmethodID ni_ibctrID; /* InterfaceAddress() */ +jfieldID ni_ibaddressID; /* InterfaceAddress.address */ +jfieldID ni_ibbroadcastID; /* InterfaceAddress.broadcast */ +jfieldID ni_ibmaskID; /* InterfaceAddress.maskLength */ + +/* + * Support routines to free netif and netaddr lists + */ +void free_netif(netif *netifP) { + netif *curr = netifP; + while (curr != NULL) { + if (curr->name != NULL) + free(curr->name); + if (curr->displayName != NULL) + free(curr->displayName); + if (curr->addrs != NULL) + free_netaddr (curr->addrs); + netifP = netifP->next; + free(curr); + curr = netifP; + } +} + +void free_netaddr(netaddr *netaddrP) { + netaddr *curr = netaddrP; + while (curr != NULL) { + netaddrP = netaddrP->next; + free(curr); + curr = netaddrP; + } +} + +/* + * Returns the interface structure from the table with the matching index. + */ +MIB_IFROW *getIF(jint index) { + MIB_IFTABLE *tableP; + MIB_IFROW *ifrowP, *ret = NULL; + ULONG size; + DWORD i, count; + jint ifindex; + + /* + * Ask the IP Helper library to enumerate the adapters + */ + size = sizeof(MIB_IFTABLE); + tableP = (MIB_IFTABLE *)malloc(size); + if(tableP == NULL) + return NULL; + + count = GetIfTable(tableP, &size, TRUE); + if (count == ERROR_INSUFFICIENT_BUFFER || count == ERROR_BUFFER_OVERFLOW) { + MIB_IFTABLE* newTableP = (MIB_IFTABLE *)realloc(tableP, size); + if (newTableP == NULL) { + free(tableP); + return NULL; + } + tableP = newTableP; + + count = GetIfTable(tableP, &size, TRUE); + } + + if (count != NO_ERROR) { + free(tableP); + return NULL; + } + + { + ifrowP = tableP->table; + for (i=0; idwNumEntries; i++) { + /* + * Warning: the real index is obtained by GetFriendlyIfIndex() + */ + ifindex = GetFriendlyIfIndex(ifrowP->dwIndex); + if (ifindex == index) { + /* + * Create a copy of the entry so that we can free the table. + */ + ret = (MIB_IFROW *) malloc(sizeof(MIB_IFROW)); + if (ret == NULL) { + free(tableP); + return NULL; + } + memcpy(ret, ifrowP, sizeof(MIB_IFROW)); + break; + } + + /* onto the next interface */ + ifrowP++; + } + free(tableP); + } + return ret; +} + +/* + * Enumerate network interfaces using IP Helper Library routine GetIfTable. + * We use GetIfTable rather than other IP helper routines because it's + * available on 98 & NT SP4+. + * + * Returns the number of interfaces found or -1 if error. If no error + * occurs then netifPP be returned as list of netif structures or NULL + * if no interfaces are found. + */ +int enumInterfaces(JNIEnv *env, netif **netifPP) +{ + MIB_IFTABLE *tableP; + MIB_IFROW *ifrowP; + ULONG size; + DWORD ret; + int count; + netif *netifP; + DWORD i; + int lo=0, eth=0, tr=0, fddi=0, ppp=0, sl=0, wlan=0, net=0, wlen=0; + + /* + * Ask the IP Helper library to enumerate the adapters + */ + size = sizeof(MIB_IFTABLE); + tableP = (MIB_IFTABLE *)malloc(size); + if (tableP == NULL) { + JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure"); + return -1; + } + + ret = GetIfTable(tableP, &size, TRUE); + if (ret == ERROR_INSUFFICIENT_BUFFER || ret == ERROR_BUFFER_OVERFLOW) { + MIB_IFTABLE * newTableP = (MIB_IFTABLE *)realloc(tableP, size); + if (newTableP == NULL) { + free(tableP); + JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure"); + return -1; + } + tableP = newTableP; + ret = GetIfTable(tableP, &size, TRUE); + } + + if (ret != NO_ERROR) { + free(tableP); + + JNU_ThrowByName(env, "java/lang/Error", + "IP Helper Library GetIfTable function failed"); + + return -1; + } + + /* + * Iterate through the list of adapters + */ + count = 0; + netifP = NULL; + + ifrowP = tableP->table; + for (i=0; idwNumEntries; i++) { + char dev_name[8]; + netif *curr; + + /* + * Generate a name for the device as Windows doesn't have any + * real concept of a device name. + */ + switch (ifrowP->dwType) { + case MIB_IF_TYPE_ETHERNET: + _snprintf_s(dev_name, 8, _TRUNCATE, "eth%d", eth++); + break; + + case MIB_IF_TYPE_TOKENRING: + _snprintf_s(dev_name, 8, _TRUNCATE, "tr%d", tr++); + break; + + case MIB_IF_TYPE_FDDI: + _snprintf_s(dev_name, 8, _TRUNCATE, "fddi%d", fddi++); + break; + + case MIB_IF_TYPE_LOOPBACK: + /* There should only be only IPv4 loopback address */ + if (lo > 0) { + continue; + } + strncpy_s(dev_name, 8, "lo", _TRUNCATE); + lo++; + break; + + case MIB_IF_TYPE_PPP: + _snprintf_s(dev_name, 8, _TRUNCATE, "ppp%d", ppp++); + break; + + case MIB_IF_TYPE_SLIP: + _snprintf_s(dev_name, 8, _TRUNCATE, "sl%d", sl++); + break; + + case IF_TYPE_IEEE80211: + _snprintf_s(dev_name, 8, _TRUNCATE, "wlan%d", wlan++); + break; + + default: + _snprintf_s(dev_name, 8, _TRUNCATE, "net%d", net++); + } + + /* + * Allocate a netif structure and space for the name and + * display name (description in this case). + */ + curr = (netif *)calloc(1, sizeof(netif)); + if (curr != NULL) { + wlen = MultiByteToWideChar(CP_OEMCP, 0, ifrowP->bDescr, + ifrowP->dwDescrLen, NULL, 0); + if(wlen == 0) { + // MultiByteToWideChar should not fail + // But in rare case it fails, we allow 'char' to be displayed + curr->displayName = (char *)malloc(ifrowP->dwDescrLen + 1); + } else { + curr->displayName = (wchar_t *)malloc(wlen*(sizeof(wchar_t))+1); + } + + curr->name = (char *)malloc(strlen(dev_name) + 1); + + if (curr->name == NULL || curr->displayName == NULL) { + if (curr->name) free(curr->name); + if (curr->displayName) free(curr->displayName); + curr = NULL; + } + } + if (curr == NULL) { + JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure"); + free_netif(netifP); + free(tableP); + return -1; + } + + /* + * Populate the interface. Note that we need to convert the + * index into its "friendly" value as otherwise we will expose + * 32-bit numbers as index values. + */ + strcpy(curr->name, dev_name); + if (wlen == 0) { + // display char type in case of MultiByteToWideChar failure + strncpy(curr->displayName, ifrowP->bDescr, ifrowP->dwDescrLen); + curr->displayName[ifrowP->dwDescrLen] = '\0'; + } else { + // call MultiByteToWideChar again to fill curr->displayName + // it should not fail, because we have called it once before + if (MultiByteToWideChar(CP_OEMCP, 0, ifrowP->bDescr, + ifrowP->dwDescrLen, curr->displayName, wlen) == 0) { + JNU_ThrowByName(env, "java/lang/Error", + "Cannot get multibyte char for interface display name"); + free_netif(netifP); + free(tableP); + free(curr->name); + free(curr->displayName); + free(curr); + return -1; + } else { + curr->displayName[wlen*(sizeof(wchar_t))] = '\0'; + curr->dNameIsUnicode = TRUE; + } + } + + curr->dwIndex = ifrowP->dwIndex; + curr->ifType = ifrowP->dwType; + curr->index = GetFriendlyIfIndex(ifrowP->dwIndex); + + /* + * Put the interface at tail of list as GetIfTable(,,TRUE) is + * returning the interfaces in index order. + */ + count++; + if (netifP == NULL) { + netifP = curr; + } else { + netif *tail = netifP; + while (tail->next != NULL) { + tail = tail->next; + } + tail->next = curr; + } + + /* onto the next interface */ + ifrowP++; + } + + /* + * Free the interface table and return the interface list + */ + if (tableP) { + free(tableP); + } + *netifPP = netifP; + return count; +} + +/* + * Enumerate the IP addresses on an interface using the IP helper library + * routine GetIfAddrTable and matching based on the index name. There are + * more efficient routines but we use GetIfAddrTable because it's avaliable + * on 98 and NT. + * + * Returns the count of addresses, or -1 if error. If no error occurs then + * netaddrPP will return a list of netaddr structures with the IP addresses. + */ +int enumAddresses_win(JNIEnv *env, netif *netifP, netaddr **netaddrPP) +{ + MIB_IPADDRTABLE *tableP; + ULONG size; + DWORD ret; + DWORD i; + netaddr *netaddrP; + int count = 0; + unsigned long mask; + + /* + * Use GetIpAddrTable to enumerate the IP Addresses + */ + size = sizeof(MIB_IPADDRTABLE); + tableP = (MIB_IPADDRTABLE *)malloc(size); + if (tableP == NULL) { + JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure"); + return -1; + } + + ret = GetIpAddrTable(tableP, &size, FALSE); + if (ret == ERROR_INSUFFICIENT_BUFFER || ret == ERROR_BUFFER_OVERFLOW) { + MIB_IPADDRTABLE * newTableP = (MIB_IPADDRTABLE *)realloc(tableP, size); + if (newTableP == NULL) { + free(tableP); + JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure"); + return -1; + } + tableP = newTableP; + + ret = GetIpAddrTable(tableP, &size, FALSE); + } + if (ret != NO_ERROR) { + if (tableP) { + free(tableP); + } + JNU_ThrowByName(env, "java/lang/Error", + "IP Helper Library GetIpAddrTable function failed"); + return -1; + } + + /* + * Iterate through the table to find the addresses with the + * matching dwIndex. Ignore 0.0.0.0 addresses. + */ + count = 0; + netaddrP = NULL; + + i = 0; + while (idwNumEntries) { + if (tableP->table[i].dwIndex == netifP->dwIndex && + tableP->table[i].dwAddr != 0) { + + netaddr *curr = (netaddr *)malloc(sizeof(netaddr)); + if (curr == NULL) { + JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure"); + free_netaddr(netaddrP); + free(tableP); + return -1; + } + + curr->addr.sa4.sin_family = AF_INET; + curr->addr.sa4.sin_addr.s_addr = tableP->table[i].dwAddr; + /* + * Get netmask / broadcast address + */ + switch (netifP->ifType) { + case MIB_IF_TYPE_ETHERNET: + case MIB_IF_TYPE_TOKENRING: + case MIB_IF_TYPE_FDDI: + case MIB_IF_TYPE_LOOPBACK: + case IF_TYPE_IEEE80211: + /** + * Contrary to what it seems to indicate, dwBCastAddr doesn't + * contain the broadcast address but 0 or 1 depending on whether + * the broadcast address should set the bits of the host part + * to 0 or 1. + * Yes, I know it's stupid, but what can I say, it's MSFTs API. + */ + curr->brdcast.sa4.sin_family = AF_INET; + if (tableP->table[i].dwBCastAddr == 1) + curr->brdcast.sa4.sin_addr.s_addr = (tableP->table[i].dwAddr & tableP->table[i].dwMask) | (0xffffffff ^ tableP->table[i].dwMask); + else + curr->brdcast.sa4.sin_addr.s_addr = (tableP->table[i].dwAddr & tableP->table[i].dwMask); + mask = ntohl(tableP->table[i].dwMask); + curr->mask = 0; + while (mask) { + mask <<= 1; + curr->mask++; + } + break; + case MIB_IF_TYPE_PPP: + case MIB_IF_TYPE_SLIP: + default: + /** + * these don't have broadcast/subnet + */ + curr->mask = -1; + break; + } + + curr->next = netaddrP; + netaddrP = curr; + count++; + } + i++; + } + + *netaddrPP = netaddrP; + free(tableP); + return count; +} + +/* + * Class: java_net_NetworkInterface + * Method: init + * Signature: ()V + */ +JNIEXPORT void JNICALL +Java_java_net_NetworkInterface_init(JNIEnv *env, jclass cls) +{ + /* + * Get the various JNI ids that we require + */ + ni_class = (*env)->NewGlobalRef(env, cls); + CHECK_NULL(ni_class); + ni_nameID = (*env)->GetFieldID(env, ni_class, "name", "Ljava/lang/String;"); + CHECK_NULL(ni_nameID); + ni_displayNameID = (*env)->GetFieldID(env, ni_class, "displayName", "Ljava/lang/String;"); + CHECK_NULL(ni_displayNameID); + ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I"); + CHECK_NULL(ni_indexID); + ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs", "[Ljava/net/InetAddress;"); + CHECK_NULL(ni_addrsID); + ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings", "[Ljava/net/InterfaceAddress;"); + CHECK_NULL(ni_bindsID); + ni_childsID = (*env)->GetFieldID(env, ni_class, "childs", "[Ljava/net/NetworkInterface;"); + CHECK_NULL(ni_childsID); + ni_ctor = (*env)->GetMethodID(env, ni_class, "", "()V"); + CHECK_NULL(ni_ctor); + ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress"); + CHECK_NULL(ni_ibcls); + ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls); + CHECK_NULL(ni_ibcls); + ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "", "()V"); + CHECK_NULL(ni_ibctrID); + ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address", "Ljava/net/InetAddress;"); + CHECK_NULL(ni_ibaddressID); + ni_ibbroadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast", "Ljava/net/Inet4Address;"); + CHECK_NULL(ni_ibbroadcastID); + ni_ibmaskID = (*env)->GetFieldID(env, ni_ibcls, "maskLength", "S"); + CHECK_NULL(ni_ibmaskID); + + initInetAddressIDs(env); +} + +/* + * Create a NetworkInterface object, populate the name and index, and + * populate the InetAddress array based on the IP addresses for this + * interface. + */ +jobject createNetworkInterface + (JNIEnv *env, netif *ifs, int netaddrCount, netaddr *netaddrP) +{ + jobject netifObj; + jobject name, displayName; + jobjectArray addrArr, bindsArr, childArr; + netaddr *addrs; + jint addr_index; + jint bind_index; + + /* + * Create a NetworkInterface object and populate it + */ + netifObj = (*env)->NewObject(env, ni_class, ni_ctor); + CHECK_NULL_RETURN(netifObj, NULL); + name = (*env)->NewStringUTF(env, ifs->name); + CHECK_NULL_RETURN(name, NULL); + if (ifs->dNameIsUnicode) { + displayName = (*env)->NewString(env, (PWCHAR)ifs->displayName, + (jsize)wcslen ((PWCHAR)ifs->displayName)); + } else { + displayName = (*env)->NewStringUTF(env, ifs->displayName); + } + CHECK_NULL_RETURN(displayName, NULL); + (*env)->SetObjectField(env, netifObj, ni_nameID, name); + (*env)->SetObjectField(env, netifObj, ni_displayNameID, displayName); + (*env)->SetIntField(env, netifObj, ni_indexID, ifs->index); + + /* + * Get the IP addresses for this interface if necessary + * Note that 0 is a valid number of addresses. + */ + if (netaddrCount < 0) { + netaddrCount = enumAddresses_win(env, ifs, &netaddrP); + if (netaddrCount == -1) { + return NULL; + } + } + addrArr = (*env)->NewObjectArray(env, netaddrCount, ia_class, NULL); + if (addrArr == NULL) { + free_netaddr(netaddrP); + return NULL; + } + + bindsArr = (*env)->NewObjectArray(env, netaddrCount, ni_ibcls, NULL); + if (bindsArr == NULL) { + free_netaddr(netaddrP); + return NULL; + } + addrs = netaddrP; + addr_index = 0; + bind_index = 0; + while (addrs != NULL) { + jobject iaObj, ia2Obj; + jobject ibObj = NULL; + if (addrs->addr.sa.sa_family == AF_INET) { + iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID); + if (iaObj == NULL) { + free_netaddr(netaddrP); + return NULL; + } + /* default ctor will set family to AF_INET */ + + setInetAddress_addr(env, iaObj, ntohl(addrs->addr.sa4.sin_addr.s_addr)); + if (addrs->mask != -1) { + ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID); + if (ibObj == NULL) { + free_netaddr(netaddrP); + return NULL; + } + (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj); + ia2Obj = (*env)->NewObject(env, ia4_class, ia4_ctrID); + if (ia2Obj == NULL) { + free_netaddr(netaddrP); + return NULL; + } + setInetAddress_addr(env, ia2Obj, ntohl(addrs->brdcast.sa4.sin_addr.s_addr)); + (*env)->SetObjectField(env, ibObj, ni_ibbroadcastID, ia2Obj); + (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask); + (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj); + } + } else /* AF_INET6 */ { + int scope; + iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID); + if (iaObj) { + jboolean ret = setInet6Address_ipaddress(env, iaObj, (jbyte *)&(addrs->addr.sa6.sin6_addr.s6_addr)); + if (ret == JNI_FALSE) { + return NULL; + } + + scope = addrs->addr.sa6.sin6_scope_id; + if (scope != 0) { /* zero is default value, no need to set */ + setInet6Address_scopeid(env, iaObj, scope); + setInet6Address_scopeifname(env, iaObj, netifObj); + } + ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID); + if (ibObj == NULL) { + free_netaddr(netaddrP); + return NULL; + } + (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj); + (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask); + (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj); + } + } + (*env)->SetObjectArrayElement(env, addrArr, addr_index, iaObj); + addrs = addrs->next; + addr_index++; + } + (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr); + (*env)->SetObjectField(env, netifObj, ni_bindsID, bindsArr); + + free_netaddr(netaddrP); + + /* + * Windows doesn't have virtual interfaces, so child array + * is always empty. + */ + childArr = (*env)->NewObjectArray(env, 0, ni_class, NULL); + if (childArr == NULL) { + return NULL; + } + (*env)->SetObjectField(env, netifObj, ni_childsID, childArr); + + /* return the NetworkInterface */ + return netifObj; +} + +/* + * Class: java_net_NetworkInterface + * Method: getByName0 + * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface; + */ +JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0 + (JNIEnv *env, jclass cls, jstring name) +{ + netif *ifList, *curr; + jboolean isCopy; + const char *name_utf; + jobject netifObj = NULL; + + // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack + if (ipv6_available()) { + return Java_java_net_NetworkInterface_getByName0_XP (env, cls, name); + } + + /* get the list of interfaces */ + if (enumInterfaces(env, &ifList) < 0) { + return NULL; + } + + /* get the name as a C string */ + name_utf = (*env)->GetStringUTFChars(env, name, &isCopy); + if (name_utf != NULL) { + + /* Search by name */ + curr = ifList; + while (curr != NULL) { + if (strcmp(name_utf, curr->name) == 0) { + break; + } + curr = curr->next; + } + + /* if found create a NetworkInterface */ + if (curr != NULL) {; + netifObj = createNetworkInterface(env, curr, -1, NULL); + } + + /* release the UTF string */ + (*env)->ReleaseStringUTFChars(env, name, name_utf); + } else { + if (!(*env)->ExceptionCheck(env)) + JNU_ThrowOutOfMemoryError(env, NULL); + } + + /* release the interface list */ + free_netif(ifList); + + return netifObj; +} + +/* + * Class: NetworkInterface + * Method: getByIndex0 + * Signature: (I)LNetworkInterface; + */ +JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0 + (JNIEnv *env, jclass cls, jint index) +{ + netif *ifList, *curr; + jobject netifObj = NULL; + + // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack + if (ipv6_available()) { + return Java_java_net_NetworkInterface_getByIndex0_XP (env, cls, index); + } + + /* get the list of interfaces */ + if (enumInterfaces(env, &ifList) < 0) { + return NULL; + } + + /* search by index */ + curr = ifList; + while (curr != NULL) { + if (index == curr->index) { + break; + } + curr = curr->next; + } + + /* if found create a NetworkInterface */ + if (curr != NULL) { + netifObj = createNetworkInterface(env, curr, -1, NULL); + } + + /* release the interface list */ + free_netif(ifList); + + return netifObj; +} + +/* + * 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 *ifList, *curr; + jint addr = getInetAddress_addr(env, iaObj); + jobject netifObj = NULL; + + // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack + if (ipv6_available()) { + return Java_java_net_NetworkInterface_getByInetAddress0_XP (env, cls, iaObj); + } + + /* get the list of interfaces */ + if (enumInterfaces(env, &ifList) < 0) { + return NULL; + } + + /* + * Enumerate the addresses on each interface until we find a + * matching address. + */ + curr = ifList; + while (curr != NULL) { + int count; + netaddr *addrList; + netaddr *addrP; + + /* enumerate the addresses on this interface */ + count = enumAddresses_win(env, curr, &addrList); + if (count < 0) { + free_netif(ifList); + return NULL; + } + + /* iterate through each address */ + addrP = addrList; + + while (addrP != NULL) { + if ((unsigned long)addr == ntohl(addrP->addr.sa4.sin_addr.s_addr)) { + break; + } + addrP = addrP->next; + } + + /* + * Address matched so create NetworkInterface for this interface + * and address list. + */ + if (addrP != NULL) { + /* createNetworkInterface will free addrList */ + netifObj = createNetworkInterface(env, curr, count, addrList); + break; + } + + /* on next interface */ + curr = curr->next; + } + + /* release the interface list */ + free_netif(ifList); + + return netifObj; +} + +/* + * Class: java_net_NetworkInterface + * Method: getAll + * Signature: ()[Ljava/net/NetworkInterface; + */ +JNIEXPORT jobjectArray JNICALL Java_java_net_NetworkInterface_getAll + (JNIEnv *env, jclass cls) +{ + int count; + netif *ifList, *curr; + jobjectArray netIFArr; + jint arr_index; + + // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack + if (ipv6_available()) { + return Java_java_net_NetworkInterface_getAll_XP (env, cls); + } + + /* + * Get list of interfaces + */ + count = enumInterfaces(env, &ifList); + if (count < 0) { + return NULL; + } + + /* allocate a NetworkInterface array */ + netIFArr = (*env)->NewObjectArray(env, count, cls, NULL); + if (netIFArr == NULL) { + return NULL; + } + + /* + * Iterate through the interfaces, create a NetworkInterface instance + * for each array element and populate the object. + */ + curr = ifList; + arr_index = 0; + while (curr != NULL) { + jobject netifObj; + + netifObj = createNetworkInterface(env, curr, -1, NULL); + if (netifObj == NULL) { + return NULL; + } + + /* put the NetworkInterface into the array */ + (*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj); + + curr = curr->next; + } + + /* release the interface list */ + free_netif(ifList); + + return netIFArr; +} + +/* + * Class: java_net_NetworkInterface + * Method: isUp0 + * Signature: (Ljava/lang/String;)Z + */ +JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0 + (JNIEnv *env, jclass cls, jstring name, jint index) { + jboolean ret = JNI_FALSE; + + // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack + if (ipv6_available()) { + return Java_java_net_NetworkInterface_isUp0_XP(env, cls, name, index); + } else { + MIB_IFROW *ifRowP; + ifRowP = getIF(index); + if (ifRowP != NULL) { + ret = ifRowP->dwAdminStatus == MIB_IF_ADMIN_STATUS_UP && + (ifRowP->dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL || + ifRowP->dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED); + free(ifRowP); + } + } + return ret; +} + +/* + * Class: java_net_NetworkInterface + * Method: isP2P0 + * Signature: (Ljava/lang/String;I)Z + */ +JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0 + (JNIEnv *env, jclass cls, jstring name, jint index) { + MIB_IFROW *ifRowP; + jboolean ret = JNI_FALSE; + + // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack + if (ipv6_available()) { + return Java_java_net_NetworkInterface_isP2P0_XP(env, cls, name, index); + } else { + ifRowP = getIF(index); + if (ifRowP != NULL) { + switch(ifRowP->dwType) { + case MIB_IF_TYPE_PPP: + case MIB_IF_TYPE_SLIP: + ret = JNI_TRUE; + break; + } + free(ifRowP); + } + } + return ret; +} + +/* + * Class: java_net_NetworkInterface + * Method: isLoopback0 + * Signature: (Ljava/lang/String;I)Z + */ +JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0 + (JNIEnv *env, jclass cls, jstring name, jint index) { + MIB_IFROW *ifRowP; + jboolean ret = JNI_FALSE; + + // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack + if (ipv6_available()) { + return Java_java_net_NetworkInterface_isLoopback0_XP(env, cls, name, index); + } else { + ifRowP = getIF(index); + if (ifRowP != NULL) { + if (ifRowP->dwType == MIB_IF_TYPE_LOOPBACK) + ret = JNI_TRUE; + free(ifRowP); + } + return ret; + } +} + +/* + * Class: java_net_NetworkInterface + * Method: supportsMulticast0 + * Signature: (Ljava/lang/String;I)Z + */ +JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0 + (JNIEnv *env, jclass cls, jstring name, jint index) { + return Java_java_net_NetworkInterface_supportsMulticast0_XP(env, cls, + name, index); +} + +/* + * Class: java_net_NetworkInterface + * Method: getMacAddr0 + * Signature: ([bLjava/lang/String;I)[b + */ +JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0 + (JNIEnv *env, jclass class, jbyteArray addrArray, jstring name, jint index) { + jbyteArray ret = NULL; + int len; + MIB_IFROW *ifRowP; + + // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack + if (ipv6_available()) { + return Java_java_net_NetworkInterface_getMacAddr0_XP(env, class, name, index); + } else { + ifRowP = getIF(index); + if (ifRowP != NULL) { + switch(ifRowP->dwType) { + case MIB_IF_TYPE_ETHERNET: + case MIB_IF_TYPE_TOKENRING: + case MIB_IF_TYPE_FDDI: + case IF_TYPE_IEEE80211: + len = ifRowP->dwPhysAddrLen; + if (len > 0) { + ret = (*env)->NewByteArray(env, len); + if (!IS_NULL(ret)) { + (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) ifRowP->bPhysAddr); + } + } + break; + } + free(ifRowP); + } + return ret; + } +} + +/* + * Class: java_net_NetworkInterface + * Method: getMTU0 + * Signature: ([bLjava/lang/String;I)I + */ +JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0 + (JNIEnv *env, jclass class, jstring name, jint index) { + jint ret = -1; + MIB_IFROW *ifRowP; + + // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack + if (ipv6_available()) { + return Java_java_net_NetworkInterface_getMTU0_XP(env, class, name, index); + } else { + ifRowP = getIF(index); + if (ifRowP != NULL) { + ret = ifRowP->dwMtu; + free(ifRowP); + } + return ret; + } +}