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