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 #ifdef _AIX 32 /* Initialize stubs for blocking I/O workarounds (see src/solaris/native/java/net/linux_close.c) */ 33 extern void aix_close_init(); 34 #endif 35 36 int IPv6_supported() ; 37 38 static int IPv6_available; 39 40 JNIEXPORT jint JNICALL ipv6_available() 41 { 42 return IPv6_available ; 43 } 44 45 JNIEXPORT jint JNICALL 46 JNI_OnLoad(JavaVM *vm, void *reserved) 47 { 48 JNIEnv *env; 49 jclass iCls; 50 jmethodID mid; 51 jstring s; 52 jint preferIPv4Stack; 53 54 if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_2) == JNI_OK) { 55 if (JVM_InitializeSocketLibrary() < 0) { 56 JNU_ThrowByName(env, "java/lang/UnsatisfiedLinkError", 57 "failed to initialize net library."); 58 return JNI_VERSION_1_2; 59 } 60 } 61 iCls = (*env)->FindClass(env, "java/lang/Boolean"); 62 CHECK_NULL_RETURN(iCls, JNI_VERSION_1_2); 63 mid = (*env)->GetStaticMethodID(env, iCls, "getBoolean", "(Ljava/lang/String;)Z"); 64 CHECK_NULL_RETURN(mid, JNI_VERSION_1_2); 65 s = (*env)->NewStringUTF(env, "java.net.preferIPv4Stack"); 66 CHECK_NULL_RETURN(s, JNI_VERSION_1_2); 67 preferIPv4Stack = (*env)->CallStaticBooleanMethod(env, iCls, mid, s); 68 69 /* 70 Since we have initialized and loaded the Socket library we will 71 check now to whether we have IPv6 on this platform and if the 72 supporting socket APIs are available 73 */ 74 IPv6_available = IPv6_supported() & (!preferIPv4Stack); 75 initLocalAddrTable (); 76 #ifdef _AIX 77 /* Initialize stubs for blocking I/O workarounds (see src/solaris/native/java/net/linux_close.c) */ 78 aix_close_init(); 79 #endif 80 parseExclusiveBindProperty(env); 81 82 return JNI_VERSION_1_2; 83 } 84 85 static int initialized = 0; 86 87 static void initInetAddrs(JNIEnv *env) { 88 if (!initialized) { 89 Java_java_net_InetAddress_init(env, 0); 90 Java_java_net_Inet4Address_init(env, 0); 91 Java_java_net_Inet6Address_init(env, 0); 92 initialized = 1; 93 } 94 } 95 96 /* The address, and family fields used to be in InetAddress 97 * but are now in an implementation object. So, there is an extra 98 * level of indirection to access them now. 99 */ 100 101 extern jclass iac_class; 102 extern jfieldID ia_holderID; 103 extern jfieldID iac_addressID; 104 extern jfieldID iac_familyID; 105 106 /** 107 * set_ methods return JNI_TRUE on success JNI_FALSE on error 108 * get_ methods that return +ve int return -1 on error 109 * get_ methods that return objects return NULL on error. 110 */ 111 jobject getInet6Address_scopeifname(JNIEnv *env, jobject iaObj) { 112 jobject holder; 113 114 initInetAddrs(env); 115 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 116 CHECK_NULL_RETURN(holder, NULL); 117 return (*env)->GetObjectField(env, holder, ia6_scopeifnameID); 118 } 119 120 int setInet6Address_scopeifname(JNIEnv *env, jobject iaObj, jobject scopeifname) { 121 jobject holder; 122 123 initInetAddrs(env); 124 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 125 CHECK_NULL_RETURN(holder, JNI_FALSE); 126 (*env)->SetObjectField(env, holder, ia6_scopeifnameID, scopeifname); 127 return JNI_TRUE; 128 } 129 130 int getInet6Address_scopeid_set(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)->GetBooleanField(env, holder, ia6_scopeidsetID); 137 } 138 139 int getInet6Address_scopeid(JNIEnv *env, jobject iaObj) { 140 jobject holder; 141 142 initInetAddrs(env); 143 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 144 CHECK_NULL_RETURN(holder, -1); 145 return (*env)->GetIntField(env, holder, ia6_scopeidID); 146 } 147 148 int setInet6Address_scopeid(JNIEnv *env, jobject iaObj, int scopeid) { 149 jobject holder; 150 151 initInetAddrs(env); 152 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 153 CHECK_NULL_RETURN(holder, JNI_FALSE); 154 (*env)->SetIntField(env, holder, ia6_scopeidID, scopeid); 155 if (scopeid > 0) { 156 (*env)->SetBooleanField(env, holder, ia6_scopeidsetID, JNI_TRUE); 157 } 158 return JNI_TRUE; 159 } 160 161 162 int getInet6Address_ipaddress(JNIEnv *env, jobject iaObj, char *dest) { 163 jobject holder, addr; 164 jbyteArray barr; 165 166 initInetAddrs(env); 167 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 168 CHECK_NULL_RETURN(holder, JNI_FALSE); 169 addr = (*env)->GetObjectField(env, holder, ia6_ipaddressID); 170 CHECK_NULL_RETURN(addr, JNI_FALSE); 171 (*env)->GetByteArrayRegion(env, addr, 0, 16, (jbyte *)dest); 172 return JNI_TRUE; 173 } 174 175 int setInet6Address_ipaddress(JNIEnv *env, jobject iaObj, char *address) { 176 jobject holder; 177 jbyteArray addr; 178 179 initInetAddrs(env); 180 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 181 CHECK_NULL_RETURN(holder, JNI_FALSE); 182 addr = (jbyteArray)(*env)->GetObjectField(env, holder, ia6_ipaddressID); 183 if (addr == NULL) { 184 addr = (*env)->NewByteArray(env, 16); 185 CHECK_NULL_RETURN(addr, JNI_FALSE); 186 (*env)->SetObjectField(env, holder, ia6_ipaddressID, addr); 187 } 188 (*env)->SetByteArrayRegion(env, addr, 0, 16, (jbyte *)address); 189 return JNI_TRUE; 190 } 191 192 void setInetAddress_addr(JNIEnv *env, jobject iaObj, int address) { 193 jobject holder; 194 initInetAddrs(env); 195 holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 196 (*env)->SetIntField(env, holder, iac_addressID, address); 197 } 198 199 void setInetAddress_family(JNIEnv *env, jobject iaObj, int family) { 200 jobject holder; 201 initInetAddrs(env); 202 holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 203 (*env)->SetIntField(env, holder, iac_familyID, family); 204 } 205 206 void setInetAddress_hostName(JNIEnv *env, jobject iaObj, jobject host) { 207 jobject holder; 208 initInetAddrs(env); 209 holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 210 (*env)->SetObjectField(env, holder, iac_hostNameID, host); 211 } 212 213 int getInetAddress_addr(JNIEnv *env, jobject iaObj) { 214 jobject holder; 215 initInetAddrs(env); 216 holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 217 return (*env)->GetIntField(env, holder, iac_addressID); 218 } 219 220 int getInetAddress_family(JNIEnv *env, jobject iaObj) { 221 jobject holder; 222 223 initInetAddrs(env); 224 holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 225 return (*env)->GetIntField(env, holder, iac_familyID); 226 } 227 228 jobject getInetAddress_hostName(JNIEnv *env, jobject iaObj) { 229 jobject holder; 230 initInetAddrs(env); 231 holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 232 return (*env)->GetObjectField(env, holder, iac_hostNameID); 233 } 234 235 JNIEXPORT jobject JNICALL 236 NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { 237 jobject iaObj; 238 initInetAddrs(env); 239 #ifdef AF_INET6 240 if (him->sa_family == AF_INET6) { 241 jbyteArray ipaddress; 242 #ifdef WIN32 243 struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him; 244 #else 245 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; 246 #endif 247 jbyte *caddr = (jbyte *)&(him6->sin6_addr); 248 if (NET_IsIPv4Mapped(caddr)) { 249 int address; 250 static jclass inet4Cls = 0; 251 if (inet4Cls == 0) { 252 jclass c = (*env)->FindClass(env, "java/net/Inet4Address"); 253 CHECK_NULL_RETURN(c, NULL); 254 inet4Cls = (*env)->NewGlobalRef(env, c); 255 CHECK_NULL_RETURN(inet4Cls, NULL); 256 (*env)->DeleteLocalRef(env, c); 257 } 258 iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID); 259 CHECK_NULL_RETURN(iaObj, NULL); 260 address = NET_IPv4MappedToIPv4(caddr); 261 setInetAddress_addr(env, iaObj, address); 262 setInetAddress_family(env, iaObj, IPv4); 263 } else { 264 static jclass inet6Cls = 0; 265 jint scope; 266 int ret; 267 if (inet6Cls == 0) { 268 jclass c = (*env)->FindClass(env, "java/net/Inet6Address"); 269 CHECK_NULL_RETURN(c, NULL); 270 inet6Cls = (*env)->NewGlobalRef(env, c); 271 CHECK_NULL_RETURN(inet6Cls, NULL); 272 (*env)->DeleteLocalRef(env, c); 273 } 274 iaObj = (*env)->NewObject(env, inet6Cls, ia6_ctrID); 275 CHECK_NULL_RETURN(iaObj, NULL); 276 ret = setInet6Address_ipaddress(env, iaObj, (char *)&(him6->sin6_addr)); 277 CHECK_NULL_RETURN(ret, NULL); 278 setInetAddress_family(env, iaObj, IPv6); 279 scope = getScopeID(him); 280 setInet6Address_scopeid(env, iaObj, scope); 281 } 282 *port = ntohs(him6->sin6_port); 283 } else 284 #endif /* AF_INET6 */ 285 { 286 struct sockaddr_in *him4 = (struct sockaddr_in *)him; 287 static jclass inet4Cls = 0; 288 289 if (inet4Cls == 0) { 290 jclass c = (*env)->FindClass(env, "java/net/Inet4Address"); 291 CHECK_NULL_RETURN(c, NULL); 292 inet4Cls = (*env)->NewGlobalRef(env, c); 293 CHECK_NULL_RETURN(inet4Cls, NULL); 294 (*env)->DeleteLocalRef(env, c); 295 } 296 iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID); 297 CHECK_NULL_RETURN(iaObj, NULL); 298 setInetAddress_family(env, iaObj, IPv4); 299 setInetAddress_addr(env, iaObj, ntohl(him4->sin_addr.s_addr)); 300 *port = ntohs(him4->sin_port); 301 } 302 return iaObj; 303 } 304 305 JNIEXPORT jint JNICALL 306 NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj) 307 { 308 jint family = AF_INET; 309 310 #ifdef AF_INET6 311 family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6; 312 if (him->sa_family == AF_INET6) { 313 #ifdef WIN32 314 struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him; 315 #else 316 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; 317 #endif 318 jbyte *caddrNew = (jbyte *)&(him6->sin6_addr); 319 if (NET_IsIPv4Mapped(caddrNew)) { 320 int addrNew; 321 int addrCur; 322 if (family == AF_INET6) { 323 return JNI_FALSE; 324 } 325 addrNew = NET_IPv4MappedToIPv4(caddrNew); 326 addrCur = getInetAddress_addr(env, iaObj); 327 if (addrNew == addrCur) { 328 return JNI_TRUE; 329 } else { 330 return JNI_FALSE; 331 } 332 } else { 333 jbyteArray ipaddress; 334 jbyte caddrCur[16]; 335 int scope; 336 337 if (family == AF_INET) { 338 return JNI_FALSE; 339 } 340 scope = getInet6Address_scopeid(env, iaObj); 341 getInet6Address_ipaddress(env, iaObj, (char *)caddrCur); 342 if (NET_IsEqual(caddrNew, caddrCur) && cmpScopeID(scope, him)) { 343 return JNI_TRUE; 344 } else { 345 return JNI_FALSE; 346 } 347 } 348 } else 349 #endif /* AF_INET6 */ 350 { 351 struct sockaddr_in *him4 = (struct sockaddr_in *)him; 352 int addrNew, addrCur; 353 if (family != AF_INET) { 354 return JNI_FALSE; 355 } 356 addrNew = ntohl(him4->sin_addr.s_addr); 357 addrCur = getInetAddress_addr(env, iaObj); 358 if (addrNew == addrCur) { 359 return JNI_TRUE; 360 } else { 361 return JNI_FALSE; 362 } 363 } 364 } 365 366 unsigned short 367 in_cksum(unsigned short *addr, int len) { 368 int nleft = len; 369 int sum = 0; 370 unsigned short *w = addr; 371 unsigned short answer = 0; 372 while(nleft > 1) { 373 sum += *w++; 374 nleft -= 2; 375 } 376 377 if (nleft == 1) { 378 *(unsigned char *) (&answer) = *(unsigned char *)w; 379 sum += answer; 380 } 381 382 sum = (sum >> 16) + (sum & 0xffff); 383 sum += (sum >> 16); 384 answer = ~sum; 385 return (answer); 386 }