mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-21 19:44:41 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
510
src/java.base/unix/native/libnet/DefaultProxySelector.c
Normal file
510
src/java.base/unix/native/libnet/DefaultProxySelector.c
Normal 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;
|
||||
}
|
||||
|
513
src/java.base/unix/native/libnet/Inet4AddressImpl.c
Normal file
513
src/java.base/unix/native/libnet/Inet4AddressImpl.c
Normal 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);
|
||||
}
|
||||
}
|
728
src/java.base/unix/native/libnet/Inet6AddressImpl.c
Normal file
728
src/java.base/unix/native/libnet/Inet6AddressImpl.c
Normal 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);
|
||||
}
|
||||
}
|
46
src/java.base/unix/native/libnet/InetAddressImplFactory.c
Normal file
46
src/java.base/unix/native/libnet/InetAddressImplFactory.c
Normal 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;
|
||||
}
|
||||
}
|
2130
src/java.base/unix/native/libnet/NetworkInterface.c
Normal file
2130
src/java.base/unix/native/libnet/NetworkInterface.c
Normal file
File diff suppressed because it is too large
Load diff
2228
src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c
Normal file
2228
src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c
Normal file
File diff suppressed because it is too large
Load diff
1040
src/java.base/unix/native/libnet/PlainSocketImpl.c
Normal file
1040
src/java.base/unix/native/libnet/PlainSocketImpl.c
Normal file
File diff suppressed because it is too large
Load diff
123
src/java.base/unix/native/libnet/ResolverConfigurationImpl.c
Normal file
123
src/java.base/unix/native/libnet/ResolverConfigurationImpl.c
Normal 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;
|
||||
}
|
126
src/java.base/unix/native/libnet/SdpSupport.c
Normal file
126
src/java.base/unix/native/libnet/SdpSupport.c
Normal 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");
|
||||
}
|
||||
}
|
47
src/java.base/unix/native/libnet/SocketImpl.c
Normal file
47
src/java.base/unix/native/libnet/SocketImpl.c
Normal 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;
|
||||
}
|
170
src/java.base/unix/native/libnet/SocketInputStream.c
Normal file
170
src/java.base/unix/native/libnet/SocketInputStream.c
Normal 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;
|
||||
}
|
131
src/java.base/unix/native/libnet/SocketOutputStream.c
Normal file
131
src/java.base/unix/native/libnet/SocketOutputStream.c
Normal 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);
|
||||
}
|
||||
}
|
1578
src/java.base/unix/native/libnet/net_util_md.c
Normal file
1578
src/java.base/unix/native/libnet/net_util_md.c
Normal file
File diff suppressed because it is too large
Load diff
108
src/java.base/unix/native/libnet/net_util_md.h
Normal file
108
src/java.base/unix/native/libnet/net_util_md.h
Normal 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 */
|
123
src/java.base/unix/native/libnet/portconfig.c
Normal file
123
src/java.base/unix/native/libnet/portconfig.c
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue