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 (*env)->SetObjectField(env, holder, iac_origHostNameID, host); 181 } 182 183 int getInetAddress_addr(JNIEnv *env, jobject iaObj) { 184 jobject holder; 185 // Android-changed: initInetAddrs(env); 186 holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 187 return (*env)->GetIntField(env, holder, iac_addressID); 188 } 189 190 int getInetAddress_family(JNIEnv *env, jobject iaObj) { 191 jobject holder; 192 193 // Android-changed: initInetAddrs(env); 194 holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 195 return (*env)->GetIntField(env, holder, iac_familyID); 196 } 197 198 jobject getInetAddress_hostName(JNIEnv *env, jobject iaObj) { 199 jobject holder; 200 // Android-changed: initInetAddrs(env); 201 holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 202 return (*env)->GetObjectField(env, holder, iac_hostNameID); 203 } 204 205 JNIEXPORT jobject JNICALL 206 NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { 207 jobject iaObj; 208 // Android-changed: initInetAddrs(env); 209 #ifdef AF_INET6 210 if (him->sa_family == AF_INET6) { 211 jbyteArray ipaddress; 212 #ifdef WIN32 213 struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him; 214 #else 215 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; 216 #endif 217 jbyte *caddr = (jbyte *)&(him6->sin6_addr); 218 if (NET_IsIPv4Mapped(caddr)) { 219 int address; 220 static jclass inet4Cls = 0; 221 if (inet4Cls == 0) { 222 jclass c = (*env)->FindClass(env, "java/net/Inet4Address"); 223 CHECK_NULL_RETURN(c, NULL); 224 inet4Cls = (*env)->NewGlobalRef(env, c); 225 CHECK_NULL_RETURN(inet4Cls, NULL); 226 (*env)->DeleteLocalRef(env, c); 227 } 228 iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID); 229 CHECK_NULL_RETURN(iaObj, NULL); 230 address = NET_IPv4MappedToIPv4(caddr); 231 setInetAddress_addr(env, iaObj, address); 232 setInetAddress_family(env, iaObj, IPv4); 233 } else { 234 static jclass inet6Cls = 0; 235 jint scope; 236 int ret; 237 if (inet6Cls == 0) { 238 jclass c = (*env)->FindClass(env, "java/net/Inet6Address"); 239 CHECK_NULL_RETURN(c, NULL); 240 inet6Cls = (*env)->NewGlobalRef(env, c); 241 CHECK_NULL_RETURN(inet6Cls, NULL); 242 (*env)->DeleteLocalRef(env, c); 243 } 244 iaObj = (*env)->NewObject(env, inet6Cls, ia6_ctrID); 245 CHECK_NULL_RETURN(iaObj, NULL); 246 ret = setInet6Address_ipaddress(env, iaObj, (char *)&(him6->sin6_addr)); 247 // Android-changed: Appease compiler type checking. 248 // CHECK_NULL_RETURN(ret, NULL); 249 if (ret == JNI_FALSE) return NULL; 250 setInetAddress_family(env, iaObj, IPv6); 251 scope = getScopeID(him); 252 setInet6Address_scopeid(env, iaObj, scope); 253 } 254 *port = ntohs(him6->sin6_port); 255 } else 256 #endif /* AF_INET6 */ 257 if (him->sa_family == AF_INET) { 258 struct sockaddr_in *him4 = (struct sockaddr_in *)him; 259 static jclass inet4Cls = 0; 260 261 if (inet4Cls == 0) { 262 jclass c = (*env)->FindClass(env, "java/net/Inet4Address"); 263 CHECK_NULL_RETURN(c, NULL); 264 inet4Cls = (*env)->NewGlobalRef(env, c); 265 CHECK_NULL_RETURN(inet4Cls, NULL); 266 (*env)->DeleteLocalRef(env, c); 267 } 268 iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID); 269 CHECK_NULL_RETURN(iaObj, NULL); 270 setInetAddress_family(env, iaObj, IPv4); 271 setInetAddress_addr(env, iaObj, ntohl(him4->sin_addr.s_addr)); 272 *port = ntohs(him4->sin_port); 273 } else { 274 // Unknown family 275 char errmsg[255]; 276 snprintf(errmsg, sizeof(errmsg), "Unknown socket family: %d", him->sa_family); 277 JNU_ThrowByName(env, "java/net/SocketException", errmsg); 278 return NULL; 279 } 280 return iaObj; 281 } 282 283 JNIEXPORT jint JNICALL 284 NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj) 285 { 286 jint family = AF_INET; 287 288 #ifdef AF_INET6 289 family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6; 290 if (him->sa_family == AF_INET6) { 291 #ifdef WIN32 292 struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him; 293 #else 294 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; 295 #endif 296 jbyte *caddrNew = (jbyte *)&(him6->sin6_addr); 297 if (NET_IsIPv4Mapped(caddrNew)) { 298 int addrNew; 299 int addrCur; 300 if (family == AF_INET6) { 301 return JNI_FALSE; 302 } 303 addrNew = NET_IPv4MappedToIPv4(caddrNew); 304 addrCur = getInetAddress_addr(env, iaObj); 305 if (addrNew == addrCur) { 306 return JNI_TRUE; 307 } else { 308 return JNI_FALSE; 309 } 310 } else { 311 jbyteArray ipaddress; 312 jbyte caddrCur[16]; 313 int scope; 314 315 if (family == AF_INET) { 316 return JNI_FALSE; 317 } 318 scope = getInet6Address_scopeid(env, iaObj); 319 getInet6Address_ipaddress(env, iaObj, (char *)caddrCur); 320 if (NET_IsEqual(caddrNew, caddrCur) && cmpScopeID(scope, him)) { 321 return JNI_TRUE; 322 } else { 323 return JNI_FALSE; 324 } 325 } 326 } else 327 #endif /* AF_INET6 */ 328 { 329 struct sockaddr_in *him4 = (struct sockaddr_in *)him; 330 int addrNew, addrCur; 331 if (family != AF_INET) { 332 return JNI_FALSE; 333 } 334 addrNew = ntohl(him4->sin_addr.s_addr); 335 addrCur = getInetAddress_addr(env, iaObj); 336 if (addrNew == addrCur) { 337 return JNI_TRUE; 338 } else { 339 return JNI_FALSE; 340 } 341 } 342 } 343 344 unsigned short 345 in_cksum(unsigned short *addr, int len) { 346 int nleft = len; 347 int sum = 0; 348 unsigned short *w = addr; 349 unsigned short answer = 0; 350 while(nleft > 1) { 351 sum += *w++; 352 nleft -= 2; 353 } 354 355 if (nleft == 1) { 356 *(unsigned char *) (&answer) = *(unsigned char *)w; 357 sum += answer; 358 } 359 360 sum = (sum >> 16) + (sum & 0xffff); 361 sum += (sum >> 16); 362 answer = ~sum; 363 return (answer); 364 } 365