blob: 8d02150091b69de02780850ce8a468ce04be6dc3 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1998-2005 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
31int IPv6_supported() ;
32
33static int IPv6_available;
34
35JNIEXPORT jint JNICALL ipv6_available()
36{
37 return IPv6_available ;
38}
39
40JNIEXPORT jint JNICALL
41JNI_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
74static int initialized = 0;
75
76void 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
85jobject
86NET_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 if (inet6Cls == 0) {
116 jclass c = (*env)->FindClass(env, "java/net/Inet6Address");
117 CHECK_NULL_RETURN(c, NULL);
118 inet6Cls = (*env)->NewGlobalRef(env, c);
119 CHECK_NULL_RETURN(inet6Cls, NULL);
120 (*env)->DeleteLocalRef(env, c);
121 }
122 iaObj = (*env)->NewObject(env, inet6Cls, ia6_ctrID);
123 CHECK_NULL_RETURN(iaObj, NULL);
124 ipaddress = (*env)->NewByteArray(env, 16);
125 CHECK_NULL_RETURN(ipaddress, NULL);
126 (*env)->SetByteArrayRegion(env, ipaddress, 0, 16,
127 (jbyte *)&(him6->sin6_addr));
128
129 (*env)->SetObjectField(env, iaObj, ia6_ipaddressID, ipaddress);
130
131 (*env)->SetIntField(env, iaObj, ia_familyID, IPv6);
132 (*env)->SetIntField(env, iaObj, ia6_scopeidID, getScopeID(him));
133 }
134 *port = ntohs(him6->sin6_port);
135 } else
136#endif /* AF_INET6 */
137 {
138 struct sockaddr_in *him4 = (struct sockaddr_in *)him;
139 static jclass inet4Cls = 0;
140
141 if (inet4Cls == 0) {
142 jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
143 CHECK_NULL_RETURN(c, NULL);
144 inet4Cls = (*env)->NewGlobalRef(env, c);
145 CHECK_NULL_RETURN(inet4Cls, NULL);
146 (*env)->DeleteLocalRef(env, c);
147 }
148 iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID);
149 CHECK_NULL_RETURN(iaObj, NULL);
150 (*env)->SetIntField(env, iaObj, ia_familyID, IPv4);
151 (*env)->SetIntField(env, iaObj, ia_addressID,
152 ntohl(him4->sin_addr.s_addr));
153 *port = ntohs(him4->sin_port);
154 }
155 return iaObj;
156}
157
158jint
159NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj)
160{
161 jint family = (*env)->GetIntField(env, iaObj, ia_familyID) == IPv4?
162 AF_INET : AF_INET6;
163
164#ifdef AF_INET6
165 if (him->sa_family == AF_INET6) {
166#ifdef WIN32
167 struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him;
168#else
169 struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
170#endif
171 jbyte *caddrNew = (jbyte *)&(him6->sin6_addr);
172 if (NET_IsIPv4Mapped(caddrNew)) {
173 int addrNew;
174 int addrCur;
175 if (family == AF_INET6) {
176 return JNI_FALSE;
177 }
178 addrNew = NET_IPv4MappedToIPv4(caddrNew);
179 addrCur = (*env)->GetIntField(env, iaObj, ia_addressID);
180 if (addrNew == addrCur) {
181 return JNI_TRUE;
182 } else {
183 return JNI_FALSE;
184 }
185 } else {
186 jbyteArray ipaddress;
187 jbyte caddrCur[16];
188 int scope;
189
190 if (family == AF_INET) {
191 return JNI_FALSE;
192 }
193 ipaddress = (*env)->GetObjectField(env, iaObj, ia6_ipaddressID);
194 scope = (*env)->GetIntField(env, iaObj, ia6_scopeidID);
195 (*env)->GetByteArrayRegion(env, ipaddress, 0, 16, caddrCur);
196 if (NET_IsEqual(caddrNew, caddrCur) && cmpScopeID(scope, him)) {
197 return JNI_TRUE;
198 } else {
199 return JNI_FALSE;
200 }
201 }
202 } else
203#endif /* AF_INET6 */
204 {
205 struct sockaddr_in *him4 = (struct sockaddr_in *)him;
206 int addrNew, addrCur;
207 if (family != AF_INET) {
208 return JNI_FALSE;
209 }
210 addrNew = ntohl(him4->sin_addr.s_addr);
211 addrCur = (*env)->GetIntField(env, iaObj, ia_addressID);
212 if (addrNew == addrCur) {
213 return JNI_TRUE;
214 } else {
215 return JNI_FALSE;
216 }
217 }
218}
219
220unsigned short
221in_cksum(unsigned short *addr, int len) {
222 int nleft = len;
223 int sum = 0;
224 unsigned short *w = addr;
225 unsigned short answer = 0;
226 while(nleft > 1) {
227 sum += *w++;
228 nleft -= 2;
229 }
230
231 if (nleft == 1) {
232 *(unsigned char *) (&answer) = *(unsigned char *)w;
233 sum += answer;
234 }
235
236 sum = (sum >> 16) + (sum & 0xffff);
237 sum += (sum >> 16);
238 answer = ~sum;
239 return (answer);
240}