8187443: Forest Consolidation: Move files to unified layout

Reviewed-by: darcy, ihse
This commit is contained in:
Erik Joelsson 2017-09-12 19:03:39 +02:00
parent 270fe13182
commit 3789983e89
56923 changed files with 3 additions and 15727 deletions

View file

@ -0,0 +1,510 @@
/*
* Copyright (c) 2004, 2017, 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 <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "jvm_md.h"
#include "proxy_util.h"
#include "sun_net_spi_DefaultProxySelector.h"
/**
* These functions are used by the sun.net.spi.DefaultProxySelector class
* to access some platform specific settings.
* This is the Solaris/Linux Gnome 2.x code using the GConf-2 library.
* Everything is loaded dynamically so no hard link with any library exists.
* The GConf-2 settings used are:
* - /system/http_proxy/use_http_proxy boolean
* - /system/http_proxy/use_authentcation boolean
* - /system/http_proxy/use_same_proxy boolean
* - /system/http_proxy/host string
* - /system/http_proxy/authentication_user string
* - /system/http_proxy/authentication_password string
* - /system/http_proxy/port int
* - /system/proxy/socks_host string
* - /system/proxy/mode string
* - /system/proxy/ftp_host string
* - /system/proxy/secure_host string
* - /system/proxy/socks_port int
* - /system/proxy/ftp_port int
* - /system/proxy/secure_port int
* - /system/proxy/no_proxy_for list
* - /system/proxy/gopher_host string
* - /system/proxy/gopher_port int
*
* The following keys are not used in the new gnome 3
* - /system/http_proxy/use_http_proxy
* - /system/http_proxy/use_same_proxy
*/
typedef void* gconf_client_get_default_func();
typedef char* gconf_client_get_string_func(void *, char *, void**);
typedef int gconf_client_get_int_func(void*, char *, void**);
typedef int gconf_client_get_bool_func(void*, char *, void**);
typedef int gconf_init_func(int, char**, void**);
typedef void g_type_init_func ();
gconf_client_get_default_func* my_get_default_func = NULL;
gconf_client_get_string_func* my_get_string_func = NULL;
gconf_client_get_int_func* my_get_int_func = NULL;
gconf_client_get_bool_func* my_get_bool_func = NULL;
gconf_init_func* my_gconf_init_func = NULL;
g_type_init_func* my_g_type_init_func = NULL;
/*
* GProxyResolver provides synchronous and asynchronous network
* proxy resolution. It is based on GSettings, which is the standard
* of Gnome 3, to get system settings.
*
* In the current implementation, GProxyResolver has a higher priority
* than the old GConf. And we only resolve the proxy synchronously. In
* the future, we can also do the asynchronous network proxy resolution
* if necessary.
*
*/
typedef struct _GProxyResolver GProxyResolver;
typedef struct _GSocketConnectable GSocketConnectable;
typedef struct GError GError;
typedef GProxyResolver* g_proxy_resolver_get_default_func();
typedef char** g_proxy_resolver_lookup_func();
typedef GSocketConnectable* g_network_address_parse_uri_func();
typedef const char* g_network_address_get_hostname_func();
typedef unsigned short g_network_address_get_port_func();
typedef void g_strfreev_func();
static g_proxy_resolver_get_default_func* g_proxy_resolver_get_default = NULL;
static g_proxy_resolver_lookup_func* g_proxy_resolver_lookup = NULL;
static g_network_address_parse_uri_func* g_network_address_parse_uri = NULL;
static g_network_address_get_hostname_func* g_network_address_get_hostname = NULL;
static g_network_address_get_port_func* g_network_address_get_port = NULL;
static g_strfreev_func* g_strfreev = NULL;
static void* gconf_client = NULL;
static int use_gproxyResolver = 0;
static int use_gconf = 0;
static int initGConf() {
/**
* Let's try to load GConf-2 library
*/
if (dlopen(JNI_LIB_NAME("gconf-2"), RTLD_GLOBAL | RTLD_LAZY) != NULL ||
dlopen(VERSIONED_JNI_LIB_NAME("gconf-2", "4"),
RTLD_GLOBAL | RTLD_LAZY) != NULL)
{
/*
* Now let's get pointer to the functions we need.
*/
my_g_type_init_func =
(g_type_init_func*)dlsym(RTLD_DEFAULT, "g_type_init");
my_get_default_func =
(gconf_client_get_default_func*)dlsym(RTLD_DEFAULT,
"gconf_client_get_default");
if (my_g_type_init_func != NULL && my_get_default_func != NULL) {
/**
* Try to connect to GConf.
*/
(*my_g_type_init_func)();
gconf_client = (*my_get_default_func)();
if (gconf_client != NULL) {
my_get_string_func =
(gconf_client_get_string_func*)dlsym(RTLD_DEFAULT,
"gconf_client_get_string");
my_get_int_func =
(gconf_client_get_int_func*)dlsym(RTLD_DEFAULT,
"gconf_client_get_int");
my_get_bool_func =
(gconf_client_get_bool_func*)dlsym(RTLD_DEFAULT,
"gconf_client_get_bool");
if (my_get_int_func != NULL && my_get_string_func != NULL &&
my_get_bool_func != NULL)
{
/**
* We did get all we need. Let's enable the System Proxy Settings.
*/
return 1;
}
}
}
}
return 0;
}
static jobjectArray getProxyByGConf(JNIEnv *env, const char* cproto,
const char* chost)
{
char *phost = NULL;
char *mode = NULL;
int pport = 0;
int use_proxy = 0;
int use_same_proxy = 0;
jobjectArray proxy_array = NULL;
jfieldID ptype_ID = ptype_httpID;
/* We only check manual proxy configurations */
mode = (*my_get_string_func)(gconf_client, "/system/proxy/mode", NULL);
if (mode && !strcasecmp(mode, "manual")) {
/*
* Even though /system/http_proxy/use_same_proxy is no longer used,
* its value is set to false in gnome 3. So it is not harmful to check
* it first in case jdk is used with an old gnome.
*/
use_same_proxy = (*my_get_bool_func)(gconf_client, "/system/http_proxy/use_same_proxy", NULL);
if (use_same_proxy) {
phost = (*my_get_string_func)(gconf_client, "/system/http_proxy/host", NULL);
pport = (*my_get_int_func)(gconf_client, "/system/http_proxy/port", NULL);
use_proxy = (phost != NULL && pport != 0);
}
if (!use_proxy) {
/**
* HTTP:
* /system/http_proxy/use_http_proxy (boolean) - it's no longer used
* /system/http_proxy/host (string)
* /system/http_proxy/port (integer)
*/
if (strcasecmp(cproto, "http") == 0) {
phost = (*my_get_string_func)(gconf_client, "/system/http_proxy/host", NULL);
pport = (*my_get_int_func)(gconf_client, "/system/http_proxy/port", NULL);
use_proxy = (phost != NULL && pport != 0);
}
/**
* HTTPS:
* /system/proxy/mode (string) [ "manual" means use proxy settings ]
* /system/proxy/secure_host (string)
* /system/proxy/secure_port (integer)
*/
if (strcasecmp(cproto, "https") == 0) {
phost = (*my_get_string_func)(gconf_client, "/system/proxy/secure_host", NULL);
pport = (*my_get_int_func)(gconf_client, "/system/proxy/secure_port", NULL);
use_proxy = (phost != NULL && pport != 0);
}
/**
* FTP:
* /system/proxy/mode (string) [ "manual" means use proxy settings ]
* /system/proxy/ftp_host (string)
* /system/proxy/ftp_port (integer)
*/
if (strcasecmp(cproto, "ftp") == 0) {
phost = (*my_get_string_func)(gconf_client, "/system/proxy/ftp_host", NULL);
pport = (*my_get_int_func)(gconf_client, "/system/proxy/ftp_port", NULL);
use_proxy = (phost != NULL && pport != 0);
}
/**
* GOPHER:
* /system/proxy/mode (string) [ "manual" means use proxy settings ]
* /system/proxy/gopher_host (string)
* /system/proxy/gopher_port (integer)
*/
if (strcasecmp(cproto, "gopher") == 0) {
phost = (*my_get_string_func)(gconf_client, "/system/proxy/gopher_host", NULL);
pport = (*my_get_int_func)(gconf_client, "/system/proxy/gopher_port", NULL);
use_proxy = (phost != NULL && pport != 0);
}
/**
* SOCKS:
* /system/proxy/mode (string) [ "manual" means use proxy settings ]
* /system/proxy/socks_host (string)
* /system/proxy/socks_port (integer)
*/
if (strcasecmp(cproto, "socks") == 0) {
phost = (*my_get_string_func)(gconf_client, "/system/proxy/socks_host", NULL);
pport = (*my_get_int_func)(gconf_client, "/system/proxy/socks_port", NULL);
use_proxy = (phost != NULL && pport != 0);
if (use_proxy)
ptype_ID = ptype_socksID;
}
}
}
if (use_proxy) {
jstring jhost;
char *noproxyfor;
char *s;
/**
* Check for the exclude list (aka "No Proxy For" list).
* It's a list of comma separated suffixes (e.g. domain name).
*/
noproxyfor = (*my_get_string_func)(gconf_client, "/system/proxy/no_proxy_for", NULL);
if (noproxyfor != NULL) {
char *tmpbuf[512];
s = strtok_r(noproxyfor, ", ", tmpbuf);
while (s != NULL && strlen(s) <= strlen(chost)) {
if (strcasecmp(chost+(strlen(chost) - strlen(s)), s) == 0) {
/**
* the URL host name matches with one of the sufixes,
* therefore we have to use a direct connection.
*/
use_proxy = 0;
break;
}
s = strtok_r(NULL, ", ", tmpbuf);
}
}
if (use_proxy) {
jobject proxy = NULL;
/* create a proxy array with one element. */
proxy_array = (*env)->NewObjectArray(env, 1, proxy_class, NULL);
if (proxy_array == NULL || (*env)->ExceptionCheck(env)) {
return NULL;
}
proxy = createProxy(env, ptype_ID, phost, pport);
if (proxy == NULL || (*env)->ExceptionCheck(env)) {
return NULL;
}
(*env)->SetObjectArrayElement(env, proxy_array, 0, proxy);
if ((*env)->ExceptionCheck(env)) {
return NULL;
}
}
}
return proxy_array;
}
static int initGProxyResolver() {
void *gio_handle;
gio_handle = dlopen("libgio-2.0.so", RTLD_LAZY);
if (!gio_handle) {
gio_handle = dlopen("libgio-2.0.so.0", RTLD_LAZY);
if (!gio_handle) {
return 0;
}
}
my_g_type_init_func = (g_type_init_func*)dlsym(gio_handle, "g_type_init");
g_proxy_resolver_get_default =
(g_proxy_resolver_get_default_func*)dlsym(gio_handle,
"g_proxy_resolver_get_default");
g_proxy_resolver_lookup =
(g_proxy_resolver_lookup_func*)dlsym(gio_handle,
"g_proxy_resolver_lookup");
g_network_address_parse_uri =
(g_network_address_parse_uri_func*)dlsym(gio_handle,
"g_network_address_parse_uri");
g_network_address_get_hostname =
(g_network_address_get_hostname_func*)dlsym(gio_handle,
"g_network_address_get_hostname");
g_network_address_get_port =
(g_network_address_get_port_func*)dlsym(gio_handle,
"g_network_address_get_port");
g_strfreev = (g_strfreev_func*)dlsym(gio_handle, "g_strfreev");
if (!my_g_type_init_func ||
!g_proxy_resolver_get_default ||
!g_proxy_resolver_lookup ||
!g_network_address_parse_uri ||
!g_network_address_get_hostname ||
!g_network_address_get_port ||
!g_strfreev)
{
dlclose(gio_handle);
return 0;
}
(*my_g_type_init_func)();
return 1;
}
static jobjectArray getProxyByGProxyResolver(JNIEnv *env, const char *cproto,
const char *chost)
{
GProxyResolver* resolver = NULL;
char** proxies = NULL;
GError *error = NULL;
size_t protoLen = 0;
size_t hostLen = 0;
char* uri = NULL;
jobjectArray proxy_array = NULL;
resolver = (*g_proxy_resolver_get_default)();
if (resolver == NULL) {
return NULL;
}
/* Construct the uri, cproto + "://" + chost */
protoLen = strlen(cproto);
hostLen = strlen(chost);
uri = malloc(protoLen + hostLen + 4);
if (!uri) {
/* Out of memory */
return NULL;
}
memcpy(uri, cproto, protoLen);
memcpy(uri + protoLen, "://", 3);
memcpy(uri + protoLen + 3, chost, hostLen + 1);
/*
* Looks into the system proxy configuration to determine what proxy,
* if any, to use to connect to uri. The returned proxy URIs are of
* the form <protocol>://[user[:password]@]host:port or direct://,
* where <protocol> could be http, rtsp, socks or other proxying protocol.
* direct:// is used when no proxy is needed.
*/
proxies = (*g_proxy_resolver_lookup)(resolver, uri, NULL, &error);
free(uri);
if (proxies) {
if (!error) {
int i;
int nr_proxies = 0;
char** p = proxies;
/* count the elements in the null terminated string vector. */
while (*p) {
nr_proxies++;
p++;
}
/* create a proxy array that has to be filled. */
proxy_array = (*env)->NewObjectArray(env, nr_proxies, proxy_class, NULL);
if (proxy_array != NULL && !(*env)->ExceptionCheck(env)) {
for (i = 0; proxies[i]; i++) {
if (strncmp(proxies[i], "direct://", 9)) {
GSocketConnectable* conn =
(*g_network_address_parse_uri)(proxies[i], 0,
&error);
if (conn && !error) {
const char *phost = NULL;
unsigned short pport = 0;
phost = (*g_network_address_get_hostname)(conn);
pport = (*g_network_address_get_port)(conn);
if (phost && pport > 0) {
jobject proxy = NULL;
jfieldID ptype_ID = ptype_httpID;
if (!strncmp(proxies[i], "socks", 5))
ptype_ID = ptype_socksID;
proxy = createProxy(env, ptype_ID, phost, pport);
if (proxy == NULL || (*env)->ExceptionCheck(env)) {
proxy_array = NULL;
break;
}
(*env)->SetObjectArrayElement(env, proxy_array, i, proxy);
if ((*env)->ExceptionCheck(env)) {
proxy_array = NULL;
break;
}
}
}
} else {
/* direct connection - no proxy */
jobject proxy = (*env)->GetStaticObjectField(env, proxy_class,
pr_no_proxyID);
if (proxy == NULL || (*env)->ExceptionCheck(env)) {
proxy_array = NULL;
break;
}
(*env)->SetObjectArrayElement(env, proxy_array, i, proxy);
if ((*env)->ExceptionCheck(env)) {
proxy_array = NULL;
break;
}
}
}
}
}
(*g_strfreev)(proxies);
}
return proxy_array;
}
/*
* Class: sun_net_spi_DefaultProxySelector
* Method: init
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL
Java_sun_net_spi_DefaultProxySelector_init(JNIEnv *env, jclass clazz) {
use_gproxyResolver = initGProxyResolver();
if (!use_gproxyResolver)
use_gconf = initGConf();
if (use_gproxyResolver || use_gconf) {
if (initJavaClass(env))
return JNI_TRUE;
}
return JNI_FALSE;
}
/*
* Class: sun_net_spi_DefaultProxySelector
* Method: getSystemProxies
* Signature: ([Ljava/lang/String;Ljava/lang/String;)[Ljava/net/Proxy;
*/
JNIEXPORT jobjectArray JNICALL
Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv *env,
jobject this,
jstring proto,
jstring host)
{
const char* cproto;
const char* chost;
jboolean isProtoCopy;
jboolean isHostCopy;
jobjectArray proxyArray = NULL;
cproto = (*env)->GetStringUTFChars(env, proto, &isProtoCopy);
if (cproto != NULL && (use_gproxyResolver || use_gconf)) {
chost = (*env)->GetStringUTFChars(env, host, &isHostCopy);
if (chost != NULL) {
if (use_gproxyResolver)
proxyArray = getProxyByGProxyResolver(env, cproto, chost);
else if (use_gconf)
proxyArray = getProxyByGConf(env, cproto, chost);
if (isHostCopy == JNI_TRUE)
(*env)->ReleaseStringUTFChars(env, host, chost);
}
if (isProtoCopy == JNI_TRUE)
(*env)->ReleaseStringUTFChars(env, proto, cproto);
}
return proxyArray;
}

