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 
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  */
getInet6Address_scopeifname(JNIEnv * env,jobject iaObj)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 
setInet6Address_scopeifname(JNIEnv * env,jobject iaObj,jobject scopeifname)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 
getInet6Address_scopeid_set(JNIEnv * env,jobject iaObj)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 
getInet6Address_scopeid(JNIEnv * env,jobject iaObj)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 
setInet6Address_scopeid(JNIEnv * env,jobject iaObj,int scopeid)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 
getInet6Address_ipaddress(JNIEnv * env,jobject iaObj,char * dest)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 
setInet6Address_ipaddress(JNIEnv * env,jobject iaObj,char * address)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 
setInetAddress_addr(JNIEnv * env,jobject iaObj,int address)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 
setInetAddress_family(JNIEnv * env,jobject iaObj,int family)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 
setInetAddress_hostName(JNIEnv * env,jobject iaObj,jobject host)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 
getInetAddress_addr(JNIEnv * env,jobject iaObj)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 
getInetAddress_family(JNIEnv * env,jobject iaObj)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 
getInetAddress_hostName(JNIEnv * env,jobject iaObj)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
NET_SockaddrToInetAddress(JNIEnv * env,struct sockaddr * him,int * port)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
NET_SockaddrEqualsInetAddress(JNIEnv * env,struct sockaddr * him,jobject iaObj)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
in_cksum(unsigned short * addr,int len)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