From 35a2969057ce2d8673d6c338e1daa7e84935c591 Mon Sep 17 00:00:00 2001 From: Rich DiCroce Date: Wed, 15 Mar 2023 17:06:32 +0000 Subject: [PATCH] 8302659: Modernize Windows native code for NetworkInterface Reviewed-by: ihse, djelinski, alanb, michaelm --- make/modules/java.base/Lib.gmk | 2 - .../windows/native/libnet/NetworkInterface.c | 1586 ++++++----------- .../windows/native/libnet/NetworkInterface.h | 55 +- .../native/libnet/NetworkInterface_winXP.c | 1010 ----------- .../native/libnet/ResolverConfigurationImpl.c | 77 +- .../java/net/SocketOption/OptionsTest.java | 4 +- 6 files changed, 654 insertions(+), 2080 deletions(-) delete mode 100644 src/java.base/windows/native/libnet/NetworkInterface_winXP.c diff --git a/make/modules/java.base/Lib.gmk b/make/modules/java.base/Lib.gmk index 3b782577258..93c0a361671 100644 --- a/make/modules/java.base/Lib.gmk +++ b/make/modules/java.base/Lib.gmk @@ -47,8 +47,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBNET, \ DISABLED_WARNINGS_gcc_NetworkInterface.c := unused-function, \ DISABLED_WARNINGS_clang_net_util_md.c := format-nonliteral, \ DISABLED_WARNINGS_microsoft_InetAddress.c := 4244, \ - DISABLED_WARNINGS_microsoft_NetworkInterface.c := 4133, \ - DISABLED_WARNINGS_microsoft_NetworkInterface_winXP.c := 4133, \ DISABLED_WARNINGS_microsoft_ResolverConfigurationImpl.c := 4996, \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ diff --git a/src/java.base/windows/native/libnet/NetworkInterface.c b/src/java.base/windows/native/libnet/NetworkInterface.c index 2be655b13bf..838921567c3 100644 --- a/src/java.base/windows/native/libnet/NetworkInterface.c +++ b/src/java.base/windows/native/libnet/NetworkInterface.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, 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 @@ -32,21 +32,11 @@ * 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. */ +#define NDIS_IF_MAX_BUFFER_SIZE NDIS_IF_MAX_STRING_SIZE + 1 +#define NO_PREFIX 255 + /* various JNI ids */ jclass ni_class; /* NetworkInterface */ @@ -67,483 +57,625 @@ jfieldID ni_ibbroadcastID; /* InterfaceAddress.broadcast */ jfieldID ni_ibmaskID; /* InterfaceAddress.maskLength */ /* - * Support routines to free netif and netaddr lists + * Gets the unicast and anycast IP address tables. + * If an error occurs while fetching a table, + * any tables already fetched are freed and an exception is set. + * It is the caller's responsibility to free the tables when they are no longer needed. */ -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; +static BOOL getAddressTables( + JNIEnv *env, MIB_UNICASTIPADDRESS_TABLE **uniAddrs, + MIB_ANYCASTIPADDRESS_TABLE **anyAddrs) { + ULONG apiRetVal; + ADDRESS_FAMILY addrFamily = ipv6_available() ? AF_UNSPEC : AF_INET; + + apiRetVal = GetUnicastIpAddressTable(addrFamily, uniAddrs); + if (apiRetVal != NO_ERROR) { + SetLastError(apiRetVal); + NET_ThrowByNameWithLastError( + env, JNU_JAVANETPKG "SocketException", "GetUnicastIpAddressTable"); + return FALSE; } + apiRetVal = GetAnycastIpAddressTable(addrFamily, anyAddrs); + if (apiRetVal != NO_ERROR) { + FreeMibTable(*uniAddrs); + SetLastError(apiRetVal); + NET_ThrowByNameWithLastError( + env, JNU_JAVANETPKG "SocketException", "GetAnycastIpAddressTable"); + return FALSE; + } + return TRUE; } -void free_netaddr(netaddr *netaddrP) { +/* + * Frees a linked list of netaddr structs. + */ +static void freeNetaddrs(netaddr *netaddrP) { netaddr *curr = netaddrP; while (curr != NULL) { - netaddrP = netaddrP->next; + netaddrP = netaddrP->Next; free(curr); curr = netaddrP; } } /* - * Returns the interface structure from the table with the matching index. + * Builds and returns a java.net.NetworkInterface object from the given MIB_IF_ROW2. + * Unlike createNetworkInterfaceForSingleRowWithTables, + * this expects that the row is already populated, either by GetIfEntry2 or GetIfTable2. + * If anything goes wrong, an exception will be set, + * but the address tables are not freed. + * Freeing the address tables is always the caller's responsibility. */ -MIB_IFROW *getIF(jint index) { - MIB_IFTABLE *tableP; - MIB_IFROW *ifrowP, *ret = NULL; - ULONG size; - DWORD i, count; - jint ifindex; +static jobject createNetworkInterface( + JNIEnv *env, MIB_IF_ROW2 *ifRow, MIB_UNICASTIPADDRESS_TABLE *uniAddrs, + MIB_ANYCASTIPADDRESS_TABLE *anyAddrs) { + WCHAR ifName[NDIS_IF_MAX_BUFFER_SIZE]; + jobject netifObj, name, displayName, inetAddr, bcastAddr, bindAddr; + jobjectArray addrArr, bindsArr, childArr; + netaddr *addrsHead = NULL, *addrsCurrent = NULL; + int addrCount = 0; + ULONG apiRetVal, i, mask; - /* - * 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) { - 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); + // instantiate the NetworkInterface object + netifObj = (*env)->NewObject(env, ni_class, ni_ctor); + if (netifObj == NULL) { 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); + // set the NetworkInterface's name + apiRetVal = ConvertInterfaceLuidToNameW( + &(ifRow->InterfaceLuid), ifName, NDIS_IF_MAX_BUFFER_SIZE); + if (apiRetVal != ERROR_SUCCESS) { + SetLastError(apiRetVal); + NET_ThrowByNameWithLastError( + env, JNU_JAVANETPKG "SocketException", "ConvertInterfaceLuidToNameW"); + return NULL; + } + name = (*env)->NewString(env, ifName, (jsize) wcslen(ifName)); + if (name == NULL) { + return NULL; + } + (*env)->SetObjectField(env, netifObj, ni_nameID, name); + (*env)->DeleteLocalRef(env, name); + + // set the NetworkInterface's display name + displayName = (*env)->NewString( + env, ifRow->Description, (jsize) wcslen(ifRow->Description)); + if (displayName == NULL) { + return NULL; + } + (*env)->SetObjectField(env, netifObj, ni_displayNameID, displayName); + (*env)->DeleteLocalRef(env, displayName); + + // set the NetworkInterface's index + (*env)->SetIntField(env, netifObj, ni_indexID, ifRow->InterfaceIndex); + + // find addresses associated with this interface + for (i = 0; i < uniAddrs->NumEntries; i++) { + if (uniAddrs->Table[i].InterfaceLuid.Value == ifRow->InterfaceLuid.Value && + (uniAddrs->Table[i].DadState == IpDadStatePreferred || + uniAddrs->Table[i].DadState == IpDadStateDeprecated)) { + addrCount++; + addrsCurrent = malloc(sizeof(netaddr)); + if (addrsCurrent == NULL) { + freeNetaddrs(addrsHead); + JNU_ThrowOutOfMemoryError(env, "native heap"); return NULL; } - memcpy(ret, ifrowP, sizeof(MIB_IFROW)); - break; + addrsCurrent->Address = uniAddrs->Table[i].Address; + addrsCurrent->PrefixLength = uniAddrs->Table[i].OnLinkPrefixLength; + addrsCurrent->Next = addrsHead; + addrsHead = addrsCurrent; } - - /* 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; - - *netifPP = NULL; - - /* - * 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) { - 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); - switch (ret) { - case ERROR_INVALID_PARAMETER: - JNU_ThrowInternalError(env, - "IP Helper Library GetIfTable function failed: " - "invalid parameter"); - break; - default: - SetLastError(ret); - JNU_ThrowByNameWithMessageAndLastError(env, - JNU_JAVANETPKG "SocketException", - "IP Helper Library GetIfTable function failed"); - break; - } - 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+1)*sizeof(wchar_t)); - } - - 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); - free(curr); - curr = NULL; + for (i = 0; i < anyAddrs->NumEntries; i++) { + if (anyAddrs->Table[i].InterfaceLuid.Value == ifRow->InterfaceLuid.Value) { + addrCount++; + addrsCurrent = malloc(sizeof(netaddr)); + if (addrsCurrent == NULL) { + freeNetaddrs(addrsHead); + JNU_ThrowOutOfMemoryError(env, "native heap"); + return NULL; } + addrsCurrent->Address = anyAddrs->Table[i].Address; + addrsCurrent->PrefixLength = NO_PREFIX; + addrsCurrent->Next = addrsHead; + addrsHead = addrsCurrent; } - 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_ThrowInternalError(env, - "Cannot get multibyte char for interface display name"); - free_netif(netifP); - free(tableP); - free(curr->name); - free(curr->displayName); - free(curr); - return -1; - } else { - ((wchar_t *)curr->displayName)[wlen] = L'\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 != NULL) { - free(tableP); + // instantiate the addrs and bindings array + addrArr = (*env)->NewObjectArray(env, addrCount, ia_class, NULL); + if (addrArr == NULL) { + freeNetaddrs(addrsHead); + return NULL; } - *netifPP = netifP; - return count; -} - -/* - * Enumerate all addresses using the IP helper library - */ -int lookupIPAddrTable(JNIEnv *env, MIB_IPADDRTABLE **tablePP) -{ - MIB_IPADDRTABLE *tableP; - ULONG size; - DWORD ret; - - *tablePP = NULL; - - /* - * 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; + bindsArr = (*env)->NewObjectArray(env, addrCount, ni_ibcls, NULL); + if (bindsArr == NULL) { + freeNetaddrs(addrsHead); + return NULL; } - ret = GetIpAddrTable(tableP, &size, FALSE); - if (ret == ERROR_INSUFFICIENT_BUFFER) { - 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 != NULL) { - free(tableP); - } - switch (ret) { - case ERROR_INVALID_PARAMETER: - JNU_ThrowInternalError(env, - "IP Helper Library GetIpAddrTable function failed: " - "invalid parameter"); - break; - default: - SetLastError(ret); - JNU_ThrowByNameWithMessageAndLastError(env, - JNU_JAVANETPKG "SocketException", - "IP Helper Library GetIpAddrTable function failed"); - break; - } - // this different error code is to handle the case when we call - // GetIpAddrTable in pure IPv6 environment - return -2; - } - *tablePP = tableP; - return 0; -} - -/* - * Enumerate the IP addresses on an interface, given an IP address table - * and matching based on index. - * - * 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_ipaddrtable(JNIEnv *env, netif *netifP, netaddr **netaddrPP, MIB_IPADDRTABLE *tableP) -{ - DWORD i; - netaddr *netaddrP; - int count = 0; - unsigned long mask; - - *netaddrPP = NULL; - - /* - * Iterate through the table to find the addresses with the - * matching dwIndex. Ignore 0.0.0.0 addresses. - */ - if (tableP == NULL) { - return 0; - } - count = 0; - netaddrP = NULL; - + // populate the addrs and bindings arrays 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); - return -1; + while (addrsCurrent != NULL) { + if (addrsCurrent->Address.si_family == AF_INET) { // IPv4 + // create and populate InetAddress object + inetAddr = (*env)->NewObject(env, ia4_class, ia4_ctrID); + if (inetAddr == NULL) { + freeNetaddrs(addrsHead); + return NULL; + } + setInetAddress_addr( + env, inetAddr, ntohl(addrsCurrent->Address.Ipv4.sin_addr.s_addr)); + if ((*env)->ExceptionCheck(env)) { + freeNetaddrs(addrsHead); + return NULL; } - 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++; + // create and populate InterfaceAddress object + bindAddr = (*env)->NewObject(env, ni_ibcls, ni_ibctrID); + if (bindAddr == NULL) { + freeNetaddrs(addrsHead); + return NULL; + } + (*env)->SetObjectField(env, bindAddr, ni_ibaddressID, inetAddr); + if (addrsCurrent->PrefixLength != NO_PREFIX) { + (*env)->SetShortField( + env, bindAddr, ni_ibmaskID, addrsCurrent->PrefixLength); + apiRetVal = ConvertLengthToIpv4Mask(addrsCurrent->PrefixLength, &mask); + if (apiRetVal != NO_ERROR) { + freeNetaddrs(addrsHead); + SetLastError(apiRetVal); + NET_ThrowByNameWithLastError( + env, JNU_JAVANETPKG "SocketException", + "ConvertLengthToIpv4Mask"); + return NULL; } - break; - case MIB_IF_TYPE_PPP: - case MIB_IF_TYPE_SLIP: - default: - /** - * these don't have broadcast/subnet - */ - curr->mask = -1; - break; + bcastAddr = (*env)->NewObject(env, ia4_class, ia4_ctrID); + if (bcastAddr == NULL) { + freeNetaddrs(addrsHead); + return NULL; + } + setInetAddress_addr( + env, bcastAddr, + ntohl(addrsCurrent->Address.Ipv4.sin_addr.s_addr | ~mask)); + if ((*env)->ExceptionCheck(env)) { + freeNetaddrs(addrsHead); + return NULL; + } + (*env)->SetObjectField(env, bindAddr, ni_ibbroadcastID, bcastAddr); + (*env)->DeleteLocalRef(env, bcastAddr); + } + } else { // IPv6 + inetAddr = (*env)->NewObject(env, ia6_class, ia6_ctrID); + if (inetAddr == NULL) { + freeNetaddrs(addrsHead); + return NULL; + } + if (setInet6Address_ipaddress( + env, inetAddr, + (jbyte *)&(addrsCurrent->Address.Ipv6.sin6_addr.s6_addr)) + == JNI_FALSE) { + freeNetaddrs(addrsHead); + return NULL; + } + /* zero is default value, no need to set */ + if (addrsCurrent->Address.Ipv6.sin6_scope_id != 0) { + setInet6Address_scopeid( + env, inetAddr, addrsCurrent->Address.Ipv6.sin6_scope_id); + setInet6Address_scopeifname(env, inetAddr, netifObj); + } + bindAddr = (*env)->NewObject(env, ni_ibcls, ni_ibctrID); + if (bindAddr == NULL) { + freeNetaddrs(addrsHead); + return NULL; + } + (*env)->SetObjectField(env, bindAddr, ni_ibaddressID, inetAddr); + if (addrsCurrent->PrefixLength != NO_PREFIX) { + (*env)->SetShortField( + env, bindAddr, ni_ibmaskID, addrsCurrent->PrefixLength); } - - curr->next = netaddrP; - netaddrP = curr; - count++; } + + // add the new elements to the arrays + (*env)->SetObjectArrayElement(env, addrArr, i, inetAddr); + (*env)->DeleteLocalRef(env, inetAddr); + (*env)->SetObjectArrayElement(env, bindsArr, i, bindAddr); + (*env)->DeleteLocalRef(env, bindAddr); + + // advance to the next address + addrsCurrent = addrsCurrent->Next; i++; } - *netaddrPP = netaddrP; - return count; -} + // free the address list since we no longer need it + freeNetaddrs(addrsHead); + // set the addrs and bindings arrays on the NetworkInterface + (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr); + (*env)->DeleteLocalRef(env, addrArr); + (*env)->SetObjectField(env, netifObj, ni_bindsID, bindsArr); + (*env)->DeleteLocalRef(env, bindsArr); + + // set child array on the NetworkInterface + // Windows doesn't have virtual interfaces, so this is always empty + childArr = (*env)->NewObjectArray(env, 0, ni_class, NULL); + if (childArr == NULL) { + return NULL; + } + (*env)->SetObjectField(env, netifObj, ni_childsID, childArr); + (*env)->DeleteLocalRef(env, childArr); + + return netifObj; +} /* - * Enumerate the IP addresses on an interface, using an IP address table - * retrieved using GetIPAddrTable and matching based on index. - * - * 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. + * Builds and returns a java.net.NetworkInterface object from the given MIB_IF_ROW2. + * This expects that the row is not yet populated, but an index has been set, + * so the row is ready to be populated by GetIfEntry2. + * If anything goes wrong, an exception will be set, + * but the address tables are not freed. + * Freeing the address tables is always the caller's responsibility. */ -int enumAddresses_win(JNIEnv *env, netif *netifP, netaddr **netaddrPP) { - MIB_IPADDRTABLE *tableP; - int count; +static jobject createNetworkInterfaceForSingleRowWithTables( + JNIEnv *env, MIB_IF_ROW2 *ifRow, + MIB_UNICASTIPADDRESS_TABLE *uniAddrs, MIB_ANYCASTIPADDRESS_TABLE *anyAddrs) { + ULONG apiRetVal; - *netaddrPP = NULL; - - int ret = lookupIPAddrTable(env, &tableP); - if (ret < 0) { - return ret; + apiRetVal = GetIfEntry2(ifRow); + if (apiRetVal != NO_ERROR) { + if (apiRetVal != ERROR_FILE_NOT_FOUND) { + SetLastError(apiRetVal); + NET_ThrowByNameWithLastError( + env, JNU_JAVANETPKG "SocketException", "GetIfEntry2"); + } + return NULL; } - count = enumAddresses_win_ipaddrtable(env, netifP, netaddrPP, tableP); - free(tableP); - return count; + return createNetworkInterface(env, ifRow, uniAddrs, anyAddrs); } +/* + * Builds and returns a java.net.NetworkInterface object from the given MIB_IF_ROW2. + * This expects that the row is not yet populated, but an index has been set, + * so the row is ready to be populated by GetIfEntry2. + * Unlike createNetworkInterfaceForSingleRowWithTables, this will get the address + * tables at the beginning and free them at the end. + * If anything goes wrong, an exception will be set. + */ +static jobject createNetworkInterfaceForSingleRow( + JNIEnv *env, MIB_IF_ROW2 *ifRow) { + MIB_UNICASTIPADDRESS_TABLE *uniAddrs; + MIB_ANYCASTIPADDRESS_TABLE *anyAddrs; + jobject netifObj; + + if (getAddressTables(env, &uniAddrs, &anyAddrs) == FALSE) { + return NULL; + } + + netifObj = createNetworkInterfaceForSingleRowWithTables( + env, ifRow, uniAddrs, anyAddrs); + + FreeMibTable(uniAddrs); + FreeMibTable(anyAddrs); + + return netifObj; +} + +/* + * Class: NetworkInterface + * Method: getByIndex0 + * Signature: (I)LNetworkInterface; + */ +JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0( + JNIEnv *env, jclass cls, jint index) { + MIB_IF_ROW2 ifRow = {0}; + + if (index == 0) { + // 0 is never a valid index, and would make GetIfEntry2 think nothing is set + return NULL; + } + + ifRow.InterfaceIndex = index; + return createNetworkInterfaceForSingleRow(env, &ifRow); +} + +/* + * 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) { + const jchar *nameChars; + ULONG apiRetVal; + MIB_IF_ROW2 ifRow = {0}; + + nameChars = (*env)->GetStringChars(env, name, NULL); + apiRetVal = ConvertInterfaceNameToLuidW(nameChars, &(ifRow.InterfaceLuid)); + (*env)->ReleaseStringChars(env, name, nameChars); + if (apiRetVal != ERROR_SUCCESS) { + if (apiRetVal != ERROR_INVALID_NAME) { + SetLastError(apiRetVal); + NET_ThrowByNameWithLastError( + env, JNU_JAVANETPKG "SocketException", + "ConvertInterfaceNameToLuidW"); + } + return NULL; + } + return createNetworkInterfaceForSingleRow(env, &ifRow); +} + +/* + * 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 inetAddr) { + MIB_UNICASTIPADDRESS_TABLE *uniAddrs; + MIB_ANYCASTIPADDRESS_TABLE *anyAddrs; + ULONG i; + MIB_IF_ROW2 ifRow = {0}; + jobject result = NULL; + + if (getAddressTables(env, &uniAddrs, &anyAddrs) == FALSE) { + return NULL; + } + + for (i = 0; i < uniAddrs->NumEntries; i++) { + if (NET_SockaddrEqualsInetAddress( + env, (SOCKETADDRESS*) &(uniAddrs->Table[i].Address), inetAddr) && + (uniAddrs->Table[i].DadState == IpDadStatePreferred || + uniAddrs->Table[i].DadState == IpDadStateDeprecated)) { + ifRow.InterfaceLuid = uniAddrs->Table[i].InterfaceLuid; + result = createNetworkInterfaceForSingleRowWithTables( + env, &ifRow, uniAddrs, anyAddrs); + goto done; + } + } + for (i = 0; i < anyAddrs->NumEntries; i++) { + if (NET_SockaddrEqualsInetAddress( + env, (SOCKETADDRESS*) &(anyAddrs->Table[i].Address), inetAddr)) { + ifRow.InterfaceLuid = anyAddrs->Table[i].InterfaceLuid; + result = createNetworkInterfaceForSingleRowWithTables( + env, &ifRow, uniAddrs, anyAddrs); + goto done; + } + } + + done: + FreeMibTable(uniAddrs); + FreeMibTable(anyAddrs); + return result; +} + +/* + * Class: java_net_NetworkInterface + * Method: boundInetAddress0 + * Signature: (Ljava/net/InetAddress;)Z + */ +JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_boundInetAddress0( + JNIEnv *env, jclass cls, jobject inetAddr) { + MIB_UNICASTIPADDRESS_TABLE *uniAddrs; + MIB_ANYCASTIPADDRESS_TABLE *anyAddrs; + ULONG i; + jboolean result = JNI_FALSE; + + if (getAddressTables(env, &uniAddrs, &anyAddrs) == FALSE) { + return JNI_FALSE; + } + + for (i = 0; i < uniAddrs->NumEntries; i++) { + if (NET_SockaddrEqualsInetAddress( + env, (SOCKETADDRESS*) &(uniAddrs->Table[i].Address), inetAddr) && + (uniAddrs->Table[i].DadState == IpDadStatePreferred || + uniAddrs->Table[i].DadState == IpDadStateDeprecated)) { + result = JNI_TRUE; + goto done; + } + } + for (i = 0; i < anyAddrs->NumEntries; i++) { + if (NET_SockaddrEqualsInetAddress( + env, (SOCKETADDRESS*) &(anyAddrs->Table[i].Address), inetAddr)) { + result = JNI_TRUE; + goto done; + } + } + + done: + FreeMibTable(uniAddrs); + FreeMibTable(anyAddrs); + return result; +} + +/* + * Class: java_net_NetworkInterface + * Method: getAll + * Signature: ()[Ljava/net/NetworkInterface; + */ +JNIEXPORT jobjectArray JNICALL Java_java_net_NetworkInterface_getAll( + JNIEnv *env, jclass cls) { + MIB_IF_TABLE2 *ifTable; + jobjectArray ifArray; + MIB_UNICASTIPADDRESS_TABLE *uniAddrs; + MIB_ANYCASTIPADDRESS_TABLE *anyAddrs; + ULONG apiRetVal, i; + jobject ifObj; + + apiRetVal = GetIfTable2(&ifTable); + if (apiRetVal != NO_ERROR) { + SetLastError(apiRetVal); + NET_ThrowByNameWithLastError( + env, JNU_JAVANETPKG "SocketException", "GetIfTable2"); + return NULL; + } + + ifArray = (*env)->NewObjectArray(env, ifTable->NumEntries, cls, NULL); + if (ifArray == NULL) { + FreeMibTable(ifTable); + return NULL; + } + + if (getAddressTables(env, &uniAddrs, &anyAddrs) == FALSE) { + FreeMibTable(ifTable); + return NULL; + } + + for (i = 0; i < ifTable->NumEntries; i++) { + ifObj = createNetworkInterface( + env, &(ifTable->Table[i]), uniAddrs, anyAddrs); + if (ifObj == NULL) { + FreeMibTable(ifTable); + FreeMibTable(uniAddrs); + FreeMibTable(anyAddrs); + return NULL; + } + (*env)->SetObjectArrayElement(env, ifArray, i, ifObj); + (*env)->DeleteLocalRef(env, ifObj); + } + + FreeMibTable(ifTable); + FreeMibTable(uniAddrs); + FreeMibTable(anyAddrs); + return ifArray; +} + +/* + * 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) { + MIB_IF_ROW2 ifRow = {0}; + ULONG apiRetVal; + + ifRow.InterfaceIndex = index; + apiRetVal = GetIfEntry2(&ifRow); + if (apiRetVal != NO_ERROR) { + SetLastError(apiRetVal); + NET_ThrowByNameWithLastError( + env, JNU_JAVANETPKG "SocketException", "GetIfEntry2"); + return JNI_FALSE; + } + return ifRow.AdminStatus == NET_IF_ADMIN_STATUS_UP && + ifRow.OperStatus == IfOperStatusUp + ? JNI_TRUE : JNI_FALSE; +} + +/* + * 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_IF_ROW2 ifRow = {0}; + ULONG apiRetVal; + + ifRow.InterfaceIndex = index; + apiRetVal = GetIfEntry2(&ifRow); + if (apiRetVal != NO_ERROR) { + SetLastError(apiRetVal); + NET_ThrowByNameWithLastError( + env, JNU_JAVANETPKG "SocketException", "GetIfEntry2"); + return JNI_FALSE; + } + return ifRow.AccessType == NET_IF_ACCESS_POINT_TO_POINT ? JNI_TRUE : JNI_FALSE; +} + +/* + * 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_IF_ROW2 ifRow = {0}; + ULONG apiRetVal; + + ifRow.InterfaceIndex = index; + apiRetVal = GetIfEntry2(&ifRow); + if (apiRetVal != NO_ERROR) { + SetLastError(apiRetVal); + NET_ThrowByNameWithLastError( + env, JNU_JAVANETPKG "SocketException", "GetIfEntry2"); + return JNI_FALSE; + } + return ifRow.Type == IF_TYPE_SOFTWARE_LOOPBACK ? JNI_TRUE : JNI_FALSE; +} + +/* + * 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) { + MIB_IF_ROW2 ifRow = {0}; + ULONG apiRetVal; + jbyteArray macAddr; + + ifRow.InterfaceIndex = index; + apiRetVal = GetIfEntry2(&ifRow); + if (apiRetVal != NO_ERROR) { + SetLastError(apiRetVal); + NET_ThrowByNameWithLastError( + env, JNU_JAVANETPKG "SocketException", "GetIfEntry2"); + return NULL; + } + if (ifRow.PhysicalAddressLength == 0) { + return NULL; + } + macAddr = (*env)->NewByteArray(env, ifRow.PhysicalAddressLength); + if (macAddr == NULL) { + return NULL; + } + (*env)->SetByteArrayRegion( + env, macAddr, 0, ifRow.PhysicalAddressLength, + (jbyte *) ifRow.PhysicalAddress); + return macAddr; +} + +/* + * 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) { + MIB_IF_ROW2 ifRow = {0}; + ULONG apiRetVal; + + ifRow.InterfaceIndex = index; + apiRetVal = GetIfEntry2(&ifRow); + if (apiRetVal != NO_ERROR) { + SetLastError(apiRetVal); + NET_ThrowByNameWithLastError( + env, JNU_JAVANETPKG "SocketException", "GetIfEntry2"); + return -1; + } + return ifRow.Mtu; +} + +/* + * 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) { + // we assume that multicast is enabled, because there are no reliable APIs to tell us + return JNI_TRUE; +} /* * Class: java_net_NetworkInterface * Method: init * Signature: ()V */ -JNIEXPORT void JNICALL -Java_java_net_NetworkInterface_init(JNIEnv *env, jclass cls) -{ +JNIEXPORT void JNICALL Java_java_net_NetworkInterface_init(JNIEnv *env, jclass cls) { /* * Get the various JNI ids that we require */ @@ -578,577 +710,3 @@ Java_java_net_NetworkInterface_init(JNIEnv *env, jclass cls) 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 < 0) { - 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 ((*env)->ExceptionCheck(env)) { - free_netaddr(netaddrP); - return NULL; - } - 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)); - if ((*env)->ExceptionCheck(env)) { - free_netaddr(netaddrP); - return NULL; - } - (*env)->SetObjectField(env, ibObj, ni_ibbroadcastID, ia2Obj); - (*env)->DeleteLocalRef(env, ia2Obj); - (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask); - (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj); - (*env)->DeleteLocalRef(env, 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) { - free_netaddr(netaddrP); - 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)->DeleteLocalRef(env, ibObj); - } - } - (*env)->SetObjectArrayElement(env, addrArr, addr_index, iaObj); - (*env)->DeleteLocalRef(env, iaObj); - addrs = addrs->next; - addr_index++; - } - (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr); - (*env)->SetObjectField(env, netifObj, ni_bindsID, bindsArr); - - free_netaddr(netaddrP); - (*env)->DeleteLocalRef(env, name); - (*env)->DeleteLocalRef(env, displayName); - (*env)->DeleteLocalRef(env, addrArr); - (*env)->DeleteLocalRef(env, bindsArr); - - /* - * 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); - (*env)->DeleteLocalRef(env, 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: boundInetAddress0 - * Signature: (Ljava/net/InetAddress;)Z - */ -JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_boundInetAddress0 - (JNIEnv *env, jclass cls, jobject iaObj) -{ - DWORD i; - - int family = getInetAddress_family(env, iaObj); - JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE); - - if (family == java_net_InetAddress_IPv6) { - if (!ipv6_available()) - return JNI_FALSE; - return Java_java_net_NetworkInterface_getByInetAddress0_XP(env, cls, iaObj) != NULL; - } else if (family == java_net_InetAddress_IPv4) { - jint addr = getInetAddress_addr(env, iaObj); - JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE); - - jboolean found = JNI_FALSE; - MIB_IPADDRTABLE *tableP; - if (lookupIPAddrTable(env, &tableP) >= 0 && tableP != NULL) { - for (i = 0; i < tableP->dwNumEntries; i++) { - if (tableP->table[i].dwAddr != 0 && - (unsigned long)addr == ntohl(tableP->table[i].dwAddr)) { - found = JNI_TRUE; - break; - } - } - free(tableP); - } - return found; - } else { - // Unknown address family - return JNI_FALSE; - } -} - -/* - * 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; - MIB_IPADDRTABLE *tableP; - jobject netifObj = NULL; - jint addr = getInetAddress_addr(env, iaObj); - JNU_CHECK_EXCEPTION_RETURN(env, NULL); - - 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. - */ - tableP = NULL; - if (lookupIPAddrTable(env, &tableP) >= 0) { - curr = ifList; - while (curr != NULL) { - int count; - netaddr *addrList; - netaddr *addrP; - - /* enumerate the addresses on this interface */ - count = enumAddresses_win_ipaddrtable(env, curr, &addrList, tableP); - if (count < 0) { - free_netif(ifList); - free(tableP); - 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; - } else { - free_netaddr(addrList); - } - - /* on next interface */ - curr = curr->next; - } - /* release the IP address table */ - free(tableP); - } - - /* 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) { - free_netif(ifList); - 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) { - free_netif(ifList); - return NULL; - } - - /* put the NetworkInterface into the array */ - (*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj); - (*env)->DeleteLocalRef(env, 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; - } -} diff --git a/src/java.base/windows/native/libnet/NetworkInterface.h b/src/java.base/windows/native/libnet/NetworkInterface.h index 9a95d77cecd..523aa1ce71d 100644 --- a/src/java.base/windows/native/libnet/NetworkInterface.h +++ b/src/java.base/windows/native/libnet/NetworkInterface.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2023, 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 @@ -31,55 +31,10 @@ /* * Structures used when enumerating interfaces and addresses */ -typedef struct _netaddr { - SOCKETADDRESS addr; /* IPv4 or IPv6 address */ - SOCKETADDRESS brdcast; - short mask; - struct _netaddr *next; +typedef struct _netaddr { + SOCKADDR_INET Address; + UINT8 PrefixLength; + struct _netaddr *Next; } netaddr; -typedef struct _netif { - char *name; - char *displayName; - DWORD dwIndex; /* Internal index */ - DWORD ifType; /* Interface type */ - int index; /* Friendly index */ - struct _netif *next; - - /* Following fields used on Windows XP when IPv6 is used only */ - jboolean hasIpv6Address; /* true when following fields valid */ - jboolean dNameIsUnicode; /* Display Name is Unicode */ - int naddrs; /* Number of addrs */ - DWORD ipv6Index; - struct _netaddr *addrs; /* addr list for interfaces */ -} netif; - -extern void free_netif(netif *netifP); -extern void free_netaddr(netaddr *netaddrP); - -/* various JNI ids */ -extern jclass ni_class; /* NetworkInterface */ - -extern jmethodID ni_ctor; /* NetworkInterface() */ - -extern jfieldID ni_indexID; /* NetworkInterface.index */ -extern jfieldID ni_addrsID; /* NetworkInterface.addrs */ -extern jfieldID ni_bindsID; /* NetworkInterface.bindings */ -extern jfieldID ni_nameID; /* NetworkInterface.name */ -extern jfieldID ni_displayNameID; /* NetworkInterface.displayName */ -extern jfieldID ni_childsID; /* NetworkInterface.childs */ - -extern jclass ni_ibcls; /* InterfaceAddress */ -extern jmethodID ni_ibctrID; /* InterfaceAddress() */ -extern jfieldID ni_ibaddressID; /* InterfaceAddress.address */ -extern jfieldID ni_ibbroadcastID; /* InterfaceAddress.broadcast */ -extern jfieldID ni_ibmaskID; /* InterfaceAddress.maskLength */ - -int enumInterfaces(JNIEnv *env, netif **netifPP); - -// Windows Visa (and later) only..... -#ifndef IF_TYPE_IEEE80211 -#define IF_TYPE_IEEE80211 71 -#endif - #endif diff --git a/src/java.base/windows/native/libnet/NetworkInterface_winXP.c b/src/java.base/windows/native/libnet/NetworkInterface_winXP.c deleted file mode 100644 index 7ec12cf2996..00000000000 --- a/src/java.base/windows/native/libnet/NetworkInterface_winXP.c +++ /dev/null @@ -1,1010 +0,0 @@ -/* - * Copyright (c) 2003, 2022, 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. - */ - -extern int enumAddresses_win_ipaddrtable(JNIEnv *env, netif *netifP, netaddr **netaddrPP, MIB_IPADDRTABLE *tableP); -extern int enumAddresses_win(JNIEnv *env, netif *netifP, netaddr **netaddrPP); -extern int lookupIPAddrTable(JNIEnv *env, MIB_IPADDRTABLE **tablePP); -int getAddrsFromAdapter(IP_ADAPTER_ADDRESSES *ptr, netaddr **netaddrPP); - -#ifdef DEBUG -void printnif (netif *nif) { -#ifdef _WIN64 - printf ("nif:0x%I64x name:%s\n", (UINT_PTR)nif, nif->name); -#else - printf ("nif:0x%x name:%s\n", (UINT_PTR)nif, nif->name); -#endif - if (nif->dNameIsUnicode) { - printf ("dName:%S index:%d ", (unsigned short *)nif->displayName, - nif->index); - } else { - printf ("dName:%s index:%d ", nif->displayName, nif->index); - } - printf ("naddrs:%d\n", nif->naddrs); -} - -void printnifs (netif *netifPP, char *str) { - netif *nif; - printf ("%s\n", str); - for (nif=netifPP; nif!=NULL; nif=nif->next) { - printnif (nif); - } - printf("-----------------\n"); -} - -#endif - -const ULONG BUFF_SIZE = 15360; -const int MAX_TRIES = 3; - -/* - * return an array of IP_ADAPTER_ADDRESSES containing one element - * for each adapter on the system. Returned in *adapters. - * Buffer is malloc'd and must be freed (unless error returned) - */ -int getAdapters (JNIEnv *env, int flags, IP_ADAPTER_ADDRESSES **adapters) { - DWORD ret; - IP_ADAPTER_ADDRESSES *adapterInfo; - ULONG len; - int try; - - *adapters = NULL; - - adapterInfo = (IP_ADAPTER_ADDRESSES *) malloc(BUFF_SIZE); - if (adapterInfo == NULL) { - JNU_ThrowByName(env, "java/lang/OutOfMemoryError", - "Native heap allocation failure"); - return -1; - } - - len = BUFF_SIZE; - ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapterInfo, &len); - - for (try = 0; ret == ERROR_BUFFER_OVERFLOW && try < MAX_TRIES; ++try) { - IP_ADAPTER_ADDRESSES * newAdapterInfo = NULL; - if (len < (ULONG_MAX - BUFF_SIZE)) { - len += BUFF_SIZE; - } - newAdapterInfo = - (IP_ADAPTER_ADDRESSES *) realloc (adapterInfo, len); - if (newAdapterInfo == NULL) { - free(adapterInfo); - JNU_ThrowByName(env, "java/lang/OutOfMemoryError", - "Native heap allocation failure"); - return -1; - } - - adapterInfo = newAdapterInfo; - - ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapterInfo, &len); - } - - if (ret != ERROR_SUCCESS) { - free (adapterInfo); - switch (ret) { - case ERROR_INVALID_PARAMETER: - JNU_ThrowInternalError(env, - "IP Helper Library GetAdaptersAddresses function failed: " - "invalid parameter"); - break; - case ERROR_NOT_ENOUGH_MEMORY: - JNU_ThrowOutOfMemoryError(env, - "IP Helper Library GetAdaptersAddresses function failed: " - "not enough memory"); - break; - case ERROR_NO_DATA: - // not an error - *adapters = NULL; - return ERROR_SUCCESS; - default: - SetLastError(ret); - JNU_ThrowByNameWithMessageAndLastError(env, - JNU_JAVANETPKG "SocketException", - "IP Helper Library GetAdaptersAddresses function failed"); - break; - } - - return -1; - } - *adapters = adapterInfo; - return ERROR_SUCCESS; -} - -/* - * return an array of IP_ADAPTER_ADDRESSES containing one element - * for each adapter on the system. Returned in *adapters. - * Buffer is malloc'd and must be freed (unless error returned) - */ -IP_ADAPTER_ADDRESSES *getAdapter (JNIEnv *env, jint index) { - DWORD flags, val; - IP_ADAPTER_ADDRESSES *adapterInfo, *ptr, *ret; - ULONG len; - int try; - adapterInfo = (IP_ADAPTER_ADDRESSES *) malloc(BUFF_SIZE); - if (adapterInfo == NULL) { - JNU_ThrowByName(env, "java/lang/OutOfMemoryError", - "Native heap allocation failure"); - return NULL; - } - len = BUFF_SIZE; - flags = GAA_FLAG_SKIP_DNS_SERVER; - flags |= GAA_FLAG_SKIP_MULTICAST; - flags |= GAA_FLAG_INCLUDE_PREFIX; - val = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapterInfo, &len); - for (try = 0; val == ERROR_BUFFER_OVERFLOW && try < MAX_TRIES; ++try) { - IP_ADAPTER_ADDRESSES * newAdapterInfo = NULL; - if (len < (ULONG_MAX - BUFF_SIZE)) { - len += BUFF_SIZE; - } - newAdapterInfo = - (IP_ADAPTER_ADDRESSES *) realloc (adapterInfo, len); - if (newAdapterInfo == NULL) { - free(adapterInfo); - JNU_ThrowByName(env, "java/lang/OutOfMemoryError", - "Native heap allocation failure"); - return NULL; - } - - adapterInfo = newAdapterInfo; - - val = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapterInfo, &len); - } - - if (val != ERROR_SUCCESS) { - free (adapterInfo); - switch (val) { - case ERROR_INVALID_PARAMETER: - JNU_ThrowInternalError(env, - "IP Helper Library GetAdaptersAddresses function failed: " - "invalid parameter"); - break; - case ERROR_NOT_ENOUGH_MEMORY: - JNU_ThrowOutOfMemoryError(env, - "IP Helper Library GetAdaptersAddresses function failed: " - "not enough memory"); - break; - case ERROR_NO_DATA: - // not an error - break; - default: - SetLastError(val); - JNU_ThrowByNameWithMessageAndLastError(env, - JNU_JAVANETPKG "SocketException", - "IP Helper Library GetAdaptersAddresses function failed"); - break; - } - return NULL; - } - - ptr = adapterInfo; - ret = NULL; - while (ptr != NULL) { - // in theory the IPv4 index and the IPv6 index can be the same - // where an interface is enabled for v4 and v6 - // IfIndex == 0 IPv4 not available on this interface - // Ipv6IfIndex == 0 IPv6 not available on this interface - if (((ptr->IfIndex != 0)&&(ptr->IfIndex == index)) || - ((ptr->Ipv6IfIndex !=0) && (ptr->Ipv6IfIndex == index))) { - ret = (IP_ADAPTER_ADDRESSES *) malloc(sizeof(IP_ADAPTER_ADDRESSES)); - if (ret == NULL) { - free(adapterInfo); - JNU_ThrowByName(env, "java/lang/OutOfMemoryError", - "Native heap allocation failure"); - return NULL; - } - - //copy the memory and break out of the while loop. - memcpy(ret, ptr, sizeof(IP_ADAPTER_ADDRESSES)); - break; - - } - ptr=ptr->Next; - } - free(adapterInfo); - return ret; -} - -/* - */ -int getAllInterfacesAndAddresses (JNIEnv *env, netif **netifPP) -{ - int ret, flags; - MIB_IPADDRTABLE *tableP; - IP_ADAPTER_ADDRESSES *ptr, *adapters=NULL; - ULONG count=0; - netif *nif=NULL, *dup_nif, *last=NULL, *loopif=NULL, *curr; - int tun=0, net=0; - - /* - * Get the IPv4 interfaces. This information is the same - * as what previous JDK versions would return. - */ - - ret = enumInterfaces(env, netifPP); - if (ret < 0) { - return -1; - } else { - count = ret; - } - - /* locate the loopback (and the last) interface */ - for (nif=*netifPP, last=nif; nif!=NULL; nif=nif->next) { - if (nif->ifType == MIB_IF_TYPE_LOOPBACK) { - loopif = nif; - } - last = nif; - } - - // Retrieve IPv4 addresses with the IP Helper API - curr = *netifPP; - ret = lookupIPAddrTable(env, &tableP); - if (ret == -1) { - free_netif(*netifPP); - return -1; - } else if (ret == -2) { - // Clear the exception and continue. - if ((*env)->ExceptionCheck(env)) { - (*env)->ExceptionClear(env); - } - tableP = NULL; - } - while (curr != NULL) { - netaddr *netaddrP; - ret = enumAddresses_win_ipaddrtable(env, curr, &netaddrP, tableP); - if (ret < 0) { - free_netif(*netifPP); - free(tableP); - return -1; - } else{ - curr->addrs = netaddrP; - curr->naddrs += ret; - curr = curr->next; - } - } - free(tableP); - - flags = GAA_FLAG_SKIP_DNS_SERVER; - flags |= GAA_FLAG_SKIP_MULTICAST; - flags |= GAA_FLAG_INCLUDE_PREFIX; - ret = getAdapters (env, flags, &adapters); - if (ret != ERROR_SUCCESS) { - free_netif(*netifPP); - return -1; - } - - /* Now get the IPv6 information. This includes: - * (a) IPv6 information associated with interfaces already found - * (b) IPv6 information for IPv6 only interfaces (probably tunnels) - * - * For compatibility with previous releases we use the naming - * information gotten from enumInterfaces() for (a) entries - * However, the index numbers are taken from the new API. - * - * The procedure is to go through the list of adapters returned - * by the new API looking for entries that correspond to IPv4 interfaces - * already found. - */ - - ptr = adapters; - while (ptr != NULL) { - int c; - netif *nif0; - if (ptr->IfType == IF_TYPE_SOFTWARE_LOOPBACK && (loopif != NULL)) { - c = getAddrsFromAdapter(ptr, &loopif->addrs); - if (c == -1) { - goto err; - } - loopif->naddrs += c; - loopif->ipv6Index = ptr->Ipv6IfIndex; - } else { - int index = ptr->IfIndex; - if (index != 0) { - /* This entry is associated with an IPv4 interface */ - for (nif=*netifPP; nif!=NULL; nif=nif->next) { - if (nif->index == index) { - /* found the interface entry - * set the index to the IPv6 index and add the - * IPv6 addresses - */ - nif->ipv6Index = ptr->Ipv6IfIndex; - c = getAddrsFromAdapter(ptr, &nif->addrs); - if (c == -1) { - goto err; - } - nif->naddrs += c; - break; - } - } - } else { - /* This entry is IPv6 only */ - char newname [128]; - int c; - - /* Windows allocates duplicate adapter entries - * for tunnel interfaces when there are multiple - * physical adapters. Need to check - * if this is a duplicate (ipv6Index is the same) - */ - dup_nif = 0; - for (nif0=*netifPP; nif0!=NULL; nif0=nif0->next) { - if (nif0->hasIpv6Address && - ptr->Ipv6IfIndex == nif0->ipv6Index) { - dup_nif = nif0; - break; - } - } - if (dup_nif == 0) { - /* new interface */ - nif = (netif *) calloc (1, sizeof(netif)); - if (nif == 0) { - goto err; - } - if (ptr->IfType == IF_TYPE_TUNNEL) { - sprintf (newname, "tun%d", tun); - tun ++; - } else { - sprintf (newname, "net%d", net); - net ++; - } - nif->name = malloc (strlen(newname)+1); - nif->displayName = malloc (wcslen(ptr->FriendlyName)*2+2); - if (nif->name == 0 || nif->displayName == 0) { - free(nif); - goto err; - } - strcpy (nif->name, newname); - wcscpy ((PWCHAR)nif->displayName, ptr->FriendlyName); - nif->dNameIsUnicode = TRUE; - - // the java.net.NetworkInterface abstraction only has index - // so the Ipv6IfIndex needs to map onto index - nif->index = ptr->Ipv6IfIndex; - nif->ipv6Index = ptr->Ipv6IfIndex; - nif->hasIpv6Address = TRUE; - - if (last) { - last->next = nif; - } else { - *netifPP = nif; - } - last = nif; - count++; - c = getAddrsFromAdapter(ptr, &nif->addrs); - if (c == -1) { - goto err; - } - nif->naddrs += c; - } else { - /* add the addresses from this adapter to the - * original (dup_nif) - */ - c = getAddrsFromAdapter(ptr, &dup_nif->addrs); - if (c == -1) { - goto err; - } - dup_nif->naddrs += c; - } - } - } - ptr=ptr->Next; - } - - free (adapters); - return count; - -err: - if (*netifPP) { - free_netif (*netifPP); - } - if (adapters) { - free (adapters); - } - return -1; -} - -/* If *netaddrPP is null, then the addresses are allocated and the beginning - * of the allocated chain is returned in *netaddrPP. - * If *netaddrPP is not null, then the addresses allocated here are appended - * to the existing chain. - * - * Returns count of addresses or -1 on error. - */ - -static int getAddrsFromAdapter(IP_ADAPTER_ADDRESSES *ptr, netaddr **netaddrPP) { - LPSOCKADDR sock; - int count = 0; - netaddr *curr, *start = NULL, *prev = NULL; - PIP_ADAPTER_UNICAST_ADDRESS uni_addr; - PIP_ADAPTER_ANYCAST_ADDRESS any_addr; - PIP_ADAPTER_PREFIX prefix; - - /* If chain passed in, find end */ - if (*netaddrPP != NULL) { - for (start=*netaddrPP; start->next!=NULL; start=start->next) - ; - - prev=start; - } - - prefix = ptr->FirstPrefix; - /* Unicast */ - uni_addr = ptr->FirstUnicastAddress; - while (uni_addr != NULL) { - /* address is only usable if dad state is preferred or deprecated */ - if (uni_addr->DadState == IpDadStateDeprecated || - uni_addr->DadState == IpDadStatePreferred) { - sock = uni_addr->Address.lpSockaddr; - - // IPv4 addresses already retrieved with enumAddresses_win - if (sock->sa_family == AF_INET) { - uni_addr = uni_addr->Next; - continue; - } - - curr = (netaddr *)calloc (1, sizeof (netaddr)); - - if (curr == NULL) - goto freeAllocatedMemory; - - if (start == NULL) - start = curr; - - if (prev != NULL) - prev->next = curr; - - prev = curr; - SOCKETADDRESS_COPY (&curr->addr, sock); - if (prefix != NULL) { - curr->mask = (short)prefix->PrefixLength; - prefix = prefix->Next; - } - count ++; - } - uni_addr = uni_addr->Next; - } - /* Anycast */ - any_addr = ptr->FirstAnycastAddress; - while (any_addr != NULL) { - curr = (netaddr *)calloc (1, sizeof (netaddr)); - - if (curr == NULL) - goto freeAllocatedMemory; - - if (start == NULL) - start = curr; - - if (prev != NULL) - prev->next = curr; - - prev = curr; - sock = any_addr->Address.lpSockaddr; - SOCKETADDRESS_COPY (&curr->addr, sock); - count ++; - any_addr = any_addr->Next; - } - if (*netaddrPP == NULL) { - *netaddrPP = start; - } - return count; - -freeAllocatedMemory: - - if (*netaddrPP != NULL) { - //N.B. the variable "start" cannot be NULL at this point because we started with an - //existing list. - curr=start->next; - start->next = NULL; - start = curr; - } - // otherwise, "start" points to the beginning of an incomplete list that we must deallocate. - - while (start != NULL) { - curr = start->next; - free(start); - start = curr; - } - - return -1; -} - -/* - * Create a NetworkInterface object, populate the name and index, and - * populate the InetAddress array based on the IP addresses for this - * interface. - */ -static jobject createNetworkInterfaceXP(JNIEnv *env, netif *ifs) -{ - jobject netifObj; - jobject name, displayName; - jobjectArray addrArr, bindsArr, childArr; - netaddr *addrs; - jint addr_index; - int netaddrCount = ifs->naddrs; - netaddr *netaddrP = ifs->addrs; - netaddr *netaddrPToFree = NULL; - jint bind_index; - - /* - * Create a NetworkInterface object and populate it - */ - netifObj = (*env)->NewObject(env, ni_class, ni_ctor); - if (netifObj == NULL) { - return NULL; - } - name = (*env)->NewStringUTF(env, ifs->name); - if (name == NULL) { - return NULL; - } - if (ifs->dNameIsUnicode) { - displayName = (*env)->NewString(env, (PWCHAR)ifs->displayName, - (jsize)wcslen ((PWCHAR)ifs->displayName)); - } else { - displayName = (*env)->NewStringUTF(env, ifs->displayName); - } - if (displayName == NULL) { - return NULL; - } - (*env)->SetObjectField(env, netifObj, ni_nameID, name); - (*env)->DeleteLocalRef(env, name); - (*env)->SetObjectField(env, netifObj, ni_displayNameID, displayName); - (*env)->DeleteLocalRef(env, 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, &netaddrPToFree); - if (netaddrCount == -1) { - return NULL; - } - if (netaddrCount == -2) { - // Clear the exception and continue. - if ((*env)->ExceptionCheck(env)) { - (*env)->ExceptionClear(env); - } - netaddrCount = 0; - netaddrPToFree = NULL; - } - netaddrP = netaddrPToFree; - } - - addrArr = (*env)->NewObjectArray(env, netaddrCount, ia_class, NULL); - if (addrArr == NULL) { - free_netaddr(netaddrPToFree); - return NULL; - } - - bindsArr = (*env)->NewObjectArray(env, netaddrCount, ni_ibcls, NULL); - if (bindsArr == NULL) { - free_netaddr(netaddrPToFree); - 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(netaddrPToFree); - return NULL; - } - /* default ctor will set family to AF_INET */ - - setInetAddress_addr(env, iaObj, ntohl(addrs->addr.sa4.sin_addr.s_addr)); - if ((*env)->ExceptionCheck(env)) { - free_netaddr(netaddrPToFree); - return NULL; - } - ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID); - if (ibObj == NULL) { - free_netaddr(netaddrPToFree); - return NULL; - } - (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj); - ia2Obj = (*env)->NewObject(env, ia4_class, ia4_ctrID); - if (ia2Obj == NULL) { - free_netaddr(netaddrPToFree); - return NULL; - } - setInetAddress_addr(env, ia2Obj, ntohl(addrs->brdcast.sa4.sin_addr.s_addr)); - if ((*env)->ExceptionCheck(env)) { - free_netaddr(netaddrPToFree); - return NULL; - } - (*env)->SetObjectField(env, ibObj, ni_ibbroadcastID, ia2Obj); - (*env)->DeleteLocalRef(env, ia2Obj); - (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask); - (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj); - (*env)->DeleteLocalRef(env, ibObj); - } else /* AF_INET6 */ { - int scope; - jboolean ret; - iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID); - if (iaObj == NULL) { - free_netaddr(netaddrPToFree); - return NULL; - } - ret = setInet6Address_ipaddress(env, iaObj, (jbyte *)&(addrs->addr.sa6.sin6_addr.s6_addr)); - if (ret == JNI_FALSE) { - free_netaddr(netaddrPToFree); - 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(netaddrPToFree); - 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)->DeleteLocalRef(env, ibObj); - } - (*env)->SetObjectArrayElement(env, addrArr, addr_index, iaObj); - (*env)->DeleteLocalRef(env, iaObj); - addrs = addrs->next; - addr_index++; - } - (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr); - (*env)->DeleteLocalRef(env, addrArr); - (*env)->SetObjectField(env, netifObj, ni_bindsID, bindsArr); - (*env)->DeleteLocalRef(env, bindsArr); - - free_netaddr(netaddrPToFree); - - /* - * 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); - (*env)->DeleteLocalRef(env, childArr); - - /* return the NetworkInterface */ - return netifObj; -} - -JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0_XP - (JNIEnv *env, jclass cls, jstring name) -{ - netif *ifList, *curr; - jboolean isCopy; - const char *name_utf; - jobject netifObj = NULL; - - if (getAllInterfacesAndAddresses (env, &ifList) < 0) { - return NULL; - } - - /* get the name as a C string */ - name_utf = (*env)->GetStringUTFChars(env, name, &isCopy); - - /* 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 = createNetworkInterfaceXP(env, curr); - } - - /* release the UTF string */ - (*env)->ReleaseStringUTFChars(env, name, name_utf); - - /* release the interface list */ - free_netif(ifList); - - return netifObj; -} - -/* - * Class: NetworkInterface - * Method: getByIndex0_XP - * Signature: (I)LNetworkInterface; - */ -JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0_XP - (JNIEnv *env, jclass cls, jint index) -{ - netif *ifList, *curr; - jobject netifObj = NULL; - - if (getAllInterfacesAndAddresses (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 = createNetworkInterfaceXP(env, curr); - } - - /* 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_XP - (JNIEnv *env, jclass cls, jobject iaObj) -{ - netif *ifList, *curr; - jobject netifObj = NULL; - - /* get the list of interfaces */ - if (getAllInterfacesAndAddresses (env, &ifList) < 0) { - return NULL; - } - - /* - * Enumerate the addresses on each interface until we find a - * matching address. - */ - curr = ifList; - while (curr != NULL) { - netaddr *addrList = curr->addrs; - netaddr *addrP; - - /* iterate through each address */ - addrP = addrList; - - while (addrP != NULL) { - if (NET_SockaddrEqualsInetAddress(env, - (struct sockaddr*)&addrP->addr, iaObj)) { - break; - } - addrP = addrP->next; - } - - /* - * Address matched so create NetworkInterface for this interface - * and address list. - */ - if (addrP != NULL) { - netifObj = createNetworkInterfaceXP(env, curr); - 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_XP - (JNIEnv *env, jclass cls) -{ - int count; - netif *ifList, *curr; - jobjectArray netIFArr; - jint arr_index; - - /* - * Get list of interfaces - */ - count = getAllInterfacesAndAddresses (env, &ifList); - if (count < 0) { - return NULL; - } - - /* allocate a NetworkInterface array */ - netIFArr = (*env)->NewObjectArray(env, count, cls, NULL); - if (netIFArr == NULL) { - free_netif(ifList); - 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 = createNetworkInterfaceXP(env, curr); - if (netifObj == NULL) { - free_netif(ifList); - return NULL; - } - - /* put the NetworkInterface into the array */ - (*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj); - (*env)->DeleteLocalRef(env, netifObj); - curr = curr->next; - } - - /* release the interface list */ - free_netif(ifList); - - return netIFArr; -} - -/* - * Class: java_net_NetworkInterface - * Method: supportsMulticast0 - * Signature: (Ljava/lang/String;I)Z - */ -JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0_XP - (JNIEnv *env, jclass cls, jstring name, jint index) { - IP_ADAPTER_ADDRESSES *ptr; - jboolean val = JNI_TRUE; - - ptr = getAdapter(env, index); - if (ptr != NULL) { - val = ptr->Flags & IP_ADAPTER_NO_MULTICAST ? JNI_FALSE : JNI_TRUE; - free(ptr); - } - return val; -} - -/* - * Class: java_net_NetworkInterface - * Method: isUp0 - * Signature: (Ljava/lang/String;I)Z - */ -JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0_XP - (JNIEnv *env, jclass cls, jstring name, jint index) { - IP_ADAPTER_ADDRESSES *ptr; - jboolean val = JNI_FALSE; - - ptr = getAdapter(env, index); - if (ptr != NULL) { - val = ptr->OperStatus == IfOperStatusUp ? JNI_TRUE : JNI_FALSE; - free(ptr); - } - return val; -} - -/* - * Class: java_net_NetworkInterface - * Method: getMacAddr0 - * Signature: (Ljava/lang/String;I)Z - */ -JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0_XP - (JNIEnv *env, jclass cls, jstring name, jint index) { - IP_ADAPTER_ADDRESSES *ptr; - jbyteArray ret = NULL; - int len; - - ptr = getAdapter(env, index); - if (ptr != NULL) { - len = ptr->PhysicalAddressLength; - if (len > 0) { - ret = (*env)->NewByteArray(env, len); - if (!IS_NULL(ret)) { - (*env)->SetByteArrayRegion(env, ret, 0, len, - (jbyte*) ptr->PhysicalAddress); - } - } - free(ptr); - } - return ret; -} - -/* - * Class: java_net_NetworkInterface - * Method: getMTU0 - * Signature: ([bLjava/lang/String;I)I - */ -JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0_XP - (JNIEnv *env, jclass cls, jstring name, jint index) { - IP_ADAPTER_ADDRESSES *ptr; - jint ret = -1; - - ptr = getAdapter(env, index); - if (ptr != NULL) { - ret = ptr->Mtu; - free(ptr); - } - return ret; -} - -/* - * Class: java_net_NetworkInterface - * Method: isLoopback0 - * Signature: (Ljava/lang/String;I)Z - */ -JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0_XP - (JNIEnv *env, jclass cls, jstring name, jint index) { - IP_ADAPTER_ADDRESSES *ptr; - jboolean val = JNI_FALSE; - - ptr = getAdapter(env, index); - if (ptr != NULL) { - val = ptr->IfType == IF_TYPE_SOFTWARE_LOOPBACK ? JNI_TRUE : JNI_FALSE; - free(ptr); - } - return val; -} - -/* - * Class: java_net_NetworkInterface - * Method: isP2P0 - * Signature: (Ljava/lang/String;I)Z - */ -JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0_XP - (JNIEnv *env, jclass cls, jstring name, jint index) { - IP_ADAPTER_ADDRESSES *ptr; - jboolean val = JNI_FALSE; - - ptr = getAdapter(env, index); - if (ptr != NULL) { - if (ptr->IfType == IF_TYPE_PPP || ptr->IfType == IF_TYPE_SLIP || - ptr->IfType == IF_TYPE_TUNNEL) { - val = JNI_TRUE; - } - free(ptr); - } - return val; -} diff --git a/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c b/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c index 03d7f1e2c54..21c472a9baa 100644 --- a/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c +++ b/src/java.base/windows/native/libnet/ResolverConfigurationImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2023, 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 @@ -33,6 +33,8 @@ #include "jni_util.h" #define MAX_STR_LEN 1024 +#define BUFF_SIZE 15360 +#define MAX_TRIES 3 #define STS_NO_CONFIG 0x0 /* no configuration found */ #define STS_SL_FOUND 0x1 /* search list found */ @@ -46,7 +48,78 @@ static jfieldID searchlistID; static jfieldID nameserversID; -extern int getAdapters(JNIEnv *env, int flags, IP_ADAPTER_ADDRESSES **adapters); +/* + * return an array of IP_ADAPTER_ADDRESSES containing one element + * for each adapter on the system. Returned in *adapters. + * Buffer is malloc'd and must be freed (unless error returned) + */ +static int getAdapters (JNIEnv *env, int flags, IP_ADAPTER_ADDRESSES **adapters) { + DWORD ret; + IP_ADAPTER_ADDRESSES *adapterInfo; + ULONG len; + int try; + + *adapters = NULL; + + adapterInfo = (IP_ADAPTER_ADDRESSES *) malloc(BUFF_SIZE); + if (adapterInfo == NULL) { + JNU_ThrowByName(env, "java/lang/OutOfMemoryError", + "Native heap allocation failure"); + return -1; + } + + len = BUFF_SIZE; + ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapterInfo, &len); + + for (try = 0; ret == ERROR_BUFFER_OVERFLOW && try < MAX_TRIES; ++try) { + IP_ADAPTER_ADDRESSES * newAdapterInfo = NULL; + if (len < (ULONG_MAX - BUFF_SIZE)) { + len += BUFF_SIZE; + } + newAdapterInfo = + (IP_ADAPTER_ADDRESSES *) realloc (adapterInfo, len); + if (newAdapterInfo == NULL) { + free(adapterInfo); + JNU_ThrowByName(env, "java/lang/OutOfMemoryError", + "Native heap allocation failure"); + return -1; + } + + adapterInfo = newAdapterInfo; + + ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapterInfo, &len); + } + + if (ret != ERROR_SUCCESS) { + free (adapterInfo); + switch (ret) { + case ERROR_INVALID_PARAMETER: + JNU_ThrowInternalError(env, + "IP Helper Library GetAdaptersAddresses function failed: " + "invalid parameter"); + break; + case ERROR_NOT_ENOUGH_MEMORY: + JNU_ThrowOutOfMemoryError(env, + "IP Helper Library GetAdaptersAddresses function failed: " + "not enough memory"); + break; + case ERROR_NO_DATA: + // not an error + *adapters = NULL; + return ERROR_SUCCESS; + default: + SetLastError(ret); + JNU_ThrowByNameWithMessageAndLastError(env, + JNU_JAVANETPKG "SocketException", + "IP Helper Library GetAdaptersAddresses function failed"); + break; + } + + return -1; + } + *adapters = adapterInfo; + return ERROR_SUCCESS; +} /* * Utility routine to append s2 to s1 with a comma delimiter. diff --git a/test/jdk/java/net/SocketOption/OptionsTest.java b/test/jdk/java/net/SocketOption/OptionsTest.java index a3b43dddba8..6ac6b1c9b1a 100644 --- a/test/jdk/java/net/SocketOption/OptionsTest.java +++ b/test/jdk/java/net/SocketOption/OptionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2023, 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 @@ -106,7 +106,7 @@ public class OptionsTest { Enumeration nifs = NetworkInterface.getNetworkInterfaces(); while (nifs.hasMoreElements()) { NetworkInterface ni = nifs.nextElement(); - if (ni.supportsMulticast()) { + if (ni.supportsMulticast() && !ni.getInterfaceAddresses().isEmpty()) { return ni; } }