View file

@ -0,0 +1,513 @@
/*
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include "net_util.h"
#include "java_net_Inet4AddressImpl.h"
#if defined(MACOSX)
extern jobjectArray lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6);
#endif
/* the initial size of our hostent buffers */
#ifndef NI_MAXHOST
#define NI_MAXHOST 1025
#endif
#define SET_NONBLOCKING(fd) { \
int flags = fcntl(fd, F_GETFL); \
flags |= O_NONBLOCK; \
fcntl(fd, F_SETFL, flags); \
}
/*
* Inet4AddressImpl
*/
/*
* Class: java_net_Inet4AddressImpl
* Method: getLocalHostName
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL
Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
char hostname[NI_MAXHOST + 1];
hostname[0] = '\0';
if (gethostname(hostname, NI_MAXHOST) != 0) {
strcpy(hostname, "localhost");
} else {
// try to resolve hostname via nameservice
// if it is known but getnameinfo fails, hostname will still be the
// value from gethostname
struct addrinfo hints, *res;
// make sure string is null-terminated
hostname[NI_MAXHOST] = '\0';
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_INET;
if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST,
NULL, 0, NI_NAMEREQD);
freeaddrinfo(res);
}
}
return (*env)->NewStringUTF(env, hostname);
}
/*
* Find an internet address for a given hostname. Note that this
* code only works for addresses of type INET. The translation
* of %d.%d.%d.%d to an address (int) occurs in java now, so the
* String "host" shouldn't be a %d.%d.%d.%d string. The only
* exception should be when any of the %d are out of range and
* we fallback to a lookup.
*
* Class: java_net_Inet4AddressImpl
* Method: lookupAllHostAddr
* Signature: (Ljava/lang/String;)[[B
*/
JNIEXPORT jobjectArray JNICALL
Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
jstring host) {
jobjectArray ret = NULL;
const char *hostname;
int error = 0;
struct addrinfo hints, *res = NULL, *resNew = NULL, *last = NULL,
*iterator;
initInetAddressIDs(env);
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
if (IS_NULL(host)) {
JNU_ThrowNullPointerException(env, "host argument is null");
return NULL;
}
hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
CHECK_NULL_RETURN(hostname, NULL);
// try once, with our static buffer
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_INET;
error = getaddrinfo(hostname, NULL, &hints, &res);
if (error) {
#if defined(MACOSX)
// If getaddrinfo fails try getifaddrs, see bug 8170910.
ret = lookupIfLocalhost(env, hostname, JNI_FALSE);
if (ret != NULL || (*env)->ExceptionCheck(env)) {
goto cleanupAndReturn;
}
#endif
// report error
NET_ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
goto cleanupAndReturn;
} else {
int i = 0;
iterator = res;
while (iterator != NULL) {
// skip duplicates
int skip = 0;
struct addrinfo *iteratorNew = resNew;
while (iteratorNew != NULL) {
struct sockaddr_in *addr1, *addr2;
addr1 = (struct sockaddr_in *)iterator->ai_addr;
addr2 = (struct sockaddr_in *)iteratorNew->ai_addr;
if (addr1->sin_addr.s_addr == addr2->sin_addr.s_addr) {
skip = 1;
break;
}
iteratorNew = iteratorNew->ai_next;
}
if (!skip) {
struct addrinfo *next
= (struct addrinfo *)malloc(sizeof(struct addrinfo));
if (!next) {
JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
ret = NULL;
goto cleanupAndReturn;
}
memcpy(next, iterator, sizeof(struct addrinfo));
next->ai_next = NULL;
if (resNew == NULL) {
resNew = next;
} else {
last->ai_next = next;
}
last = next;
i++;
}
iterator = iterator->ai_next;
}
// allocate array - at this point i contains the number of addresses
ret = (*env)->NewObjectArray(env, i, ia_class, NULL);
if (IS_NULL(ret)) {
goto cleanupAndReturn;
}
i = 0;
iterator = resNew;
while (iterator != NULL) {
jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
if (IS_NULL(iaObj)) {
ret = NULL;
goto cleanupAndReturn;
}
setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in *)
(iterator->ai_addr))->sin_addr.s_addr));
setInetAddress_hostName(env, iaObj, host);
(*env)->SetObjectArrayElement(env, ret, i++, iaObj);
iterator = iterator->ai_next;
}
}
cleanupAndReturn:
JNU_ReleaseStringPlatformChars(env, host, hostname);
while (resNew != NULL) {
last = resNew;
resNew = resNew->ai_next;
free(last);
}
if (res != NULL) {
freeaddrinfo(res);
}
return ret;
}
/*
* Class: java_net_Inet4AddressImpl
* Method: getHostByAddr
* Signature: (I)Ljava/lang/String;
*
* Theoretically the UnknownHostException could be enriched with gai error
* information. But as it is silently ignored anyway, there's no need for this.
* It's only important that either a valid hostname is returned or an
* UnknownHostException is thrown.
*/
JNIEXPORT jstring JNICALL
Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
jbyteArray addrArray) {
jstring ret = NULL;
char host[NI_MAXHOST + 1];
jbyte caddr[4];
jint addr;
struct sockaddr_in sa;
// construct a sockaddr_in structure
memset((char *)&sa, 0, sizeof(struct sockaddr_in));
(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
addr = ((caddr[0] << 24) & 0xff000000);
addr |= ((caddr[1] << 16) & 0xff0000);
addr |= ((caddr[2] << 8) & 0xff00);
addr |= (caddr[3] & 0xff);
sa.sin_addr.s_addr = htonl(addr);
sa.sin_family = AF_INET;
if (getnameinfo((struct sockaddr *)&sa, sizeof(struct sockaddr_in),
host, NI_MAXHOST, NULL, 0, NI_NAMEREQD)) {
JNU_ThrowByName(env, "java/net/UnknownHostException", NULL);
} else {
ret = (*env)->NewStringUTF(env, host);
if (ret == NULL) {
JNU_ThrowByName(env, "java/net/UnknownHostException", NULL);
}
}
return ret;
}
/**
* ping implementation using tcp port 7 (echo)
*/
static jboolean
tcp_ping4(JNIEnv *env, SOCKETADDRESS *sa, SOCKETADDRESS *netif, jint timeout,
jint ttl)
{
jint fd;
int connect_rv = -1;
// open a TCP socket
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1) {
// note: if you run out of fds, you may not be able to load
// the exception class, and get a NoClassDefFoundError instead.
NET_ThrowNew(env, errno, "Can't create socket");
return JNI_FALSE;
}
// set TTL
if (ttl > 0) {
setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
}
// A network interface was specified, so let's bind to it.
if (netif != NULL) {
if (bind(fd, &netif->sa, sizeof(struct sockaddr_in)) < 0) {
NET_ThrowNew(env, errno, "Can't bind socket");
close(fd);
return JNI_FALSE;
}
}
// Make the socket non blocking so we can use select/poll.
SET_NONBLOCKING(fd);
sa->sa4.sin_port = htons(7); // echo port
connect_rv = NET_Connect(fd, &sa->sa, sizeof(struct sockaddr_in));
// connection established or refused immediately, either way it means
// we were able to reach the host!
if (connect_rv == 0 || errno == ECONNREFUSED) {
close(fd);
return JNI_TRUE;
}
switch (errno) {
case ENETUNREACH: // Network Unreachable
case EAFNOSUPPORT: // Address Family not supported
case EADDRNOTAVAIL: // address is not available on the remote machine
#if defined(__linux__) || defined(_AIX)
// On some Linux versions, when a socket is bound to the loopback
// interface, connect will fail and errno will be set to EINVAL
// or EHOSTUNREACH. When that happens, don't throw an exception,
// just return false.
case EINVAL:
case EHOSTUNREACH: // No route to host
#endif
close(fd);
return JNI_FALSE;
case EINPROGRESS: // this is expected as we'll probably have to wait
break;
default:
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
"connect failed");
close(fd);
return JNI_FALSE;
}
timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
if (timeout >= 0) {
// connection has been established, check for error condition
socklen_t optlen = (socklen_t)sizeof(connect_rv);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
&optlen) <0)
{
connect_rv = errno;
}
if (connect_rv == 0 || connect_rv == ECONNREFUSED) {
close(fd);
return JNI_TRUE;
}
}
close(fd);
return JNI_FALSE;
}
/**
* ping implementation.
* Send an ICMP_ECHO_REQUEST packet every second until either the timeout
* expires or an answer is received.
* Returns true if an ECHO_REPLY is received, false otherwise.
*/
static jboolean
ping4(JNIEnv *env, jint fd, SOCKETADDRESS *sa, SOCKETADDRESS *netif,
jint timeout, jint ttl)
{
jint n, size = 60 * 1024, hlen, tmout2, seq = 1;
socklen_t len;
unsigned char sendbuf[1500], recvbuf[1500];
struct icmp *icmp;
struct ip *ip;
struct sockaddr_in sa_recv;
jchar pid;
struct timeval tv;
size_t plen = ICMP_ADVLENMIN + sizeof(tv);
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
// sets the ttl (max number of hops)
if (ttl > 0) {
setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
}
// a specific interface was specified, so let's bind the socket
// to that interface to ensure the requests are sent only through it.
if (netif != NULL) {
if (bind(fd, &netif->sa, sizeof(struct sockaddr_in)) < 0) {
NET_ThrowNew(env, errno, "Can't bind socket");
close(fd);
return JNI_FALSE;
}
}
// icmp_id is a 16 bit data type, therefore down cast the pid
pid = (jchar)getpid();
// Make the socket non blocking so we can use select
SET_NONBLOCKING(fd);
do {
// create the ICMP request
icmp = (struct icmp *)sendbuf;
icmp->icmp_type = ICMP_ECHO;
icmp->icmp_code = 0;
// let's tag the ECHO packet with our pid so we can identify it
icmp->icmp_id = htons(pid);
icmp->icmp_seq = htons(seq);
seq++;
gettimeofday(&tv, NULL);
memcpy(icmp->icmp_data, &tv, sizeof(tv));
icmp->icmp_cksum = 0;
// manually calculate checksum
icmp->icmp_cksum = in_cksum((u_short *)icmp, plen);
// send it
n = sendto(fd, sendbuf, plen, 0, &sa->sa, sizeof(struct sockaddr_in));
if (n < 0 && errno != EINPROGRESS) {
#if defined(__linux__)
/*
* On some Linux versions, when a socket is bound to the loopback
* interface, sendto will fail and errno will be set to
* EINVAL or EHOSTUNREACH. When that happens, don't throw an
* exception, just return false.
*/
if (errno != EINVAL && errno != EHOSTUNREACH) {
NET_ThrowNew(env, errno, "Can't send ICMP packet");
}
#else
NET_ThrowNew(env, errno, "Can't send ICMP packet");
#endif
close(fd);
return JNI_FALSE;
}
tmout2 = timeout > 1000 ? 1000 : timeout;
do {
tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
if (tmout2 >= 0) {
len = sizeof(sa_recv);
n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0,
(struct sockaddr *)&sa_recv, &len);
// check if we received enough data
if (n < (jint)sizeof(struct ip)) {
continue;
}
ip = (struct ip *)recvbuf;
hlen = ((jint)(unsigned int)(ip->ip_hl)) << 2;
// check if we received enough data
if (n < (jint)(hlen + sizeof(struct icmp))) {
continue;
}
icmp = (struct icmp *)(recvbuf + hlen);
// We did receive something, but is it what we were expecting?
// I.E.: An ICMP_ECHO_REPLY packet with the proper PID and
// from the host that we are trying to determine is reachable.
if (icmp->icmp_type == ICMP_ECHOREPLY &&
(ntohs(icmp->icmp_id) == pid))
{
if (sa->sa4.sin_addr.s_addr == sa_recv.sin_addr.s_addr) {
close(fd);
return JNI_TRUE;
} else if (sa->sa4.sin_addr.s_addr == 0) {
close(fd);
return JNI_TRUE;
}
}
}
} while (tmout2 > 0);
timeout -= 1000;
} while (timeout > 0);
close(fd);
return JNI_FALSE;
}
/*
* Class: java_net_Inet4AddressImpl
* Method: isReachable0
* Signature: ([bI[bI)Z
*/
JNIEXPORT jboolean JNICALL
Java_java_net_Inet4AddressImpl_isReachable0(JNIEnv *env, jobject this,
jbyteArray addrArray, jint timeout,
jbyteArray ifArray, jint ttl)
{
jbyte caddr[4];
jint addr = 0, sz, fd;
SOCKETADDRESS sa, inf, *netif = NULL;
// check if address array size is 4 (IPv4 address)
sz = (*env)->GetArrayLength(env, addrArray);
if (sz != 4) {
return JNI_FALSE;
}
// convert IP address from byte array to integer
memset((char *)caddr, 0, sizeof(caddr));
(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
addr = ((caddr[0] << 24) & 0xff000000);
addr |= ((caddr[1] << 16) & 0xff0000);
addr |= ((caddr[2] << 8) & 0xff00);
addr |= (caddr[3] & 0xff);
memset((char *)&sa, 0, sizeof(SOCKETADDRESS));
sa.sa4.sin_addr.s_addr = htonl(addr);
sa.sa4.sin_family = AF_INET;
// If a network interface was specified, let's convert its address as well.
if (!(IS_NULL(ifArray))) {
memset((char *)caddr, 0, sizeof(caddr));
(*env)->GetByteArrayRegion(env, ifArray, 0, 4, caddr);
addr = ((caddr[0] << 24) & 0xff000000);
addr |= ((caddr[1] << 16) & 0xff0000);
addr |= ((caddr[2] << 8) & 0xff00);
addr |= (caddr[3] & 0xff);
memset((char *)&inf, 0, sizeof(SOCKETADDRESS));
inf.sa4.sin_addr.s_addr = htonl(addr);
inf.sa4.sin_family = AF_INET;
netif = &inf;
}
// Let's try to create a RAW socket to send ICMP packets.
// This usually requires "root" privileges, so it's likely to fail.
fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (fd == -1) {
return tcp_ping4(env, &sa, netif, timeout, ttl);
} else {
// It didn't fail, so we can use ICMP_ECHO requests.
return ping4(env, fd, &sa, netif, timeout, ttl);
}
}

View file

@ -0,0 +1,728 @@
/*
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/icmp6.h>
#if defined(_ALLBSD_SOURCE)
#include <ifaddrs.h>
#include <net/if.h>
#endif
#include "net_util.h"
#include "java_net_InetAddress.h"
#include "java_net_Inet4AddressImpl.h"
#include "java_net_Inet6AddressImpl.h"
/* the initial size of our hostent buffers */
#ifndef NI_MAXHOST
#define NI_MAXHOST 1025
#endif
#define SET_NONBLOCKING(fd) { \
int flags = fcntl(fd, F_GETFL); \
flags |= O_NONBLOCK; \
fcntl(fd, F_SETFL, flags); \
}
/*
* Inet6AddressImpl
*/
/*
* Class: java_net_Inet6AddressImpl
* Method: getLocalHostName
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL
Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
char hostname[NI_MAXHOST + 1];
hostname[0] = '\0';
if (gethostname(hostname, NI_MAXHOST) != 0) {
strcpy(hostname, "localhost");
#if defined(__solaris__)
} else {
// try to resolve hostname via nameservice
// if it is known but getnameinfo fails, hostname will still be the
// value from gethostname
struct addrinfo hints, *res;
// make sure string is null-terminated
hostname[NI_MAXHOST] = '\0';
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_UNSPEC;
if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST,
NULL, 0, NI_NAMEREQD);
freeaddrinfo(res);
}
}
#else
} else {
// make sure string is null-terminated
hostname[NI_MAXHOST] = '\0';
}
#endif
return (*env)->NewStringUTF(env, hostname);
}
#if defined(MACOSX)
/* also called from Inet4AddressImpl.c */
__private_extern__ jobjectArray
lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6)
{
jobjectArray result = NULL;
char myhostname[NI_MAXHOST+1];
struct ifaddrs *ifa = NULL;
int familyOrder = 0;
int count = 0, i, j;
int addrs4 = 0, addrs6 = 0, numV4Loopbacks = 0, numV6Loopbacks = 0;
jboolean includeLoopback = JNI_FALSE;
jobject name;
initInetAddressIDs(env);
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
/* If the requested name matches this host's hostname, return IP addresses
* from all attached interfaces. (#2844683 et al) This prevents undesired
* PPP dialup, but may return addresses that don't actually correspond to
* the name (if the name actually matches something in DNS etc.
*/
myhostname[0] = '\0';
if (gethostname(myhostname, NI_MAXHOST) == -1) {
/* Something went wrong, maybe networking is not setup? */
return NULL;
}
myhostname[NI_MAXHOST] = '\0';
if (strcmp(myhostname, hostname) != 0) {
// Non-self lookup
return NULL;
}
if (getifaddrs(&ifa) != 0) {
NET_ThrowNew(env, errno, "Can't get local interface addresses");
return NULL;
}
name = (*env)->NewStringUTF(env, hostname);
if (name == NULL) {
freeifaddrs(ifa);
return NULL;
}
/* Iterate over the interfaces, and total up the number of IPv4 and IPv6
* addresses we have. Also keep a count of loopback addresses. We need to
* exclude them in the normal case, but return them if we don't get an IP
* address.
*/
struct ifaddrs *iter = ifa;
while (iter) {
int family = iter->ifa_addr->sa_family;
if (iter->ifa_name[0] != '\0' && iter->ifa_addr)
{
jboolean isLoopback = iter->ifa_flags & IFF_LOOPBACK;
if (family == AF_INET) {
addrs4++;
if (isLoopback) numV4Loopbacks++;
} else if (family == AF_INET6 && includeV6) {
addrs6++;
if (isLoopback) numV6Loopbacks++;
} // else we don't care, e.g. AF_LINK
}
iter = iter->ifa_next;
}
if (addrs4 == numV4Loopbacks && addrs6 == numV6Loopbacks) {
// We don't have a real IP address, just loopback. We need to include
// loopback in our results.
includeLoopback = JNI_TRUE;
}
/* Create and fill the Java array. */
int arraySize = addrs4 + addrs6 -
(includeLoopback ? 0 : (numV4Loopbacks + numV6Loopbacks));
result = (*env)->NewObjectArray(env, arraySize, ia_class, NULL);
if (!result) goto done;
if ((*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID)) {
i = includeLoopback ? addrs6 : (addrs6 - numV6Loopbacks);
j = 0;
} else {
i = 0;
j = includeLoopback ? addrs4 : (addrs4 - numV4Loopbacks);
}
// Now loop around the ifaddrs
iter = ifa;
while (iter != NULL) {
jboolean isLoopback = iter->ifa_flags & IFF_LOOPBACK;
int family = iter->ifa_addr->sa_family;
if (iter->ifa_name[0] != '\0' && iter->ifa_addr &&
(family == AF_INET || (family == AF_INET6 && includeV6)) &&
(!isLoopback || includeLoopback))
{
int port;
int index = (family == AF_INET) ? i++ : j++;
jobject o = NET_SockaddrToInetAddress(env,
(SOCKETADDRESS *)iter->ifa_addr, &port);
if (!o) {
freeifaddrs(ifa);
if (!(*env)->ExceptionCheck(env))
JNU_ThrowOutOfMemoryError(env, "Object allocation failed");
return NULL;
}
setInetAddress_hostName(env, o, name);
(*env)->SetObjectArrayElement(env, result, index, o);
(*env)->DeleteLocalRef(env, o);
}
iter = iter->ifa_next;
}
done:
freeifaddrs(ifa);
return result;
}
#endif
/*
* Class: java_net_Inet6AddressImpl
* Method: lookupAllHostAddr
* Signature: (Ljava/lang/String;)[[B
*/
JNIEXPORT jobjectArray JNICALL
Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
jstring host) {
jobjectArray ret = NULL;
const char *hostname;
int error = 0;
struct addrinfo hints, *res = NULL, *resNew = NULL, *last = NULL,
*iterator;
initInetAddressIDs(env);
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
if (IS_NULL(host)) {
JNU_ThrowNullPointerException(env, "host argument is null");
return NULL;
}
hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
CHECK_NULL_RETURN(hostname, NULL);
// try once, with our static buffer
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_UNSPEC;
error = getaddrinfo(hostname, NULL, &hints, &res);
if (error) {
#if defined(MACOSX)
// if getaddrinfo fails try getifaddrs
ret = lookupIfLocalhost(env, hostname, JNI_TRUE);
if (ret != NULL || (*env)->ExceptionCheck(env)) {
goto cleanupAndReturn;
}
#endif
// report error
NET_ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
goto cleanupAndReturn;
} else {
int i = 0, inetCount = 0, inet6Count = 0, inetIndex = 0,
inet6Index = 0, originalIndex = 0;
int addressPreference =
(*env)->GetStaticIntField(env, ia_class, ia_preferIPv6AddressID);;
iterator = res;
while (iterator != NULL) {
// skip duplicates
int skip = 0;
struct addrinfo *iteratorNew = resNew;
while (iteratorNew != NULL) {
if (iterator->ai_family == iteratorNew->ai_family &&
iterator->ai_addrlen == iteratorNew->ai_addrlen) {
if (iteratorNew->ai_family == AF_INET) { /* AF_INET */
struct sockaddr_in *addr1, *addr2;
addr1 = (struct sockaddr_in *)iterator->ai_addr;
addr2 = (struct sockaddr_in *)iteratorNew->ai_addr;
if (addr1->sin_addr.s_addr == addr2->sin_addr.s_addr) {
skip = 1;
break;
}
} else {
int t;
struct sockaddr_in6 *addr1, *addr2;
addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
addr2 = (struct sockaddr_in6 *)iteratorNew->ai_addr;
for (t = 0; t < 16; t++) {
if (addr1->sin6_addr.s6_addr[t] !=
addr2->sin6_addr.s6_addr[t]) {
break;
}
}
if (t < 16) {
iteratorNew = iteratorNew->ai_next;
continue;
} else {
skip = 1;
break;
}
}
} else if (iterator->ai_family != AF_INET &&
iterator->ai_family != AF_INET6) {
// we can't handle other family types
skip = 1;
break;
}
iteratorNew = iteratorNew->ai_next;
}
if (!skip) {
struct addrinfo *next
= (struct addrinfo *)malloc(sizeof(struct addrinfo));
if (!next) {
JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
ret = NULL;
goto cleanupAndReturn;
}
memcpy(next, iterator, sizeof(struct addrinfo));
next->ai_next = NULL;
if (resNew == NULL) {
resNew = next;
} else {
last->ai_next = next;
}
last = next;
i++;
if (iterator->ai_family == AF_INET) {
inetCount++;
} else if (iterator->ai_family == AF_INET6) {
inet6Count++;
}
}
iterator = iterator->ai_next;
}
// allocate array - at this point i contains the number of addresses
ret = (*env)->NewObjectArray(env, i, ia_class, NULL);
if (IS_NULL(ret)) {
/* we may have memory to free at the end of this */
goto cleanupAndReturn;
}
if (addressPreference == java_net_InetAddress_PREFER_IPV6_VALUE) {
inetIndex = inet6Count;
inet6Index = 0;
} else if (addressPreference == java_net_InetAddress_PREFER_IPV4_VALUE) {
inetIndex = 0;
inet6Index = inetCount;
} else if (addressPreference == java_net_InetAddress_PREFER_SYSTEM_VALUE) {
inetIndex = inet6Index = originalIndex = 0;
}
iterator = resNew;
while (iterator != NULL) {
if (iterator->ai_family == AF_INET) {
jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
if (IS_NULL(iaObj)) {
ret = NULL;
goto cleanupAndReturn;
}
setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
setInetAddress_hostName(env, iaObj, host);
(*env)->SetObjectArrayElement(env, ret, (inetIndex | originalIndex), iaObj);
inetIndex++;
} else if (iterator->ai_family == AF_INET6) {
jint scope = 0;
jboolean ret1;
jobject iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
if (IS_NULL(iaObj)) {
ret = NULL;
goto cleanupAndReturn;
}
ret1 = setInet6Address_ipaddress(env, iaObj, (char *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr));
if (ret1 == JNI_FALSE) {
ret = NULL;
goto cleanupAndReturn;
}
scope = ((struct sockaddr_in6 *)iterator->ai_addr)->sin6_scope_id;
if (scope != 0) { // zero is default value, no need to set
setInet6Address_scopeid(env, iaObj, scope);
}
setInetAddress_hostName(env, iaObj, host);
(*env)->SetObjectArrayElement(env, ret, (inet6Index | originalIndex), iaObj);
inet6Index++;
}
if (addressPreference == java_net_InetAddress_PREFER_SYSTEM_VALUE) {
originalIndex++;
inetIndex = inet6Index = 0;
}
iterator = iterator->ai_next;
}
}
cleanupAndReturn:
JNU_ReleaseStringPlatformChars(env, host, hostname);
while (resNew != NULL) {
last = resNew;
resNew = resNew->ai_next;
free(last);
}
if (res != NULL) {
freeaddrinfo(res);
}
return ret;
}
/*
* Class: java_net_Inet6AddressImpl
* Method: getHostByAddr
* Signature: (I)Ljava/lang/String;
*
* Theoretically the UnknownHostException could be enriched with gai error
* information. But as it is silently ignored anyway, there's no need for this.
* It's only important that either a valid hostname is returned or an
* UnknownHostException is thrown.
*/
JNIEXPORT jstring JNICALL
Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
jbyteArray addrArray) {
jstring ret = NULL;
char host[NI_MAXHOST + 1];
int len = 0;
jbyte caddr[16];
SOCKETADDRESS sa;
memset((void *)&sa, 0, sizeof(SOCKETADDRESS));
// construct a sockaddr_in structure (AF_INET or AF_INET6)
if ((*env)->GetArrayLength(env, addrArray) == 4) {
jint addr;
(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
addr = ((caddr[0] << 24) & 0xff000000);
addr |= ((caddr[1] << 16) & 0xff0000);
addr |= ((caddr[2] << 8) & 0xff00);
addr |= (caddr[3] & 0xff);
sa.sa4.sin_addr.s_addr = htonl(addr);
sa.sa4.sin_family = AF_INET;
len = sizeof(struct sockaddr_in);
} else {
(*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
memcpy((void *)&sa.sa6.sin6_addr, caddr, sizeof(struct in6_addr));
sa.sa6.sin6_family = AF_INET6;
len = sizeof(struct sockaddr_in6);
}
if (getnameinfo(&sa.sa, len, host, NI_MAXHOST, NULL, 0, NI_NAMEREQD)) {
JNU_ThrowByName(env, "java/net/UnknownHostException", NULL);
} else {
ret = (*env)->NewStringUTF(env, host);
if (ret == NULL) {
JNU_ThrowByName(env, "java/net/UnknownHostException", NULL);
}
}
return ret;
}
/**
* ping implementation using tcp port 7 (echo)
*/
static jboolean
tcp_ping6(JNIEnv *env, SOCKETADDRESS *sa, SOCKETADDRESS *netif, jint timeout,
jint ttl)
{
jint fd;
int connect_rv = -1;
// open a TCP socket
fd = socket(AF_INET6, SOCK_STREAM, 0);
if (fd == -1) {
// note: if you run out of fds, you may not be able to load
// the exception class, and get a NoClassDefFoundError instead.
NET_ThrowNew(env, errno, "Can't create socket");
return JNI_FALSE;
}
// set TTL
if (ttl > 0) {
setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
}
// A network interface was specified, so let's bind to it.
if (netif != NULL) {
if (bind(fd, &netif->sa, sizeof(struct sockaddr_in6)) <0) {
NET_ThrowNew(env, errno, "Can't bind socket");
close(fd);
return JNI_FALSE;
}
}
// Make the socket non blocking so we can use select/poll.
SET_NONBLOCKING(fd);
sa->sa6.sin6_port = htons(7); // echo port
connect_rv = NET_Connect(fd, &sa->sa, sizeof(struct sockaddr_in6));
// connection established or refused immediately, either way it means
// we were able to reach the host!
if (connect_rv == 0 || errno == ECONNREFUSED) {
close(fd);
return JNI_TRUE;
}
switch (errno) {
case ENETUNREACH: // Network Unreachable
case EAFNOSUPPORT: // Address Family not supported
case EADDRNOTAVAIL: // address is not available on the remote machine
#if defined(__linux__) || defined(_AIX)
// On some Linux versions, when a socket is bound to the loopback
// interface, connect will fail and errno will be set to EINVAL
// or EHOSTUNREACH. When that happens, don't throw an exception,
// just return false.
case EINVAL:
case EHOSTUNREACH: // No route to host
#endif
close(fd);
return JNI_FALSE;
case EINPROGRESS: // this is expected as we'll probably have to wait
break;
default:
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
"connect failed");
close(fd);
return JNI_FALSE;
}
timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
if (timeout >= 0) {
// connection has been established, check for error condition
socklen_t optlen = (socklen_t)sizeof(connect_rv);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
&optlen) <0)
{
connect_rv = errno;
}
if (connect_rv == 0 || connect_rv == ECONNREFUSED) {
close(fd);
return JNI_TRUE;
}
}
close(fd);
return JNI_FALSE;
}
/**
* ping implementation.
* Send an ICMP_ECHO_REQUEST packet every second until either the timeout
* expires or an answer is received.
* Returns true if an ECHO_REPLY is received, false otherwise.
*/
static jboolean
ping6(JNIEnv *env, jint fd, SOCKETADDRESS *sa, SOCKETADDRESS *netif,
jint timeout, jint ttl)
{
jint n, size = 60 * 1024, tmout2, seq = 1;
socklen_t len;
unsigned char sendbuf[1500], recvbuf[1500];
struct icmp6_hdr *icmp6;
struct sockaddr_in6 sa_recv;
jchar pid;
struct timeval tv;
size_t plen = sizeof(struct icmp6_hdr) + sizeof(tv);
#if defined(__linux__)
/**
* For some strange reason, the linux kernel won't calculate the
* checksum of ICMPv6 packets unless you set this socket option
*/
int csum_offset = 2;
setsockopt(fd, SOL_RAW, IPV6_CHECKSUM, &csum_offset, sizeof(int));
#endif
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
// sets the ttl (max number of hops)
if (ttl > 0) {
setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
}
// a specific interface was specified, so let's bind the socket
// to that interface to ensure the requests are sent only through it.
if (netif != NULL) {
if (bind(fd, &netif->sa, sizeof(struct sockaddr_in6)) <0) {
NET_ThrowNew(env, errno, "Can't bind socket");
close(fd);
return JNI_FALSE;
}
}
// icmp_id is a 16 bit data type, therefore down cast the pid
pid = (jchar)getpid();
// Make the socket non blocking so we can use select
SET_NONBLOCKING(fd);
do {
// create the ICMP request
icmp6 = (struct icmp6_hdr *)sendbuf;
icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
icmp6->icmp6_code = 0;
// let's tag the ECHO packet with our pid so we can identify it
icmp6->icmp6_id = htons(pid);
icmp6->icmp6_seq = htons(seq);
seq++;
gettimeofday(&tv, NULL);
memcpy(sendbuf + sizeof(struct icmp6_hdr), &tv, sizeof(tv));
icmp6->icmp6_cksum = 0;
// send it
n = sendto(fd, sendbuf, plen, 0, &sa->sa, sizeof(struct sockaddr_in6));
if (n < 0 && errno != EINPROGRESS) {
#if defined(__linux__)
/*
* On some Linux versions, when a socket is bound to the loopback
* interface, sendto will fail and errno will be set to
* EINVAL or EHOSTUNREACH. When that happens, don't throw an
* exception, just return false.
*/
if (errno != EINVAL && errno != EHOSTUNREACH) {
NET_ThrowNew(env, errno, "Can't send ICMP packet");
}
#else
NET_ThrowNew(env, errno, "Can't send ICMP packet");
#endif
close(fd);
return JNI_FALSE;
}
tmout2 = timeout > 1000 ? 1000 : timeout;
do {
tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
if (tmout2 >= 0) {
len = sizeof(sa_recv);
n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0,
(struct sockaddr *)&sa_recv, &len);
// check if we received enough data
if (n < (jint)sizeof(struct icmp6_hdr)) {
continue;
}
icmp6 = (struct icmp6_hdr *)recvbuf;
// We did receive something, but is it what we were expecting?
// I.E.: An ICMP6_ECHO_REPLY packet with the proper PID and
// from the host that we are trying to determine is reachable.
if (icmp6->icmp6_type == ICMP6_ECHO_REPLY &&
(ntohs(icmp6->icmp6_id) == pid))
{
if (NET_IsEqual((jbyte *)&sa->sa6.sin6_addr,
(jbyte *)&sa_recv.sin6_addr)) {
close(fd);
return JNI_TRUE;
} else if (NET_IsZeroAddr((jbyte *)&sa->sa6.sin6_addr)) {
close(fd);
return JNI_TRUE;
}
}
}
} while (tmout2 > 0);
timeout -= 1000;
} while (timeout > 0);
close(fd);
return JNI_FALSE;
}
/*
* Class: java_net_Inet6AddressImpl
* Method: isReachable0
* Signature: ([bII[bI)Z
*/
JNIEXPORT jboolean JNICALL
Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this,
jbyteArray addrArray, jint scope,
jint timeout, jbyteArray ifArray,
jint ttl, jint if_scope)
{
jbyte caddr[16];
jint sz, fd;
SOCKETADDRESS sa, inf, *netif = NULL;
// If IPv6 is not enabled, then we can't reach an IPv6 address, can we?
// Actually, we probably shouldn't even get here.
if (!ipv6_available()) {
return JNI_FALSE;
}
// If it's an IPv4 address, ICMP won't work with IPv4 mapped address,
// therefore, let's delegate to the Inet4Address method.
sz = (*env)->GetArrayLength(env, addrArray);
if (sz == 4) {
return Java_java_net_Inet4AddressImpl_isReachable0(env, this,
addrArray, timeout,
ifArray, ttl);
}
// load address to SOCKETADDRESS
memset((char *)caddr, 0, 16);
(*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
memset((char *)&sa, 0, sizeof(SOCKETADDRESS));
memcpy((void *)&sa.sa6.sin6_addr, caddr, sizeof(struct in6_addr));
sa.sa6.sin6_family = AF_INET6;
if (scope > 0) {
sa.sa6.sin6_scope_id = scope;
#if defined(__linux__)
} else {
sa.sa6.sin6_scope_id = getDefaultIPv6Interface(&sa.sa6.sin6_addr);
#endif
}
// load network interface address to SOCKETADDRESS, if specified
if (!(IS_NULL(ifArray))) {
memset((char *)caddr, 0, 16);
(*env)->GetByteArrayRegion(env, ifArray, 0, 16, caddr);
memset((char *)&inf, 0, sizeof(SOCKETADDRESS));
memcpy((void *)&inf.sa6.sin6_addr, caddr, sizeof(struct in6_addr));
inf.sa6.sin6_family = AF_INET6;
inf.sa6.sin6_scope_id = if_scope;
netif = &inf;
}
// Let's try to create a RAW socket to send ICMP packets.
// This usually requires "root" privileges, so it's likely to fail.
fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
if (fd == -1) {
return tcp_ping6(env, &sa, netif, timeout, ttl);
} else {
// It didn't fail, so we can use ICMP_ECHO requests.
return ping6(env, fd, &sa, netif, timeout, ttl);
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "java_net_InetAddressImplFactory.h"
#include "net_util.h"
/************************************************************************
* InetAddressImplFactory
*/
/*
* Class: java_net_InetAddressImplFactory
* Method: isIPv6Supported
* Signature: ()I
*/
JNIEXPORT jboolean JNICALL
Java_java_net_InetAddressImplFactory_isIPv6Supported(JNIEnv *env, jclass cls) {
if (ipv6_available()) {
return JNI_TRUE;
} else {
return JNI_FALSE;
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,123 @@
/*
* Copyright (c) 2002, 2012, 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#ifdef __solaris__
#include <sys/systeminfo.h>
#endif
#include <string.h>
#include "jni.h"
#ifndef MAXDNAME
#define MAXDNAME 1025
#endif
/*
* Class: sun_net_dns_ResolverConfgurationImpl
* Method: localDomain0
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL
Java_sun_net_dns_ResolverConfigurationImpl_localDomain0(JNIEnv *env, jclass cls)
{
/*
* On Solaris the LOCALDOMAIN environment variable has absolute
* priority.
*/
#ifdef __solaris__
{
char *cp = getenv("LOCALDOMAIN");
if (cp != NULL) {
jstring s = (*env)->NewStringUTF(env, cp);
return s;
}
}
#endif
return (jstring)NULL;
}
/*
* Class: sun_net_dns_ResolverConfgurationImpl
* Method: loadConfig0
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL
Java_sun_net_dns_ResolverConfigurationImpl_fallbackDomain0(JNIEnv *env, jclass cls)
{
char buf[MAXDNAME];
/*
* On Solaris if domain or search directives aren't specified
* in /etc/resolv.conf then sysinfo or gethostname is used to
* determine the domain name.
*
* On Linux if domain or search directives aren't specified
* then gethostname is used.
*/
#ifdef __solaris__
{
int ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf));
if ((ret > 0) && (ret<sizeof(buf))) {
char *cp;
jstring s;
if (buf[0] == '+') {
buf[0] = '.';
}
cp = strchr(buf, '.');
if (cp == NULL) {
s = (*env)->NewStringUTF(env, buf);
} else {
s = (*env)->NewStringUTF(env, cp+1);
}
return s;
}
}
#endif
if (gethostname(buf, sizeof(buf)) == 0) {
char *cp;
/* gethostname doesn't null terminate if insufficient space */
buf[sizeof(buf)-1] = '\0';
cp = strchr(buf, '.');
if (cp != NULL) {
jstring s = (*env)->NewStringUTF(env, cp+1);
return s;
}
}
return (jstring)NULL;
}

View file

@ -0,0 +1,126 @@
/*
* Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#if defined(__solaris__)
#if !defined(PROTO_SDP)
#define PROTO_SDP 257
#endif
#elif defined(__linux__)
#if !defined(AF_INET_SDP)
#define AF_INET_SDP 27
#endif
#endif
#include "jni.h"
#include "jni_util.h"
#include "net_util.h"
#define RESTARTABLE(_cmd, _result) do { \
do { \
_result = _cmd; \
} while((_result == -1) && (errno == EINTR)); \
} while(0)
/**
* Creates a SDP socket.
*/
static int create(JNIEnv* env)
{
int s;
#if defined(__solaris__)
int domain = ipv6_available() ? AF_INET6 : AF_INET;
s = socket(domain, SOCK_STREAM, PROTO_SDP);
#elif defined(__linux__)
/**
* IPv6 not supported by SDP on Linux
*/
if (ipv6_available()) {
JNU_ThrowIOException(env, "IPv6 not supported");
return -1;
}
s = socket(AF_INET_SDP, SOCK_STREAM, 0);
#else
/* not supported on other platforms at this time */
s = -1;
errno = EPROTONOSUPPORT;
#endif
if (s < 0)
JNU_ThrowIOExceptionWithLastError(env, "socket");
return s;
}
/**
* Creates a SDP socket, returning file descriptor referencing the socket.
*/
JNIEXPORT jint JNICALL
Java_sun_net_sdp_SdpSupport_create0(JNIEnv *env, jclass cls)
{
return create(env);
}
/**
* Converts an existing file descriptor, that references an unbound TCP socket,
* to SDP.
*/
JNIEXPORT void JNICALL
Java_sun_net_sdp_SdpSupport_convert0(JNIEnv *env, jclass cls, int fd)
{
int s = create(env);
if (s >= 0) {
socklen_t len;
int arg, res;
struct linger linger;
/* copy socket options that are relevant to SDP */
len = sizeof(arg);
if (getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, &len) == 0)
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, len);
#ifdef SO_REUSEPORT
len = sizeof(arg);
if (getsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char*)&arg, &len) == 0)
setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (char*)&arg, len);
#endif
len = sizeof(arg);
if (getsockopt(fd, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, &len) == 0)
setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, len);
len = sizeof(linger);
if (getsockopt(fd, SOL_SOCKET, SO_LINGER, (void*)&linger, &len) == 0)
setsockopt(s, SOL_SOCKET, SO_LINGER, (char*)&linger, len);
RESTARTABLE(dup2(s, fd), res);
if (res < 0)
JNU_ThrowIOExceptionWithLastError(env, "dup2");
res = close(s);
if (res < 0 && !(*env)->ExceptionOccurred(env))
JNU_ThrowIOExceptionWithLastError(env, "close");
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <jni.h>
#include <string.h>
#include "net_util.h"
JNIEXPORT jboolean JNICALL
Java_java_net_AbstractPlainSocketImpl_isReusePortAvailable0(JNIEnv* env, jclass c1)
{
return (reuseport_available()) ? JNI_TRUE : JNI_FALSE;
}
JNIEXPORT jboolean JNICALL
Java_java_net_AbstractPlainDatagramSocketImpl_isReusePortAvailable0(JNIEnv* env, jclass c1)
{
return (reuseport_available()) ? JNI_TRUE : JNI_FALSE;
}
JNIEXPORT jboolean JNICALL
Java_jdk_net_Sockets_isReusePortAvailable0(JNIEnv* env, jclass c1)
{
return (reuseport_available()) ? JNI_TRUE : JNI_FALSE;
}

