| /* |
| * 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; i<tableP->dwNumEntries; 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; i<tableP->dwNumEntries; 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 (i<tableP->dwNumEntries) { |
| 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, "<init>", "()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, "<init>", "()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; |
| } |
| } |