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         if (JVM_InitializeSocketLibrary() < 0) {
  51             JNU_ThrowByName(env, "java/lang/UnsatisfiedLinkError",
  52                             "failed to initialize net library.");
  53             return JNI_VERSION_1_2;
  54         }
  55     }

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