1 /*
   2  * Copyright 1998-2008 Sun Microsystems, Inc.  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.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any 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     initLocalAddrTable ();
  71     return JNI_VERSION_1_2;
  72 }
  73 
  74 static int initialized = 0;
  75 
  76 void init(JNIEnv *env) {
  77     if (!initialized) {
  78         Java_java_net_InetAddress_init(env, 0);
  79         Java_java_net_Inet4Address_init(env, 0);
  80         Java_java_net_Inet6Address_init(env, 0);
  81         initialized = 1;
  82     }
  83 }
  84 
  85 JNIEXPORT jobject JNICALL
  86 NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) {
  87     jobject iaObj;
  88     init(env);
  89 #ifdef AF_INET6
  90     if (him->sa_family == AF_INET6) {
  91         jbyteArray ipaddress;
  92 #ifdef WIN32
  93         struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him;
  94 #else
  95         struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
  96 #endif
  97         jbyte *caddr = (jbyte *)&(him6->sin6_addr);
  98         if (NET_IsIPv4Mapped(caddr)) {
  99             int address;
 100             static jclass inet4Cls = 0;
 101             if (inet4Cls == 0) {
 102                 jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
 103                 CHECK_NULL_RETURN(c, NULL);
 104                 inet4Cls = (*env)->NewGlobalRef(env, c);
 105                 CHECK_NULL_RETURN(inet4Cls, NULL);
 106                 (*env)->DeleteLocalRef(env, c);
 107             }
 108             iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID);
 109             CHECK_NULL_RETURN(iaObj, NULL);
 110             address = NET_IPv4MappedToIPv4(caddr);
 111             (*env)->SetIntField(env, iaObj, ia_addressID, address);
 112             (*env)->SetIntField(env, iaObj, ia_familyID, IPv4);
 113         } else {
 114             static jclass inet6Cls = 0;
 115             jint scope;
 116             if (inet6Cls == 0) {
 117                 jclass c = (*env)->FindClass(env, "java/net/Inet6Address");
 118                 CHECK_NULL_RETURN(c, NULL);
 119                 inet6Cls = (*env)->NewGlobalRef(env, c);
 120                 CHECK_NULL_RETURN(inet6Cls, NULL);
 121                 (*env)->DeleteLocalRef(env, c);
 122             }
 123             iaObj = (*env)->NewObject(env, inet6Cls, ia6_ctrID);
 124             CHECK_NULL_RETURN(iaObj, NULL);
 125             ipaddress = (*env)->NewByteArray(env, 16);
 126             CHECK_NULL_RETURN(ipaddress, NULL);
 127             (*env)->SetByteArrayRegion(env, ipaddress, 0, 16,
 128                                        (jbyte *)&(him6->sin6_addr));
 129 
 130             (*env)->SetObjectField(env, iaObj, ia6_ipaddressID, ipaddress);
 131 
 132             (*env)->SetIntField(env, iaObj, ia_familyID, IPv6);
 133             scope = getScopeID(him);
 134             (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
 135             if (scope > 0)
 136                 (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
 137         }
 138         *port = ntohs(him6->sin6_port);
 139     } else
 140 #endif /* AF_INET6 */
 141         {
 142             struct sockaddr_in *him4 = (struct sockaddr_in *)him;
 143             static jclass inet4Cls = 0;
 144 
 145             if (inet4Cls == 0) {
 146                 jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
 147                 CHECK_NULL_RETURN(c, NULL);
 148                 inet4Cls = (*env)->NewGlobalRef(env, c);
 149                 CHECK_NULL_RETURN(inet4Cls, NULL);
 150                 (*env)->DeleteLocalRef(env, c);
 151             }
 152             iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID);
 153             CHECK_NULL_RETURN(iaObj, NULL);
 154             (*env)->SetIntField(env, iaObj, ia_familyID, IPv4);
 155             (*env)->SetIntField(env, iaObj, ia_addressID,
 156                                 ntohl(him4->sin_addr.s_addr));
 157             *port = ntohs(him4->sin_port);
 158         }
 159     return iaObj;
 160 }
 161 
 162 JNIEXPORT jint JNICALL
 163 NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj)
 164 {
 165     jint family = AF_INET;
 166 
 167 #ifdef AF_INET6
 168     family = (*env)->GetIntField(env, iaObj, ia_familyID) == IPv4?
 169         AF_INET : AF_INET6;
 170     if (him->sa_family == AF_INET6) {
 171 #ifdef WIN32
 172         struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him;
 173 #else
 174         struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
 175 #endif
 176         jbyte *caddrNew = (jbyte *)&(him6->sin6_addr);
 177         if (NET_IsIPv4Mapped(caddrNew)) {
 178             int addrNew;
 179             int addrCur;
 180             if (family == AF_INET6) {
 181                 return JNI_FALSE;
 182             }
 183             addrNew = NET_IPv4MappedToIPv4(caddrNew);
 184             addrCur = (*env)->GetIntField(env, iaObj, ia_addressID);
 185             if (addrNew == addrCur) {
 186                 return JNI_TRUE;
 187             } else {
 188                 return JNI_FALSE;
 189             }
 190         } else {
 191             jbyteArray ipaddress;
 192             jbyte caddrCur[16];
 193             int scope;
 194 
 195             if (family == AF_INET) {
 196                 return JNI_FALSE;
 197             }
 198             ipaddress = (*env)->GetObjectField(env, iaObj, ia6_ipaddressID);
 199             scope = (*env)->GetIntField(env, iaObj, ia6_scopeidID);
 200             (*env)->GetByteArrayRegion(env, ipaddress, 0, 16, caddrCur);
 201             if (NET_IsEqual(caddrNew, caddrCur) && cmpScopeID(scope, him)) {
 202                 return JNI_TRUE;
 203             } else {
 204                 return JNI_FALSE;
 205             }
 206         }
 207     } else
 208 #endif /* AF_INET6 */
 209         {
 210             struct sockaddr_in *him4 = (struct sockaddr_in *)him;
 211             int addrNew, addrCur;
 212             if (family != AF_INET) {
 213                 return JNI_FALSE;
 214             }
 215             addrNew = ntohl(him4->sin_addr.s_addr);
 216             addrCur = (*env)->GetIntField(env, iaObj, ia_addressID);
 217             if (addrNew == addrCur) {
 218                 return JNI_TRUE;
 219             } else {
 220                 return JNI_FALSE;
 221             }
 222         }
 223 }
 224 
 225 unsigned short
 226 in_cksum(unsigned short *addr, int len) {
 227     int nleft = len;
 228     int sum = 0;
 229     unsigned short *w = addr;
 230     unsigned short answer = 0;
 231     while(nleft > 1) {
 232         sum += *w++;
 233         nleft -= 2;
 234     }
 235 
 236     if (nleft == 1) {
 237         *(unsigned char *) (&answer) = *(unsigned char *)w;
 238         sum += answer;
 239     }
 240 
 241     sum = (sum >> 16) + (sum & 0xffff);
 242     sum += (sum >> 16);
 243     answer = ~sum;
 244     return (answer);
 245 }