Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright (c) 1998, 2012, 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 "jvm.h"
     28 #include "jni_util.h"
     29 #include "net_util.h"
     30 
     31 int IPv6_supported();
     32 
     33 static int IPv6_available;
     34 
     35 JNIEXPORT jint JNICALL ipv6_available()
     36 {
     37     return IPv6_available ;
     38 }
     39 
     40 JNIEXPORT jint JNICALL
     41 net_JNI_OnLoad(JavaVM *vm, void* ignored)
     42 {
     43     JNIEnv *env;
     44 
     45     if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_2) == JNI_OK) {
     46         if (JVM_InitializeSocketLibrary() < 0) {
     47             JNU_ThrowByName(env, "java/lang/UnsatisfiedLinkError",
     48                             "failed to initialize net library.");
     49             return JNI_VERSION_1_2;
     50         }
     51     }
     52 
     53     /*
     54        Since we have initialized and loaded the Socket library we will
     55        check now to whether we have IPv6 on this platform and if the
     56        supporting socket APIs are available
     57     */
     58     IPv6_available = IPv6_supported();
     59     initLocalAddrTable();
     60     parseExclusiveBindProperty(env);
     61 
     62     return JNI_VERSION_1_2;
     63 }
     64 
     65 /* The address, and family fields used to be in InetAddress
     66  * but are now in an implementation object. So, there is an extra
     67  * level of indirection to access them now.
     68  */
     69 
     70 extern jclass iac_class;
     71 extern jfieldID ia_holderID;
     72 extern jfieldID iac_addressID;
     73 extern jfieldID iac_familyID;
     74 
     75 /**
     76  * set_ methods return JNI_TRUE on success JNI_FALSE on error
     77  * get_ methods that return +ve int return -1 on error
     78  * get_ methods that return objects return NULL on error.
     79  */
     80 jobject getInet6Address_scopeifname(JNIEnv *env, jobject iaObj) {
     81     jobject holder;
     82 
     83     // Android-changed: initInetAddrs(env);
     84     holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
     85     CHECK_NULL_RETURN(holder, NULL);
     86     return (*env)->GetObjectField(env, holder, ia6_scopeifnameID);
     87 }
     88 
     89 int setInet6Address_scopeifname(JNIEnv *env, jobject iaObj, jobject scopeifname) {
     90     jobject holder;
     91 
     92     // Android-changed: initInetAddrs(env);
     93     holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
     94     CHECK_NULL_RETURN(holder, JNI_FALSE);
     95     (*env)->SetObjectField(env, holder, ia6_scopeifnameID, scopeifname);
     96     return JNI_TRUE;
     97 }
     98 
     99 int getInet6Address_scopeid_set(JNIEnv *env, jobject iaObj) {
    100     jobject holder;
    101 
    102     // Android-changed: initInetAddrs(env);
    103     holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
    104     CHECK_NULL_RETURN(holder, -1);
    105     return (*env)->GetBooleanField(env, holder, ia6_scopeidsetID);
    106 }
    107 
    108 int getInet6Address_scopeid(JNIEnv *env, jobject iaObj) {
    109     jobject holder;
    110 
    111     // Android-changed: initInetAddrs(env);
    112     holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
    113     CHECK_NULL_RETURN(holder, -1);
    114     return (*env)->GetIntField(env, holder, ia6_scopeidID);
    115 }
    116 
    117 int setInet6Address_scopeid(JNIEnv *env, jobject iaObj, int scopeid) {
    118     jobject holder;
    119 
    120     // Android-changed: initInetAddrs(env);
    121     holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
    122     CHECK_NULL_RETURN(holder, JNI_FALSE);
    123     (*env)->SetIntField(env, holder, ia6_scopeidID, scopeid);
    124     if (scopeid > 0) {
    125             (*env)->SetBooleanField(env, holder, ia6_scopeidsetID, JNI_TRUE);
    126     }
    127     return JNI_TRUE;
    128 }
    129 
    130 
    131 int getInet6Address_ipaddress(JNIEnv *env, jobject iaObj, char *dest) {
    132     jobject holder, addr;
    133     jbyteArray barr;
    134 
    135     // Android-changed: initInetAddrs(env);
    136     holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
    137     CHECK_NULL_RETURN(holder, JNI_FALSE);
    138     addr =  (*env)->GetObjectField(env, holder, ia6_ipaddressID);
    139     CHECK_NULL_RETURN(addr, JNI_FALSE);
    140     (*env)->GetByteArrayRegion(env, addr, 0, 16, (jbyte *)dest);
    141     return JNI_TRUE;
    142 }
    143 
    144 int setInet6Address_ipaddress(JNIEnv *env, jobject iaObj, char *address) {
    145     jobject holder;
    146     jbyteArray addr;
    147 
    148     // Android-changed: initInetAddrs(env);
    149     holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
    150     CHECK_NULL_RETURN(holder, JNI_FALSE);
    151     addr =  (jbyteArray)(*env)->GetObjectField(env, holder, ia6_ipaddressID);
    152     if (addr == NULL) {
    153         addr = (*env)->NewByteArray(env, 16);
    154         CHECK_NULL_RETURN(addr, JNI_FALSE);
    155         (*env)->SetObjectField(env, holder, ia6_ipaddressID, addr);
    156     }
    157     (*env)->SetByteArrayRegion(env, addr, 0, 16, (jbyte *)address);
    158     return JNI_TRUE;
    159 }
    160 
    161 void setInetAddress_addr(JNIEnv *env, jobject iaObj, int address) {
    162     jobject holder;
    163     // Android-changed: initInetAddrs(env);
    164     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
    165     (*env)->SetIntField(env, holder, iac_addressID, address);
    166 }
    167 
    168 void setInetAddress_family(JNIEnv *env, jobject iaObj, int family) {
    169     jobject holder;
    170     // Android-changed: initInetAddrs(env);
    171     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
    172     (*env)->SetIntField(env, holder, iac_familyID, family);
    173 }
    174 
    175 void setInetAddress_hostName(JNIEnv *env, jobject iaObj, jobject host) {
    176     jobject holder;
    177     // Android-changed: initInetAddrs(env);
    178     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
    179     (*env)->SetObjectField(env, holder, iac_hostNameID, host);
    180     (*env)->SetObjectField(env, holder, iac_origHostNameID, host);
    181 }
    182 
    183 int getInetAddress_addr(JNIEnv *env, jobject iaObj) {
    184     jobject holder;
    185     // Android-changed: initInetAddrs(env);
    186     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
    187     return (*env)->GetIntField(env, holder, iac_addressID);
    188 }
    189 
    190 int getInetAddress_family(JNIEnv *env, jobject iaObj) {
    191     jobject holder;
    192 
    193     // Android-changed: initInetAddrs(env);
    194     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
    195     return (*env)->GetIntField(env, holder, iac_familyID);
    196 }
    197 
    198 jobject getInetAddress_hostName(JNIEnv *env, jobject iaObj) {
    199     jobject holder;
    200     // Android-changed: initInetAddrs(env);
    201     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
    202     return (*env)->GetObjectField(env, holder, iac_hostNameID);
    203 }
    204 
    205 JNIEXPORT jobject JNICALL
    206 NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) {
    207     jobject iaObj;
    208     // Android-changed: initInetAddrs(env);
    209 #ifdef AF_INET6
    210     if (him->sa_family == AF_INET6) {
    211         jbyteArray ipaddress;
    212 #ifdef WIN32
    213         struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him;
    214 #else
    215         struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
    216 #endif
    217         jbyte *caddr = (jbyte *)&(him6->sin6_addr);
    218         if (NET_IsIPv4Mapped(caddr)) {
    219             int address;
    220             static jclass inet4Cls = 0;
    221             if (inet4Cls == 0) {
    222                 jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
    223                 CHECK_NULL_RETURN(c, NULL);
    224                 inet4Cls = (*env)->NewGlobalRef(env, c);
    225                 CHECK_NULL_RETURN(inet4Cls, NULL);
    226                 (*env)->DeleteLocalRef(env, c);
    227             }
    228             iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID);
    229             CHECK_NULL_RETURN(iaObj, NULL);
    230             address = NET_IPv4MappedToIPv4(caddr);
    231             setInetAddress_addr(env, iaObj, address);
    232             setInetAddress_family(env, iaObj, IPv4);
    233         } else {
    234             static jclass inet6Cls = 0;
    235             jint scope;
    236             int ret;
    237             if (inet6Cls == 0) {
    238                 jclass c = (*env)->FindClass(env, "java/net/Inet6Address");
    239                 CHECK_NULL_RETURN(c, NULL);
    240                 inet6Cls = (*env)->NewGlobalRef(env, c);
    241                 CHECK_NULL_RETURN(inet6Cls, NULL);
    242                 (*env)->DeleteLocalRef(env, c);
    243             }
    244             iaObj = (*env)->NewObject(env, inet6Cls, ia6_ctrID);
    245             CHECK_NULL_RETURN(iaObj, NULL);
    246             ret = setInet6Address_ipaddress(env, iaObj, (char *)&(him6->sin6_addr));
    247             // Android-changed: Appease compiler type checking.
    248             // CHECK_NULL_RETURN(ret, NULL);
    249             if (ret == JNI_FALSE) return NULL;
    250             setInetAddress_family(env, iaObj, IPv6);
    251             scope = getScopeID(him);
    252             setInet6Address_scopeid(env, iaObj, scope);
    253         }
    254         *port = ntohs(him6->sin6_port);
    255     } else
    256 #endif /* AF_INET6 */
    257     if (him->sa_family == AF_INET) {
    258         struct sockaddr_in *him4 = (struct sockaddr_in *)him;
    259         static jclass inet4Cls = 0;
    260 
    261         if (inet4Cls == 0) {
    262             jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
    263             CHECK_NULL_RETURN(c, NULL);
    264             inet4Cls = (*env)->NewGlobalRef(env, c);
    265             CHECK_NULL_RETURN(inet4Cls, NULL);
    266             (*env)->DeleteLocalRef(env, c);
    267         }
    268         iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID);
    269         CHECK_NULL_RETURN(iaObj, NULL);
    270         setInetAddress_family(env, iaObj, IPv4);
    271         setInetAddress_addr(env, iaObj, ntohl(him4->sin_addr.s_addr));
    272         *port = ntohs(him4->sin_port);
    273     } else {
    274         // Unknown family
    275         char errmsg[255];
    276         snprintf(errmsg, sizeof(errmsg), "Unknown socket family: %d", him->sa_family);
    277         JNU_ThrowByName(env, "java/net/SocketException", errmsg);
    278         return NULL;
    279     }
    280     return iaObj;
    281 }
    282 
    283 JNIEXPORT jint JNICALL
    284 NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj)
    285 {
    286     jint family = AF_INET;
    287 
    288 #ifdef AF_INET6
    289     family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
    290     if (him->sa_family == AF_INET6) {
    291 #ifdef WIN32
    292         struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him;
    293 #else
    294         struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
    295 #endif
    296         jbyte *caddrNew = (jbyte *)&(him6->sin6_addr);
    297         if (NET_IsIPv4Mapped(caddrNew)) {
    298             int addrNew;
    299             int addrCur;
    300             if (family == AF_INET6) {
    301                 return JNI_FALSE;
    302             }
    303             addrNew = NET_IPv4MappedToIPv4(caddrNew);
    304             addrCur = getInetAddress_addr(env, iaObj);
    305             if (addrNew == addrCur) {
    306                 return JNI_TRUE;
    307             } else {
    308                 return JNI_FALSE;
    309             }
    310         } else {
    311             jbyteArray ipaddress;
    312             jbyte caddrCur[16];
    313             int scope;
    314 
    315             if (family == AF_INET) {
    316                 return JNI_FALSE;
    317             }
    318             scope = getInet6Address_scopeid(env, iaObj);
    319             getInet6Address_ipaddress(env, iaObj, (char *)caddrCur);
    320             if (NET_IsEqual(caddrNew, caddrCur) && cmpScopeID(scope, him)) {
    321                 return JNI_TRUE;
    322             } else {
    323                 return JNI_FALSE;
    324             }
    325         }
    326     } else
    327 #endif /* AF_INET6 */
    328         {
    329             struct sockaddr_in *him4 = (struct sockaddr_in *)him;
    330             int addrNew, addrCur;
    331             if (family != AF_INET) {
    332                 return JNI_FALSE;
    333             }
    334             addrNew = ntohl(him4->sin_addr.s_addr);
    335             addrCur = getInetAddress_addr(env, iaObj);
    336             if (addrNew == addrCur) {
    337                 return JNI_TRUE;
    338             } else {
    339                 return JNI_FALSE;
    340             }
    341         }
    342 }
    343 
    344 unsigned short
    345 in_cksum(unsigned short *addr, int len) {
    346     int nleft = len;
    347     int sum = 0;
    348     unsigned short *w = addr;
    349     unsigned short answer = 0;
    350     while(nleft > 1) {
    351         sum += *w++;
    352         nleft -= 2;
    353     }
    354 
    355     if (nleft == 1) {
    356         *(unsigned char *) (&answer) = *(unsigned char *)w;
    357         sum += answer;
    358     }
    359 
    360     sum = (sum >> 16) + (sum & 0xffff);
    361     sum += (sum >> 16);
    362     answer = ~sum;
    363     return (answer);
    364 }
    365