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 JNIEXPORT void JNICALL initInetAddressIDs(JNIEnv *env) { 79 if (!initialized) { 80 Java_java_net_InetAddress_init(env, 0); 81 JNU_CHECK_EXCEPTION(env); 82 Java_java_net_Inet4Address_init(env, 0); 83 JNU_CHECK_EXCEPTION(env); 84 Java_java_net_Inet6Address_init(env, 0); 85 JNU_CHECK_EXCEPTION(env); 86 initialized = 1; 87 } 88 } 89 90 /* The address, and family fields used to be in InetAddress 91 * but are now in an implementation object. So, there is an extra 92 * level of indirection to access them now. 93 */ 94 95 extern jclass iac_class; 96 extern jfieldID ia_holderID; 97 extern jfieldID iac_addressID; 98 extern jfieldID iac_familyID; 99 100 /** 101 * set_ methods return JNI_TRUE on success JNI_FALSE on error 102 * get_ methods that return +ve int return -1 on error 103 * get_ methods that return objects return NULL on error. 104 */ 105 jobject getInet6Address_scopeifname(JNIEnv *env, jobject iaObj) { 106 jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 107 CHECK_NULL_RETURN(holder, NULL); 108 return (*env)->GetObjectField(env, holder, ia6_scopeifnameID); 109 } 110 111 jboolean setInet6Address_scopeifname(JNIEnv *env, jobject iaObj, jobject scopeifname) { 112 jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 113 CHECK_NULL_RETURN(holder, JNI_FALSE); 114 (*env)->SetObjectField(env, holder, ia6_scopeifnameID, scopeifname); 115 return JNI_TRUE; 116 } 117 118 int getInet6Address_scopeid_set(JNIEnv *env, jobject iaObj) { 119 jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 120 CHECK_NULL_RETURN(holder, -1); 121 return (*env)->GetBooleanField(env, holder, ia6_scopeidsetID); 122 } 123 124 int getInet6Address_scopeid(JNIEnv *env, jobject iaObj) { 125 jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 126 CHECK_NULL_RETURN(holder, -1); 127 return (*env)->GetIntField(env, holder, ia6_scopeidID); 128 } 129 130 jboolean setInet6Address_scopeid(JNIEnv *env, jobject iaObj, int scopeid) { 131 jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 132 CHECK_NULL_RETURN(holder, JNI_FALSE); 133 (*env)->SetIntField(env, holder, ia6_scopeidID, scopeid); 134 if (scopeid > 0) { 135 (*env)->SetBooleanField(env, holder, ia6_scopeidsetID, JNI_TRUE); 136 } 137 return JNI_TRUE; 138 } 139 140 jboolean getInet6Address_ipaddress(JNIEnv *env, jobject iaObj, char *dest) { 141 jobject holder, addr; 142 143 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 144 CHECK_NULL_RETURN(holder, JNI_FALSE); 145 addr = (*env)->GetObjectField(env, holder, ia6_ipaddressID); 146 CHECK_NULL_RETURN(addr, JNI_FALSE); 147 (*env)->GetByteArrayRegion(env, addr, 0, 16, (jbyte *)dest); 148 return JNI_TRUE; 149 } 150 151 jboolean setInet6Address_ipaddress(JNIEnv *env, jobject iaObj, char *address) { 152 jobject holder; 153 jbyteArray addr; 154 155 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 156 CHECK_NULL_RETURN(holder, JNI_FALSE); 157 addr = (jbyteArray)(*env)->GetObjectField(env, holder, ia6_ipaddressID); 158 if (addr == NULL) { 159 addr = (*env)->NewByteArray(env, 16); 160 CHECK_NULL_RETURN(addr, JNI_FALSE); 161 (*env)->SetObjectField(env, holder, ia6_ipaddressID, addr); 162 } 163 (*env)->SetByteArrayRegion(env, addr, 0, 16, (jbyte *)address); 164 return JNI_TRUE; 165 } 166 167 void setInetAddress_addr(JNIEnv *env, jobject iaObj, int address) { 168 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 169 (*env)->SetIntField(env, holder, iac_addressID, address); 170 } 171 172 void setInetAddress_family(JNIEnv *env, jobject iaObj, int family) { 173 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 174 (*env)->SetIntField(env, holder, iac_familyID, family); 175 } 176 177 void setInetAddress_hostName(JNIEnv *env, jobject iaObj, jobject host) { 178 jobject 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 = (*env)->GetObjectField(env, iaObj, ia_holderID); 184 return (*env)->GetIntField(env, holder, iac_addressID); 185 } 186 187 int getInetAddress_family(JNIEnv *env, jobject iaObj) { 188 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 189 return (*env)->GetIntField(env, holder, iac_familyID); 190 } 191 192 jobject getInetAddress_hostName(JNIEnv *env, jobject iaObj) { 193 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 194 return (*env)->GetObjectField(env, holder, iac_hostNameID); 195 } 196 197 JNIEXPORT jobject JNICALL 198 NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { 199 jobject iaObj; 200 #ifdef AF_INET6 201 if (him->sa_family == AF_INET6) { 202 #ifdef WIN32 203 struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him; 204 #else 205 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; 206 #endif 207 jbyte *caddr = (jbyte *)&(him6->sin6_addr); 208 if (NET_IsIPv4Mapped(caddr)) { 209 int address; 210 iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID); 211 CHECK_NULL_RETURN(iaObj, NULL); 212 address = NET_IPv4MappedToIPv4(caddr); 213 setInetAddress_addr(env, iaObj, address); 214 setInetAddress_family(env, iaObj, IPv4); 215 } else { 216 jint scope; 217 jboolean ret; 218 iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID); 219 CHECK_NULL_RETURN(iaObj, NULL); 220 ret = setInet6Address_ipaddress(env, iaObj, (char *)&(him6->sin6_addr)); 221 if (ret == JNI_FALSE) 222 return NULL; 223 setInetAddress_family(env, iaObj, IPv6); 224 scope = getScopeID(him); 225 setInet6Address_scopeid(env, iaObj, scope); 226 } 227 *port = ntohs(him6->sin6_port); 228 } else 229 #endif /* AF_INET6 */ 230 { 231 struct sockaddr_in *him4 = (struct sockaddr_in *)him; 232 iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID); 233 CHECK_NULL_RETURN(iaObj, NULL); 234 setInetAddress_family(env, iaObj, IPv4); 235 setInetAddress_addr(env, iaObj, ntohl(him4->sin_addr.s_addr)); 236 *port = ntohs(him4->sin_port); 237 } 238 return iaObj; 239 } 240 241 JNIEXPORT jint JNICALL 242 NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj) 243 { 244 jint family = AF_INET; 245 246 #ifdef AF_INET6 247 family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6; 248 if (him->sa_family == AF_INET6) { 249 #ifdef WIN32 250 struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him; 251 #else 252 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; 253 #endif 254 jbyte *caddrNew = (jbyte *)&(him6->sin6_addr); 255 if (NET_IsIPv4Mapped(caddrNew)) { 256 int addrNew; 257 int addrCur; 258 if (family == AF_INET6) { 259 return JNI_FALSE; 260 } 261 addrNew = NET_IPv4MappedToIPv4(caddrNew); 262 addrCur = getInetAddress_addr(env, iaObj); 263 if (addrNew == addrCur) { 264 return JNI_TRUE; 265 } else { 266 return JNI_FALSE; 267 } 268 } else { 269 jbyte caddrCur[16]; 270 int scope; 271 272 if (family == AF_INET) { 273 return JNI_FALSE; 274 } 275 scope = getInet6Address_scopeid(env, iaObj); 276 getInet6Address_ipaddress(env, iaObj, (char *)caddrCur); 277 if (NET_IsEqual(caddrNew, caddrCur) && cmpScopeID(scope, him)) { 278 return JNI_TRUE; 279 } else { 280 return JNI_FALSE; 281 } 282 } 283 } else 284 #endif /* AF_INET6 */ 285 { 286 struct sockaddr_in *him4 = (struct sockaddr_in *)him; 287 int addrNew, addrCur; 288 if (family != AF_INET) { 289 return JNI_FALSE; 290 } 291 addrNew = ntohl(him4->sin_addr.s_addr); 292 addrCur = getInetAddress_addr(env, iaObj); 293 if (addrNew == addrCur) { 294 return JNI_TRUE; 295 } else { 296 return JNI_FALSE; 297 } 298 } 299 } 300 301 unsigned short 302 in_cksum(unsigned short *addr, int len) { 303 int nleft = len; 304 int sum = 0; 305 unsigned short *w = addr; 306 unsigned short answer = 0; 307 while(nleft > 1) { 308 sum += *w++; 309 nleft -= 2; 310 } 311 312 if (nleft == 1) { 313 *(unsigned char *) (&answer) = *(unsigned char *)w; 314 sum += answer; 315 } 316 317 sum = (sum >> 16) + (sum & 0xffff); 318 sum += (sum >> 16); 319 answer = ~sum; 320 return (answer); 321 }