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 
ipv6_available()35 JNIEXPORT jint JNICALL ipv6_available()
36 {
37     return IPv6_available ;
38 }
39 
40 JNIEXPORT jint JNICALL
net_JNI_OnLoad(JavaVM * vm,void * ignored)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 
setInetAddress_addr(JNIEnv * env,jobject iaObj,int address)75 void setInetAddress_addr(JNIEnv *env, jobject iaObj, int address) {
76     jobject holder;
77     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
78     (*env)->SetIntField(env, holder, iac_addressID, address);
79 }
80 
setInetAddress_family(JNIEnv * env,jobject iaObj,int family)81 void setInetAddress_family(JNIEnv *env, jobject iaObj, int family) {
82     jobject holder;
83     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
84     (*env)->SetIntField(env, holder, iac_familyID, family);
85 }
86 
setInetAddress_hostName(JNIEnv * env,jobject iaObj,jobject host)87 void setInetAddress_hostName(JNIEnv *env, jobject iaObj, jobject host) {
88     jobject holder;
89     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
90     (*env)->SetObjectField(env, holder, iac_hostNameID, host);
91 }
92 
getInetAddress_addr(JNIEnv * env,jobject iaObj)93 int getInetAddress_addr(JNIEnv *env, jobject iaObj) {
94     jobject holder;
95     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
96     return (*env)->GetIntField(env, holder, iac_addressID);
97 }
98 
getInetAddress_family(JNIEnv * env,jobject iaObj)99 int getInetAddress_family(JNIEnv *env, jobject iaObj) {
100     jobject holder;
101 
102     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
103     return (*env)->GetIntField(env, holder, iac_familyID);
104 }
105 
getInetAddress_hostName(JNIEnv * env,jobject iaObj)106 jobject getInetAddress_hostName(JNIEnv *env, jobject iaObj) {
107     jobject holder;
108     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
109     return (*env)->GetObjectField(env, holder, iac_hostNameID);
110 }
111 
112 JNIEXPORT jobject JNICALL
NET_SockaddrToInetAddress(JNIEnv * env,struct sockaddr * him,int * port)113 NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) {
114     jobject iaObj;
115 #ifdef AF_INET6
116     if (him->sa_family == AF_INET6) {
117         jbyteArray ipaddress;
118 #ifdef WIN32
119         struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him;
120 #else
121         struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
122 #endif
123         jbyte *caddr = (jbyte *)&(him6->sin6_addr);
124         if (NET_IsIPv4Mapped(caddr)) {
125             int address;
126             static jclass inet4Cls = 0;
127             if (inet4Cls == 0) {
128                 jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
129                 CHECK_NULL_RETURN(c, NULL);
130                 inet4Cls = (*env)->NewGlobalRef(env, c);
131                 CHECK_NULL_RETURN(inet4Cls, NULL);
132                 (*env)->DeleteLocalRef(env, c);
133             }
134             iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID);
135             CHECK_NULL_RETURN(iaObj, NULL);
136             address = NET_IPv4MappedToIPv4(caddr);
137             setInetAddress_addr(env, iaObj, address);
138             setInetAddress_family(env, iaObj, IPv4);
139         } else {
140             static jclass inet6Cls = 0;
141             jint scope;
142             if (inet6Cls == 0) {
143                 jclass c = (*env)->FindClass(env, "java/net/Inet6Address");
144                 CHECK_NULL_RETURN(c, NULL);
145                 inet6Cls = (*env)->NewGlobalRef(env, c);
146                 CHECK_NULL_RETURN(inet6Cls, NULL);
147                 (*env)->DeleteLocalRef(env, c);
148             }
149             iaObj = (*env)->NewObject(env, inet6Cls, ia6_ctrID);
150             CHECK_NULL_RETURN(iaObj, NULL);
151             ipaddress = (*env)->NewByteArray(env, 16);
152             CHECK_NULL_RETURN(ipaddress, NULL);
153             (*env)->SetByteArrayRegion(env, ipaddress, 0, 16,
154                                        (jbyte *)&(him6->sin6_addr));
155 
156             (*env)->SetObjectField(env, iaObj, ia6_ipaddressID, ipaddress);
157 
158             setInetAddress_family(env, iaObj, IPv6);
159             scope = getScopeID(him);
160             (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
161             if (scope > 0)
162                 (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
163         }
164         *port = ntohs(him6->sin6_port);
165     } else
166 #endif /* AF_INET6 */
167         {
168             struct sockaddr_in *him4 = (struct sockaddr_in *)him;
169             static jclass inet4Cls = 0;
170 
171             if (inet4Cls == 0) {
172                 jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
173                 CHECK_NULL_RETURN(c, NULL);
174                 inet4Cls = (*env)->NewGlobalRef(env, c);
175                 CHECK_NULL_RETURN(inet4Cls, NULL);
176                 (*env)->DeleteLocalRef(env, c);
177             }
178             iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID);
179             CHECK_NULL_RETURN(iaObj, NULL);
180             setInetAddress_family(env, iaObj, IPv4);
181             setInetAddress_addr(env, iaObj, ntohl(him4->sin_addr.s_addr));
182             *port = ntohs(him4->sin_port);
183         }
184     return iaObj;
185 }
186 
187 JNIEXPORT jint JNICALL
NET_SockaddrEqualsInetAddress(JNIEnv * env,struct sockaddr * him,jobject iaObj)188 NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj)
189 {
190     jint family = AF_INET;
191 
192 #ifdef AF_INET6
193     family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
194     if (him->sa_family == AF_INET6) {
195 #ifdef WIN32
196         struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him;
197 #else
198         struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
199 #endif
200         jbyte *caddrNew = (jbyte *)&(him6->sin6_addr);
201         if (NET_IsIPv4Mapped(caddrNew)) {
202             int addrNew;
203             int addrCur;
204             if (family == AF_INET6) {
205                 return JNI_FALSE;
206             }
207             addrNew = NET_IPv4MappedToIPv4(caddrNew);
208             addrCur = getInetAddress_addr(env, iaObj);
209             if (addrNew == addrCur) {
210                 return JNI_TRUE;
211             } else {
212                 return JNI_FALSE;
213             }
214         } else {
215             jbyteArray ipaddress;
216             jbyte caddrCur[16];
217             int scope;
218 
219             if (family == AF_INET) {
220                 return JNI_FALSE;
221             }
222             ipaddress = (*env)->GetObjectField(env, iaObj, ia6_ipaddressID);
223             scope = (*env)->GetIntField(env, iaObj, ia6_scopeidID);
224             (*env)->GetByteArrayRegion(env, ipaddress, 0, 16, caddrCur);
225             if (NET_IsEqual(caddrNew, caddrCur) && cmpScopeID(scope, him)) {
226                 return JNI_TRUE;
227             } else {
228                 return JNI_FALSE;
229             }
230         }
231     } else
232 #endif /* AF_INET6 */
233         {
234             struct sockaddr_in *him4 = (struct sockaddr_in *)him;
235             int addrNew, addrCur;
236             if (family != AF_INET) {
237                 return JNI_FALSE;
238             }
239             addrNew = ntohl(him4->sin_addr.s_addr);
240             addrCur = getInetAddress_addr(env, iaObj);
241             if (addrNew == addrCur) {
242                 return JNI_TRUE;
243             } else {
244                 return JNI_FALSE;
245             }
246         }
247 }
248 
249 unsigned short
in_cksum(unsigned short * addr,int len)250 in_cksum(unsigned short *addr, int len) {
251     int nleft = len;
252     int sum = 0;
253     unsigned short *w = addr;
254     unsigned short answer = 0;
255     while(nleft > 1) {
256         sum += *w++;
257         nleft -= 2;
258     }
259 
260     if (nleft == 1) {
261         *(unsigned char *) (&answer) = *(unsigned char *)w;
262         sum += answer;
263     }
264 
265     sum = (sum >> 16) + (sum & 0xffff);
266     sum += (sum >> 16);
267     answer = ~sum;
268     return (answer);
269 }
270