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