2
|
1 |
/*
|
|
2 |
* Copyright 2000-2006 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 <windows.h>
|
|
27 |
#include <winsock2.h>
|
|
28 |
#include <ctype.h>
|
|
29 |
#include <stdio.h>
|
|
30 |
#include <stdlib.h>
|
|
31 |
#include <malloc.h>
|
|
32 |
#include <sys/types.h>
|
|
33 |
|
|
34 |
#include "java_net_InetAddress.h"
|
|
35 |
#include "java_net_Inet4AddressImpl.h"
|
|
36 |
#include "java_net_Inet6AddressImpl.h"
|
|
37 |
#include "net_util.h"
|
|
38 |
#include "icmp.h"
|
|
39 |
|
|
40 |
#ifdef WIN32
|
|
41 |
#ifndef _WIN64
|
|
42 |
|
|
43 |
/* Retain this code a little longer to support building in
|
|
44 |
* old environments. _MSC_VER is defined as:
|
|
45 |
* 1200 for MSVC++ 6.0
|
|
46 |
* 1310 for Vc7
|
|
47 |
*/
|
|
48 |
#if defined(_MSC_VER) && _MSC_VER < 1310
|
|
49 |
#define sockaddr_in6 SOCKADDR_IN6
|
|
50 |
#endif
|
|
51 |
#endif
|
|
52 |
#define uint32_t UINT32
|
|
53 |
#endif
|
|
54 |
|
|
55 |
/*
|
|
56 |
* Inet6AddressImpl
|
|
57 |
*/
|
|
58 |
|
|
59 |
/*
|
|
60 |
* Class: java_net_Inet6AddressImpl
|
|
61 |
* Method: getLocalHostName
|
|
62 |
* Signature: ()Ljava/lang/String;
|
|
63 |
*/
|
|
64 |
JNIEXPORT jstring JNICALL
|
|
65 |
Java_java_net_Inet6AddressImpl_getLocalHostName (JNIEnv *env, jobject this) {
|
|
66 |
char hostname [256];
|
|
67 |
|
|
68 |
if (gethostname (hostname, sizeof (hostname)) == -1) {
|
|
69 |
strcpy (hostname, "localhost");
|
|
70 |
}
|
|
71 |
return JNU_NewStringPlatform (env, hostname);
|
|
72 |
}
|
|
73 |
|
|
74 |
static jclass ni_iacls;
|
|
75 |
static jclass ni_ia4cls;
|
|
76 |
static jclass ni_ia6cls;
|
|
77 |
static jmethodID ni_ia4ctrID;
|
|
78 |
static jmethodID ni_ia6ctrID;
|
|
79 |
static jfieldID ni_iaaddressID;
|
|
80 |
static jfieldID ni_iahostID;
|
|
81 |
static jfieldID ni_iafamilyID;
|
|
82 |
static jfieldID ni_ia6ipaddressID;
|
|
83 |
static int initialized = 0;
|
|
84 |
|
|
85 |
JNIEXPORT jobjectArray JNICALL
|
|
86 |
Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
|
|
87 |
jstring host) {
|
|
88 |
const char *hostname;
|
|
89 |
jobject name;
|
|
90 |
jobjectArray ret = 0;
|
|
91 |
int retLen = 0;
|
|
92 |
jboolean preferIPv6Address;
|
|
93 |
|
|
94 |
int error=0;
|
|
95 |
struct addrinfo hints, *res, *resNew = NULL;
|
|
96 |
|
|
97 |
if (!initialized) {
|
|
98 |
ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
|
|
99 |
ni_iacls = (*env)->NewGlobalRef(env, ni_iacls);
|
|
100 |
ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address");
|
|
101 |
ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls);
|
|
102 |
ni_ia6cls = (*env)->FindClass(env, "java/net/Inet6Address");
|
|
103 |
ni_ia6cls = (*env)->NewGlobalRef(env, ni_ia6cls);
|
|
104 |
ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V");
|
|
105 |
ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "<init>", "()V");
|
|
106 |
ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I");
|
|
107 |
ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I");
|
|
108 |
ni_iahostID = (*env)->GetFieldID(env, ni_iacls, "hostName", "Ljava/lang/String;");
|
|
109 |
ni_ia6ipaddressID = (*env)->GetFieldID(env, ni_ia6cls, "ipaddress", "[B");
|
|
110 |
initialized = 1;
|
|
111 |
}
|
|
112 |
if (IS_NULL(host)) {
|
|
113 |
JNU_ThrowNullPointerException(env, "host is null");
|
|
114 |
return 0;
|
|
115 |
}
|
|
116 |
hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
|
|
117 |
CHECK_NULL_RETURN(hostname, NULL);
|
|
118 |
|
|
119 |
if (NET_addrtransAvailable()) {
|
|
120 |
static jfieldID ia_preferIPv6AddressID;
|
|
121 |
if (ia_preferIPv6AddressID == NULL) {
|
|
122 |
jclass c = (*env)->FindClass(env,"java/net/InetAddress");
|
|
123 |
if (c) {
|
|
124 |
ia_preferIPv6AddressID =
|
|
125 |
(*env)->GetStaticFieldID(env, c, "preferIPv6Address", "Z");
|
|
126 |
}
|
|
127 |
if (ia_preferIPv6AddressID == NULL) {
|
|
128 |
JNU_ReleaseStringPlatformChars(env, host, hostname);
|
|
129 |
return NULL;
|
|
130 |
}
|
|
131 |
}
|
|
132 |
/* get the address preference */
|
|
133 |
preferIPv6Address
|
|
134 |
= (*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID);
|
|
135 |
|
|
136 |
/* Try once, with our static buffer. */
|
|
137 |
memset(&hints, 0, sizeof(hints));
|
|
138 |
hints.ai_flags = AI_CANONNAME;
|
|
139 |
hints.ai_family = AF_UNSPEC;
|
|
140 |
|
|
141 |
error = (*getaddrinfo_ptr)(hostname, NULL, &hints, &res);
|
|
142 |
|
|
143 |
if (error) {
|
|
144 |
/* report error */
|
|
145 |
JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
|
|
146 |
(char *)hostname);
|
|
147 |
JNU_ReleaseStringPlatformChars(env, host, hostname);
|
|
148 |
return NULL;
|
|
149 |
} else {
|
|
150 |
int i = 0;
|
|
151 |
int inetCount = 0, inet6Count = 0, inetIndex, inet6Index;
|
|
152 |
struct addrinfo *itr, *last, *iterator = res;
|
|
153 |
while (iterator != NULL) {
|
|
154 |
int skip = 0;
|
|
155 |
itr = resNew;
|
|
156 |
while (itr != NULL) {
|
|
157 |
if (iterator->ai_family == itr->ai_family &&
|
|
158 |
iterator->ai_addrlen == itr->ai_addrlen) {
|
|
159 |
if (itr->ai_family == AF_INET) { /* AF_INET */
|
|
160 |
struct sockaddr_in *addr1, *addr2;
|
|
161 |
addr1 = (struct sockaddr_in *)iterator->ai_addr;
|
|
162 |
addr2 = (struct sockaddr_in *)itr->ai_addr;
|
|
163 |
if (addr1->sin_addr.s_addr ==
|
|
164 |
addr2->sin_addr.s_addr) {
|
|
165 |
skip = 1;
|
|
166 |
break;
|
|
167 |
}
|
|
168 |
} else {
|
|
169 |
int t;
|
|
170 |
struct sockaddr_in6 *addr1, *addr2;
|
|
171 |
addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
|
|
172 |
addr2 = (struct sockaddr_in6 *)itr->ai_addr;
|
|
173 |
|
|
174 |
for (t = 0; t < 16; t++) {
|
|
175 |
if (addr1->sin6_addr.s6_addr[t] !=
|
|
176 |
addr2->sin6_addr.s6_addr[t]) {
|
|
177 |
break;
|
|
178 |
}
|
|
179 |
}
|
|
180 |
if (t < 16) {
|
|
181 |
itr = itr->ai_next;
|
|
182 |
continue;
|
|
183 |
} else {
|
|
184 |
skip = 1;
|
|
185 |
break;
|
|
186 |
}
|
|
187 |
}
|
|
188 |
} else if (iterator->ai_family != AF_INET &&
|
|
189 |
iterator->ai_family != AF_INET6) {
|
|
190 |
/* we can't handle other family types */
|
|
191 |
skip = 1;
|
|
192 |
break;
|
|
193 |
}
|
|
194 |
itr = itr->ai_next;
|
|
195 |
}
|
|
196 |
|
|
197 |
if (!skip) {
|
|
198 |
struct addrinfo *next
|
|
199 |
= (struct addrinfo*) malloc(sizeof(struct addrinfo));
|
|
200 |
if (!next) {
|
|
201 |
JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
|
|
202 |
ret = NULL;
|
|
203 |
goto cleanupAndReturn;
|
|
204 |
}
|
|
205 |
memcpy(next, iterator, sizeof(struct addrinfo));
|
|
206 |
next->ai_next = NULL;
|
|
207 |
if (resNew == NULL) {
|
|
208 |
resNew = next;
|
|
209 |
} else {
|
|
210 |
last->ai_next = next;
|
|
211 |
}
|
|
212 |
last = next;
|
|
213 |
i++;
|
|
214 |
if (iterator->ai_family == AF_INET) {
|
|
215 |
inetCount ++;
|
|
216 |
} else if (iterator->ai_family == AF_INET6) {
|
|
217 |
inet6Count ++;
|
|
218 |
}
|
|
219 |
}
|
|
220 |
iterator = iterator->ai_next;
|
|
221 |
}
|
|
222 |
retLen = i;
|
|
223 |
iterator = resNew;
|
|
224 |
i = 0;
|
|
225 |
ret = (*env)->NewObjectArray(env, retLen, ni_iacls, NULL);
|
|
226 |
|
|
227 |
if (IS_NULL(ret)) {
|
|
228 |
/* we may have memory to free at the end of this */
|
|
229 |
goto cleanupAndReturn;
|
|
230 |
}
|
|
231 |
|
|
232 |
if (preferIPv6Address) {
|
|
233 |
inetIndex = inet6Count;
|
|
234 |
inet6Index = 0;
|
|
235 |
} else {
|
|
236 |
inetIndex = 0;
|
|
237 |
inet6Index = inetCount;
|
|
238 |
}
|
|
239 |
|
|
240 |
name = (*env)->NewStringUTF(env, hostname);
|
|
241 |
if (IS_NULL(name)) {
|
|
242 |
ret = NULL;
|
|
243 |
goto cleanupAndReturn;
|
|
244 |
}
|
|
245 |
|
|
246 |
while (iterator != NULL) {
|
|
247 |
if (iterator->ai_family == AF_INET) {
|
|
248 |
jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
|
|
249 |
if (IS_NULL(iaObj)) {
|
|
250 |
ret = NULL;
|
|
251 |
goto cleanupAndReturn;
|
|
252 |
}
|
|
253 |
(*env)->SetIntField(env, iaObj, ni_iaaddressID,
|
|
254 |
ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
|
|
255 |
(*env)->SetObjectField(env, iaObj, ni_iahostID, name);
|
|
256 |
(*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj);
|
|
257 |
inetIndex ++;
|
|
258 |
} else if (iterator->ai_family == AF_INET6) {
|
|
259 |
jint scope = 0;
|
|
260 |
jbyteArray ipaddress;
|
|
261 |
jobject iaObj = (*env)->NewObject(env, ni_ia6cls, ni_ia6ctrID);
|
|
262 |
if (IS_NULL(iaObj)) {
|
|
263 |
ret = NULL;
|
|
264 |
goto cleanupAndReturn;
|
|
265 |
}
|
|
266 |
ipaddress = (*env)->NewByteArray(env, 16);
|
|
267 |
if (IS_NULL(ipaddress)) {
|
|
268 |
ret = NULL;
|
|
269 |
goto cleanupAndReturn;
|
|
270 |
}
|
|
271 |
(*env)->SetByteArrayRegion(env, ipaddress, 0, 16,
|
|
272 |
(jbyte *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr));
|
|
273 |
scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
|
|
274 |
if (scope != 0) { /* zero is default value, no need to set */
|
|
275 |
(*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
|
|
276 |
(*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
|
|
277 |
}
|
|
278 |
(*env)->SetObjectField(env, iaObj, ni_ia6ipaddressID, ipaddress);
|
|
279 |
(*env)->SetObjectField(env, iaObj, ni_iahostID, name);
|
|
280 |
(*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj);
|
|
281 |
inet6Index ++;
|
|
282 |
}
|
|
283 |
iterator = iterator->ai_next;
|
|
284 |
}
|
|
285 |
}
|
|
286 |
}
|
|
287 |
|
|
288 |
cleanupAndReturn:
|
|
289 |
{
|
|
290 |
struct addrinfo *iterator, *tmp;
|
|
291 |
iterator = resNew;
|
|
292 |
while (iterator != NULL) {
|
|
293 |
tmp = iterator;
|
|
294 |
iterator = iterator->ai_next;
|
|
295 |
free(tmp);
|
|
296 |
}
|
|
297 |
JNU_ReleaseStringPlatformChars(env, host, hostname);
|
|
298 |
}
|
|
299 |
|
|
300 |
if (NET_addrtransAvailable())
|
|
301 |
(*freeaddrinfo_ptr)(res);
|
|
302 |
|
|
303 |
return ret;
|
|
304 |
}
|
|
305 |
|
|
306 |
/*
|
|
307 |
* Class: java_net_Inet6AddressImpl
|
|
308 |
* Method: getHostByAddr
|
|
309 |
* Signature: (I)Ljava/lang/String;
|
|
310 |
*/
|
|
311 |
JNIEXPORT jstring JNICALL
|
|
312 |
Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
|
|
313 |
jbyteArray addrArray) {
|
|
314 |
jstring ret = NULL;
|
|
315 |
|
|
316 |
char host[NI_MAXHOST+1];
|
|
317 |
jfieldID fid;
|
|
318 |
int error = 0;
|
|
319 |
jint family;
|
|
320 |
struct sockaddr *him ;
|
|
321 |
int len = 0;
|
|
322 |
jbyte caddr[16];
|
|
323 |
|
|
324 |
if (NET_addrtransAvailable()) {
|
|
325 |
struct sockaddr_in him4;
|
|
326 |
struct sockaddr_in6 him6;
|
|
327 |
struct sockaddr *sa;
|
|
328 |
|
|
329 |
/*
|
|
330 |
* For IPv4 addresses construct a sockaddr_in structure.
|
|
331 |
*/
|
|
332 |
if ((*env)->GetArrayLength(env, addrArray) == 4) {
|
|
333 |
jint addr;
|
|
334 |
(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
|
|
335 |
addr = ((caddr[0]<<24) & 0xff000000);
|
|
336 |
addr |= ((caddr[1] <<16) & 0xff0000);
|
|
337 |
addr |= ((caddr[2] <<8) & 0xff00);
|
|
338 |
addr |= (caddr[3] & 0xff);
|
|
339 |
memset((char *) &him4, 0, sizeof(him4));
|
|
340 |
him4.sin_addr.s_addr = (uint32_t) htonl(addr);
|
|
341 |
him4.sin_family = AF_INET;
|
|
342 |
sa = (struct sockaddr *) &him4;
|
|
343 |
len = sizeof(him4);
|
|
344 |
} else {
|
|
345 |
/*
|
|
346 |
* For IPv6 address construct a sockaddr_in6 structure.
|
|
347 |
*/
|
|
348 |
(*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
|
|
349 |
memset((char *) &him6, 0, sizeof(him6));
|
|
350 |
memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
|
|
351 |
him6.sin6_family = AF_INET6;
|
|
352 |
sa = (struct sockaddr *) &him6 ;
|
|
353 |
len = sizeof(him6) ;
|
|
354 |
}
|
|
355 |
|
|
356 |
error = (*getnameinfo_ptr)(sa, len, host, NI_MAXHOST, NULL, 0,
|
|
357 |
NI_NAMEREQD);
|
|
358 |
|
|
359 |
if (!error) {
|
|
360 |
ret = (*env)->NewStringUTF(env, host);
|
|
361 |
}
|
|
362 |
}
|
|
363 |
|
|
364 |
if (ret == NULL) {
|
|
365 |
JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
|
|
366 |
}
|
|
367 |
|
|
368 |
return ret;
|
|
369 |
}
|
|
370 |
|
|
371 |
#ifdef AF_INET6
|
|
372 |
|
|
373 |
|
|
374 |
/**
|
|
375 |
* ping implementation.
|
|
376 |
* Send a ICMP_ECHO_REQUEST packet every second until either the timeout
|
|
377 |
* expires or a answer is received.
|
|
378 |
* Returns true is an ECHO_REPLY is received, otherwise, false.
|
|
379 |
*/
|
|
380 |
static jboolean
|
|
381 |
ping6(JNIEnv *env, jint fd, struct SOCKADDR_IN6* him, jint timeout,
|
|
382 |
struct SOCKADDR_IN6* netif, jint ttl) {
|
|
383 |
jint size;
|
|
384 |
jint n, len, hlen1, icmplen, i;
|
|
385 |
char sendbuf[1500];
|
|
386 |
char auxbuf[1500];
|
|
387 |
unsigned char recvbuf[1500];
|
|
388 |
struct icmp6_hdr *icmp6;
|
|
389 |
struct SOCKADDR_IN6 sa_recv;
|
|
390 |
unsigned short pid, seq;
|
|
391 |
int read_rv = 0;
|
|
392 |
WSAEVENT hEvent;
|
|
393 |
struct ip6_pseudo_hdr *pseudo_ip6;
|
|
394 |
int timestamp;
|
|
395 |
int tmout2;
|
|
396 |
|
|
397 |
/* Initialize the sequence number to a suitable random number and
|
|
398 |
shift right one place to allow sufficient room for increamenting. */
|
|
399 |
seq = ((unsigned short)rand()) >> 1;
|
|
400 |
|
|
401 |
/* icmp_id is a 16 bit data type, therefore down cast the pid */
|
|
402 |
pid = (unsigned short) getpid();
|
|
403 |
|
|
404 |
size = 60*1024;
|
|
405 |
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *)&size, sizeof(size));
|
|
406 |
/**
|
|
407 |
* A TTL was specified, let's set the socket option.
|
|
408 |
*/
|
|
409 |
if (ttl > 0) {
|
|
410 |
setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (const char *) &ttl, sizeof(ttl));
|
|
411 |
}
|
|
412 |
|
|
413 |
/**
|
|
414 |
* A network interface was specified, let's bind to it.
|
|
415 |
*/
|
|
416 |
if (netif != NULL) {
|
|
417 |
if (NET_Bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) < 0){
|
|
418 |
NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket to interface");
|
|
419 |
closesocket(fd);
|
|
420 |
return JNI_FALSE;
|
|
421 |
}
|
|
422 |
}
|
|
423 |
|
|
424 |
/*
|
|
425 |
* Make the socket non blocking
|
|
426 |
*/
|
|
427 |
hEvent = WSACreateEvent();
|
|
428 |
WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE);
|
|
429 |
|
|
430 |
/**
|
|
431 |
* send 1 ICMP REQUEST every second until either we get a valid reply
|
|
432 |
* or the timeout expired.
|
|
433 |
*/
|
|
434 |
do {
|
|
435 |
/* let's tag the ECHO packet with our pid so we can identify it */
|
|
436 |
timestamp = GetCurrentTime();
|
|
437 |
memset(sendbuf, 0, 1500);
|
|
438 |
icmp6 = (struct icmp6_hdr *) sendbuf;
|
|
439 |
icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
|
|
440 |
icmp6->icmp6_code = 0;
|
|
441 |
icmp6->icmp6_id = htons(pid);
|
|
442 |
icmp6->icmp6_seq = htons(seq);
|
|
443 |
icmp6->icmp6_cksum = 0;
|
|
444 |
memcpy((icmp6 + 1), ×tamp, sizeof(int));
|
|
445 |
if (netif != NULL) {
|
|
446 |
memset(auxbuf, 0, 1500);
|
|
447 |
pseudo_ip6 = (struct ip6_pseudo_hdr*) auxbuf;
|
|
448 |
memcpy(&pseudo_ip6->ip6_src, &netif->sin6_addr, sizeof(struct in6_addr));
|
|
449 |
memcpy(&pseudo_ip6->ip6_dst, &him->sin6_addr, sizeof(struct in6_addr));
|
|
450 |
pseudo_ip6->ip6_plen= htonl( 64 );
|
|
451 |
pseudo_ip6->ip6_nxt = htonl( IPPROTO_ICMPV6 );
|
|
452 |
memcpy(auxbuf + sizeof(struct ip6_pseudo_hdr), icmp6, 64);
|
|
453 |
/**
|
|
454 |
* We shouldn't have to do that as computing the checksum is supposed
|
|
455 |
* to be done by the IPv6 stack. Unfortunately windows, here too, is
|
|
456 |
* uterly broken, or non compliant, so let's do it.
|
|
457 |
* Problem is to compute the checksum I need to know the source address
|
|
458 |
* which happens only if I know the interface to be used...
|
|
459 |
*/
|
|
460 |
icmp6->icmp6_cksum = in_cksum((u_short *)pseudo_ip6, sizeof(struct ip6_pseudo_hdr) + 64);
|
|
461 |
}
|
|
462 |
|
|
463 |
/**
|
|
464 |
* Ping!
|
|
465 |
*/
|
|
466 |
n = sendto(fd, sendbuf, 64, 0, (struct sockaddr*) him, sizeof(struct sockaddr_in6));
|
|
467 |
if (n < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEADDRNOTAVAIL)) {
|
|
468 |
// Happens when using a "tunnel interface" for instance.
|
|
469 |
// Or trying to send a packet on a different scope.
|
|
470 |
closesocket(fd);
|
|
471 |
WSACloseEvent(hEvent);
|
|
472 |
return JNI_FALSE;
|
|
473 |
}
|
|
474 |
if (n < 0 && WSAGetLastError() != WSAEWOULDBLOCK) {
|
|
475 |
NET_ThrowNew(env, WSAGetLastError(), "Can't send ICMP packet");
|
|
476 |
closesocket(fd);
|
|
477 |
WSACloseEvent(hEvent);
|
|
478 |
return JNI_FALSE;
|
|
479 |
}
|
|
480 |
|
|
481 |
tmout2 = timeout > 1000 ? 1000 : timeout;
|
|
482 |
do {
|
|
483 |
tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
|
|
484 |
|
|
485 |
if (tmout2 >= 0) {
|
|
486 |
len = sizeof(sa_recv);
|
|
487 |
memset(recvbuf, 0, 1500);
|
|
488 |
/**
|
|
489 |
* For some unknown reason, besides plain stupidity, windows
|
|
490 |
* truncates the first 4 bytes of the icmpv6 header some we can't
|
|
491 |
* check for the ICMP_ECHOREPLY value.
|
|
492 |
* we'll check the other values, though
|
|
493 |
*/
|
|
494 |
n = recvfrom(fd, recvbuf + 4, sizeof(recvbuf) - 4, 0, (struct sockaddr*) &sa_recv, &len);
|
|
495 |
icmp6 = (struct icmp6_hdr *) (recvbuf);
|
|
496 |
memcpy(&i, (icmp6 + 1), sizeof(int));
|
|
497 |
/**
|
|
498 |
* Is that the reply we were expecting?
|
|
499 |
*/
|
|
500 |
if (n >= 8 && ntohs(icmp6->icmp6_seq) == seq &&
|
|
501 |
ntohs(icmp6->icmp6_id) == pid && i == timestamp) {
|
|
502 |
closesocket(fd);
|
|
503 |
WSACloseEvent(hEvent);
|
|
504 |
return JNI_TRUE;
|
|
505 |
}
|
|
506 |
}
|
|
507 |
} while (tmout2 > 0);
|
|
508 |
timeout -= 1000;
|
|
509 |
seq++;
|
|
510 |
} while (timeout > 0);
|
|
511 |
closesocket(fd);
|
|
512 |
WSACloseEvent(hEvent);
|
|
513 |
return JNI_FALSE;
|
|
514 |
}
|
|
515 |
#endif /* AF_INET6 */
|
|
516 |
|
|
517 |
/*
|
|
518 |
* Class: java_net_Inet6AddressImpl
|
|
519 |
* Method: isReachable0
|
|
520 |
* Signature: ([bII[bI)Z
|
|
521 |
*/
|
|
522 |
JNIEXPORT jboolean JNICALL
|
|
523 |
Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this,
|
|
524 |
jbyteArray addrArray,
|
|
525 |
jint scope,
|
|
526 |
jint timeout,
|
|
527 |
jbyteArray ifArray,
|
|
528 |
jint ttl, jint if_scope) {
|
|
529 |
#ifdef AF_INET6
|
|
530 |
jint addr;
|
|
531 |
jbyte caddr[16];
|
|
532 |
jint fd, sz;
|
|
533 |
struct sockaddr_in6 him6;
|
|
534 |
struct sockaddr_in6* netif = NULL;
|
|
535 |
struct sockaddr_in6 inf6;
|
|
536 |
WSAEVENT hEvent;
|
|
537 |
int len = 0;
|
|
538 |
int connect_rv = -1;
|
|
539 |
|
|
540 |
/*
|
|
541 |
* If IPv6 is not enable, then we can't reach an IPv6 address, can we?
|
|
542 |
* Actually, we probably shouldn't even get here.
|
|
543 |
*/
|
|
544 |
if (!ipv6_available()) {
|
|
545 |
return JNI_FALSE;
|
|
546 |
}
|
|
547 |
/*
|
|
548 |
* If it's an IPv4 address, ICMP won't work with IPv4 mapped address,
|
|
549 |
* therefore, let's delegate to the Inet4Address method.
|
|
550 |
*/
|
|
551 |
sz = (*env)->GetArrayLength(env, addrArray);
|
|
552 |
if (sz == 4) {
|
|
553 |
return Java_java_net_Inet4AddressImpl_isReachable0(env, this,
|
|
554 |
addrArray,
|
|
555 |
timeout,
|
|
556 |
ifArray, ttl);
|
|
557 |
}
|
|
558 |
|
|
559 |
memset((char *) caddr, 0, 16);
|
|
560 |
memset((char *) &him6, 0, sizeof(him6));
|
|
561 |
(*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
|
|
562 |
memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
|
|
563 |
him6.sin6_family = AF_INET6;
|
|
564 |
if (scope > 0) {
|
|
565 |
him6.sin6_scope_id = scope;
|
|
566 |
}
|
|
567 |
len = sizeof(struct sockaddr_in6);
|
|
568 |
/**
|
|
569 |
* A network interface was specified, let's convert the address
|
|
570 |
*/
|
|
571 |
if (!(IS_NULL(ifArray))) {
|
|
572 |
memset((char *) caddr, 0, 16);
|
|
573 |
memset((char *) &inf6, 0, sizeof(inf6));
|
|
574 |
(*env)->GetByteArrayRegion(env, ifArray, 0, 16, caddr);
|
|
575 |
memcpy((void *)&(inf6.sin6_addr), caddr, sizeof(struct in6_addr) );
|
|
576 |
inf6.sin6_family = AF_INET6;
|
|
577 |
inf6.sin6_port = 0;
|
|
578 |
inf6.sin6_scope_id = if_scope;
|
|
579 |
netif = &inf6;
|
|
580 |
}
|
|
581 |
|
|
582 |
#if 0
|
|
583 |
/*
|
|
584 |
* Windows implementation of ICMP & RAW sockets is too unreliable for now.
|
|
585 |
* Therefore it's best not to try it at all and rely only on TCP
|
|
586 |
* We may revisit and enable this code in the future.
|
|
587 |
*/
|
|
588 |
|
|
589 |
/*
|
|
590 |
* Right now, windows doesn't generate the ICMP checksum automatically
|
|
591 |
* so we have to compute it, but we can do it only if we know which
|
|
592 |
* interface will be used. Therefore, don't try to use ICMP if no
|
|
593 |
* interface was specified.
|
|
594 |
* When ICMPv6 support improves in windows, we may change this.
|
|
595 |
*/
|
|
596 |
if (!(IS_NULL(ifArray))) {
|
|
597 |
/*
|
|
598 |
* If we can create a RAW socket, then when can use the ICMP ECHO_REQUEST
|
|
599 |
* otherwise we'll try a tcp socket to the Echo port (7).
|
|
600 |
* Note that this is empiric, and not connecting could mean it's blocked
|
|
601 |
* or the echo servioe has been disabled.
|
|
602 |
*/
|
|
603 |
fd = NET_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
|
|
604 |
|
|
605 |
if (fd != -1) { /* Good to go, let's do a ping */
|
|
606 |
return ping6(env, fd, &him6, timeout, netif, ttl);
|
|
607 |
}
|
|
608 |
}
|
|
609 |
#endif
|
|
610 |
|
|
611 |
/* No good, let's fall back on TCP */
|
|
612 |
fd = NET_Socket(AF_INET6, SOCK_STREAM, 0);
|
|
613 |
if (fd == JVM_IO_ERR) {
|
|
614 |
/* note: if you run out of fds, you may not be able to load
|
|
615 |
* the exception class, and get a NoClassDefFoundError
|
|
616 |
* instead.
|
|
617 |
*/
|
|
618 |
NET_ThrowNew(env, errno, "Can't create socket");
|
|
619 |
return JNI_FALSE;
|
|
620 |
}
|
|
621 |
|
|
622 |
/**
|
|
623 |
* A TTL was specified, let's set the socket option.
|
|
624 |
*/
|
|
625 |
if (ttl > 0) {
|
|
626 |
setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (const char *)&ttl, sizeof(ttl));
|
|
627 |
}
|
|
628 |
|
|
629 |
/**
|
|
630 |
* A network interface was specified, let's bind to it.
|
|
631 |
*/
|
|
632 |
if (netif != NULL) {
|
|
633 |
if (NET_Bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) < 0) {
|
|
634 |
NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket to interface");
|
|
635 |
closesocket(fd);
|
|
636 |
return JNI_FALSE;
|
|
637 |
}
|
|
638 |
}
|
|
639 |
|
|
640 |
/**
|
|
641 |
* Make the socket non blocking.
|
|
642 |
*/
|
|
643 |
hEvent = WSACreateEvent();
|
|
644 |
WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE);
|
|
645 |
|
|
646 |
/* no need to use NET_Connect as non-blocking */
|
|
647 |
him6.sin6_port = htons((short) 7); /* Echo port */
|
|
648 |
connect_rv = connect(fd, (struct sockaddr *)&him6, len);
|
|
649 |
|
|
650 |
/**
|
|
651 |
* connection established or refused immediately, either way it means
|
|
652 |
* we were able to reach the host!
|
|
653 |
*/
|
|
654 |
if (connect_rv == 0 || WSAGetLastError() == WSAECONNREFUSED) {
|
|
655 |
WSACloseEvent(hEvent);
|
|
656 |
closesocket(fd);
|
|
657 |
return JNI_TRUE;
|
|
658 |
} else {
|
|
659 |
int optlen;
|
|
660 |
|
|
661 |
switch (WSAGetLastError()) {
|
|
662 |
case WSAEHOSTUNREACH: /* Host Unreachable */
|
|
663 |
case WSAENETUNREACH: /* Network Unreachable */
|
|
664 |
case WSAENETDOWN: /* Network is down */
|
|
665 |
case WSAEPFNOSUPPORT: /* Protocol Family unsupported */
|
|
666 |
WSACloseEvent(hEvent);
|
|
667 |
closesocket(fd);
|
|
668 |
return JNI_FALSE;
|
|
669 |
}
|
|
670 |
|
|
671 |
if (WSAGetLastError() != WSAEWOULDBLOCK) {
|
|
672 |
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
|
|
673 |
"connect failed");
|
|
674 |
WSACloseEvent(hEvent);
|
|
675 |
closesocket(fd);
|
|
676 |
return JNI_FALSE;
|
|
677 |
}
|
|
678 |
|
|
679 |
timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
|
|
680 |
|
|
681 |
if (timeout >= 0) {
|
|
682 |
/* has connection been established? */
|
|
683 |
optlen = sizeof(connect_rv);
|
|
684 |
if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
|
|
685 |
&optlen) <0) {
|
|
686 |
connect_rv = WSAGetLastError();
|
|
687 |
}
|
|
688 |
|
|
689 |
if (connect_rv == 0 || connect_rv == WSAECONNREFUSED) {
|
|
690 |
WSACloseEvent(hEvent);
|
|
691 |
closesocket(fd);
|
|
692 |
return JNI_TRUE;
|
|
693 |
}
|
|
694 |
}
|
|
695 |
}
|
|
696 |
WSACloseEvent(hEvent);
|
|
697 |
closesocket(fd);
|
|
698 |
#endif /* AF_INET6 */
|
|
699 |
return JNI_FALSE;
|
|
700 |
}
|