View file

@ -0,0 +1,170 @@
/*
* Copyright (c) 1997, 2017, 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 <errno.h>
#include <stdlib.h>
#include <string.h>
#include "jvm.h"
#include "net_util.h"
#include "java_net_SocketInputStream.h"
/*
* SocketInputStream
*/
static jfieldID IO_fd_fdID;
/*
* Class: java_net_SocketInputStream
* Method: init
* Signature: ()V
*/
JNIEXPORT void JNICALL
Java_java_net_SocketInputStream_init(JNIEnv *env, jclass cls) {
IO_fd_fdID = NET_GetFileDescriptorID(env);
}
static int NET_ReadWithTimeout(JNIEnv *env, int fd, char *bufP, int len, long timeout) {
int result = 0;
jlong prevNanoTime = JVM_NanoTime(env, 0);
jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC;
while (nanoTimeout >= NET_NSEC_PER_MSEC) {
result = NET_Timeout(env, fd, nanoTimeout / NET_NSEC_PER_MSEC, prevNanoTime);
if (result <= 0) {
if (result == 0) {
JNU_ThrowByName(env, "java/net/SocketTimeoutException", "Read timed out");
} else if (result == -1) {
if (errno == EBADF) {
JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
} else if (errno == ENOMEM) {
JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
} else {
JNU_ThrowByNameWithMessageAndLastError
(env, "java/net/SocketException", "select/poll failed");
}
}
return -1;
}
result = NET_NonBlockingRead(fd, bufP, len);
if (result == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) {
jlong newtNanoTime = JVM_NanoTime(env, 0);
nanoTimeout -= newtNanoTime - prevNanoTime;
if (nanoTimeout >= NET_NSEC_PER_MSEC) {
prevNanoTime = newtNanoTime;
}
} else {
break;
}
}
return result;
}
/*
* Class: java_net_SocketInputStream
* Method: socketRead0
* Signature: (Ljava/io/FileDescriptor;[BIII)I
*/
JNIEXPORT jint JNICALL
Java_java_net_SocketInputStream_socketRead0(JNIEnv *env, jobject this,
jobject fdObj, jbyteArray data,
jint off, jint len, jint timeout)
{
char BUF[MAX_BUFFER_LEN];
char *bufP;
jint fd, nread;
if (IS_NULL(fdObj)) {
JNU_ThrowByName(env, "java/net/SocketException",
"Socket closed");
return -1;
}
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
if (fd == -1) {
JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
return -1;
}
/*
* If the read is greater than our stack allocated buffer then
* we allocate from the heap (up to a limit)
*/
if (len > MAX_BUFFER_LEN) {
if (len > MAX_HEAP_BUFFER_LEN) {
len = MAX_HEAP_BUFFER_LEN;
}
bufP = (char *)malloc((size_t)len);
if (bufP == NULL) {
bufP = BUF;
len = MAX_BUFFER_LEN;
}
} else {
bufP = BUF;
}
if (timeout) {
nread = NET_ReadWithTimeout(env, fd, bufP, len, timeout);
if ((*env)->ExceptionCheck(env)) {
if (bufP != BUF) {
free(bufP);
}
return nread;
}
} else {
nread = NET_Read(fd, bufP, len);
}
if (nread <= 0) {
if (nread < 0) {
switch (errno) {
case ECONNRESET:
case EPIPE:
JNU_ThrowByName(env, "sun/net/ConnectionResetException",
"Connection reset");
break;
case EBADF:
JNU_ThrowByName(env, "java/net/SocketException",
"Socket closed");
break;
case EINTR:
JNU_ThrowByName(env, "java/io/InterruptedIOException",
"Operation interrupted");
break;
default:
JNU_ThrowByNameWithMessageAndLastError
(env, "java/net/SocketException", "Read failed");
}
}
} else {
(*env)->SetByteArrayRegion(env, data, off, nread, (jbyte *)bufP);
}
if (bufP != BUF) {
free(bufP);
}
return nread;
}

