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