quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

ares_android.c (14173B)


      1 /* MIT License
      2  *
      3  * Copyright (c) John Schember
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a copy
      6  * of this software and associated documentation files (the "Software"), to deal
      7  * in the Software without restriction, including without limitation the rights
      8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      9  * copies of the Software, and to permit persons to whom the Software is
     10  * furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the next
     13  * paragraph) shall be included in all copies or substantial portions of the
     14  * Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     22  * SOFTWARE.
     23  *
     24  * SPDX-License-Identifier: MIT
     25  */
     26 #if defined(ANDROID) || defined(__ANDROID__)
     27 #  include "ares_private.h"
     28 #  include <jni.h>
     29 #  include <sys/prctl.h>
     30 #  include "ares_android.h"
     31 
     32 static JavaVM   *android_jvm                  = NULL;
     33 static jobject   android_connectivity_manager = NULL;
     34 
     35 /* ConnectivityManager.getActiveNetwork */
     36 static jmethodID android_cm_active_net_mid = NULL;
     37 /* ConnectivityManager.getLinkProperties */
     38 static jmethodID android_cm_link_props_mid = NULL;
     39 /* LinkProperties.getDnsServers */
     40 static jmethodID android_lp_dns_servers_mid = NULL;
     41 /* LinkProperties.getDomains */
     42 static jmethodID android_lp_domains_mid = NULL;
     43 /* List.size */
     44 static jmethodID android_list_size_mid = NULL;
     45 /* List.get */
     46 static jmethodID android_list_get_mid = NULL;
     47 /* InetAddress.getHostAddress */
     48 static jmethodID android_ia_host_addr_mid = NULL;
     49 
     50 static jclass    jni_get_class(JNIEnv *env, const char *path)
     51 {
     52   jclass cls = NULL;
     53 
     54   if (env == NULL || path == NULL || *path == '\0') {
     55     return NULL;
     56   }
     57 
     58   cls = (*env)->FindClass(env, path);
     59   if ((*env)->ExceptionOccurred(env)) {
     60     (*env)->ExceptionClear(env);
     61     return NULL;
     62   }
     63   return cls;
     64 }
     65 
     66 static jmethodID jni_get_method_id(JNIEnv *env, jclass cls,
     67                                    const char *func_name, const char *signature)
     68 {
     69   jmethodID mid = NULL;
     70 
     71   if (env == NULL || cls == NULL || func_name == NULL || *func_name == '\0' ||
     72       signature == NULL || *signature == '\0') {
     73     return NULL;
     74   }
     75 
     76   mid = (*env)->GetMethodID(env, cls, func_name, signature);
     77   if ((*env)->ExceptionOccurred(env)) {
     78     (*env)->ExceptionClear(env);
     79     return NULL;
     80   }
     81 
     82   return mid;
     83 }
     84 
     85 static int jvm_attach(JNIEnv **env)
     86 {
     87   char             name[17] = { 0 };
     88 
     89   JavaVMAttachArgs args;
     90 
     91   args.version = JNI_VERSION_1_6;
     92   if (prctl(PR_GET_NAME, name) == 0) {
     93     args.name = name;
     94   } else {
     95     args.name = NULL;
     96   }
     97   args.group = NULL;
     98 
     99   return (*android_jvm)->AttachCurrentThread(android_jvm, env, &args);
    100 }
    101 
    102 void ares_library_init_jvm(JavaVM *jvm)
    103 {
    104   android_jvm = jvm;
    105 }
    106 
    107 int ares_library_init_android(jobject connectivity_manager)
    108 {
    109   JNIEnv       *env          = NULL;
    110   int           need_detatch = 0;
    111   int           res;
    112   ares_status_t ret     = ARES_ENOTINITIALIZED;
    113   jclass        obj_cls = NULL;
    114 
    115   if (android_jvm == NULL) {
    116     goto cleanup;
    117   }
    118 
    119   res = (*android_jvm)->GetEnv(android_jvm, (void **)&env, JNI_VERSION_1_6);
    120   if (res == JNI_EDETACHED) {
    121     env          = NULL;
    122     res          = jvm_attach(&env);
    123     need_detatch = 1;
    124   }
    125   if (res != JNI_OK || env == NULL) {
    126     goto cleanup;
    127   }
    128 
    129   android_connectivity_manager =
    130     (*env)->NewGlobalRef(env, connectivity_manager);
    131   if (android_connectivity_manager == NULL) {
    132     goto cleanup;
    133   }
    134 
    135   /* Initialization has succeeded. Now attempt to cache the methods that will be
    136    * called by ares_get_android_server_list. */
    137   ret = ARES_SUCCESS;
    138 
    139   /* ConnectivityManager in API 1. */
    140   obj_cls = jni_get_class(env, "android/net/ConnectivityManager");
    141   if (obj_cls == NULL) {
    142     goto cleanup;
    143   }
    144 
    145   /* ConnectivityManager.getActiveNetwork in API 23. */
    146   android_cm_active_net_mid = jni_get_method_id(
    147     env, obj_cls, "getActiveNetwork", "()Landroid/net/Network;");
    148   if (android_cm_active_net_mid == NULL) {
    149     goto cleanup;
    150   }
    151 
    152   /* ConnectivityManager.getLinkProperties in API 21. */
    153   android_cm_link_props_mid =
    154     jni_get_method_id(env, obj_cls, "getLinkProperties",
    155                       "(Landroid/net/Network;)Landroid/net/LinkProperties;");
    156   if (android_cm_link_props_mid == NULL) {
    157     goto cleanup;
    158   }
    159 
    160   /* LinkProperties in API 21. */
    161   (*env)->DeleteLocalRef(env, obj_cls);
    162   obj_cls = jni_get_class(env, "android/net/LinkProperties");
    163   if (obj_cls == NULL) {
    164     goto cleanup;
    165   }
    166 
    167   /* getDnsServers in API 21. */
    168   android_lp_dns_servers_mid =
    169     jni_get_method_id(env, obj_cls, "getDnsServers", "()Ljava/util/List;");
    170   if (android_lp_dns_servers_mid == NULL) {
    171     goto cleanup;
    172   }
    173 
    174   /* getDomains in API 21. */
    175   android_lp_domains_mid =
    176     jni_get_method_id(env, obj_cls, "getDomains", "()Ljava/lang/String;");
    177   if (android_lp_domains_mid == NULL) {
    178     goto cleanup;
    179   }
    180 
    181   (*env)->DeleteLocalRef(env, obj_cls);
    182   obj_cls = jni_get_class(env, "java/util/List");
    183   if (obj_cls == NULL) {
    184     goto cleanup;
    185   }
    186 
    187   android_list_size_mid = jni_get_method_id(env, obj_cls, "size", "()I");
    188   if (android_list_size_mid == NULL) {
    189     goto cleanup;
    190   }
    191 
    192   android_list_get_mid =
    193     jni_get_method_id(env, obj_cls, "get", "(I)Ljava/lang/Object;");
    194   if (android_list_get_mid == NULL) {
    195     goto cleanup;
    196   }
    197 
    198   (*env)->DeleteLocalRef(env, obj_cls);
    199   obj_cls = jni_get_class(env, "java/net/InetAddress");
    200   if (obj_cls == NULL) {
    201     goto cleanup;
    202   }
    203 
    204   android_ia_host_addr_mid =
    205     jni_get_method_id(env, obj_cls, "getHostAddress", "()Ljava/lang/String;");
    206   if (android_ia_host_addr_mid == NULL) {
    207     goto cleanup;
    208   }
    209 
    210   (*env)->DeleteLocalRef(env, obj_cls);
    211   goto done;
    212 
    213 cleanup:
    214   if (obj_cls != NULL) {
    215     (*env)->DeleteLocalRef(env, obj_cls);
    216   }
    217 
    218   android_cm_active_net_mid  = NULL;
    219   android_cm_link_props_mid  = NULL;
    220   android_lp_dns_servers_mid = NULL;
    221   android_lp_domains_mid     = NULL;
    222   android_list_size_mid      = NULL;
    223   android_list_get_mid       = NULL;
    224   android_ia_host_addr_mid   = NULL;
    225 
    226 done:
    227   if (need_detatch) {
    228     (*android_jvm)->DetachCurrentThread(android_jvm);
    229   }
    230 
    231   return (int)ret;
    232 }
    233 
    234 int ares_library_android_initialized(void)
    235 {
    236   if (android_jvm == NULL || android_connectivity_manager == NULL) {
    237     return ARES_ENOTINITIALIZED;
    238   }
    239   return ARES_SUCCESS;
    240 }
    241 
    242 void ares_library_cleanup_android(void)
    243 {
    244   JNIEnv *env          = NULL;
    245   int     need_detatch = 0;
    246   int     res;
    247 
    248   if (android_jvm == NULL || android_connectivity_manager == NULL) {
    249     return;
    250   }
    251 
    252   res = (*android_jvm)->GetEnv(android_jvm, (void **)&env, JNI_VERSION_1_6);
    253   if (res == JNI_EDETACHED) {
    254     env          = NULL;
    255     res          = jvm_attach(&env);
    256     need_detatch = 1;
    257   }
    258   if (res != JNI_OK || env == NULL) {
    259     return;
    260   }
    261 
    262   android_cm_active_net_mid  = NULL;
    263   android_cm_link_props_mid  = NULL;
    264   android_lp_dns_servers_mid = NULL;
    265   android_lp_domains_mid     = NULL;
    266   android_list_size_mid      = NULL;
    267   android_list_get_mid       = NULL;
    268   android_ia_host_addr_mid   = NULL;
    269 
    270   (*env)->DeleteGlobalRef(env, android_connectivity_manager);
    271   android_connectivity_manager = NULL;
    272 
    273   if (need_detatch) {
    274     (*android_jvm)->DetachCurrentThread(android_jvm);
    275   }
    276 }
    277 
    278 char **ares_get_android_server_list(size_t max_servers, size_t *num_servers)
    279 {
    280   JNIEnv     *env             = NULL;
    281   jobject     active_network  = NULL;
    282   jobject     link_properties = NULL;
    283   jobject     server_list     = NULL;
    284   jobject     server          = NULL;
    285   jstring     str             = NULL;
    286   jint        nserv;
    287   const char *ch_server_address;
    288   int         res;
    289   size_t      i;
    290   char      **dns_list     = NULL;
    291   int         need_detatch = 0;
    292 
    293   if (android_jvm == NULL || android_connectivity_manager == NULL ||
    294       max_servers == 0 || num_servers == NULL) {
    295     return NULL;
    296   }
    297 
    298   if (android_cm_active_net_mid == NULL || android_cm_link_props_mid == NULL ||
    299       android_lp_dns_servers_mid == NULL || android_list_size_mid == NULL ||
    300       android_list_get_mid == NULL || android_ia_host_addr_mid == NULL) {
    301     return NULL;
    302   }
    303 
    304   res = (*android_jvm)->GetEnv(android_jvm, (void **)&env, JNI_VERSION_1_6);
    305   if (res == JNI_EDETACHED) {
    306     env          = NULL;
    307     res          = jvm_attach(&env);
    308     need_detatch = 1;
    309   }
    310   if (res != JNI_OK || env == NULL) {
    311     goto done;
    312   }
    313 
    314   /* JNI below is equivalent to this Java code.
    315      import android.content.Context;
    316      import android.net.ConnectivityManager;
    317      import android.net.LinkProperties;
    318      import android.net.Network;
    319      import java.net.InetAddress;
    320      import java.util.List;
    321 
    322      ConnectivityManager cm = (ConnectivityManager)this.getApplicationContext()
    323        .getSystemService(Context.CONNECTIVITY_SERVICE);
    324      Network an = cm.getActiveNetwork();
    325      LinkProperties lp = cm.getLinkProperties(an);
    326      List<InetAddress> dns = lp.getDnsServers();
    327      for (InetAddress ia: dns) {
    328        String ha = ia.getHostAddress();
    329      }
    330 
    331      Note: The JNI ConnectivityManager object and all method IDs were previously
    332            initialized in ares_library_init_android.
    333    */
    334 
    335   active_network = (*env)->CallObjectMethod(env, android_connectivity_manager,
    336                                             android_cm_active_net_mid);
    337   if (active_network == NULL) {
    338     goto done;
    339   }
    340 
    341   link_properties =
    342     (*env)->CallObjectMethod(env, android_connectivity_manager,
    343                              android_cm_link_props_mid, active_network);
    344   if (link_properties == NULL) {
    345     goto done;
    346   }
    347 
    348   server_list =
    349     (*env)->CallObjectMethod(env, link_properties, android_lp_dns_servers_mid);
    350   if (server_list == NULL) {
    351     goto done;
    352   }
    353 
    354   nserv = (*env)->CallIntMethod(env, server_list, android_list_size_mid);
    355   if (nserv > (jint)max_servers) {
    356     nserv = (jint)max_servers;
    357   }
    358   if (nserv <= 0) {
    359     goto done;
    360   }
    361   *num_servers = (size_t)nserv;
    362 
    363   dns_list = ares_malloc(sizeof(*dns_list) * (*num_servers));
    364   for (i = 0; i < *num_servers; i++) {
    365     size_t len = 64;
    366     server =
    367       (*env)->CallObjectMethod(env, server_list, android_list_get_mid, (jint)i);
    368     dns_list[i]    = ares_malloc(len);
    369     dns_list[i][0] = 0;
    370     if (server == NULL) {
    371       continue;
    372     }
    373     str = (*env)->CallObjectMethod(env, server, android_ia_host_addr_mid);
    374     ch_server_address = (*env)->GetStringUTFChars(env, str, 0);
    375     ares_strcpy(dns_list[i], ch_server_address, len);
    376     (*env)->ReleaseStringUTFChars(env, str, ch_server_address);
    377     (*env)->DeleteLocalRef(env, str);
    378     (*env)->DeleteLocalRef(env, server);
    379   }
    380 
    381 done:
    382   if ((*env)->ExceptionOccurred(env)) {
    383     (*env)->ExceptionClear(env);
    384   }
    385 
    386   if (server_list != NULL) {
    387     (*env)->DeleteLocalRef(env, server_list);
    388   }
    389   if (link_properties != NULL) {
    390     (*env)->DeleteLocalRef(env, link_properties);
    391   }
    392   if (active_network != NULL) {
    393     (*env)->DeleteLocalRef(env, active_network);
    394   }
    395 
    396   if (need_detatch) {
    397     (*android_jvm)->DetachCurrentThread(android_jvm);
    398   }
    399   return dns_list;
    400 }
    401 
    402 char *ares_get_android_search_domains_list(void)
    403 {
    404   JNIEnv     *env             = NULL;
    405   jobject     active_network  = NULL;
    406   jobject     link_properties = NULL;
    407   jstring     domains         = NULL;
    408   const char *domain;
    409   int         res;
    410   char       *domain_list  = NULL;
    411   int         need_detatch = 0;
    412 
    413   if (android_jvm == NULL || android_connectivity_manager == NULL) {
    414     return NULL;
    415   }
    416 
    417   if (android_cm_active_net_mid == NULL || android_cm_link_props_mid == NULL ||
    418       android_lp_domains_mid == NULL) {
    419     return NULL;
    420   }
    421 
    422   res = (*android_jvm)->GetEnv(android_jvm, (void **)&env, JNI_VERSION_1_6);
    423   if (res == JNI_EDETACHED) {
    424     env          = NULL;
    425     res          = jvm_attach(&env);
    426     need_detatch = 1;
    427   }
    428   if (res != JNI_OK || env == NULL) {
    429     goto done;
    430   }
    431 
    432   /* JNI below is equivalent to this Java code.
    433      import android.content.Context;
    434      import android.net.ConnectivityManager;
    435      import android.net.LinkProperties;
    436 
    437      ConnectivityManager cm = (ConnectivityManager)this.getApplicationContext()
    438        .getSystemService(Context.CONNECTIVITY_SERVICE);
    439      Network an = cm.getActiveNetwork();
    440      LinkProperties lp = cm.getLinkProperties(an);
    441    String domains = lp.getDomains();
    442      for (String domain: domains.split(",")) {
    443        String d = domain;
    444      }
    445 
    446      Note: The JNI ConnectivityManager object and all method IDs were previously
    447            initialized in ares_library_init_android.
    448    */
    449 
    450   active_network = (*env)->CallObjectMethod(env, android_connectivity_manager,
    451                                             android_cm_active_net_mid);
    452   if (active_network == NULL) {
    453     goto done;
    454   }
    455 
    456   link_properties =
    457     (*env)->CallObjectMethod(env, android_connectivity_manager,
    458                              android_cm_link_props_mid, active_network);
    459   if (link_properties == NULL) {
    460     goto done;
    461   }
    462 
    463   /* Get the domains. It is a common separated list of domains to search. */
    464   domains =
    465     (*env)->CallObjectMethod(env, link_properties, android_lp_domains_mid);
    466   if (domains == NULL) {
    467     goto done;
    468   }
    469 
    470   /* Split on , */
    471   domain      = (*env)->GetStringUTFChars(env, domains, 0);
    472   domain_list = ares_strdup(domain);
    473   (*env)->ReleaseStringUTFChars(env, domains, domain);
    474   (*env)->DeleteLocalRef(env, domains);
    475 
    476 done:
    477   if ((*env)->ExceptionOccurred(env)) {
    478     (*env)->ExceptionClear(env);
    479   }
    480 
    481   if (link_properties != NULL) {
    482     (*env)->DeleteLocalRef(env, link_properties);
    483   }
    484   if (active_network != NULL) {
    485     (*env)->DeleteLocalRef(env, active_network);
    486   }
    487 
    488   if (need_detatch) {
    489     (*android_jvm)->DetachCurrentThread(android_jvm);
    490   }
    491   return domain_list;
    492 }
    493 #else
    494 /* warning: ISO C forbids an empty translation unit */
    495 typedef int dummy_make_iso_compilers_happy;
    496 #endif