View file

@ -0,0 +1,131 @@
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "net_util.h"
#include "java_net_SocketOutputStream.h"
#define min(a, b) ((a) < (b) ? (a) : (b))
/*
* SocketOutputStream
*/
static jfieldID IO_fd_fdID;
/*
* Class: java_net_SocketOutputStream
* Method: init
* Signature: ()V
*/
JNIEXPORT void JNICALL
Java_java_net_SocketOutputStream_init(JNIEnv *env, jclass cls) {
IO_fd_fdID = NET_GetFileDescriptorID(env);
}
/*
* Class: java_net_SocketOutputStream
* Method: socketWrite0
* Signature: (Ljava/io/FileDescriptor;[BII)V
*/
JNIEXPORT void JNICALL
Java_java_net_SocketOutputStream_socketWrite0(JNIEnv *env, jobject this,
jobject fdObj,
jbyteArray data,
jint off, jint len) {
char *bufP;
char BUF[MAX_BUFFER_LEN];
int buflen;
int fd;
if (IS_NULL(fdObj)) {
JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
return;
} else {
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
/* Bug 4086704 - If the Socket associated with this file descriptor
* was closed (sysCloseFD), the file descriptor is set to -1.
*/
if (fd == -1) {
JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
return;
}
}
if (len <= MAX_BUFFER_LEN) {
bufP = BUF;
buflen = MAX_BUFFER_LEN;
} else {
buflen = min(MAX_HEAP_BUFFER_LEN, len);
bufP = (char *)malloc((size_t)buflen);
/* if heap exhausted resort to stack buffer */
if (bufP == NULL) {
bufP = BUF;
buflen = MAX_BUFFER_LEN;
}
}
while(len > 0) {
int loff = 0;
int chunkLen = min(buflen, len);
int llen = chunkLen;
(*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP);
if ((*env)->ExceptionCheck(env)) {
break;
} else {
while(llen > 0) {
int n = NET_Send(fd, bufP + loff, llen, 0);
if (n > 0) {
llen -= n;
loff += n;
continue;
}
if (errno == ECONNRESET) {
JNU_ThrowByName(env, "sun/net/ConnectionResetException",
"Connection reset");
} else {
JNU_ThrowByNameWithMessageAndLastError
(env, "java/net/SocketException", "Write failed");
}
if (bufP != BUF) {
free(bufP);
}
return;
}
len -= chunkLen;
off += chunkLen;
}
}
if (bufP != BUF) {
free(bufP);
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,108 @@
/*
* Copyright (c) 1997, 2017, 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.
*/
#ifndef NET_UTILS_MD_H
#define NET_UTILS_MD_H
#include <netdb.h>
#include <poll.h>
#include <sys/socket.h>
/************************************************************************
* Macros and constants
*/
#define NET_NSEC_PER_MSEC 1000000
#define NET_NSEC_PER_SEC 1000000000
#define NET_NSEC_PER_USEC 1000
/* Defines SO_REUSEPORT */
#ifndef SO_REUSEPORT
#ifdef __linux__
#define SO_REUSEPORT 15
#elif __solaris__
#define SO_REUSEPORT 0x100e
#elif defined(AIX) || defined(MACOSX)
#define SO_REUSEPORT 0x0200
#else
#define SO_REUSEPORT 0
#endif
#endif
/*
* On 64-bit JDKs we use a much larger stack and heap buffer.
*/
#ifdef _LP64
#define MAX_BUFFER_LEN 65536
#define MAX_HEAP_BUFFER_LEN 131072
#else
#define MAX_BUFFER_LEN 8192
#define MAX_HEAP_BUFFER_LEN 65536
#endif
typedef union {
struct sockaddr sa;
struct sockaddr_in sa4;
struct sockaddr_in6 sa6;
} SOCKETADDRESS;
/************************************************************************
* Functions
*/
int NET_Timeout(JNIEnv *env, int s, long timeout, jlong nanoTimeStamp);
int NET_Read(int s, void* buf, size_t len);
int NET_NonBlockingRead(int s, void* buf, size_t len);
int NET_RecvFrom(int s, void *buf, int len, unsigned int flags,
struct sockaddr *from, socklen_t *fromlen);
int NET_ReadV(int s, const struct iovec * vector, int count);
int NET_Send(int s, void *msg, int len, unsigned int flags);
int NET_SendTo(int s, const void *msg, int len, unsigned int
flags, const struct sockaddr *to, int tolen);
int NET_Writev(int s, const struct iovec * vector, int count);
int NET_Connect(int s, struct sockaddr *addr, int addrlen);
int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen);
int NET_SocketClose(int s);
int NET_Dup2(int oldfd, int newfd);
int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout);
int NET_SocketAvailable(int s, jint *pbytes);
void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env,
const char* hostname,
int gai_error);
void NET_ThrowByNameWithLastError(JNIEnv *env, const char *name,
const char *defaultDetail);
void NET_SetTrafficClass(SOCKETADDRESS *sa, int trafficClass);
#ifdef __linux__
int kernelIsV24();
int getDefaultIPv6Interface(struct in6_addr *target_addr);
#endif
#ifdef __solaris__
int net_getParam(char *driver, char *param);
#endif
#endif /* NET_UTILS_MD_H */

