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 void setInetAddress_addr(JNIEnv *env, jobject iaObj, int address) {
     76     jobject holder;
     77     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
     78     (*env)->SetIntField(env, holder, iac_addressID, address);
     79 }
     80 
     81 void setInetAddress_family(JNIEnv *env, jobject iaObj, int family) {
     82     jobject holder;
     83     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
     84     (*env)->SetIntField(env, holder, iac_familyID, family);
     85 }
     86 
     87 void setInetAddress_hostName(JNIEnv *env, jobject iaObj, jobject host) {
     88     jobject holder;
     89     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
     90     (*env)->SetObjectField(env, holder, iac_hostNameID, host);
     91 }
     92 
     93 int getInetAddress_addr(JNIEnv *env, jobject iaObj) {
     94     jobject holder;
     95     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
     96     return (*env)->GetIntField(env, holder, iac_addressID);
     97 }
     98 
     99 int getInetAddress_family(JNIEnv *env, jobject iaObj) {
    100     jobject holder;
    101 
    102     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
    103     return (*env)->GetIntField(env, holder, iac_familyID);
    104 }
    105 
    106 jobject getInetAddress_hostName(JNIEnv *env, jobject iaObj) {
    107     jobject holder;
    108     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
    109     return (*env)->GetObjectField(env, holder, iac_hostNameID);
    110 }
    111 
    112 JNIEXPORT jobject JNICALL
    113 NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) {
    114     jobject iaObj;
    115 #ifdef AF_INET6
    116     if (him->sa_family == AF_INET6) {
    117         jbyteArray ipaddress;
    118 #ifdef WIN32
    119         struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him;
    120 #else
    121         struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
    122 #endif
    123         jbyte *caddr = (jbyte *)&(him6->sin6_addr);
    124         if (NET_IsIPv4Mapped(caddr)) {
    125             int address;
    126             static jclass inet4Cls = 0;
    127             if (inet4Cls == 0) {
    128                 jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
    129                 CHECK_NULL_RETURN(c, NULL);
    130                 inet4Cls = (*env)->NewGlobalRef(env, c);
    131                 CHECK_NULL_RETURN(inet4Cls, NULL);
    132                 (*env)->DeleteLocalRef(env, c);
    133             }
    134             iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID);
    135             CHECK_NULL_RETURN(iaObj, NULL);
    136             address = NET_IPv4MappedToIPv4(caddr);
    137             setInetAddress_addr(env, iaObj, address);
    138             setInetAddress_family(env, iaObj, IPv4);
    139         } else {
    140             static jclass inet6Cls = 0;
    141             jint scope;
    142             if (inet6Cls == 0) {
    143                 jclass c = (*env)->FindClass(env, "java/net/Inet6Address");
    144                 CHECK_NULL_RETURN(c, NULL);
    145                 inet6Cls = (*env)->NewGlobalRef(env, c);
    146                 CHECK_NULL_RETURN(inet6Cls, NULL);
    147                 (*env)->DeleteLocalRef(env, c);
    148             }
    149             iaObj = (*env)->NewObject(env, inet6Cls, ia6_ctrID);
    150             CHECK_NULL_RETURN(iaObj, NULL);
    151             ipaddress = (*env)->NewByteArray(env, 16);
    152             CHECK_NULL_RETURN(ipaddress, NULL);
    153             (*env)->SetByteArrayRegion(env, ipaddress, 0, 16,
    154                                        (jbyte *)&(him6->sin6_addr));
    155 
    156             (*env)->SetObjectField(env, iaObj, ia6_ipaddressID, ipaddress);
    157 
    158             setInetAddress_family(env, iaObj, IPv6);
    159             scope = getScopeID(him);
    160             (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
    161             if (scope > 0)
    162                 (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
    163         }
    164         *port = ntohs(him6->sin6_port);
    165     } else
    166 #endif /* AF_INET6 */
    167         {
    168             struct sockaddr_in *him4 = (struct sockaddr_in *)him;
    169             static jclass inet4Cls = 0;
    170 
    171             if (inet4Cls == 0) {
    172                 jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
    173                 CHECK_NULL_RETURN(c, NULL);
    174                 inet4Cls = (*env)->NewGlobalRef(env, c);
    175                 CHECK_NULL_RETURN(inet4Cls, NULL);
    176                 (*env)->DeleteLocalRef(env, c);
    177             }
    178             iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID);
    179             CHECK_NULL_RETURN(iaObj, NULL);
    180             setInetAddress_family(env, iaObj, IPv4);
    181             setInetAddress_addr(env, iaObj, ntohl(him4->sin_addr.s_addr));
    182             *port = ntohs(him4->sin_port);
    183         }
    184     return iaObj;
    185 }
    186 
    187 JNIEXPORT jint JNICALL
    188 NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj)
    189 {
    190     jint family = AF_INET;
    191 
    192 #ifdef AF_INET6
    193     family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
    194     if (him->sa_family == AF_INET6) {
    195 #ifdef WIN32
    196         struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him;
    197 #else
    198         struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
    199 #endif
    200         jbyte *caddrNew = (jbyte *)&(him6->sin6_addr);
    201         if (NET_IsIPv4Mapped(caddrNew)) {
    202             int addrNew;
    203             int addrCur;
    204             if (family == AF_INET6) {
    205                 return JNI_FALSE;
    206             }
    207             addrNew = NET_IPv4MappedToIPv4(caddrNew);
    208             addrCur = getInetAddress_addr(env, iaObj);
    209             if (addrNew == addrCur) {
    210                 return JNI_TRUE;
    211             } else {
    212                 return JNI_FALSE;
    213             }
    214         } else {
    215             jbyteArray ipaddress;
    216             jbyte caddrCur[16];
    217             int scope;
    218 
    219             if (family == AF_INET) {
    220                 return JNI_FALSE;
    221             }
    222             ipaddress = (*env)->GetObjectField(env, iaObj, ia6_ipaddressID);
    223             scope = (*env)->GetIntField(env, iaObj, ia6_scopeidID);
    224             (*env)->GetByteArrayRegion(env, ipaddress, 0, 16, caddrCur);
    225             if (NET_IsEqual(caddrNew, caddrCur) && cmpScopeID(scope, him)) {
    226                 return JNI_TRUE;
    227             } else {
    228                 return JNI_FALSE;
    229             }
    230         }
    231     } else
    232 #endif /* AF_INET6 */
    233         {
    234             struct sockaddr_in *him4 = (struct sockaddr_in *)him;
    235             int addrNew, addrCur;
    236             if (family != AF_INET) {
    237                 return JNI_FALSE;
    238             }
    239             addrNew = ntohl(him4->sin_addr.s_addr);
    240             addrCur = getInetAddress_addr(env, iaObj);
    241             if (addrNew == addrCur) {
    242                 return JNI_TRUE;
    243             } else {
    244                 return JNI_FALSE;
    245             }
    246         }
    247 }
    248 
    249 unsigned short
    250 in_cksum(unsigned short *addr, int len) {
    251     int nleft = len;
    252     int sum = 0;
    253     unsigned short *w = addr;
    254     unsigned short answer = 0;
    255     while(nleft > 1) {
    256         sum += *w++;
    257         nleft -= 2;
    258     }
    259 
    260     if (nleft == 1) {
    261         *(unsigned char *) (&answer) = *(unsigned char *)w;
    262         sum += answer;
    263     }
    264 
    265     sum = (sum >> 16) + (sum & 0xffff);
    266     sum += (sum >> 16);
    267     answer = ~sum;
    268     return (answer);
    269 }
    270