author | ohair |
Wed, 06 Apr 2011 22:06:11 -0700 | |
changeset 9035 | 1255eb81cc2f |
parent 7814 | dff0b40f9ac8 |
child 9050 | 26c2c1de1631 |
permissions | -rw-r--r-- |
2 | 1 |
/* |
9035
1255eb81cc2f
7033660: Update copyright year to 2011 on any files changed in 2011
ohair
parents:
7814
diff
changeset
|
2 |
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. |
2 | 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 |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 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 |
* |
|
5506 | 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. |
|
2 | 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> |
|
910 | 33 |
#include <process.h> |
2 | 34 |
|
35 |
#include "java_net_InetAddress.h" |
|
36 |
#include "java_net_Inet4AddressImpl.h" |
|
37 |
#include "java_net_Inet6AddressImpl.h" |
|
38 |
#include "net_util.h" |
|
39 |
#include "icmp.h" |
|
40 |
||
41 |
#ifdef WIN32 |
|
42 |
#ifndef _WIN64 |
|
43 |
||
44 |
/* Retain this code a little longer to support building in |
|
45 |
* old environments. _MSC_VER is defined as: |
|
46 |
* 1200 for MSVC++ 6.0 |
|
47 |
* 1310 for Vc7 |
|
48 |
*/ |
|
49 |
#if defined(_MSC_VER) && _MSC_VER < 1310 |
|
50 |
#define sockaddr_in6 SOCKADDR_IN6 |
|
51 |
#endif |
|
52 |
#endif |
|
53 |
#define uint32_t UINT32 |
|
54 |
#endif |
|
55 |
||
56 |
/* |
|
57 |
* Inet6AddressImpl |
|
58 |
*/ |
|
59 |
||
60 |
/* |
|
61 |
* Class: java_net_Inet6AddressImpl |
|
62 |
* Method: getLocalHostName |
|
63 |
* Signature: ()Ljava/lang/String; |
|
64 |
*/ |
|
65 |
JNIEXPORT jstring JNICALL |
|
66 |
Java_java_net_Inet6AddressImpl_getLocalHostName (JNIEnv *env, jobject this) { |
|
67 |
char hostname [256]; |
|
68 |
||
69 |
if (gethostname (hostname, sizeof (hostname)) == -1) { |
|
70 |
strcpy (hostname, "localhost"); |
|
71 |
} |
|
72 |
return JNU_NewStringPlatform (env, hostname); |
|
73 |
} |
|
74 |
||
75 |
static jclass ni_iacls; |
|
76 |
static jclass ni_ia4cls; |
|
77 |
static jclass ni_ia6cls; |
|
78 |
static jmethodID ni_ia4ctrID; |
|
79 |
static jmethodID ni_ia6ctrID; |
|
80 |
static jfieldID ni_iaaddressID; |
|
81 |
static jfieldID ni_iahostID; |
|
82 |
static jfieldID ni_iafamilyID; |
|
83 |
static jfieldID ni_ia6ipaddressID; |
|
84 |
static int initialized = 0; |
|
85 |
||
86 |
JNIEXPORT jobjectArray JNICALL |
|
87 |
Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, |
|
88 |
jstring host) { |
|
89 |
const char *hostname; |
|
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 |
while (iterator != NULL) { |
|
241 |
if (iterator->ai_family == AF_INET) { |
|
242 |
jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID); |
|
243 |
if (IS_NULL(iaObj)) { |
|
244 |
ret = NULL; |
|
245 |
goto cleanupAndReturn; |
|
246 |
} |
|
247 |
(*env)->SetIntField(env, iaObj, ni_iaaddressID, |
|
248 |
ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr)); |
|
707
4e060643fb54
6698625: InetAddress.getLocalHost() failed in returning chinese local host name
chegar
parents:
2
diff
changeset
|
249 |
(*env)->SetObjectField(env, iaObj, ni_iahostID, host); |
2 | 250 |
(*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj); |
251 |
inetIndex ++; |
|
252 |
} else if (iterator->ai_family == AF_INET6) { |
|
253 |
jint scope = 0; |
|
254 |
jbyteArray ipaddress; |
|
255 |
jobject iaObj = (*env)->NewObject(env, ni_ia6cls, ni_ia6ctrID); |
|
256 |
if (IS_NULL(iaObj)) { |
|
257 |
ret = NULL; |
|
258 |
goto cleanupAndReturn; |
|
259 |
} |
|
260 |
ipaddress = (*env)->NewByteArray(env, 16); |
|
261 |
if (IS_NULL(ipaddress)) { |
|
262 |
ret = NULL; |
|
263 |
goto cleanupAndReturn; |
|
264 |
} |
|
265 |
(*env)->SetByteArrayRegion(env, ipaddress, 0, 16, |
|
266 |
(jbyte *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr)); |
|
267 |
scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id; |
|
268 |
if (scope != 0) { /* zero is default value, no need to set */ |
|
269 |
(*env)->SetIntField(env, iaObj, ia6_scopeidID, scope); |
|
270 |
(*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE); |
|
271 |
} |
|
272 |
(*env)->SetObjectField(env, iaObj, ni_ia6ipaddressID, ipaddress); |
|
707
4e060643fb54
6698625: InetAddress.getLocalHost() failed in returning chinese local host name
chegar
parents:
2
diff
changeset
|
273 |
(*env)->SetObjectField(env, iaObj, ni_iahostID, host); |
2 | 274 |
(*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj); |
275 |
inet6Index ++; |
|
276 |
} |
|
277 |
iterator = iterator->ai_next; |
|
278 |
} |
|
279 |
} |
|
280 |
} |
|
281 |
||
282 |
cleanupAndReturn: |
|
283 |
{ |
|
284 |
struct addrinfo *iterator, *tmp; |
|
285 |
iterator = resNew; |
|
286 |
while (iterator != NULL) { |
|
287 |
tmp = iterator; |
|
288 |
iterator = iterator->ai_next; |
|
289 |
free(tmp); |
|
290 |
} |
|
291 |
JNU_ReleaseStringPlatformChars(env, host, hostname); |
|
292 |
} |
|
293 |
||
294 |
if (NET_addrtransAvailable()) |
|
295 |
(*freeaddrinfo_ptr)(res); |
|
296 |
||
297 |
return ret; |
|
298 |
} |
|
299 |
||
300 |
/* |
|
301 |
* Class: java_net_Inet6AddressImpl |
|
302 |
* Method: getHostByAddr |
|
303 |
* Signature: (I)Ljava/lang/String; |
|
304 |
*/ |
|
305 |
JNIEXPORT jstring JNICALL |
|
306 |
Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this, |
|
307 |
jbyteArray addrArray) { |
|
308 |
jstring ret = NULL; |
|
309 |
||
310 |
char host[NI_MAXHOST+1]; |
|
311 |
int error = 0; |
|
312 |
int len = 0; |
|
313 |
jbyte caddr[16]; |
|
314 |
||
315 |
if (NET_addrtransAvailable()) { |
|
316 |
struct sockaddr_in him4; |
|
317 |
struct sockaddr_in6 him6; |
|
318 |
struct sockaddr *sa; |
|
319 |
||
320 |
/* |
|
321 |
* For IPv4 addresses construct a sockaddr_in structure. |
|
322 |
*/ |
|
323 |
if ((*env)->GetArrayLength(env, addrArray) == 4) { |
|
324 |
jint addr; |
|
325 |
(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr); |
|
326 |
addr = ((caddr[0]<<24) & 0xff000000); |
|
327 |
addr |= ((caddr[1] <<16) & 0xff0000); |
|
328 |
addr |= ((caddr[2] <<8) & 0xff00); |
|
329 |
addr |= (caddr[3] & 0xff); |
|
330 |
memset((char *) &him4, 0, sizeof(him4)); |
|
331 |
him4.sin_addr.s_addr = (uint32_t) htonl(addr); |
|
332 |
him4.sin_family = AF_INET; |
|
333 |
sa = (struct sockaddr *) &him4; |
|
334 |
len = sizeof(him4); |
|
335 |
} else { |
|
336 |
/* |
|
337 |
* For IPv6 address construct a sockaddr_in6 structure. |
|
338 |
*/ |
|
339 |
(*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr); |
|
340 |
memset((char *) &him6, 0, sizeof(him6)); |
|
341 |
memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) ); |
|
342 |
him6.sin6_family = AF_INET6; |
|
343 |
sa = (struct sockaddr *) &him6 ; |
|
344 |
len = sizeof(him6) ; |
|
345 |
} |
|
346 |
||
347 |
error = (*getnameinfo_ptr)(sa, len, host, NI_MAXHOST, NULL, 0, |
|
348 |
NI_NAMEREQD); |
|
349 |
||
350 |
if (!error) { |
|
351 |
ret = (*env)->NewStringUTF(env, host); |
|
352 |
} |
|
353 |
} |
|
354 |
||
355 |
if (ret == NULL) { |
|
356 |
JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL); |
|
357 |
} |
|
358 |
||
359 |
return ret; |
|
360 |
} |
|
361 |
||
362 |
#ifdef AF_INET6 |
|
363 |
||
364 |
||
365 |
/** |
|
366 |
* ping implementation. |
|
367 |
* Send a ICMP_ECHO_REQUEST packet every second until either the timeout |
|
368 |
* expires or a answer is received. |
|
369 |
* Returns true is an ECHO_REPLY is received, otherwise, false. |
|
370 |
*/ |
|
371 |
static jboolean |
|
372 |
ping6(JNIEnv *env, jint fd, struct SOCKADDR_IN6* him, jint timeout, |
|
373 |
struct SOCKADDR_IN6* netif, jint ttl) { |
|
374 |
jint size; |
|
910 | 375 |
jint n, len, i; |
2 | 376 |
char sendbuf[1500]; |
377 |
char auxbuf[1500]; |
|
378 |
unsigned char recvbuf[1500]; |
|
379 |
struct icmp6_hdr *icmp6; |
|
380 |
struct SOCKADDR_IN6 sa_recv; |
|
381 |
unsigned short pid, seq; |
|
382 |
int read_rv = 0; |
|
383 |
WSAEVENT hEvent; |
|
384 |
struct ip6_pseudo_hdr *pseudo_ip6; |
|
385 |
int timestamp; |
|
386 |
int tmout2; |
|
387 |
||
388 |
/* Initialize the sequence number to a suitable random number and |
|
389 |
shift right one place to allow sufficient room for increamenting. */ |
|
390 |
seq = ((unsigned short)rand()) >> 1; |
|
391 |
||
392 |
/* icmp_id is a 16 bit data type, therefore down cast the pid */ |
|
910 | 393 |
pid = (unsigned short) _getpid(); |
2 | 394 |
|
395 |
size = 60*1024; |
|
396 |
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *)&size, sizeof(size)); |
|
397 |
/** |
|
398 |
* A TTL was specified, let's set the socket option. |
|
399 |
*/ |
|
400 |
if (ttl > 0) { |
|
401 |
setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (const char *) &ttl, sizeof(ttl)); |
|
402 |
} |
|
403 |
||
404 |
/** |
|
405 |
* A network interface was specified, let's bind to it. |
|
406 |
*/ |
|
407 |
if (netif != NULL) { |
|
408 |
if (NET_Bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) < 0){ |
|
409 |
NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket to interface"); |
|
410 |
closesocket(fd); |
|
411 |
return JNI_FALSE; |
|
412 |
} |
|
413 |
} |
|
414 |
||
415 |
/* |
|
416 |
* Make the socket non blocking |
|
417 |
*/ |
|
418 |
hEvent = WSACreateEvent(); |
|
419 |
WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE); |
|
420 |
||
421 |
/** |
|
422 |
* send 1 ICMP REQUEST every second until either we get a valid reply |
|
423 |
* or the timeout expired. |
|
424 |
*/ |
|
425 |
do { |
|
426 |
/* let's tag the ECHO packet with our pid so we can identify it */ |
|
427 |
timestamp = GetCurrentTime(); |
|
428 |
memset(sendbuf, 0, 1500); |
|
429 |
icmp6 = (struct icmp6_hdr *) sendbuf; |
|
430 |
icmp6->icmp6_type = ICMP6_ECHO_REQUEST; |
|
431 |
icmp6->icmp6_code = 0; |
|
432 |
icmp6->icmp6_id = htons(pid); |
|
433 |
icmp6->icmp6_seq = htons(seq); |
|
434 |
icmp6->icmp6_cksum = 0; |
|
435 |
memcpy((icmp6 + 1), ×tamp, sizeof(int)); |
|
436 |
if (netif != NULL) { |
|
437 |
memset(auxbuf, 0, 1500); |
|
438 |
pseudo_ip6 = (struct ip6_pseudo_hdr*) auxbuf; |
|
439 |
memcpy(&pseudo_ip6->ip6_src, &netif->sin6_addr, sizeof(struct in6_addr)); |
|
440 |
memcpy(&pseudo_ip6->ip6_dst, &him->sin6_addr, sizeof(struct in6_addr)); |
|
441 |
pseudo_ip6->ip6_plen= htonl( 64 ); |
|
442 |
pseudo_ip6->ip6_nxt = htonl( IPPROTO_ICMPV6 ); |
|
443 |
memcpy(auxbuf + sizeof(struct ip6_pseudo_hdr), icmp6, 64); |
|
444 |
/** |
|
445 |
* We shouldn't have to do that as computing the checksum is supposed |
|
446 |
* to be done by the IPv6 stack. Unfortunately windows, here too, is |
|
447 |
* uterly broken, or non compliant, so let's do it. |
|
448 |
* Problem is to compute the checksum I need to know the source address |
|
449 |
* which happens only if I know the interface to be used... |
|
450 |
*/ |
|
451 |
icmp6->icmp6_cksum = in_cksum((u_short *)pseudo_ip6, sizeof(struct ip6_pseudo_hdr) + 64); |
|
452 |
} |
|
453 |
||
454 |
/** |
|
455 |
* Ping! |
|
456 |
*/ |
|
457 |
n = sendto(fd, sendbuf, 64, 0, (struct sockaddr*) him, sizeof(struct sockaddr_in6)); |
|
458 |
if (n < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEADDRNOTAVAIL)) { |
|
459 |
// Happens when using a "tunnel interface" for instance. |
|
460 |
// Or trying to send a packet on a different scope. |
|
461 |
closesocket(fd); |
|
462 |
WSACloseEvent(hEvent); |
|
463 |
return JNI_FALSE; |
|
464 |
} |
|
465 |
if (n < 0 && WSAGetLastError() != WSAEWOULDBLOCK) { |
|
466 |
NET_ThrowNew(env, WSAGetLastError(), "Can't send ICMP packet"); |
|
467 |
closesocket(fd); |
|
468 |
WSACloseEvent(hEvent); |
|
469 |
return JNI_FALSE; |
|
470 |
} |
|
471 |
||
472 |
tmout2 = timeout > 1000 ? 1000 : timeout; |
|
473 |
do { |
|
474 |
tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2); |
|
475 |
||
476 |
if (tmout2 >= 0) { |
|
477 |
len = sizeof(sa_recv); |
|
478 |
memset(recvbuf, 0, 1500); |
|
479 |
/** |
|
480 |
* For some unknown reason, besides plain stupidity, windows |
|
481 |
* truncates the first 4 bytes of the icmpv6 header some we can't |
|
482 |
* check for the ICMP_ECHOREPLY value. |
|
483 |
* we'll check the other values, though |
|
484 |
*/ |
|
485 |
n = recvfrom(fd, recvbuf + 4, sizeof(recvbuf) - 4, 0, (struct sockaddr*) &sa_recv, &len); |
|
486 |
icmp6 = (struct icmp6_hdr *) (recvbuf); |
|
487 |
memcpy(&i, (icmp6 + 1), sizeof(int)); |
|
488 |
/** |
|
489 |
* Is that the reply we were expecting? |
|
490 |
*/ |
|
491 |
if (n >= 8 && ntohs(icmp6->icmp6_seq) == seq && |
|
492 |
ntohs(icmp6->icmp6_id) == pid && i == timestamp) { |
|
493 |
closesocket(fd); |
|
494 |
WSACloseEvent(hEvent); |
|
495 |
return JNI_TRUE; |
|
496 |
} |
|
497 |
} |
|
498 |
} while (tmout2 > 0); |
|
499 |
timeout -= 1000; |
|
500 |
seq++; |
|
501 |
} while (timeout > 0); |
|
502 |
closesocket(fd); |
|
503 |
WSACloseEvent(hEvent); |
|
504 |
return JNI_FALSE; |
|
505 |
} |
|
506 |
#endif /* AF_INET6 */ |
|
507 |
||
508 |
/* |
|
509 |
* Class: java_net_Inet6AddressImpl |
|
510 |
* Method: isReachable0 |
|
511 |
* Signature: ([bII[bI)Z |
|
512 |
*/ |
|
513 |
JNIEXPORT jboolean JNICALL |
|
514 |
Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this, |
|
515 |
jbyteArray addrArray, |
|
516 |
jint scope, |
|
517 |
jint timeout, |
|
518 |
jbyteArray ifArray, |
|
519 |
jint ttl, jint if_scope) { |
|
520 |
#ifdef AF_INET6 |
|
521 |
jbyte caddr[16]; |
|
522 |
jint fd, sz; |
|
523 |
struct sockaddr_in6 him6; |
|
524 |
struct sockaddr_in6* netif = NULL; |
|
525 |
struct sockaddr_in6 inf6; |
|
526 |
WSAEVENT hEvent; |
|
527 |
int len = 0; |
|
528 |
int connect_rv = -1; |
|
529 |
||
530 |
/* |
|
531 |
* If IPv6 is not enable, then we can't reach an IPv6 address, can we? |
|
532 |
* Actually, we probably shouldn't even get here. |
|
533 |
*/ |
|
534 |
if (!ipv6_available()) { |
|
535 |
return JNI_FALSE; |
|
536 |
} |
|
537 |
/* |
|
538 |
* If it's an IPv4 address, ICMP won't work with IPv4 mapped address, |
|
539 |
* therefore, let's delegate to the Inet4Address method. |
|
540 |
*/ |
|
541 |
sz = (*env)->GetArrayLength(env, addrArray); |
|
542 |
if (sz == 4) { |
|
543 |
return Java_java_net_Inet4AddressImpl_isReachable0(env, this, |
|
544 |
addrArray, |
|
545 |
timeout, |
|
546 |
ifArray, ttl); |
|
547 |
} |
|
548 |
||
549 |
memset((char *) caddr, 0, 16); |
|
550 |
memset((char *) &him6, 0, sizeof(him6)); |
|
551 |
(*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr); |
|
552 |
memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) ); |
|
553 |
him6.sin6_family = AF_INET6; |
|
554 |
if (scope > 0) { |
|
555 |
him6.sin6_scope_id = scope; |
|
556 |
} |
|
557 |
len = sizeof(struct sockaddr_in6); |
|
558 |
/** |
|
559 |
* A network interface was specified, let's convert the address |
|
560 |
*/ |
|
561 |
if (!(IS_NULL(ifArray))) { |
|
562 |
memset((char *) caddr, 0, 16); |
|
563 |
memset((char *) &inf6, 0, sizeof(inf6)); |
|
564 |
(*env)->GetByteArrayRegion(env, ifArray, 0, 16, caddr); |
|
565 |
memcpy((void *)&(inf6.sin6_addr), caddr, sizeof(struct in6_addr) ); |
|
566 |
inf6.sin6_family = AF_INET6; |
|
567 |
inf6.sin6_port = 0; |
|
568 |
inf6.sin6_scope_id = if_scope; |
|
569 |
netif = &inf6; |
|
570 |
} |
|
571 |
||
572 |
#if 0 |
|
573 |
/* |
|
574 |
* Windows implementation of ICMP & RAW sockets is too unreliable for now. |
|
575 |
* Therefore it's best not to try it at all and rely only on TCP |
|
576 |
* We may revisit and enable this code in the future. |
|
577 |
*/ |
|
578 |
||
579 |
/* |
|
580 |
* Right now, windows doesn't generate the ICMP checksum automatically |
|
581 |
* so we have to compute it, but we can do it only if we know which |
|
582 |
* interface will be used. Therefore, don't try to use ICMP if no |
|
583 |
* interface was specified. |
|
584 |
* When ICMPv6 support improves in windows, we may change this. |
|
585 |
*/ |
|
586 |
if (!(IS_NULL(ifArray))) { |
|
587 |
/* |
|
588 |
* If we can create a RAW socket, then when can use the ICMP ECHO_REQUEST |
|
589 |
* otherwise we'll try a tcp socket to the Echo port (7). |
|
590 |
* Note that this is empiric, and not connecting could mean it's blocked |
|
591 |
* or the echo servioe has been disabled. |
|
592 |
*/ |
|
593 |
fd = NET_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); |
|
594 |
||
595 |
if (fd != -1) { /* Good to go, let's do a ping */ |
|
596 |
return ping6(env, fd, &him6, timeout, netif, ttl); |
|
597 |
} |
|
598 |
} |
|
599 |
#endif |
|
600 |
||
601 |
/* No good, let's fall back on TCP */ |
|
602 |
fd = NET_Socket(AF_INET6, SOCK_STREAM, 0); |
|
603 |
if (fd == JVM_IO_ERR) { |
|
604 |
/* note: if you run out of fds, you may not be able to load |
|
605 |
* the exception class, and get a NoClassDefFoundError |
|
606 |
* instead. |
|
607 |
*/ |
|
608 |
NET_ThrowNew(env, errno, "Can't create socket"); |
|
609 |
return JNI_FALSE; |
|
610 |
} |
|
611 |
||
612 |
/** |
|
613 |
* A TTL was specified, let's set the socket option. |
|
614 |
*/ |
|
615 |
if (ttl > 0) { |
|
616 |
setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (const char *)&ttl, sizeof(ttl)); |
|
617 |
} |
|
618 |
||
619 |
/** |
|
620 |
* A network interface was specified, let's bind to it. |
|
621 |
*/ |
|
622 |
if (netif != NULL) { |
|
623 |
if (NET_Bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) < 0) { |
|
624 |
NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket to interface"); |
|
625 |
closesocket(fd); |
|
626 |
return JNI_FALSE; |
|
627 |
} |
|
628 |
} |
|
629 |
||
630 |
/** |
|
631 |
* Make the socket non blocking. |
|
632 |
*/ |
|
633 |
hEvent = WSACreateEvent(); |
|
634 |
WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE); |
|
635 |
||
636 |
/* no need to use NET_Connect as non-blocking */ |
|
637 |
him6.sin6_port = htons((short) 7); /* Echo port */ |
|
638 |
connect_rv = connect(fd, (struct sockaddr *)&him6, len); |
|
639 |
||
640 |
/** |
|
641 |
* connection established or refused immediately, either way it means |
|
642 |
* we were able to reach the host! |
|
643 |
*/ |
|
644 |
if (connect_rv == 0 || WSAGetLastError() == WSAECONNREFUSED) { |
|
645 |
WSACloseEvent(hEvent); |
|
646 |
closesocket(fd); |
|
647 |
return JNI_TRUE; |
|
648 |
} else { |
|
649 |
int optlen; |
|
650 |
||
651 |
switch (WSAGetLastError()) { |
|
652 |
case WSAEHOSTUNREACH: /* Host Unreachable */ |
|
653 |
case WSAENETUNREACH: /* Network Unreachable */ |
|
654 |
case WSAENETDOWN: /* Network is down */ |
|
655 |
case WSAEPFNOSUPPORT: /* Protocol Family unsupported */ |
|
656 |
WSACloseEvent(hEvent); |
|
657 |
closesocket(fd); |
|
658 |
return JNI_FALSE; |
|
659 |
} |
|
660 |
||
661 |
if (WSAGetLastError() != WSAEWOULDBLOCK) { |
|
662 |
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException", |
|
663 |
"connect failed"); |
|
664 |
WSACloseEvent(hEvent); |
|
665 |
closesocket(fd); |
|
666 |
return JNI_FALSE; |
|
667 |
} |
|
668 |
||
669 |
timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout); |
|
670 |
||
671 |
if (timeout >= 0) { |
|
672 |
/* has connection been established? */ |
|
673 |
optlen = sizeof(connect_rv); |
|
7814
dff0b40f9ac8
7010192: InetAddress.isReachable hits ShouldNotReachHere with hs20-b04 (win)
alanb
parents:
5506
diff
changeset
|
674 |
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv, |
dff0b40f9ac8
7010192: InetAddress.isReachable hits ShouldNotReachHere with hs20-b04 (win)
alanb
parents:
5506
diff
changeset
|
675 |
&optlen) <0) { |
2 | 676 |
connect_rv = WSAGetLastError(); |
677 |
} |
|
678 |
||
679 |
if (connect_rv == 0 || connect_rv == WSAECONNREFUSED) { |
|
680 |
WSACloseEvent(hEvent); |
|
681 |
closesocket(fd); |
|
682 |
return JNI_TRUE; |
|
683 |
} |
|
684 |
} |
|
685 |
} |
|
686 |
WSACloseEvent(hEvent); |
|
687 |
closesocket(fd); |
|
688 |
#endif /* AF_INET6 */ |
|
689 |
return JNI_FALSE; |
|
690 |
} |