View file

@ -0,0 +1,123 @@
/*
* Copyright (c) 2013, 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#if defined(_ALLBSD_SOURCE)
#include <sys/sysctl.h>
#endif
#include "jni.h"
#include "net_util.h"
#include "sun_net_PortConfig.h"
#ifdef __cplusplus
extern "C" {
#endif
struct portrange {
int lower;
int higher;
};
static int getPortRange(struct portrange *range)
{
#ifdef __linux__
{
FILE *f;
int ret;
f = fopen("/proc/sys/net/ipv4/ip_local_port_range", "r");
if (f != NULL) {
ret = fscanf(f, "%d %d", &range->lower, &range->higher);
fclose(f);
return ret == 2 ? 0 : -1;
}
return -1;
}
#elif defined(__solaris__)
{
range->higher = net_getParam("/dev/tcp", "tcp_largest_anon_port");
range->lower = net_getParam("/dev/tcp", "tcp_smallest_anon_port");
return 0;
}
#elif defined(_ALLBSD_SOURCE)
{
int ret;
size_t size = sizeof(range->lower);
ret = sysctlbyname(
"net.inet.ip.portrange.first", &range->lower, &size, 0, 0
);
if (ret == -1) {
return -1;
}
size = sizeof(range->higher);
ret = sysctlbyname(
"net.inet.ip.portrange.last", &range->higher, &size, 0, 0
);
return ret;
}
#else
return -1;
#endif
}
/*
* Class: sun_net_PortConfig
* Method: getLower0
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_sun_net_PortConfig_getLower0
(JNIEnv *env, jclass clazz)
{
struct portrange range;
if (getPortRange(&range) < 0) {
return -1;
}
return range.lower;
}
/*
* Class: sun_net_PortConfig
* Method: getUpper0
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_sun_net_PortConfig_getUpper0
(JNIEnv *env, jclass clazz)
{
struct portrange range;
if (getPortRange(&range) < 0) {
return -1;
}
return range.higher;
}
#ifdef __cplusplus
}
#endif