Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/native/sun/net/spi/DefaultProxySelector.c
32288 views
/*1* Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include "jni.h"26#include "jni_util.h"27#include "jvm.h"28#include "jvm_md.h"29#include "jlong.h"30#include "sun_net_spi_DefaultProxySelector.h"31#include <dlfcn.h>32#include <stdio.h>33#include <stdlib.h>34#if defined(__linux__) || defined(_ALLBSD_SOURCE)35#include <string.h>36#else37#include <strings.h>38#endif3940/**41* These functions are used by the sun.net.spi.DefaultProxySelector class42* to access some platform specific settings.43* This is the Solaris/Linux Gnome 2.x code using the GConf-2 library.44* Everything is loaded dynamically so no hard link with any library exists.45* The GConf-2 settings used are:46* - /system/http_proxy/use_http_proxy boolean47* - /system/http_proxy/use_authentcation boolean48* - /system/http_proxy/use_same_proxy boolean49* - /system/http_proxy/host string50* - /system/http_proxy/authentication_user string51* - /system/http_proxy/authentication_password string52* - /system/http_proxy/port int53* - /system/proxy/socks_host string54* - /system/proxy/mode string55* - /system/proxy/ftp_host string56* - /system/proxy/secure_host string57* - /system/proxy/socks_port int58* - /system/proxy/ftp_port int59* - /system/proxy/secure_port int60* - /system/proxy/no_proxy_for list61* - /system/proxy/gopher_host string62* - /system/proxy/gopher_port int63*64* The following keys are not used in the new gnome 365* - /system/http_proxy/use_http_proxy66* - /system/http_proxy/use_same_proxy67*/68typedef void* gconf_client_get_default_func();69typedef char* gconf_client_get_string_func(void *, char *, void**);70typedef int gconf_client_get_int_func(void*, char *, void**);71typedef int gconf_client_get_bool_func(void*, char *, void**);72typedef int gconf_init_func(int, char**, void**);73typedef void g_type_init_func ();74gconf_client_get_default_func* my_get_default_func = NULL;75gconf_client_get_string_func* my_get_string_func = NULL;76gconf_client_get_int_func* my_get_int_func = NULL;77gconf_client_get_bool_func* my_get_bool_func = NULL;78gconf_init_func* my_gconf_init_func = NULL;79g_type_init_func* my_g_type_init_func = NULL;808182/*83* GProxyResolver provides synchronous and asynchronous network84* proxy resolution. It is based on GSettings, which is the standard85* of Gnome 3, to get system settings.86*87* In the current implementation, GProxyResolver has a higher priority88* than the old GConf. And we only resolve the proxy synchronously. In89* the future, we can also do the asynchronous network proxy resolution90* if necessary.91*92*/93typedef struct _GProxyResolver GProxyResolver;94typedef struct _GSocketConnectable GSocketConnectable;95typedef struct GError GError;96typedef GProxyResolver* g_proxy_resolver_get_default_func();97typedef char** g_proxy_resolver_lookup_func();98typedef GSocketConnectable* g_network_address_parse_uri_func();99typedef const char* g_network_address_get_hostname_func();100typedef unsigned short g_network_address_get_port_func();101typedef void g_strfreev_func();102103static g_proxy_resolver_get_default_func* g_proxy_resolver_get_default = NULL;104static g_proxy_resolver_lookup_func* g_proxy_resolver_lookup = NULL;105static g_network_address_parse_uri_func* g_network_address_parse_uri = NULL;106static g_network_address_get_hostname_func* g_network_address_get_hostname = NULL;107static g_network_address_get_port_func* g_network_address_get_port = NULL;108static g_strfreev_func* g_strfreev = NULL;109110111static jclass proxy_class;112static jclass isaddr_class;113static jclass ptype_class;114static jmethodID isaddr_createUnresolvedID;115static jmethodID proxy_ctrID;116static jfieldID pr_no_proxyID;117static jfieldID ptype_httpID;118static jfieldID ptype_socksID;119120121static void* gconf_client = NULL;122123static int use_gproxyResolver = 0;124static int use_gconf = 0;125126#define CHECK_NULL(X) { if ((X) == NULL) fprintf (stderr,"JNI errror at line %d\n", __LINE__); }127128129static int initGConf() {130/**131* Let's try to load GConf-2 library132*/133if (dlopen(JNI_LIB_NAME("gconf-2"), RTLD_GLOBAL | RTLD_LAZY) != NULL ||134dlopen(VERSIONED_JNI_LIB_NAME("gconf-2", "4"),135RTLD_GLOBAL | RTLD_LAZY) != NULL)136{137/*138* Now let's get pointer to the functions we need.139*/140my_g_type_init_func =141(g_type_init_func*)dlsym(RTLD_DEFAULT, "g_type_init");142my_get_default_func =143(gconf_client_get_default_func*)dlsym(RTLD_DEFAULT,144"gconf_client_get_default");145146if (my_g_type_init_func != NULL && my_get_default_func != NULL) {147/**148* Try to connect to GConf.149*/150(*my_g_type_init_func)();151gconf_client = (*my_get_default_func)();152if (gconf_client != NULL) {153my_get_string_func =154(gconf_client_get_string_func*)dlsym(RTLD_DEFAULT,155"gconf_client_get_string");156my_get_int_func =157(gconf_client_get_int_func*)dlsym(RTLD_DEFAULT,158"gconf_client_get_int");159my_get_bool_func =160(gconf_client_get_bool_func*)dlsym(RTLD_DEFAULT,161"gconf_client_get_bool");162if (my_get_int_func != NULL && my_get_string_func != NULL &&163my_get_bool_func != NULL)164{165/**166* We did get all we need. Let's enable the System Proxy Settings.167*/168return 1;169}170}171}172}173return 0;174}175176static jobject getProxyByGConf(JNIEnv *env, const char* cproto,177const char* chost)178{179char *phost = NULL;180char *mode = NULL;181int pport = 0;182int use_proxy = 0;183int use_same_proxy = 0;184jobject isa = NULL;185jobject proxy = NULL;186jobject type_proxy = NULL;187188// We only check manual proxy configurations189mode = (*my_get_string_func)(gconf_client, "/system/proxy/mode", NULL);190if (mode && !strcasecmp(mode, "manual")) {191/*192* Even though /system/http_proxy/use_same_proxy is no longer used,193* its value is set to false in gnome 3. So it is not harmful to check194* it first in case jdk is used with an old gnome.195*/196use_same_proxy = (*my_get_bool_func)(gconf_client, "/system/http_proxy/use_same_proxy", NULL);197if (use_same_proxy) {198phost = (*my_get_string_func)(gconf_client, "/system/http_proxy/host", NULL);199pport = (*my_get_int_func)(gconf_client, "/system/http_proxy/port", NULL);200use_proxy = (phost != NULL && pport != 0);201if (use_proxy)202type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_httpID);203}204205if (!use_proxy) {206/**207* HTTP:208* /system/http_proxy/use_http_proxy (boolean) - it's no longer used209* /system/http_proxy/host (string)210* /system/http_proxy/port (integer)211*/212if (strcasecmp(cproto, "http") == 0) {213phost = (*my_get_string_func)(gconf_client, "/system/http_proxy/host", NULL);214pport = (*my_get_int_func)(gconf_client, "/system/http_proxy/port", NULL);215use_proxy = (phost != NULL && pport != 0);216if (use_proxy)217type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_httpID);218}219220/**221* HTTPS:222* /system/proxy/mode (string) [ "manual" means use proxy settings ]223* /system/proxy/secure_host (string)224* /system/proxy/secure_port (integer)225*/226if (strcasecmp(cproto, "https") == 0) {227phost = (*my_get_string_func)(gconf_client, "/system/proxy/secure_host", NULL);228pport = (*my_get_int_func)(gconf_client, "/system/proxy/secure_port", NULL);229use_proxy = (phost != NULL && pport != 0);230if (use_proxy)231type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_httpID);232}233234/**235* FTP:236* /system/proxy/mode (string) [ "manual" means use proxy settings ]237* /system/proxy/ftp_host (string)238* /system/proxy/ftp_port (integer)239*/240if (strcasecmp(cproto, "ftp") == 0) {241phost = (*my_get_string_func)(gconf_client, "/system/proxy/ftp_host", NULL);242pport = (*my_get_int_func)(gconf_client, "/system/proxy/ftp_port", NULL);243use_proxy = (phost != NULL && pport != 0);244if (use_proxy)245type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_httpID);246}247248/**249* GOPHER:250* /system/proxy/mode (string) [ "manual" means use proxy settings ]251* /system/proxy/gopher_host (string)252* /system/proxy/gopher_port (integer)253*/254if (strcasecmp(cproto, "gopher") == 0) {255phost = (*my_get_string_func)(gconf_client, "/system/proxy/gopher_host", NULL);256pport = (*my_get_int_func)(gconf_client, "/system/proxy/gopher_port", NULL);257use_proxy = (phost != NULL && pport != 0);258if (use_proxy)259type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_httpID);260}261262/**263* SOCKS:264* /system/proxy/mode (string) [ "manual" means use proxy settings ]265* /system/proxy/socks_host (string)266* /system/proxy/socks_port (integer)267*/268if (strcasecmp(cproto, "socks") == 0) {269phost = (*my_get_string_func)(gconf_client, "/system/proxy/socks_host", NULL);270pport = (*my_get_int_func)(gconf_client, "/system/proxy/socks_port", NULL);271use_proxy = (phost != NULL && pport != 0);272if (use_proxy)273type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_socksID);274}275}276}277278if (use_proxy) {279jstring jhost;280char *noproxyfor;281char *s;282283/**284* check for the exclude list (aka "No Proxy For" list).285* It's a list of comma separated suffixes (e.g. domain name).286*/287noproxyfor = (*my_get_string_func)(gconf_client, "/system/proxy/no_proxy_for", NULL);288if (noproxyfor != NULL) {289char *tmpbuf[512];290s = strtok_r(noproxyfor, ", ", tmpbuf);291292while (s != NULL && strlen(s) <= strlen(chost)) {293if (strcasecmp(chost+(strlen(chost) - strlen(s)), s) == 0) {294/**295* the URL host name matches with one of the sufixes,296* therefore we have to use a direct connection.297*/298use_proxy = 0;299break;300}301s = strtok_r(NULL, ", ", tmpbuf);302}303}304if (use_proxy) {305CHECK_NULL(type_proxy);306jhost = (*env)->NewStringUTF(env, phost);307isa = (*env)->CallStaticObjectMethod(env, isaddr_class, isaddr_createUnresolvedID, jhost, pport);308proxy = (*env)->NewObject(env, proxy_class, proxy_ctrID, type_proxy, isa);309}310}311312return proxy;313}314315static int initGProxyResolver() {316void *gio_handle;317318gio_handle = dlopen("libgio-2.0.so", RTLD_LAZY);319if (!gio_handle) {320gio_handle = dlopen("libgio-2.0.so.0", RTLD_LAZY);321if (!gio_handle) {322return 0;323}324}325326my_g_type_init_func = (g_type_init_func*)dlsym(gio_handle, "g_type_init");327328g_proxy_resolver_get_default =329(g_proxy_resolver_get_default_func*)dlsym(gio_handle,330"g_proxy_resolver_get_default");331332g_proxy_resolver_lookup =333(g_proxy_resolver_lookup_func*)dlsym(gio_handle,334"g_proxy_resolver_lookup");335336g_network_address_parse_uri =337(g_network_address_parse_uri_func*)dlsym(gio_handle,338"g_network_address_parse_uri");339340g_network_address_get_hostname =341(g_network_address_get_hostname_func*)dlsym(gio_handle,342"g_network_address_get_hostname");343344g_network_address_get_port =345(g_network_address_get_port_func*)dlsym(gio_handle,346"g_network_address_get_port");347348g_strfreev = (g_strfreev_func*)dlsym(gio_handle, "g_strfreev");349350if (!my_g_type_init_func ||351!g_proxy_resolver_get_default ||352!g_proxy_resolver_lookup ||353!g_network_address_parse_uri ||354!g_network_address_get_hostname ||355!g_network_address_get_port ||356!g_strfreev)357{358dlclose(gio_handle);359return 0;360}361362(*my_g_type_init_func)();363return 1;364}365366static jobject getProxyByGProxyResolver(JNIEnv *env, const char* cproto,367const char* chost)368{369GProxyResolver* resolver = NULL;370char** proxies = NULL;371GError *error = NULL;372373size_t protoLen = 0;374size_t hostLen = 0;375char* uri = NULL;376377jobject objProxy = NULL;378379resolver = (*g_proxy_resolver_get_default)();380if (resolver == NULL) {381return NULL;382}383384// Construct the uri, cproto + "://" + chost385protoLen = strlen(cproto);386hostLen = strlen(chost);387uri = malloc(protoLen + hostLen + 4);388if (!uri) {389// Out of memory390return NULL;391}392memcpy(uri, cproto, protoLen);393memcpy(uri + protoLen, "://", 3);394memcpy(uri + protoLen + 3, chost, hostLen + 1);395396/*397* Looks into the system proxy configuration to determine what proxy,398* if any, to use to connect to uri. The returned proxy URIs are of399* the form <protocol>://[user[:password]@]host:port or direct://,400* where <protocol> could be http, rtsp, socks or other proxying protocol.401* direct:// is used when no proxy is needed.402*/403proxies = (*g_proxy_resolver_lookup)(resolver, uri, NULL, &error);404free(uri);405406if (proxies) {407if (!error) {408int i;409for(i = 0; proxies[i] && !objProxy; i++) {410if (strcmp(proxies[i], "direct://")) {411GSocketConnectable* conn =412(*g_network_address_parse_uri)(proxies[i], 0,413&error);414if (conn && !error) {415const char* phost = NULL;416unsigned short pport = 0;417phost = (*g_network_address_get_hostname)(conn);418pport = (*g_network_address_get_port)(conn);419if (phost && pport > 0) {420jobject type_proxy = NULL;421jstring jhost = NULL;422jobject isa = NULL;423jfieldID ptype_ID = ptype_httpID;424if (!strncmp(proxies[i], "socks", 5)) {425ptype_ID = ptype_socksID;426}427428type_proxy = (*env)->GetStaticObjectField(env,429ptype_class, ptype_ID);430CHECK_NULL(type_proxy);431jhost = (*env)->NewStringUTF(env, phost);432CHECK_NULL(jhost);433isa = (*env)->CallStaticObjectMethod(env,434isaddr_class, isaddr_createUnresolvedID,435jhost, pport);436CHECK_NULL(isa);437objProxy = (*env)->NewObject(env, proxy_class,438proxy_ctrID, type_proxy, isa);439}440}441}442}443}444(*g_strfreev)(proxies);445}446447return objProxy;448}449450static void initJavaClass(JNIEnv *env) {451jclass cls = NULL;452CHECK_NULL(cls = (*env)->FindClass(env,"java/net/Proxy"));453proxy_class = (*env)->NewGlobalRef(env, cls);454CHECK_NULL(cls = (*env)->FindClass(env,"java/net/Proxy$Type"));455ptype_class = (*env)->NewGlobalRef(env, cls);456CHECK_NULL(cls = (*env)->FindClass(env, "java/net/InetSocketAddress"));457isaddr_class = (*env)->NewGlobalRef(env, cls);458proxy_ctrID = (*env)->GetMethodID(env, proxy_class, "<init>",459"(Ljava/net/Proxy$Type;Ljava/net/SocketAddress;)V");460CHECK_NULL(proxy_ctrID);461pr_no_proxyID = (*env)->GetStaticFieldID(env, proxy_class, "NO_PROXY",462"Ljava/net/Proxy;");463CHECK_NULL(pr_no_proxyID);464ptype_httpID = (*env)->GetStaticFieldID(env, ptype_class, "HTTP",465"Ljava/net/Proxy$Type;");466CHECK_NULL(ptype_httpID);467ptype_socksID = (*env)->GetStaticFieldID(env, ptype_class, "SOCKS",468"Ljava/net/Proxy$Type;");469CHECK_NULL(ptype_socksID);470isaddr_createUnresolvedID = (*env)->GetStaticMethodID(env, isaddr_class,471"createUnresolved",472"(Ljava/lang/String;I)Ljava/net/InetSocketAddress;");473CHECK_NULL(isaddr_createUnresolvedID);474}475476477/*478* Class: sun_net_spi_DefaultProxySelector479* Method: init480* Signature: ()Z481*/482JNIEXPORT jboolean JNICALL483Java_sun_net_spi_DefaultProxySelector_init(JNIEnv *env, jclass clazz) {484use_gproxyResolver = initGProxyResolver();485if (!use_gproxyResolver)486use_gconf = initGConf();487488if (use_gproxyResolver || use_gconf) {489initJavaClass(env);490return JNI_TRUE;491} else492return JNI_FALSE;493}494495/*496* Class: sun_net_spi_DefaultProxySelector497* Method: getSystemProxy498* Signature: ([Ljava/lang/String;Ljava/lang/String;)Ljava/net/Proxy;499*/500JNIEXPORT jobject JNICALL501Java_sun_net_spi_DefaultProxySelector_getSystemProxy(JNIEnv *env,502jobject this,503jstring proto,504jstring host)505{506const char* cproto;507const char* chost;508509jboolean isProtoCopy;510jboolean isHostCopy;511512jobject proxy = NULL;513514cproto = (*env)->GetStringUTFChars(env, proto, &isProtoCopy);515516if (cproto != NULL && (use_gproxyResolver || use_gconf)) {517chost = (*env)->GetStringUTFChars(env, host, &isHostCopy);518if (chost != NULL) {519if (use_gproxyResolver)520proxy = getProxyByGProxyResolver(env, cproto, chost);521else if (use_gconf)522proxy = getProxyByGConf(env, cproto, chost);523524if (isHostCopy == JNI_TRUE)525(*env)->ReleaseStringUTFChars(env, host, chost);526}527if (isProtoCopy == JNI_TRUE)528(*env)->ReleaseStringUTFChars(env, proto, cproto);529}530531if (proxy == NULL) {532CHECK_NULL(proxy = (*env)->GetStaticObjectField(env, proxy_class,533pr_no_proxyID));534}535return proxy;536}537538539540