Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/java/net/Inet4AddressImpl.c
32287 views
/*1* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <windows.h>26#include <winsock2.h>27#include <ctype.h>28#include <stdio.h>29#include <stdlib.h>30#include <malloc.h>31#include <sys/types.h>32#include <process.h>33#include <iphlpapi.h>34#include <icmpapi.h>35#include <WinError.h>3637#include "java_net_InetAddress.h"38#include "java_net_Inet4AddressImpl.h"39#include "net_util.h"40#include "icmp.h"414243/*44* Returns true if hostname is in dotted IP address format. Note that this45* function performs a syntax check only. For each octet it just checks that46* the octet is at most 3 digits.47*/48jboolean isDottedIPAddress(const char *hostname, unsigned int *addrp) {49char *c = (char *)hostname;50int octets = 0;51unsigned int cur = 0;52int digit_cnt = 0;5354while (*c) {55if (*c == '.') {56if (digit_cnt == 0) {57return JNI_FALSE;58} else {59if (octets < 4) {60addrp[octets++] = cur;61cur = 0;62digit_cnt = 0;63} else {64return JNI_FALSE;65}66}67c++;68continue;69}7071if ((*c < '0') || (*c > '9')) {72return JNI_FALSE;73}7475digit_cnt++;76if (digit_cnt > 3) {77return JNI_FALSE;78}7980/* don't check if current octet > 255 */81cur = cur*10 + (*c - '0');8283/* Move onto next character and check for EOF */84c++;85if (*c == '\0') {86if (octets < 4) {87addrp[octets++] = cur;88} else {89return JNI_FALSE;90}91}92}9394return (jboolean)(octets == 4);95}9697/*98* Inet4AddressImpl99*/100101/*102* Class: java_net_Inet4AddressImpl103* Method: getLocalHostName104* Signature: ()Ljava/lang/String;105*/106JNIEXPORT jstring JNICALL107Java_java_net_Inet4AddressImpl_getLocalHostName (JNIEnv *env, jobject this) {108char hostname[256];109110if (gethostname(hostname, sizeof hostname) == -1) {111strcpy(hostname, "localhost");112}113return JNU_NewStringPlatform(env, hostname);114}115116/*117* Find an internet address for a given hostname. Not this this118* code only works for addresses of type INET. The translation119* of %d.%d.%d.%d to an address (int) occurs in java now, so the120* String "host" shouldn't be a %d.%d.%d.%d string. The only121* exception should be when any of the %d are out of range and122* we fallback to a lookup.123*124* Class: java_net_Inet4AddressImpl125* Method: lookupAllHostAddr126* Signature: (Ljava/lang/String;)[[B127*128* This is almost shared code129*/130131JNIEXPORT jobjectArray JNICALL132Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,133jstring host) {134const char *hostname;135struct hostent *hp;136unsigned int addr[4];137138jobjectArray ret = NULL;139140initInetAddressIDs(env);141JNU_CHECK_EXCEPTION_RETURN(env, NULL);142143if (IS_NULL(host)) {144JNU_ThrowNullPointerException(env, "host argument");145return NULL;146}147hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);148CHECK_NULL_RETURN(hostname, NULL);149150/*151* The NT/2000 resolver tolerates a space in front of localhost. This152* is not consistent with other implementations of gethostbyname.153* In addition we must do a white space check on Solaris to avoid a154* bug whereby 0.0.0.0 is returned if any host name has a white space.155*/156if (isspace(hostname[0])) {157JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", hostname);158goto cleanupAndReturn;159}160161/*162* If the format is x.x.x.x then don't use gethostbyname as Windows163* is unable to handle octets which are out of range.164*/165if (isDottedIPAddress(hostname, &addr[0])) {166unsigned int address;167jobject iaObj;168169/*170* Are any of the octets out of range?171*/172if (addr[0] > 255 || addr[1] > 255 || addr[2] > 255 || addr[3] > 255) {173JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", hostname);174goto cleanupAndReturn;175}176177/*178* Return an byte array with the populated address.179*/180address = (addr[3]<<24) & 0xff000000;181address |= (addr[2]<<16) & 0xff0000;182address |= (addr[1]<<8) & 0xff00;183address |= addr[0];184185ret = (*env)->NewObjectArray(env, 1, ia_class, NULL);186187if (IS_NULL(ret)) {188goto cleanupAndReturn;189}190191iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);192if (IS_NULL(iaObj)) {193ret = NULL;194goto cleanupAndReturn;195}196setInetAddress_addr(env, iaObj, ntohl(address));197if ((*env)->ExceptionCheck(env))198goto cleanupAndReturn;199(*env)->SetObjectArrayElement(env, ret, 0, iaObj);200JNU_ReleaseStringPlatformChars(env, host, hostname);201return ret;202}203204/*205* Perform the lookup206*/207if ((hp = gethostbyname((char*)hostname)) != NULL) {208struct in_addr **addrp = (struct in_addr **) hp->h_addr_list;209int len = sizeof(struct in_addr);210int i = 0;211212while (*addrp != (struct in_addr *) 0) {213i++;214addrp++;215}216217ret = (*env)->NewObjectArray(env, i, ia_class, NULL);218219if (IS_NULL(ret)) {220goto cleanupAndReturn;221}222223addrp = (struct in_addr **) hp->h_addr_list;224i = 0;225while (*addrp != (struct in_addr *) 0) {226jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);227if (IS_NULL(iaObj)) {228ret = NULL;229goto cleanupAndReturn;230}231setInetAddress_addr(env, iaObj, ntohl((*addrp)->s_addr));232if ((*env)->ExceptionCheck(env))233goto cleanupAndReturn;234setInetAddress_hostName(env, iaObj, host);235if ((*env)->ExceptionCheck(env))236goto cleanupAndReturn;237(*env)->SetObjectArrayElement(env, ret, i, iaObj);238addrp++;239i++;240}241} else if (WSAGetLastError() == WSATRY_AGAIN) {242NET_ThrowByNameWithLastError(env,243JNU_JAVANETPKG "UnknownHostException",244hostname);245} else {246JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", hostname);247}248249cleanupAndReturn:250JNU_ReleaseStringPlatformChars(env, host, hostname);251return ret;252}253254/*255* Class: java_net_Inet4AddressImpl256* Method: getHostByAddr257* Signature: (I)Ljava/lang/String;258*/259JNIEXPORT jstring JNICALL260Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,261jbyteArray addrArray) {262struct hostent *hp;263jbyte caddr[4];264jint addr;265(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);266addr = ((caddr[0]<<24) & 0xff000000);267addr |= ((caddr[1] <<16) & 0xff0000);268addr |= ((caddr[2] <<8) & 0xff00);269addr |= (caddr[3] & 0xff);270addr = htonl(addr);271272hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);273if (hp == NULL) {274JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", 0);275return NULL;276}277if (hp->h_name == NULL) { /* Deal with bug in Windows XP */278JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", 0);279return NULL;280}281return JNU_NewStringPlatform(env, hp->h_name);282}283284285static BOOL286WindowsVersionCheck(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor) {287OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 };288DWORDLONG const dwlConditionMask = VerSetConditionMask(289VerSetConditionMask(290VerSetConditionMask(2910, VER_MAJORVERSION, VER_GREATER_EQUAL),292VER_MINORVERSION, VER_GREATER_EQUAL),293VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);294295osvi.dwMajorVersion = wMajorVersion;296osvi.dwMinorVersion = wMinorVersion;297osvi.wServicePackMajor = wServicePackMajor;298299return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;300}301302static BOOL303isVistaSP1OrGreater() {304return WindowsVersionCheck(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 1);305}306307static jboolean308tcp_ping4(JNIEnv *env,309jbyteArray addrArray,310jint timeout,311jbyteArray ifArray,312jint ttl)313{314jint addr;315jbyte caddr[4];316jint fd;317struct sockaddr_in him;318struct sockaddr_in* netif = NULL;319struct sockaddr_in inf;320int len = 0;321WSAEVENT hEvent;322int connect_rv = -1;323int sz;324325/**326* Convert IP address from byte array to integer327*/328sz = (*env)->GetArrayLength(env, addrArray);329if (sz != 4) {330return JNI_FALSE;331}332memset((char *) &him, 0, sizeof(him));333memset((char *) caddr, 0, sizeof(caddr));334(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);335addr = ((caddr[0]<<24) & 0xff000000);336addr |= ((caddr[1] <<16) & 0xff0000);337addr |= ((caddr[2] <<8) & 0xff00);338addr |= (caddr[3] & 0xff);339addr = htonl(addr);340/**341* Socket address342*/343him.sin_addr.s_addr = addr;344him.sin_family = AF_INET;345len = sizeof(him);346347/**348* If a network interface was specified, let's convert its address349* as well.350*/351if (!(IS_NULL(ifArray))) {352memset((char *) caddr, 0, sizeof(caddr));353(*env)->GetByteArrayRegion(env, ifArray, 0, 4, caddr);354addr = ((caddr[0]<<24) & 0xff000000);355addr |= ((caddr[1] <<16) & 0xff0000);356addr |= ((caddr[2] <<8) & 0xff00);357addr |= (caddr[3] & 0xff);358addr = htonl(addr);359inf.sin_addr.s_addr = addr;360inf.sin_family = AF_INET;361inf.sin_port = 0;362netif = &inf;363}364365/*366* Can't create a raw socket, so let's try a TCP socket367*/368fd = NET_Socket(AF_INET, SOCK_STREAM, 0);369if (fd == JVM_IO_ERR) {370/* note: if you run out of fds, you may not be able to load371* the exception class, and get a NoClassDefFoundError372* instead.373*/374NET_ThrowNew(env, WSAGetLastError(), "Can't create socket");375return JNI_FALSE;376}377if (ttl > 0) {378setsockopt(fd, IPPROTO_IP, IP_TTL, (const char *)&ttl, sizeof(ttl));379}380/*381* A network interface was specified, so let's bind to it.382*/383if (netif != NULL) {384if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {385NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket");386closesocket(fd);387return JNI_FALSE;388}389}390391/*392* Make the socket non blocking so we can use select/poll.393*/394hEvent = WSACreateEvent();395WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE);396397/* no need to use NET_Connect as non-blocking */398him.sin_port = htons(7); /* Echo */399connect_rv = connect(fd, (struct sockaddr *)&him, len);400401/**402* connection established or refused immediately, either way it means403* we were able to reach the host!404*/405if (connect_rv == 0 || WSAGetLastError() == WSAECONNREFUSED) {406WSACloseEvent(hEvent);407closesocket(fd);408return JNI_TRUE;409} else {410int optlen;411412switch (WSAGetLastError()) {413case WSAEHOSTUNREACH: /* Host Unreachable */414case WSAENETUNREACH: /* Network Unreachable */415case WSAENETDOWN: /* Network is down */416case WSAEPFNOSUPPORT: /* Protocol Family unsupported */417WSACloseEvent(hEvent);418closesocket(fd);419return JNI_FALSE;420}421422if (WSAGetLastError() != WSAEWOULDBLOCK) {423NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",424"connect failed");425WSACloseEvent(hEvent);426closesocket(fd);427return JNI_FALSE;428}429430timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);431432/* has connection been established */433434if (timeout >= 0) {435optlen = sizeof(connect_rv);436if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,437&optlen) <0) {438connect_rv = WSAGetLastError();439}440441if (connect_rv == 0 || connect_rv == WSAECONNREFUSED) {442WSACloseEvent(hEvent);443closesocket(fd);444return JNI_TRUE;445}446}447}448WSACloseEvent(hEvent);449closesocket(fd);450return JNI_FALSE;451}452453/**454* ping implementation.455* Send a ICMP_ECHO_REQUEST packet every second until either the timeout456* expires or a answer is received.457* Returns true is an ECHO_REPLY is received, otherwise, false.458*/459static jboolean460ping4(JNIEnv *env,461unsigned long src_addr,462unsigned long dest_addr,463jint timeout,464HANDLE hIcmpFile)465{466// See https://msdn.microsoft.com/en-us/library/aa366050%28VS.85%29.aspx467468DWORD dwRetVal = 0;469char SendData[32] = {0};470LPVOID ReplyBuffer = NULL;471DWORD ReplySize = 0;472jboolean ret = JNI_FALSE;473474// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366051%28v=vs.85%29.aspx475ReplySize = sizeof(ICMP_ECHO_REPLY) // The buffer should be large enough476// to hold at least one ICMP_ECHO_REPLY477// structure478+ sizeof(SendData) // plus RequestSize bytes of data.479+ 8; // This buffer should also be large enough480// to also hold 8 more bytes of data481// (the size of an ICMP error message)482483ReplyBuffer = (VOID*) malloc(ReplySize);484if (ReplyBuffer == NULL) {485IcmpCloseHandle(hIcmpFile);486NET_ThrowNew(env, -1, "Unable to allocate memory");487return JNI_FALSE;488}489490if (src_addr == 0) {491dwRetVal = IcmpSendEcho(hIcmpFile, // HANDLE IcmpHandle,492dest_addr, // IPAddr DestinationAddress,493SendData, // LPVOID RequestData,494sizeof(SendData), // WORD RequestSize,495NULL, // PIP_OPTION_INFORMATION RequestOptions,496ReplyBuffer,// LPVOID ReplyBuffer,497ReplySize, // DWORD ReplySize,498// Note: IcmpSendEcho and its derivatives499// seem to have an undocumented minimum500// timeout of 1000ms below which the501// api behaves inconsistently.502(timeout < 1000) ? 1000 : timeout); // DWORD Timeout503} else {504dwRetVal = IcmpSendEcho2Ex(hIcmpFile, // HANDLE IcmpHandle,505NULL, // HANDLE Event506NULL, // PIO_APC_ROUTINE ApcRoutine507NULL, // ApcContext508src_addr, // IPAddr SourceAddress,509dest_addr, // IPAddr DestinationAddress,510SendData, // LPVOID RequestData,511sizeof(SendData), // WORD RequestSize,512NULL, // PIP_OPTION_INFORMATION RequestOptions,513ReplyBuffer,// LPVOID ReplyBuffer,514ReplySize, // DWORD ReplySize,515(timeout < 1000) ? 1000 : timeout); // DWORD Timeout516}517518if (dwRetVal == 0) { // if the call failed519TCHAR *buf;520DWORD err = WSAGetLastError();521switch (err) {522case ERROR_NO_NETWORK:523case ERROR_NETWORK_UNREACHABLE:524case ERROR_HOST_UNREACHABLE:525case ERROR_PROTOCOL_UNREACHABLE:526case ERROR_PORT_UNREACHABLE:527case ERROR_REQUEST_ABORTED:528case ERROR_INCORRECT_ADDRESS:529case ERROR_HOST_DOWN:530case ERROR_INVALID_COMPUTERNAME:531case ERROR_INVALID_NETNAME:532case WSAEHOSTUNREACH: /* Host Unreachable */533case WSAENETUNREACH: /* Network Unreachable */534case WSAENETDOWN: /* Network is down */535case WSAEPFNOSUPPORT: /* Protocol Family unsupported */536case IP_REQ_TIMED_OUT:537break;538default:539FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,540NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),541(LPTSTR)&buf, 0, NULL);542NET_ThrowNew(env, err, buf);543LocalFree(buf);544break;545}546} else {547PICMP_ECHO_REPLY pEchoReply = (PICMP_ECHO_REPLY)ReplyBuffer;548549// This is to take into account the undocumented minimum550// timeout mentioned in the IcmpSendEcho call above.551// We perform an extra check to make sure that our552// roundtrip time was less than our desired timeout553// for cases where that timeout is < 1000ms.554if (pEchoReply->Status == IP_SUCCESS555&& (int)pEchoReply->RoundTripTime <= timeout)556{557ret = JNI_TRUE;558}559}560561free(ReplyBuffer);562IcmpCloseHandle(hIcmpFile);563564return ret;565}566567/*568* Class: java_net_Inet4AddressImpl569* Method: isReachable0570* Signature: ([bI[bI)Z571*/572JNIEXPORT jboolean JNICALL573Java_java_net_Inet4AddressImpl_isReachable0(JNIEnv *env, jobject this,574jbyteArray addrArray,575jint timeout,576jbyteArray ifArray,577jint ttl) {578579if (isVistaSP1OrGreater()) {580jint src_addr = 0;581jint dest_addr = 0;582jbyte caddr[4];583int sz;584HANDLE hIcmpFile;585586/**587* Convert IP address from byte array to integer588*/589sz = (*env)->GetArrayLength(env, addrArray);590if (sz != 4) {591return JNI_FALSE;592}593memset((char *) caddr, 0, sizeof(caddr));594(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);595dest_addr = ((caddr[0]<<24) & 0xff000000);596dest_addr |= ((caddr[1] <<16) & 0xff0000);597dest_addr |= ((caddr[2] <<8) & 0xff00);598dest_addr |= (caddr[3] & 0xff);599dest_addr = htonl(dest_addr);600601/**602* If a network interface was specified, let's convert its address603* as well.604*/605if (!(IS_NULL(ifArray))) {606memset((char *) caddr, 0, sizeof(caddr));607(*env)->GetByteArrayRegion(env, ifArray, 0, 4, caddr);608src_addr = ((caddr[0]<<24) & 0xff000000);609src_addr |= ((caddr[1] <<16) & 0xff0000);610src_addr |= ((caddr[2] <<8) & 0xff00);611src_addr |= (caddr[3] & 0xff);612src_addr = htonl(src_addr);613}614615hIcmpFile = IcmpCreateFile();616if (hIcmpFile == INVALID_HANDLE_VALUE) {617int err = WSAGetLastError();618if (err == ERROR_ACCESS_DENIED) {619// fall back to TCP echo if access is denied to ICMP620return tcp_ping4(env, addrArray, timeout, ifArray, ttl);621} else {622NET_ThrowNew(env, err, "Unable to create ICMP file handle");623return JNI_FALSE;624}625} else {626return ping4(env, src_addr, dest_addr, timeout, hIcmpFile);627}628} else {629tcp_ping4(env, addrArray, timeout, ifArray, ttl);630}631}632633634