src/java.base/unix/native/libnet/DefaultProxySelector.c
changeset 47216 71c04702a3d5
parent 43501 243c346dc905
child 52725 c470f977ade8
child 56230 489867818774
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 #include <dlfcn.h>
       
    27 #include <stdio.h>
       
    28 #include <stdlib.h>
       
    29 #include <string.h>
       
    30 
       
    31 #include "jni.h"
       
    32 #include "jni_util.h"
       
    33 #include "jvm.h"
       
    34 #include "jvm_md.h"
       
    35 
       
    36 #include "proxy_util.h"
       
    37 
       
    38 #include "sun_net_spi_DefaultProxySelector.h"
       
    39 
       
    40 
       
    41 /**
       
    42  * These functions are used by the sun.net.spi.DefaultProxySelector class
       
    43  * to access some platform specific settings.
       
    44  * This is the Solaris/Linux Gnome 2.x code using the GConf-2 library.
       
    45  * Everything is loaded dynamically so no hard link with any library exists.
       
    46  * The GConf-2 settings used are:
       
    47  * - /system/http_proxy/use_http_proxy          boolean
       
    48  * - /system/http_proxy/use_authentcation       boolean
       
    49  * - /system/http_proxy/use_same_proxy          boolean
       
    50  * - /system/http_proxy/host                    string
       
    51  * - /system/http_proxy/authentication_user     string
       
    52  * - /system/http_proxy/authentication_password string
       
    53  * - /system/http_proxy/port                    int
       
    54  * - /system/proxy/socks_host                   string
       
    55  * - /system/proxy/mode                         string
       
    56  * - /system/proxy/ftp_host                     string
       
    57  * - /system/proxy/secure_host                  string
       
    58  * - /system/proxy/socks_port                   int
       
    59  * - /system/proxy/ftp_port                     int
       
    60  * - /system/proxy/secure_port                  int
       
    61  * - /system/proxy/no_proxy_for                 list
       
    62  * - /system/proxy/gopher_host                  string
       
    63  * - /system/proxy/gopher_port                  int
       
    64  *
       
    65  * The following keys are not used in the new gnome 3
       
    66  * - /system/http_proxy/use_http_proxy
       
    67  * - /system/http_proxy/use_same_proxy
       
    68  */
       
    69 typedef void* gconf_client_get_default_func();
       
    70 typedef char* gconf_client_get_string_func(void *, char *, void**);
       
    71 typedef int   gconf_client_get_int_func(void*, char *, void**);
       
    72 typedef int   gconf_client_get_bool_func(void*, char *, void**);
       
    73 typedef int   gconf_init_func(int, char**, void**);
       
    74 typedef void  g_type_init_func ();
       
    75 gconf_client_get_default_func* my_get_default_func = NULL;
       
    76 gconf_client_get_string_func* my_get_string_func = NULL;
       
    77 gconf_client_get_int_func* my_get_int_func = NULL;
       
    78 gconf_client_get_bool_func* my_get_bool_func = NULL;
       
    79 gconf_init_func* my_gconf_init_func = NULL;
       
    80 g_type_init_func* my_g_type_init_func = NULL;
       
    81 
       
    82 
       
    83 /*
       
    84  * GProxyResolver provides synchronous and asynchronous network
       
    85  * proxy resolution. It is based on GSettings, which is the standard
       
    86  * of Gnome 3, to get system settings.
       
    87  *
       
    88  * In the current implementation, GProxyResolver has a higher priority
       
    89  * than the old GConf. And we only resolve the proxy synchronously. In
       
    90  * the future, we can also do the asynchronous network proxy resolution
       
    91  * if necessary.
       
    92  *
       
    93  */
       
    94 typedef struct _GProxyResolver GProxyResolver;
       
    95 typedef struct _GSocketConnectable GSocketConnectable;
       
    96 typedef struct GError GError;
       
    97 typedef GProxyResolver* g_proxy_resolver_get_default_func();
       
    98 typedef char** g_proxy_resolver_lookup_func();
       
    99 typedef GSocketConnectable* g_network_address_parse_uri_func();
       
   100 typedef const char* g_network_address_get_hostname_func();
       
   101 typedef unsigned short g_network_address_get_port_func();
       
   102 typedef void g_strfreev_func();
       
   103 
       
   104 static g_proxy_resolver_get_default_func* g_proxy_resolver_get_default = NULL;
       
   105 static g_proxy_resolver_lookup_func* g_proxy_resolver_lookup = NULL;
       
   106 static g_network_address_parse_uri_func* g_network_address_parse_uri = NULL;
       
   107 static g_network_address_get_hostname_func* g_network_address_get_hostname = NULL;
       
   108 static g_network_address_get_port_func* g_network_address_get_port = NULL;
       
   109 static g_strfreev_func* g_strfreev = NULL;
       
   110 
       
   111 static void* gconf_client = NULL;
       
   112 static int use_gproxyResolver = 0;
       
   113 static int use_gconf = 0;
       
   114 
       
   115 
       
   116 static int initGConf() {
       
   117     /**
       
   118      * Let's try to load GConf-2 library
       
   119      */
       
   120     if (dlopen(JNI_LIB_NAME("gconf-2"), RTLD_GLOBAL | RTLD_LAZY) != NULL ||
       
   121         dlopen(VERSIONED_JNI_LIB_NAME("gconf-2", "4"),
       
   122                RTLD_GLOBAL | RTLD_LAZY) != NULL)
       
   123     {
       
   124         /*
       
   125          * Now let's get pointer to the functions we need.
       
   126          */
       
   127         my_g_type_init_func =
       
   128                 (g_type_init_func*)dlsym(RTLD_DEFAULT, "g_type_init");
       
   129         my_get_default_func =
       
   130                 (gconf_client_get_default_func*)dlsym(RTLD_DEFAULT,
       
   131                         "gconf_client_get_default");
       
   132 
       
   133         if (my_g_type_init_func != NULL && my_get_default_func != NULL) {
       
   134             /**
       
   135              * Try to connect to GConf.
       
   136              */
       
   137             (*my_g_type_init_func)();
       
   138             gconf_client = (*my_get_default_func)();
       
   139             if (gconf_client != NULL) {
       
   140                 my_get_string_func =
       
   141                         (gconf_client_get_string_func*)dlsym(RTLD_DEFAULT,
       
   142                                 "gconf_client_get_string");
       
   143                 my_get_int_func =
       
   144                         (gconf_client_get_int_func*)dlsym(RTLD_DEFAULT,
       
   145                                 "gconf_client_get_int");
       
   146                 my_get_bool_func =
       
   147                         (gconf_client_get_bool_func*)dlsym(RTLD_DEFAULT,
       
   148                                 "gconf_client_get_bool");
       
   149                 if (my_get_int_func != NULL && my_get_string_func != NULL &&
       
   150                         my_get_bool_func != NULL)
       
   151                 {
       
   152                     /**
       
   153                      * We did get all we need. Let's enable the System Proxy Settings.
       
   154                      */
       
   155                     return 1;
       
   156                 }
       
   157             }
       
   158         }
       
   159     }
       
   160     return 0;
       
   161 }
       
   162 
       
   163 static jobjectArray getProxyByGConf(JNIEnv *env, const char* cproto,
       
   164                                     const char* chost)
       
   165 {
       
   166     char *phost = NULL;
       
   167     char *mode = NULL;
       
   168     int pport = 0;
       
   169     int use_proxy = 0;
       
   170     int use_same_proxy = 0;
       
   171     jobjectArray proxy_array = NULL;
       
   172     jfieldID ptype_ID = ptype_httpID;
       
   173 
       
   174     /* We only check manual proxy configurations */
       
   175     mode =  (*my_get_string_func)(gconf_client, "/system/proxy/mode", NULL);
       
   176     if (mode && !strcasecmp(mode, "manual")) {
       
   177         /*
       
   178          * Even though /system/http_proxy/use_same_proxy is no longer used,
       
   179          * its value is set to false in gnome 3. So it is not harmful to check
       
   180          * it first in case jdk is used with an old gnome.
       
   181          */
       
   182         use_same_proxy = (*my_get_bool_func)(gconf_client, "/system/http_proxy/use_same_proxy", NULL);
       
   183         if (use_same_proxy) {
       
   184             phost = (*my_get_string_func)(gconf_client, "/system/http_proxy/host", NULL);
       
   185             pport = (*my_get_int_func)(gconf_client, "/system/http_proxy/port", NULL);
       
   186             use_proxy = (phost != NULL && pport != 0);
       
   187         }
       
   188 
       
   189         if (!use_proxy) {
       
   190             /**
       
   191              * HTTP:
       
   192              * /system/http_proxy/use_http_proxy (boolean) - it's no longer used
       
   193              * /system/http_proxy/host (string)
       
   194              * /system/http_proxy/port (integer)
       
   195              */
       
   196             if (strcasecmp(cproto, "http") == 0) {
       
   197                 phost = (*my_get_string_func)(gconf_client, "/system/http_proxy/host", NULL);
       
   198                 pport = (*my_get_int_func)(gconf_client, "/system/http_proxy/port", NULL);
       
   199                 use_proxy = (phost != NULL && pport != 0);
       
   200             }
       
   201 
       
   202             /**
       
   203              * HTTPS:
       
   204              * /system/proxy/mode (string) [ "manual" means use proxy settings ]
       
   205              * /system/proxy/secure_host (string)
       
   206              * /system/proxy/secure_port (integer)
       
   207              */
       
   208             if (strcasecmp(cproto, "https") == 0) {
       
   209                 phost = (*my_get_string_func)(gconf_client, "/system/proxy/secure_host", NULL);
       
   210                 pport = (*my_get_int_func)(gconf_client, "/system/proxy/secure_port", NULL);
       
   211                 use_proxy = (phost != NULL && pport != 0);
       
   212             }
       
   213 
       
   214             /**
       
   215              * FTP:
       
   216              * /system/proxy/mode (string) [ "manual" means use proxy settings ]
       
   217              * /system/proxy/ftp_host (string)
       
   218              * /system/proxy/ftp_port (integer)
       
   219              */
       
   220             if (strcasecmp(cproto, "ftp") == 0) {
       
   221                 phost = (*my_get_string_func)(gconf_client, "/system/proxy/ftp_host", NULL);
       
   222                 pport = (*my_get_int_func)(gconf_client, "/system/proxy/ftp_port", NULL);
       
   223                 use_proxy = (phost != NULL && pport != 0);
       
   224             }
       
   225 
       
   226             /**
       
   227              * GOPHER:
       
   228              * /system/proxy/mode (string) [ "manual" means use proxy settings ]
       
   229              * /system/proxy/gopher_host (string)
       
   230              * /system/proxy/gopher_port (integer)
       
   231              */
       
   232             if (strcasecmp(cproto, "gopher") == 0) {
       
   233                 phost = (*my_get_string_func)(gconf_client, "/system/proxy/gopher_host", NULL);
       
   234                 pport = (*my_get_int_func)(gconf_client, "/system/proxy/gopher_port", NULL);
       
   235                 use_proxy = (phost != NULL && pport != 0);
       
   236             }
       
   237 
       
   238             /**
       
   239              * SOCKS:
       
   240              * /system/proxy/mode (string) [ "manual" means use proxy settings ]
       
   241              * /system/proxy/socks_host (string)
       
   242              * /system/proxy/socks_port (integer)
       
   243              */
       
   244             if (strcasecmp(cproto, "socks") == 0) {
       
   245                 phost = (*my_get_string_func)(gconf_client, "/system/proxy/socks_host", NULL);
       
   246                 pport = (*my_get_int_func)(gconf_client, "/system/proxy/socks_port", NULL);
       
   247                 use_proxy = (phost != NULL && pport != 0);
       
   248                 if (use_proxy)
       
   249                     ptype_ID = ptype_socksID;
       
   250             }
       
   251         }
       
   252     }
       
   253 
       
   254     if (use_proxy) {
       
   255         jstring jhost;
       
   256         char *noproxyfor;
       
   257         char *s;
       
   258 
       
   259         /**
       
   260          * Check for the exclude list (aka "No Proxy For" list).
       
   261          * It's a list of comma separated suffixes (e.g. domain name).
       
   262          */
       
   263         noproxyfor = (*my_get_string_func)(gconf_client, "/system/proxy/no_proxy_for", NULL);
       
   264         if (noproxyfor != NULL) {
       
   265             char *tmpbuf[512];
       
   266             s = strtok_r(noproxyfor, ", ", tmpbuf);
       
   267 
       
   268             while (s != NULL && strlen(s) <= strlen(chost)) {
       
   269                 if (strcasecmp(chost+(strlen(chost) - strlen(s)), s) == 0) {
       
   270                     /**
       
   271                      * the URL host name matches with one of the sufixes,
       
   272                      * therefore we have to use a direct connection.
       
   273                      */
       
   274                     use_proxy = 0;
       
   275                     break;
       
   276                 }
       
   277                 s = strtok_r(NULL, ", ", tmpbuf);
       
   278             }
       
   279         }
       
   280         if (use_proxy) {
       
   281             jobject proxy = NULL;
       
   282             /* create a proxy array with one element. */
       
   283             proxy_array = (*env)->NewObjectArray(env, 1, proxy_class, NULL);
       
   284             if (proxy_array == NULL || (*env)->ExceptionCheck(env)) {
       
   285                 return NULL;
       
   286             }
       
   287             proxy = createProxy(env, ptype_ID, phost, pport);
       
   288             if (proxy == NULL || (*env)->ExceptionCheck(env)) {
       
   289                 return NULL;
       
   290             }
       
   291             (*env)->SetObjectArrayElement(env, proxy_array, 0, proxy);
       
   292             if ((*env)->ExceptionCheck(env)) {
       
   293                 return NULL;
       
   294             }
       
   295         }
       
   296     }
       
   297 
       
   298     return proxy_array;
       
   299 }
       
   300 
       
   301 static int initGProxyResolver() {
       
   302     void *gio_handle;
       
   303 
       
   304     gio_handle = dlopen("libgio-2.0.so", RTLD_LAZY);
       
   305     if (!gio_handle) {
       
   306         gio_handle = dlopen("libgio-2.0.so.0", RTLD_LAZY);
       
   307         if (!gio_handle) {
       
   308             return 0;
       
   309         }
       
   310     }
       
   311 
       
   312     my_g_type_init_func = (g_type_init_func*)dlsym(gio_handle, "g_type_init");
       
   313 
       
   314     g_proxy_resolver_get_default =
       
   315             (g_proxy_resolver_get_default_func*)dlsym(gio_handle,
       
   316                     "g_proxy_resolver_get_default");
       
   317 
       
   318     g_proxy_resolver_lookup =
       
   319             (g_proxy_resolver_lookup_func*)dlsym(gio_handle,
       
   320                     "g_proxy_resolver_lookup");
       
   321 
       
   322     g_network_address_parse_uri =
       
   323             (g_network_address_parse_uri_func*)dlsym(gio_handle,
       
   324                     "g_network_address_parse_uri");
       
   325 
       
   326     g_network_address_get_hostname =
       
   327             (g_network_address_get_hostname_func*)dlsym(gio_handle,
       
   328                     "g_network_address_get_hostname");
       
   329 
       
   330     g_network_address_get_port =
       
   331             (g_network_address_get_port_func*)dlsym(gio_handle,
       
   332                     "g_network_address_get_port");
       
   333 
       
   334     g_strfreev = (g_strfreev_func*)dlsym(gio_handle, "g_strfreev");
       
   335 
       
   336     if (!my_g_type_init_func ||
       
   337         !g_proxy_resolver_get_default ||
       
   338         !g_proxy_resolver_lookup ||
       
   339         !g_network_address_parse_uri ||
       
   340         !g_network_address_get_hostname ||
       
   341         !g_network_address_get_port ||
       
   342         !g_strfreev)
       
   343     {
       
   344         dlclose(gio_handle);
       
   345         return 0;
       
   346     }
       
   347 
       
   348     (*my_g_type_init_func)();
       
   349     return 1;
       
   350 }
       
   351 
       
   352 static jobjectArray getProxyByGProxyResolver(JNIEnv *env, const char *cproto,
       
   353                                              const char *chost)
       
   354 {
       
   355     GProxyResolver* resolver = NULL;
       
   356     char** proxies = NULL;
       
   357     GError *error = NULL;
       
   358 
       
   359     size_t protoLen = 0;
       
   360     size_t hostLen = 0;
       
   361     char* uri = NULL;
       
   362 
       
   363     jobjectArray proxy_array = NULL;
       
   364 
       
   365     resolver = (*g_proxy_resolver_get_default)();
       
   366     if (resolver == NULL) {
       
   367         return NULL;
       
   368     }
       
   369 
       
   370     /* Construct the uri, cproto + "://" + chost */
       
   371     protoLen = strlen(cproto);
       
   372     hostLen = strlen(chost);
       
   373     uri = malloc(protoLen + hostLen + 4);
       
   374     if (!uri) {
       
   375         /* Out of memory */
       
   376         return NULL;
       
   377     }
       
   378     memcpy(uri, cproto, protoLen);
       
   379     memcpy(uri + protoLen, "://", 3);
       
   380     memcpy(uri + protoLen + 3, chost, hostLen + 1);
       
   381 
       
   382     /*
       
   383      * Looks into the system proxy configuration to determine what proxy,
       
   384      * if any, to use to connect to uri. The returned proxy URIs are of
       
   385      * the form <protocol>://[user[:password]@]host:port or direct://,
       
   386      * where <protocol> could be http, rtsp, socks or other proxying protocol.
       
   387      * direct:// is used when no proxy is needed.
       
   388      */
       
   389     proxies = (*g_proxy_resolver_lookup)(resolver, uri, NULL, &error);
       
   390     free(uri);
       
   391 
       
   392     if (proxies) {
       
   393         if (!error) {
       
   394             int i;
       
   395             int nr_proxies = 0;
       
   396             char** p = proxies;
       
   397             /* count the elements in the null terminated string vector. */
       
   398             while (*p) {
       
   399                 nr_proxies++;
       
   400                 p++;
       
   401             }
       
   402             /* create a proxy array that has to be filled. */
       
   403             proxy_array = (*env)->NewObjectArray(env, nr_proxies, proxy_class, NULL);
       
   404             if (proxy_array != NULL && !(*env)->ExceptionCheck(env)) {
       
   405                 for (i = 0; proxies[i]; i++) {
       
   406                     if (strncmp(proxies[i], "direct://", 9)) {
       
   407                         GSocketConnectable* conn =
       
   408                                 (*g_network_address_parse_uri)(proxies[i], 0,
       
   409                                                                &error);
       
   410                         if (conn && !error) {
       
   411                             const char *phost = NULL;
       
   412                             unsigned short pport = 0;
       
   413                             phost = (*g_network_address_get_hostname)(conn);
       
   414                             pport = (*g_network_address_get_port)(conn);
       
   415                             if (phost && pport > 0) {
       
   416                                 jobject proxy = NULL;
       
   417                                 jfieldID ptype_ID = ptype_httpID;
       
   418                                 if (!strncmp(proxies[i], "socks", 5))
       
   419                                     ptype_ID = ptype_socksID;
       
   420 
       
   421                                 proxy = createProxy(env, ptype_ID, phost, pport);
       
   422                                 if (proxy == NULL || (*env)->ExceptionCheck(env)) {
       
   423                                     proxy_array = NULL;
       
   424                                     break;
       
   425                                 }
       
   426                                 (*env)->SetObjectArrayElement(env, proxy_array, i, proxy);
       
   427                                 if ((*env)->ExceptionCheck(env)) {
       
   428                                     proxy_array = NULL;
       
   429                                     break;
       
   430                                 }
       
   431                             }
       
   432                         }
       
   433                     } else {
       
   434                         /* direct connection - no proxy */
       
   435                         jobject proxy = (*env)->GetStaticObjectField(env, proxy_class,
       
   436                                                                      pr_no_proxyID);
       
   437                         if (proxy == NULL || (*env)->ExceptionCheck(env)) {
       
   438                             proxy_array = NULL;
       
   439                             break;
       
   440                         }
       
   441                         (*env)->SetObjectArrayElement(env, proxy_array, i, proxy);
       
   442                         if ((*env)->ExceptionCheck(env)) {
       
   443                             proxy_array = NULL;
       
   444                             break;
       
   445                         }
       
   446                     }
       
   447                 }
       
   448             }
       
   449         }
       
   450         (*g_strfreev)(proxies);
       
   451     }
       
   452 
       
   453     return proxy_array;
       
   454 }
       
   455 
       
   456 /*
       
   457  * Class:     sun_net_spi_DefaultProxySelector
       
   458  * Method:    init
       
   459  * Signature: ()Z
       
   460  */
       
   461 JNIEXPORT jboolean JNICALL
       
   462 Java_sun_net_spi_DefaultProxySelector_init(JNIEnv *env, jclass clazz) {
       
   463     use_gproxyResolver = initGProxyResolver();
       
   464     if (!use_gproxyResolver)
       
   465         use_gconf = initGConf();
       
   466 
       
   467     if (use_gproxyResolver || use_gconf) {
       
   468         if (initJavaClass(env))
       
   469             return JNI_TRUE;
       
   470     }
       
   471     return JNI_FALSE;
       
   472 }
       
   473 
       
   474 /*
       
   475  * Class:     sun_net_spi_DefaultProxySelector
       
   476  * Method:    getSystemProxies
       
   477  * Signature: ([Ljava/lang/String;Ljava/lang/String;)[Ljava/net/Proxy;
       
   478  */
       
   479 JNIEXPORT jobjectArray JNICALL
       
   480 Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv *env,
       
   481                                                        jobject this,
       
   482                                                        jstring proto,
       
   483                                                        jstring host)
       
   484 {
       
   485     const char* cproto;
       
   486     const char* chost;
       
   487 
       
   488     jboolean isProtoCopy;
       
   489     jboolean isHostCopy;
       
   490 
       
   491     jobjectArray proxyArray = NULL;
       
   492 
       
   493     cproto = (*env)->GetStringUTFChars(env, proto, &isProtoCopy);
       
   494 
       
   495     if (cproto != NULL && (use_gproxyResolver || use_gconf)) {
       
   496         chost = (*env)->GetStringUTFChars(env, host, &isHostCopy);
       
   497         if (chost != NULL) {
       
   498             if (use_gproxyResolver)
       
   499                 proxyArray = getProxyByGProxyResolver(env, cproto, chost);
       
   500             else if (use_gconf)
       
   501                 proxyArray = getProxyByGConf(env, cproto, chost);
       
   502             if (isHostCopy == JNI_TRUE)
       
   503                 (*env)->ReleaseStringUTFChars(env, host, chost);
       
   504         }
       
   505         if (isProtoCopy == JNI_TRUE)
       
   506             (*env)->ReleaseStringUTFChars(env, proto, cproto);
       
   507     }
       
   508     return proxyArray;
       
   509 }
       
   510