Path: blob/master/src/java.base/unix/native/libnet/DefaultProxySelector.c
41119 views
/*1* Copyright (c) 2004, 2019, 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 <dlfcn.h>26#include <stdio.h>27#include <stdlib.h>28#include <string.h>2930#include "jni.h"31#include "jni_util.h"32#include "jvm.h"33#include "jvm_md.h"3435#include "proxy_util.h"3637#include "sun_net_spi_DefaultProxySelector.h"383940/**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*62* The following keys are not used in the new gnome 363* - /system/http_proxy/use_http_proxy64* - /system/http_proxy/use_same_proxy65*/66typedef void* gconf_client_get_default_func();67typedef char* gconf_client_get_string_func(void *, char *, void**);68typedef int gconf_client_get_int_func(void*, char *, void**);69typedef int gconf_client_get_bool_func(void*, char *, void**);70typedef int gconf_init_func(int, char**, void**);71typedef void g_type_init_func ();72gconf_client_get_default_func* my_get_default_func = NULL;73gconf_client_get_string_func* my_get_string_func = NULL;74gconf_client_get_int_func* my_get_int_func = NULL;75gconf_client_get_bool_func* my_get_bool_func = NULL;76g_type_init_func* my_g_type_init_func = NULL;777879/*80* GProxyResolver provides synchronous and asynchronous network81* proxy resolution. It is based on GSettings, which is the standard82* of Gnome 3, to get system settings.83*84* In the current implementation, GProxyResolver has a higher priority85* than the old GConf. And we only resolve the proxy synchronously. In86* the future, we can also do the asynchronous network proxy resolution87* if necessary.88*89*/90typedef struct _GProxyResolver GProxyResolver;91typedef struct _GSocketConnectable GSocketConnectable;92typedef struct GError GError;93typedef GProxyResolver* g_proxy_resolver_get_default_func();94typedef char** g_proxy_resolver_lookup_func();95typedef GSocketConnectable* g_network_address_parse_uri_func();96typedef const char* g_network_address_get_hostname_func();97typedef unsigned short g_network_address_get_port_func();98typedef void g_strfreev_func();99100static g_proxy_resolver_get_default_func* g_proxy_resolver_get_default = NULL;101static g_proxy_resolver_lookup_func* g_proxy_resolver_lookup = NULL;102static g_network_address_parse_uri_func* g_network_address_parse_uri = NULL;103static g_network_address_get_hostname_func* g_network_address_get_hostname = NULL;104static g_network_address_get_port_func* g_network_address_get_port = NULL;105static g_strfreev_func* g_strfreev = NULL;106107static void* gconf_client = NULL;108static int use_gproxyResolver = 0;109static int use_gconf = 0;110111112static int initGConf() {113/**114* Let's try to load GConf-2 library115*/116if (dlopen(JNI_LIB_NAME("gconf-2"), RTLD_GLOBAL | RTLD_LAZY) != NULL ||117dlopen(VERSIONED_JNI_LIB_NAME("gconf-2", "4"),118RTLD_GLOBAL | RTLD_LAZY) != NULL)119{120/*121* Now let's get pointer to the functions we need.122*/123my_g_type_init_func =124(g_type_init_func*)dlsym(RTLD_DEFAULT, "g_type_init");125my_get_default_func =126(gconf_client_get_default_func*)dlsym(RTLD_DEFAULT,127"gconf_client_get_default");128129if (my_g_type_init_func != NULL && my_get_default_func != NULL) {130/**131* Try to connect to GConf.132*/133(*my_g_type_init_func)();134gconf_client = (*my_get_default_func)();135if (gconf_client != NULL) {136my_get_string_func =137(gconf_client_get_string_func*)dlsym(RTLD_DEFAULT,138"gconf_client_get_string");139my_get_int_func =140(gconf_client_get_int_func*)dlsym(RTLD_DEFAULT,141"gconf_client_get_int");142my_get_bool_func =143(gconf_client_get_bool_func*)dlsym(RTLD_DEFAULT,144"gconf_client_get_bool");145if (my_get_int_func != NULL && my_get_string_func != NULL &&146my_get_bool_func != NULL)147{148/**149* We did get all we need. Let's enable the System Proxy Settings.150*/151return 1;152}153}154}155}156return 0;157}158159static jobjectArray getProxyByGConf(JNIEnv *env, const char* cproto,160const char* chost)161{162char *phost = NULL;163char *mode = NULL;164int pport = 0;165int use_proxy = 0;166int use_same_proxy = 0;167jobjectArray proxy_array = NULL;168jfieldID ptype_ID = ptype_httpID;169170/* We only check manual proxy configurations */171mode = (*my_get_string_func)(gconf_client, "/system/proxy/mode", NULL);172if (mode && !strcasecmp(mode, "manual")) {173/*174* Even though /system/http_proxy/use_same_proxy is no longer used,175* its value is set to false in gnome 3. So it is not harmful to check176* it first in case jdk is used with an old gnome.177*/178use_same_proxy = (*my_get_bool_func)(gconf_client, "/system/http_proxy/use_same_proxy", NULL);179if (use_same_proxy) {180phost = (*my_get_string_func)(gconf_client, "/system/http_proxy/host", NULL);181pport = (*my_get_int_func)(gconf_client, "/system/http_proxy/port", NULL);182use_proxy = (phost != NULL && pport != 0);183}184185if (!use_proxy) {186/**187* HTTP:188* /system/http_proxy/use_http_proxy (boolean) - it's no longer used189* /system/http_proxy/host (string)190* /system/http_proxy/port (integer)191*/192if (strcasecmp(cproto, "http") == 0) {193phost = (*my_get_string_func)(gconf_client, "/system/http_proxy/host", NULL);194pport = (*my_get_int_func)(gconf_client, "/system/http_proxy/port", NULL);195use_proxy = (phost != NULL && pport != 0);196}197198/**199* HTTPS:200* /system/proxy/mode (string) [ "manual" means use proxy settings ]201* /system/proxy/secure_host (string)202* /system/proxy/secure_port (integer)203*/204if (strcasecmp(cproto, "https") == 0) {205phost = (*my_get_string_func)(gconf_client, "/system/proxy/secure_host", NULL);206pport = (*my_get_int_func)(gconf_client, "/system/proxy/secure_port", NULL);207use_proxy = (phost != NULL && pport != 0);208}209210/**211* FTP:212* /system/proxy/mode (string) [ "manual" means use proxy settings ]213* /system/proxy/ftp_host (string)214* /system/proxy/ftp_port (integer)215*/216if (strcasecmp(cproto, "ftp") == 0) {217phost = (*my_get_string_func)(gconf_client, "/system/proxy/ftp_host", NULL);218pport = (*my_get_int_func)(gconf_client, "/system/proxy/ftp_port", NULL);219use_proxy = (phost != NULL && pport != 0);220}221222/**223* SOCKS:224* /system/proxy/mode (string) [ "manual" means use proxy settings ]225* /system/proxy/socks_host (string)226* /system/proxy/socks_port (integer)227*/228if (strcasecmp(cproto, "socks") == 0) {229phost = (*my_get_string_func)(gconf_client, "/system/proxy/socks_host", NULL);230pport = (*my_get_int_func)(gconf_client, "/system/proxy/socks_port", NULL);231use_proxy = (phost != NULL && pport != 0);232if (use_proxy)233ptype_ID = ptype_socksID;234}235}236}237238if (use_proxy) {239jstring jhost;240char *noproxyfor;241char *s;242243/**244* Check for the exclude list (aka "No Proxy For" list).245* It's a list of comma separated suffixes (e.g. domain name).246*/247noproxyfor = (*my_get_string_func)(gconf_client, "/system/proxy/no_proxy_for", NULL);248if (noproxyfor != NULL) {249char *tmpbuf[512];250s = strtok_r(noproxyfor, ", ", tmpbuf);251252while (s != NULL && strlen(s) <= strlen(chost)) {253if (strcasecmp(chost+(strlen(chost) - strlen(s)), s) == 0) {254/**255* the URL host name matches with one of the sufixes,256* therefore we have to use a direct connection.257*/258use_proxy = 0;259break;260}261s = strtok_r(NULL, ", ", tmpbuf);262}263}264if (use_proxy) {265jobject proxy = NULL;266/* create a proxy array with one element. */267proxy_array = (*env)->NewObjectArray(env, 1, proxy_class, NULL);268if (proxy_array == NULL || (*env)->ExceptionCheck(env)) {269return NULL;270}271proxy = createProxy(env, ptype_ID, phost, pport);272if (proxy == NULL || (*env)->ExceptionCheck(env)) {273return NULL;274}275(*env)->SetObjectArrayElement(env, proxy_array, 0, proxy);276if ((*env)->ExceptionCheck(env)) {277return NULL;278}279}280}281282return proxy_array;283}284285static int initGProxyResolver() {286void *gio_handle;287288gio_handle = dlopen("libgio-2.0.so", RTLD_LAZY);289if (!gio_handle) {290gio_handle = dlopen("libgio-2.0.so.0", RTLD_LAZY);291if (!gio_handle) {292return 0;293}294}295296my_g_type_init_func = (g_type_init_func*)dlsym(gio_handle, "g_type_init");297298g_proxy_resolver_get_default =299(g_proxy_resolver_get_default_func*)dlsym(gio_handle,300"g_proxy_resolver_get_default");301302g_proxy_resolver_lookup =303(g_proxy_resolver_lookup_func*)dlsym(gio_handle,304"g_proxy_resolver_lookup");305306g_network_address_parse_uri =307(g_network_address_parse_uri_func*)dlsym(gio_handle,308"g_network_address_parse_uri");309310g_network_address_get_hostname =311(g_network_address_get_hostname_func*)dlsym(gio_handle,312"g_network_address_get_hostname");313314g_network_address_get_port =315(g_network_address_get_port_func*)dlsym(gio_handle,316"g_network_address_get_port");317318g_strfreev = (g_strfreev_func*)dlsym(gio_handle, "g_strfreev");319320if (!my_g_type_init_func ||321!g_proxy_resolver_get_default ||322!g_proxy_resolver_lookup ||323!g_network_address_parse_uri ||324!g_network_address_get_hostname ||325!g_network_address_get_port ||326!g_strfreev)327{328dlclose(gio_handle);329return 0;330}331332(*my_g_type_init_func)();333return 1;334}335336static jobjectArray getProxyByGProxyResolver(JNIEnv *env, const char *cproto,337const char *chost)338{339GProxyResolver* resolver = NULL;340char** proxies = NULL;341GError *error = NULL;342343size_t protoLen = 0;344size_t hostLen = 0;345char* uri = NULL;346347jobjectArray proxy_array = NULL;348349resolver = (*g_proxy_resolver_get_default)();350if (resolver == NULL) {351return NULL;352}353354/* Construct the uri, cproto + "://" + chost */355protoLen = strlen(cproto);356hostLen = strlen(chost);357uri = malloc(protoLen + hostLen + 4);358if (!uri) {359/* Out of memory */360return NULL;361}362memcpy(uri, cproto, protoLen);363memcpy(uri + protoLen, "://", 3);364memcpy(uri + protoLen + 3, chost, hostLen + 1);365366/*367* Looks into the system proxy configuration to determine what proxy,368* if any, to use to connect to uri. The returned proxy URIs are of369* the form <protocol>://[user[:password]@]host:port or direct://,370* where <protocol> could be http, rtsp, socks or other proxying protocol.371* direct:// is used when no proxy is needed.372*/373proxies = (*g_proxy_resolver_lookup)(resolver, uri, NULL, &error);374free(uri);375376if (proxies) {377if (!error) {378int i;379int nr_proxies = 0;380char** p = proxies;381/* count the elements in the null terminated string vector. */382while (*p) {383nr_proxies++;384p++;385}386/* create a proxy array that has to be filled. */387proxy_array = (*env)->NewObjectArray(env, nr_proxies, proxy_class, NULL);388if (proxy_array != NULL && !(*env)->ExceptionCheck(env)) {389for (i = 0; proxies[i]; i++) {390if (strncmp(proxies[i], "direct://", 9)) {391GSocketConnectable* conn =392(*g_network_address_parse_uri)(proxies[i], 0,393&error);394if (conn && !error) {395const char *phost = NULL;396unsigned short pport = 0;397phost = (*g_network_address_get_hostname)(conn);398pport = (*g_network_address_get_port)(conn);399if (phost && pport > 0) {400jobject proxy = NULL;401jfieldID ptype_ID = ptype_httpID;402if (!strncmp(proxies[i], "socks", 5))403ptype_ID = ptype_socksID;404405proxy = createProxy(env, ptype_ID, phost, pport);406if (proxy == NULL || (*env)->ExceptionCheck(env)) {407proxy_array = NULL;408break;409}410(*env)->SetObjectArrayElement(env, proxy_array, i, proxy);411if ((*env)->ExceptionCheck(env)) {412proxy_array = NULL;413break;414}415}416}417} else {418/* direct connection - no proxy */419jobject proxy = (*env)->GetStaticObjectField(env, proxy_class,420pr_no_proxyID);421if (proxy == NULL || (*env)->ExceptionCheck(env)) {422proxy_array = NULL;423break;424}425(*env)->SetObjectArrayElement(env, proxy_array, i, proxy);426if ((*env)->ExceptionCheck(env)) {427proxy_array = NULL;428break;429}430}431}432}433}434(*g_strfreev)(proxies);435}436437return proxy_array;438}439440/*441* Class: sun_net_spi_DefaultProxySelector442* Method: init443* Signature: ()Z444*/445JNIEXPORT jboolean JNICALL446Java_sun_net_spi_DefaultProxySelector_init(JNIEnv *env, jclass clazz) {447use_gproxyResolver = initGProxyResolver();448if (!use_gproxyResolver)449use_gconf = initGConf();450451if (use_gproxyResolver || use_gconf) {452if (initJavaClass(env))453return JNI_TRUE;454}455return JNI_FALSE;456}457458/*459* Class: sun_net_spi_DefaultProxySelector460* Method: getSystemProxies461* Signature: ([Ljava/lang/String;Ljava/lang/String;)[Ljava/net/Proxy;462*/463JNIEXPORT jobjectArray JNICALL464Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv *env,465jobject this,466jstring proto,467jstring host)468{469const char* cproto;470const char* chost;471472jboolean isProtoCopy;473jboolean isHostCopy;474475jobjectArray proxyArray = NULL;476477cproto = (*env)->GetStringUTFChars(env, proto, &isProtoCopy);478479if (cproto != NULL && (use_gproxyResolver || use_gconf)) {480chost = (*env)->GetStringUTFChars(env, host, &isHostCopy);481if (chost != NULL) {482if (use_gproxyResolver)483proxyArray = getProxyByGProxyResolver(env, cproto, chost);484else if (use_gconf)485proxyArray = getProxyByGConf(env, cproto, chost);486if (isHostCopy == JNI_TRUE)487(*env)->ReleaseStringUTFChars(env, host, chost);488}489if (isProtoCopy == JNI_TRUE)490(*env)->ReleaseStringUTFChars(env, proto, cproto);491}492return proxyArray;493}494495496497