1 /*
   2  * Copyright (c) 2004, 2006, 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 "jni.h"
  27 #include "jni_util.h"
  28 #include "jvm.h"
  29 #include "jlong.h"
  30 #include "sun_net_spi_DefaultProxySelector.h"
  31 #include <dlfcn.h>
  32 #include <stdio.h>
  33 #ifdef __linux__
  34 #include <string.h>
  35 #else
  36 #include <strings.h>
  37 #endif
  38 
  39 /**
  40  * These functions are used by the sun.net.spi.DefaultProxySelector class
  41  * to access some platform specific settings.
  42  * This is the Solaris/Linux Gnome 2.x code using the GConf-2 library.
  43  * Everything is loaded dynamically so no hard link with any library exists.
  44  * The GConf-2 settings used are:
  45  * - /system/http_proxy/use_http_proxy          boolean
  46  * - /system/http_proxy/use_authentcation       boolean
  47  * - /system/http_proxy/use_same_proxy          boolean
  48  * - /system/http_proxy/host                    string
  49  * - /system/http_proxy/authentication_user     string
  50  * - /system/http_proxy/authentication_password string
  51  * - /system/http_proxy/port                    int
  52  * - /system/proxy/socks_host                   string
  53  * - /system/proxy/mode                         string
  54  * - /system/proxy/ftp_host                     string
  55  * - /system/proxy/secure_host                  string
  56  * - /system/proxy/socks_port                   int
  57  * - /system/proxy/ftp_port                     int
  58  * - /system/proxy/secure_port                  int
  59  * - /system/proxy/no_proxy_for                 list
  60  * - /system/proxy/gopher_host                  string
  61  * - /system/proxy/gopher_port                  int
  62  */
  63 typedef void* gconf_client_get_default_func();
  64 typedef char* gconf_client_get_string_func(void *, char *, void**);
  65 typedef int   gconf_client_get_int_func(void*, char *, void**);
  66 typedef int   gconf_client_get_bool_func(void*, char *, void**);
  67 typedef int   gconf_init_func(int, char**, void**);
  68 typedef void  g_type_init_func ();
  69 gconf_client_get_default_func* my_get_default_func = NULL;
  70 gconf_client_get_string_func* my_get_string_func = NULL;
  71 gconf_client_get_int_func* my_get_int_func = NULL;
  72 gconf_client_get_bool_func* my_get_bool_func = NULL;
  73 gconf_init_func* my_gconf_init_func = NULL;
  74 g_type_init_func* my_g_type_init_func = NULL;
  75 
  76 static jclass proxy_class;
  77 static jclass isaddr_class;
  78 static jclass ptype_class;
  79 static jmethodID isaddr_createUnresolvedID;
  80 static jmethodID proxy_ctrID;
  81 static jfieldID pr_no_proxyID;
  82 static jfieldID ptype_httpID;
  83 static jfieldID ptype_socksID;
  84 
  85 static int gconf_ver = 0;
  86 static void* gconf_client = NULL;
  87 
  88 #define CHECK_NULL(X) { if ((X) == NULL) fprintf (stderr,"JNI errror at line %d\n", __LINE__); }
  89 
  90 /*
  91  * Class:     sun_net_spi_DefaultProxySelector
  92  * Method:    init
  93  * Signature: ()Z
  94  */
  95 JNIEXPORT jboolean JNICALL
  96 Java_sun_net_spi_DefaultProxySelector_init(JNIEnv *env, jclass clazz) {
  97   jclass cls = NULL;
  98   CHECK_NULL(cls = (*env)->FindClass(env,"java/net/Proxy"));
  99   proxy_class = (*env)->NewGlobalRef(env, cls);
 100   CHECK_NULL(cls = (*env)->FindClass(env,"java/net/Proxy$Type"));
 101   ptype_class = (*env)->NewGlobalRef(env, cls);
 102   CHECK_NULL(cls = (*env)->FindClass(env, "java/net/InetSocketAddress"));
 103   isaddr_class = (*env)->NewGlobalRef(env, cls);
 104   proxy_ctrID = (*env)->GetMethodID(env, proxy_class, "<init>", "(Ljava/net/Proxy$Type;Ljava/net/SocketAddress;)V");
 105   pr_no_proxyID = (*env)->GetStaticFieldID(env, proxy_class, "NO_PROXY", "Ljava/net/Proxy;");
 106   ptype_httpID = (*env)->GetStaticFieldID(env, ptype_class, "HTTP", "Ljava/net/Proxy$Type;");
 107   ptype_socksID = (*env)->GetStaticFieldID(env, ptype_class, "SOCKS", "Ljava/net/Proxy$Type;");
 108   isaddr_createUnresolvedID = (*env)->GetStaticMethodID(env, isaddr_class, "createUnresolved", "(Ljava/lang/String;I)Ljava/net/InetSocketAddress;");
 109 
 110   /**
 111    * Let's try to load le GConf-2 library
 112    */
 113   if (dlopen("libgconf-2.so", RTLD_GLOBAL | RTLD_LAZY) != NULL ||
 114       dlopen("libgconf-2.so.4", RTLD_GLOBAL | RTLD_LAZY) != NULL) {
 115     gconf_ver = 2;
 116   }
 117   if (gconf_ver > 0) {
 118     /*
 119      * Now let's get pointer to the functions we need.
 120      */
 121     my_g_type_init_func = (g_type_init_func*) dlsym(RTLD_DEFAULT, "g_type_init");
 122     my_get_default_func = (gconf_client_get_default_func*) dlsym(RTLD_DEFAULT, "gconf_client_get_default");
 123     if (my_g_type_init_func != NULL && my_get_default_func != NULL) {
 124       /**
 125        * Try to connect to GConf.
 126        */
 127       (*my_g_type_init_func)();
 128       gconf_client = (*my_get_default_func)();
 129       if (gconf_client != NULL) {
 130         my_get_string_func = (gconf_client_get_string_func*) dlsym(RTLD_DEFAULT, "gconf_client_get_string");
 131         my_get_int_func = (gconf_client_get_int_func*) dlsym(RTLD_DEFAULT, "gconf_client_get_int");
 132         my_get_bool_func = (gconf_client_get_bool_func*) dlsym(RTLD_DEFAULT, "gconf_client_get_bool");
 133         if (my_get_int_func != NULL && my_get_string_func != NULL &&
 134             my_get_bool_func != NULL) {
 135           /**
 136            * We did get all we need. Let's enable the System Proxy Settings.
 137            */
 138           return JNI_TRUE;
 139         }
 140       }
 141     }
 142   }
 143   return JNI_FALSE;
 144 }
 145 
 146 
 147 /*
 148  * Class:     sun_net_spi_DefaultProxySelector
 149  * Method:    getSystemProxy
 150  * Signature: ([Ljava/lang/String;Ljava/lang/String;)Ljava/net/Proxy;
 151  */
 152 JNIEXPORT jobject JNICALL
 153 Java_sun_net_spi_DefaultProxySelector_getSystemProxy(JNIEnv *env,
 154                                                      jobject this,
 155                                                      jstring proto,
 156                                                      jstring host)
 157 {
 158   char *phost = NULL;
 159   char *mode = NULL;
 160   int pport = 0;
 161   int use_proxy = 0;
 162   int use_same_proxy = 0;
 163   const char* urlhost;
 164   jobject isa = NULL;
 165   jobject proxy = NULL;
 166   jobject type_proxy = NULL;
 167   jobject no_proxy = NULL;
 168   const char *cproto;
 169   jboolean isCopy;
 170 
 171   if (gconf_ver > 0) {
 172     if (gconf_client == NULL) {
 173       (*my_g_type_init_func)();
 174       gconf_client = (*my_get_default_func)();
 175     }
 176     if (gconf_client != NULL) {
 177       cproto = (*env)->GetStringUTFChars(env, proto, &isCopy);
 178       if (cproto != NULL) {
 179         /**
 180          * We will have to check protocol by protocol as they do use different
 181          * entries.
 182          */
 183 
 184         use_same_proxy = (*my_get_bool_func)(gconf_client, "/system/http_proxy/use_same_proxy", NULL);
 185         if (use_same_proxy) {
 186           use_proxy = (*my_get_bool_func)(gconf_client, "/system/http_proxy/use_http_proxy", NULL);
 187           if (use_proxy) {
 188             phost = (*my_get_string_func)(gconf_client, "/system/http_proxy/host", NULL);
 189             pport = (*my_get_int_func)(gconf_client, "/system/http_proxy/port", NULL);
 190           }
 191         }
 192 
 193         /**
 194          * HTTP:
 195          * /system/http_proxy/use_http_proxy (boolean)
 196          * /system/http_proxy/host (string)
 197          * /system/http_proxy/port (integer)
 198          */
 199         if (strcasecmp(cproto, "http") == 0) {
 200           use_proxy = (*my_get_bool_func)(gconf_client, "/system/http_proxy/use_http_proxy", NULL);
 201           if (use_proxy) {
 202             if (!use_same_proxy) {
 203               phost = (*my_get_string_func)(gconf_client, "/system/http_proxy/host", NULL);
 204               pport = (*my_get_int_func)(gconf_client, "/system/http_proxy/port", NULL);
 205             }
 206             CHECK_NULL(type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_httpID));
 207           }
 208         }
 209 
 210         /**
 211          * HTTPS:
 212          * /system/proxy/mode (string) [ "manual" means use proxy settings ]
 213          * /system/proxy/secure_host (string)
 214          * /system/proxy/secure_port (integer)
 215          */
 216         if (strcasecmp(cproto, "https") == 0) {
 217           mode =  (*my_get_string_func)(gconf_client, "/system/proxy/mode", NULL);
 218           if (mode != NULL && (strcasecmp(mode,"manual") == 0)) {
 219             if (!use_same_proxy) {
 220               phost = (*my_get_string_func)(gconf_client, "/system/proxy/secure_host", NULL);
 221               pport = (*my_get_int_func)(gconf_client, "/system/proxy/secure_port", NULL);
 222             }
 223             use_proxy = (phost != NULL);
 224             if (use_proxy)
 225               type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_httpID);
 226           }
 227         }
 228 
 229         /**
 230          * FTP:
 231          * /system/proxy/mode (string) [ "manual" means use proxy settings ]
 232          * /system/proxy/ftp_host (string)
 233          * /system/proxy/ftp_port (integer)
 234          */
 235         if (strcasecmp(cproto, "ftp") == 0) {
 236           mode =  (*my_get_string_func)(gconf_client, "/system/proxy/mode", NULL);
 237           if (mode != NULL && (strcasecmp(mode,"manual") == 0)) {
 238             if (!use_same_proxy) {
 239               phost = (*my_get_string_func)(gconf_client, "/system/proxy/ftp_host", NULL);
 240               pport = (*my_get_int_func)(gconf_client, "/system/proxy/ftp_port", NULL);
 241             }
 242             use_proxy = (phost != NULL);
 243             if (use_proxy)
 244               type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_httpID);
 245           }
 246         }
 247 
 248         /**
 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          */
 254         if (strcasecmp(cproto, "gopher") == 0) {
 255           mode =  (*my_get_string_func)(gconf_client, "/system/proxy/mode", NULL);
 256           if (mode != NULL && (strcasecmp(mode,"manual") == 0)) {
 257             if (!use_same_proxy) {
 258               phost = (*my_get_string_func)(gconf_client, "/system/proxy/gopher_host", NULL);
 259               pport = (*my_get_int_func)(gconf_client, "/system/proxy/gopher_port", NULL);
 260             }
 261             use_proxy = (phost != NULL);
 262             if (use_proxy)
 263               type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_httpID);
 264           }
 265         }
 266 
 267         /**
 268          * SOCKS:
 269          * /system/proxy/mode (string) [ "manual" means use proxy settings ]
 270          * /system/proxy/socks_host (string)
 271          * /system/proxy/socks_port (integer)
 272          */
 273         if (strcasecmp(cproto, "socks") == 0) {
 274           mode =  (*my_get_string_func)(gconf_client, "/system/proxy/mode", NULL);
 275           if (mode != NULL && (strcasecmp(mode,"manual") == 0)) {
 276             if (!use_same_proxy) {
 277               phost = (*my_get_string_func)(gconf_client, "/system/proxy/socks_host", NULL);
 278               pport = (*my_get_int_func)(gconf_client, "/system/proxy/socks_port", NULL);
 279             }
 280             use_proxy = (phost != NULL);
 281             if (use_proxy)
 282               type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_socksID);
 283           }
 284         }
 285 
 286         if (isCopy == JNI_TRUE)
 287           (*env)->ReleaseStringUTFChars(env, proto, cproto);
 288 
 289         if (use_proxy && (phost != NULL)) {
 290           jstring jhost;
 291           char *noproxyfor;
 292           char *s;
 293 
 294           /**
 295            * check for the exclude list (aka "No Proxy For" list).
 296            * It's a list of comma separated suffixes (e.g. domain name).
 297            */
 298           noproxyfor = (*my_get_string_func)(gconf_client, "/system/proxy/no_proxy_for", NULL);
 299           if (noproxyfor != NULL) {
 300             char *tmpbuf[512];
 301 
 302             s = strtok_r(noproxyfor, ", ", tmpbuf);
 303             urlhost = (*env)->GetStringUTFChars(env, host, &isCopy);
 304             if (urlhost != NULL) {
 305               while (s != NULL && strlen(s) <= strlen(urlhost)) {
 306                 if (strcasecmp(urlhost+(strlen(urlhost) - strlen(s)), s) == 0) {
 307                   /**
 308                    * the URL host name matches with one of the sufixes,
 309                    * therefore we have to use a direct connection.
 310                    */
 311                   use_proxy = 0;
 312                   break;
 313                 }
 314                 s = strtok_r(NULL, ", ", tmpbuf);
 315               }
 316               if (isCopy == JNI_TRUE)
 317                 (*env)->ReleaseStringUTFChars(env, host, urlhost);
 318             }
 319           }
 320           if (use_proxy) {
 321             jhost = (*env)->NewStringUTF(env, phost);
 322             isa = (*env)->CallStaticObjectMethod(env, isaddr_class, isaddr_createUnresolvedID, jhost, pport);
 323             proxy = (*env)->NewObject(env, proxy_class, proxy_ctrID, type_proxy, isa);
 324             return proxy;
 325           }
 326         }
 327       }
 328     }
 329   }
 330 
 331   CHECK_NULL(no_proxy = (*env)->GetStaticObjectField(env, proxy_class, pr_no_proxyID));
 332   return no_proxy;
 333 }