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 static void initInetAddrs(JNIEnv *env) { 79 if (!initialized) { 80 Java_java_net_InetAddress_init(env, 0); 81 Java_java_net_Inet4Address_init(env, 0); 82 Java_java_net_Inet6Address_init(env, 0); 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; 104 105 initInetAddrs(env); 106 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 107 CHECK_NULL_RETURN(holder, NULL); 108 return (*env)->GetObjectField(env, holder, ia6_scopeifnameID); 109 } 110 111 int setInet6Address_scopeifname(JNIEnv *env, jobject iaObj, jobject scopeifname) { 112 jobject holder; 113 114 initInetAddrs(env); 115 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 116 CHECK_NULL_RETURN(holder, JNI_FALSE); 117 (*env)->SetObjectField(env, holder, ia6_scopeifnameID, scopeifname); 118 return JNI_TRUE; 119 } 120 121 int getInet6Address_scopeid_set(JNIEnv *env, jobject iaObj) { 122 jobject holder; 123 124 initInetAddrs(env); 125 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 126 CHECK_NULL_RETURN(holder, -1); 127 return (*env)->GetBooleanField(env, holder, ia6_scopeidsetID); 128 } 129 130 int getInet6Address_scopeid(JNIEnv *env, jobject iaObj) { 131 jobject holder; 132 133 initInetAddrs(env); 134 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 135 CHECK_NULL_RETURN(holder, -1); 136 return (*env)->GetIntField(env, holder, ia6_scopeidID); 137 } 138 139 int setInet6Address_scopeid(JNIEnv *env, jobject iaObj, int scopeid) { 140 jobject holder; 141 142 initInetAddrs(env); 143 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 144 CHECK_NULL_RETURN(holder, JNI_FALSE); 145 (*env)->SetIntField(env, holder, ia6_scopeidID, scopeid); 146 if (scopeid > 0) { 147 (*env)->SetBooleanField(env, holder, ia6_scopeidsetID, JNI_TRUE); 148 } 149 return JNI_TRUE; 150 } 151 152 153 int getInet6Address_ipaddress(JNIEnv *env, jobject iaObj, char *dest) { 154 jobject holder, addr; 155 jbyteArray barr; 156 157 initInetAddrs(env); 158 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 159 CHECK_NULL_RETURN(holder, JNI_FALSE); 160 addr = (*env)->GetObjectField(env, holder, ia6_ipaddressID); 161 CHECK_NULL_RETURN(addr, JNI_FALSE); 162 (*env)->GetByteArrayRegion(env, addr, 0, 16, (jbyte *)dest); 163 return JNI_TRUE; 164 } 165 166 int setInet6Address_ipaddress(JNIEnv *env, jobject iaObj, char *address) { 167 jobject holder; 168 jbyteArray addr; 169 170 initInetAddrs(env); 171 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 172 CHECK_NULL_RETURN(holder, JNI_FALSE); 173 addr = (jbyteArray)(*env)->GetObjectField(env, holder, ia6_ipaddressID); 174 if (addr == NULL) { 175 addr = (*env)->NewByteArray(env, 16); 176 CHECK_NULL_RETURN(addr, JNI_FALSE); 177 (*env)->SetObjectField(env, holder, ia6_ipaddressID, addr); 178 } 179 (*env)->SetByteArrayRegion(env, addr, 0, 16, (jbyte *)address); 180 return JNI_TRUE; 181 } 182 183 void setInetAddress_addr(JNIEnv *env, jobject iaObj, int address) { 184 jobject holder; 185 initInetAddrs(env); 186 holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 187 (*env)->SetIntField(env, holder, iac_addressID, address); 188 } 189 190 void setInetAddress_family(JNIEnv *env, jobject iaObj, int family) { 191 jobject holder; 192 initInetAddrs(env); 193 holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 194 (*env)->SetIntField(env, holder, iac_familyID, family); 195 } 196 197 void setInetAddress_hostName(JNIEnv *env, jobject iaObj, jobject host) { 198 jobject holder; 199 initInetAddrs(env); 200 holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 201 (*env)->SetObjectField(env, holder, iac_hostNameID, host); 202 } 203 204 int getInetAddress_addr(JNIEnv *env, jobject iaObj) { 205 jobject holder; 206 initInetAddrs(env); 207 holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 208 return (*env)->GetIntField(env, holder, iac_addressID); 209 } 210 211 int getInetAddress_family(JNIEnv *env, jobject iaObj) { 212 jobject holder; 213 214 initInetAddrs(env); 215 holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 216 return (*env)->GetIntField(env, holder, iac_familyID); 217 } 218 219 jobject getInetAddress_hostName(JNIEnv *env, jobject iaObj) { 220 jobject holder; 221 initInetAddrs(env); 222 holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 223 return (*env)->GetObjectField(env, holder, iac_hostNameID); 224 } 225 226 JNIEXPORT jobject JNICALL 227 NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { 228 jobject iaObj; 229 initInetAddrs(env); 230 #ifdef AF_INET6 231 if (him->sa_family == AF_INET6) { 232 jbyteArray ipaddress; 233 #ifdef WIN32 234 struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him; 235 #else 236 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; 237 #endif 238 jbyte *caddr = (jbyte *)&(him6->sin6_addr); 239 if (NET_IsIPv4Mapped(caddr)) { 240 int address; 241 static jclass inet4Cls = 0; 242 if (inet4Cls == 0) { 243 jclass c = (*env)->FindClass(env, "java/net/Inet4Address"); 244 CHECK_NULL_RETURN(c, NULL); 245 inet4Cls = (*env)->NewGlobalRef(env, c); 246 CHECK_NULL_RETURN(inet4Cls, NULL); 247 (*env)->DeleteLocalRef(env, c); 248 } 249 iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID); 250 CHECK_NULL_RETURN(iaObj, NULL); 251 address = NET_IPv4MappedToIPv4(caddr); 252 setInetAddress_addr(env, iaObj, address); 253 setInetAddress_family(env, iaObj, IPv4); 254 } else { 255 static jclass inet6Cls = 0; 256 jint scope; 257 int ret; 258 if (inet6Cls == 0) { 259 jclass c = (*env)->FindClass(env, "java/net/Inet6Address"); 260 CHECK_NULL_RETURN(c, NULL); 261 inet6Cls = (*env)->NewGlobalRef(env, c); 262 CHECK_NULL_RETURN(inet6Cls, NULL); 263 (*env)->DeleteLocalRef(env, c); 264 } 265 iaObj = (*env)->NewObject(env, inet6Cls, ia6_ctrID); 266 CHECK_NULL_RETURN(iaObj, NULL); 267 ret = setInet6Address_ipaddress(env, iaObj, (char *)&(him6->sin6_addr)); 268 CHECK_NULL_RETURN(ret, NULL); 269 setInetAddress_family(env, iaObj, IPv6); 270 scope = getScopeID(him); 271 setInet6Address_scopeid(env, iaObj, scope); 272 } 273 *port = ntohs(him6->sin6_port); 274 } else 275 #endif /* AF_INET6 */ 276 { 277 struct sockaddr_in *him4 = (struct sockaddr_in *)him; 278 static jclass inet4Cls = 0; 279 280 if (inet4Cls == 0) { 281 jclass c = (*env)->FindClass(env, "java/net/Inet4Address"); 282 CHECK_NULL_RETURN(c, NULL); 283 inet4Cls = (*env)->NewGlobalRef(env, c); 284 CHECK_NULL_RETURN(inet4Cls, NULL); 285 (*env)->DeleteLocalRef(env, c); 286 } 287 iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID); 288 CHECK_NULL_RETURN(iaObj, NULL); 289 setInetAddress_family(env, iaObj, IPv4); 290 setInetAddress_addr(env, iaObj, ntohl(him4->sin_addr.s_addr)); 291 *port = ntohs(him4->sin_port); 292 } 293 return iaObj; 294 } 295 296 JNIEXPORT jint JNICALL 297 NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj) 298 { 299 jint family = AF_INET; 300 301 #ifdef AF_INET6 302 family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6; 303 if (him->sa_family == AF_INET6) { 304 #ifdef WIN32 305 struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him; 306 #else 307 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; 308 #endif 309 jbyte *caddrNew = (jbyte *)&(him6->sin6_addr); 310 if (NET_IsIPv4Mapped(caddrNew)) { 311 int addrNew; 312 int addrCur; 313 if (family == AF_INET6) { 314 return JNI_FALSE; 315 } 316 addrNew = NET_IPv4MappedToIPv4(caddrNew); 317 addrCur = getInetAddress_addr(env, iaObj); 318 if (addrNew == addrCur) { 319 return JNI_TRUE; 320 } else { 321 return JNI_FALSE; 322 } 323 } else { 324 jbyteArray ipaddress; 325 jbyte caddrCur[16]; 326 int scope; 327 328 if (family == AF_INET) { 329 return JNI_FALSE; 330 } 331 scope = getInet6Address_scopeid(env, iaObj); 332 getInet6Address_ipaddress(env, iaObj, (char *)caddrCur); 333 if (NET_IsEqual(caddrNew, caddrCur) && cmpScopeID(scope, him)) { 334 return JNI_TRUE; 335 } else { 336 return JNI_FALSE; 337 } 338 } 339 } else 340 #endif /* AF_INET6 */ 341 { 342 struct sockaddr_in *him4 = (struct sockaddr_in *)him; 343 int addrNew, addrCur; 344 if (family != AF_INET) { 345 return JNI_FALSE; 346 } 347 addrNew = ntohl(him4->sin_addr.s_addr); 348 addrCur = getInetAddress_addr(env, iaObj); 349 if (addrNew == addrCur) { 350 return JNI_TRUE; 351 } else { 352 return JNI_FALSE; 353 } 354 } 355 } 356 357 unsigned short 358 in_cksum(unsigned short *addr, int len) { 359 int nleft = len; 360 int sum = 0; 361 unsigned short *w = addr; 362 unsigned short answer = 0; 363 while(nleft > 1) { 364 sum += *w++; 365 nleft -= 2; 366 } 367 368 if (nleft == 1) { 369 *(unsigned char *) (&answer) = *(unsigned char *)w; 370 sum += answer; 371 } 372 373 sum = (sum >> 16) + (sum & 0xffff); 374 sum += (sum >> 16); 375 answer = ~sum; 376 return (answer); 377 }