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 }