1 /*
   2  * Copyright (c) 1998, 2013, 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 JNI_OnLoad(JavaVM *vm, void *reserved)
  42 {
  43     JNIEnv *env;
  44     jclass iCls;
  45     jmethodID mid;
  46     jstring s;
  47     jint preferIPv4Stack;
  48 
  49     if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_2) != JNI_OK) {
  50         return JNI_EVERSION; /* JNI version not supported */
  51     }
  52 
  53     iCls = (*env)->FindClass(env, "java/lang/Boolean");
  54     CHECK_NULL_RETURN(iCls, JNI_VERSION_1_2);
  55     mid = (*env)->GetStaticMethodID(env, iCls, "getBoolean", "(Ljava/lang/String;)Z");
  56     CHECK_NULL_RETURN(mid, JNI_VERSION_1_2);
  57     s = (*env)->NewStringUTF(env, "java.net.preferIPv4Stack");
  58     CHECK_NULL_RETURN(s, JNI_VERSION_1_2);
  59     preferIPv4Stack = (*env)->CallStaticBooleanMethod(env, iCls, mid, s);
  60 
  61     /*
  62        Since we have initialized and loaded the Socket library we will
  63        check now to whether we have IPv6 on this platform and if the
  64        supporting socket APIs are available
  65     */
  66     IPv6_available = IPv6_supported() & (!preferIPv4Stack);
  67     platformInit();
  68     parseExclusiveBindProperty(env);
  69 
  70     return JNI_VERSION_1_2;
  71 }
  72 
  73 static int initialized = 0;
  74 
  75 JNIEXPORT void JNICALL initInetAddressIDs(JNIEnv *env) {
  76     if (!initialized) {
  77         Java_java_net_InetAddress_init(env, 0);
  78         JNU_CHECK_EXCEPTION(env);
  79         Java_java_net_Inet4Address_init(env, 0);
  80         JNU_CHECK_EXCEPTION(env);
  81         Java_java_net_Inet6Address_init(env, 0);
  82         JNU_CHECK_EXCEPTION(env);
  83         initialized = 1;
  84     }
  85 }
  86 
  87 /* The address, and family fields used to be in InetAddress
  88  * but are now in an implementation object. So, there is an extra
  89  * level of indirection to access them now.
  90  */
  91 
  92 extern jclass iac_class;
  93 extern jfieldID ia_holderID;
  94 extern jfieldID iac_addressID;
  95 extern jfieldID iac_familyID;
  96 
  97 /**
  98  * set_ methods return JNI_TRUE on success JNI_FALSE on error
  99  * get_ methods that return +ve int return -1 on error
 100  * get_ methods that return objects return NULL on error.
 101  */
 102 jobject getInet6Address_scopeifname(JNIEnv *env, jobject iaObj) {
 103     jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
 104     CHECK_NULL_RETURN(holder, NULL);
 105     return (*env)->GetObjectField(env, holder, ia6_scopeifnameID);
 106 }
 107 
 108 jboolean setInet6Address_scopeifname(JNIEnv *env, jobject iaObj, jobject scopeifname) {
 109     jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
 110     CHECK_NULL_RETURN(holder, JNI_FALSE);
 111     (*env)->SetObjectField(env, holder, ia6_scopeifnameID, scopeifname);
 112     return JNI_TRUE;
 113 }
 114 
 115 int getInet6Address_scopeid_set(JNIEnv *env, jobject iaObj) {
 116     jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
 117     CHECK_NULL_RETURN(holder, -1);
 118     return (*env)->GetBooleanField(env, holder, ia6_scopeidsetID);
 119 }
 120 
 121 int getInet6Address_scopeid(JNIEnv *env, jobject iaObj) {
 122     jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
 123     CHECK_NULL_RETURN(holder, -1);
 124     return (*env)->GetIntField(env, holder, ia6_scopeidID);
 125 }
 126 
 127 jboolean setInet6Address_scopeid(JNIEnv *env, jobject iaObj, int scopeid) {
 128     jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
 129     CHECK_NULL_RETURN(holder, JNI_FALSE);
 130     (*env)->SetIntField(env, holder, ia6_scopeidID, scopeid);
 131     if (scopeid > 0) {
 132         (*env)->SetBooleanField(env, holder, ia6_scopeidsetID, JNI_TRUE);
 133     }
 134     return JNI_TRUE;
 135 }
 136 
 137 jboolean getInet6Address_ipaddress(JNIEnv *env, jobject iaObj, char *dest) {
 138     jobject holder, addr;
 139 
 140     holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
 141     CHECK_NULL_RETURN(holder, JNI_FALSE);
 142     addr =  (*env)->GetObjectField(env, holder, ia6_ipaddressID);
 143     CHECK_NULL_RETURN(addr, JNI_FALSE);
 144     (*env)->GetByteArrayRegion(env, addr, 0, 16, (jbyte *)dest);
 145     return JNI_TRUE;
 146 }
 147 
 148 jboolean setInet6Address_ipaddress(JNIEnv *env, jobject iaObj, char *address) {
 149     jobject holder;
 150     jbyteArray addr;
 151 
 152     holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
 153     CHECK_NULL_RETURN(holder, JNI_FALSE);
 154     addr =  (jbyteArray)(*env)->GetObjectField(env, holder, ia6_ipaddressID);
 155     if (addr == NULL) {
 156         addr = (*env)->NewByteArray(env, 16);
 157         CHECK_NULL_RETURN(addr, JNI_FALSE);
 158         (*env)->SetObjectField(env, holder, ia6_ipaddressID, addr);
 159     }
 160     (*env)->SetByteArrayRegion(env, addr, 0, 16, (jbyte *)address);
 161     return JNI_TRUE;
 162 }
 163 
 164 void setInetAddress_addr(JNIEnv *env, jobject iaObj, int address) {
 165     jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
 166     (*env)->SetIntField(env, holder, iac_addressID, address);
 167 }
 168 
 169 void setInetAddress_family(JNIEnv *env, jobject iaObj, int family) {
 170     jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
 171     (*env)->SetIntField(env, holder, iac_familyID, family);
 172 }
 173 
 174 void setInetAddress_hostName(JNIEnv *env, jobject iaObj, jobject host) {
 175     jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
 176     (*env)->SetObjectField(env, holder, iac_hostNameID, host);
 177 }
 178 
 179 int getInetAddress_addr(JNIEnv *env, jobject iaObj) {
 180     jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
 181     return (*env)->GetIntField(env, holder, iac_addressID);
 182 }
 183 
 184 int getInetAddress_family(JNIEnv *env, jobject iaObj) {
 185     jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
 186     return (*env)->GetIntField(env, holder, iac_familyID);
 187 }
 188 
 189 jobject getInetAddress_hostName(JNIEnv *env, jobject iaObj) {
 190     jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
 191     return (*env)->GetObjectField(env, holder, iac_hostNameID);
 192 }
 193 
 194 JNIEXPORT jobject JNICALL
 195 NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) {
 196     jobject iaObj;
 197 #ifdef AF_INET6
 198     if (him->sa_family == AF_INET6) {
 199 #ifdef WIN32
 200         struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him;
 201 #else
 202         struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
 203 #endif
 204         jbyte *caddr = (jbyte *)&(him6->sin6_addr);
 205         if (NET_IsIPv4Mapped(caddr)) {
 206             int address;
 207             iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
 208             CHECK_NULL_RETURN(iaObj, NULL);
 209             address = NET_IPv4MappedToIPv4(caddr);
 210             setInetAddress_addr(env, iaObj, address);
 211             setInetAddress_family(env, iaObj, IPv4);
 212         } else {
 213             jint scope;
 214             jboolean ret;
 215             iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
 216             CHECK_NULL_RETURN(iaObj, NULL);
 217             ret = setInet6Address_ipaddress(env, iaObj, (char *)&(him6->sin6_addr));
 218             if (ret == JNI_FALSE)
 219                 return NULL;
 220             setInetAddress_family(env, iaObj, IPv6);
 221             scope = getScopeID(him);
 222             setInet6Address_scopeid(env, iaObj, scope);
 223         }
 224         *port = ntohs(him6->sin6_port);
 225     } else
 226 #endif /* AF_INET6 */
 227         {
 228             struct sockaddr_in *him4 = (struct sockaddr_in *)him;
 229             iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
 230             CHECK_NULL_RETURN(iaObj, NULL);
 231             setInetAddress_family(env, iaObj, IPv4);
 232             setInetAddress_addr(env, iaObj, ntohl(him4->sin_addr.s_addr));
 233             *port = ntohs(him4->sin_port);
 234         }
 235     return iaObj;
 236 }
 237 
 238 JNIEXPORT jint JNICALL
 239 NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj)
 240 {
 241     jint family = AF_INET;
 242 
 243 #ifdef AF_INET6
 244     family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
 245     if (him->sa_family == AF_INET6) {
 246 #ifdef WIN32
 247         struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him;
 248 #else
 249         struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
 250 #endif
 251         jbyte *caddrNew = (jbyte *)&(him6->sin6_addr);
 252         if (NET_IsIPv4Mapped(caddrNew)) {
 253             int addrNew;
 254             int addrCur;
 255             if (family == AF_INET6) {
 256                 return JNI_FALSE;
 257             }
 258             addrNew = NET_IPv4MappedToIPv4(caddrNew);
 259             addrCur = getInetAddress_addr(env, iaObj);
 260             if (addrNew == addrCur) {
 261                 return JNI_TRUE;
 262             } else {
 263                 return JNI_FALSE;
 264             }
 265         } else {
 266             jbyte caddrCur[16];
 267             int scope;
 268 
 269             if (family == AF_INET) {
 270                 return JNI_FALSE;
 271             }
 272             scope = getInet6Address_scopeid(env, iaObj);
 273             getInet6Address_ipaddress(env, iaObj, (char *)caddrCur);
 274             if (NET_IsEqual(caddrNew, caddrCur) && cmpScopeID(scope, him)) {
 275                 return JNI_TRUE;
 276             } else {
 277                 return JNI_FALSE;
 278             }
 279         }
 280     } else
 281 #endif /* AF_INET6 */
 282         {
 283             struct sockaddr_in *him4 = (struct sockaddr_in *)him;
 284             int addrNew, addrCur;
 285             if (family != AF_INET) {
 286                 return JNI_FALSE;
 287             }
 288             addrNew = ntohl(him4->sin_addr.s_addr);
 289             addrCur = getInetAddress_addr(env, iaObj);
 290             if (addrNew == addrCur) {
 291                 return JNI_TRUE;
 292             } else {
 293                 return JNI_FALSE;
 294             }
 295         }
 296 }
 297 
 298 unsigned short
 299 in_cksum(unsigned short *addr, int len) {
 300     int nleft = len;
 301     int sum = 0;
 302     unsigned short *w = addr;
 303     unsigned short answer = 0;
 304     while(nleft > 1) {
 305         sum += *w++;
 306         nleft -= 2;
 307     }
 308 
 309     if (nleft == 1) {
 310         *(unsigned char *) (&answer) = *(unsigned char *)w;
 311         sum += answer;
 312     }
 313 
 314     sum = (sum >> 16) + (sum & 0xffff);
 315     sum += (sum >> 16);
 316     answer = ~sum;
 317     return (answer);
 318 }