Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/native/java/net/Inet4AddressImpl.c
32287 views
1
/*
2
* Copyright (c) 2000, 2018, 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 <errno.h>
27
#include <sys/time.h>
28
#include <sys/types.h>
29
#include <sys/socket.h>
30
#include <netinet/in_systm.h>
31
#include <netinet/in.h>
32
#include <netinet/ip.h>
33
#include <netinet/ip_icmp.h>
34
#include <netdb.h>
35
#include <string.h>
36
#include <stdlib.h>
37
#include <ctype.h>
38
39
#ifdef _ALLBSD_SOURCE
40
#include <unistd.h>
41
#include <sys/param.h>
42
#endif
43
44
#include "jvm.h"
45
#include "jni_util.h"
46
#include "net_util.h"
47
48
#include "java_net_Inet4AddressImpl.h"
49
50
#if !defined(__ANDROID__) && defined(__GLIBC__) || (defined(__FreeBSD__) && (__FreeBSD_version >= 601104))
51
#define HAS_GLIBC_GETHOSTBY_R 1
52
#endif
53
54
55
#if defined(_ALLBSD_SOURCE) && !defined(HAS_GLIBC_GETHOSTBY_R)
56
extern jobjectArray lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6);
57
58
/* Use getaddrinfo(3), which is thread safe */
59
/************************************************************************
60
* Inet4AddressImpl
61
*/
62
63
/*
64
* Class: java_net_Inet4AddressImpl
65
* Method: getLocalHostName
66
* Signature: ()Ljava/lang/String;
67
*/
68
JNIEXPORT jstring JNICALL
69
Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
70
char hostname[NI_MAXHOST + 1];
71
72
hostname[0] = '\0';
73
if (JVM_GetHostName(hostname, NI_MAXHOST)) {
74
strcpy(hostname, "localhost");
75
#if defined(__solaris__)
76
} else {
77
// try to resolve hostname via nameservice
78
// if it is known but getnameinfo fails, hostname will still be the
79
// value from gethostname
80
struct addrinfo hints, *res;
81
82
// make sure string is null-terminated
83
hostname[NI_MAXHOST] = '\0';
84
memset(&hints, 0, sizeof(hints));
85
hints.ai_flags = AI_CANONNAME;
86
hints.ai_family = AF_INET;
87
88
if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
89
getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST,
90
NULL, 0, NI_NAMEREQD);
91
freeaddrinfo(res);
92
}
93
}
94
#else
95
} else {
96
// make sure string is null-terminated
97
hostname[NI_MAXHOST] = '\0';
98
}
99
#endif
100
return (*env)->NewStringUTF(env, hostname);
101
}
102
103
/*
104
* Find an internet address for a given hostname. Note that this
105
* code only works for addresses of type INET. The translation
106
* of %d.%d.%d.%d to an address (int) occurs in java now, so the
107
* String "host" shouldn't *ever* be a %d.%d.%d.%d string
108
*
109
* Class: java_net_Inet4AddressImpl
110
* Method: lookupAllHostAddr
111
* Signature: (Ljava/lang/String;)[[B
112
*/
113
114
JNIEXPORT jobjectArray JNICALL
115
Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
116
jstring host) {
117
const char *hostname;
118
jobject name;
119
jobjectArray ret = 0;
120
int retLen = 0;
121
122
int getaddrinfo_error=0;
123
struct addrinfo hints, *res, *resNew = NULL;
124
125
initInetAddressIDs(env);
126
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
127
128
if (IS_NULL(host)) {
129
JNU_ThrowNullPointerException(env, "host is null");
130
return 0;
131
}
132
hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
133
CHECK_NULL_RETURN(hostname, NULL);
134
135
memset(&hints, 0, sizeof(hints));
136
hints.ai_flags = AI_CANONNAME;
137
hints.ai_family = AF_INET;
138
139
/*
140
* Workaround for Solaris bug 4160367 - if a hostname contains a
141
* white space then 0.0.0.0 is returned
142
*/
143
if (isspace((unsigned char)hostname[0])) {
144
JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
145
(char *)hostname);
146
JNU_ReleaseStringPlatformChars(env, host, hostname);
147
return NULL;
148
}
149
150
getaddrinfo_error = getaddrinfo(hostname, NULL, &hints, &res);
151
152
#ifdef MACOSX
153
if (getaddrinfo_error) {
154
// If getaddrinfo fails try getifaddrs.
155
ret = lookupIfLocalhost(env, hostname, JNI_FALSE);
156
if (ret != NULL || (*env)->ExceptionCheck(env)) {
157
JNU_ReleaseStringPlatformChars(env, host, hostname);
158
return ret;
159
}
160
}
161
#endif
162
163
if (getaddrinfo_error) {
164
/* report error */
165
ThrowUnknownHostExceptionWithGaiError(
166
env, hostname, getaddrinfo_error);
167
JNU_ReleaseStringPlatformChars(env, host, hostname);
168
return NULL;
169
} else {
170
int i = 0;
171
struct addrinfo *itr, *last = NULL, *iterator = res;
172
while (iterator != NULL) {
173
int skip = 0;
174
itr = resNew;
175
176
while (itr != NULL) {
177
struct sockaddr_in *addr1, *addr2;
178
179
addr1 = (struct sockaddr_in *)iterator->ai_addr;
180
addr2 = (struct sockaddr_in *)itr->ai_addr;
181
if (addr1->sin_addr.s_addr ==
182
addr2->sin_addr.s_addr) {
183
skip = 1;
184
break;
185
}
186
187
itr = itr->ai_next;
188
}
189
190
if (!skip) {
191
struct addrinfo *next
192
= (struct addrinfo*) malloc(sizeof(struct addrinfo));
193
if (!next) {
194
JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
195
ret = NULL;
196
goto cleanupAndReturn;
197
}
198
memcpy(next, iterator, sizeof(struct addrinfo));
199
next->ai_next = NULL;
200
if (resNew == NULL) {
201
resNew = next;
202
} else {
203
last->ai_next = next;
204
}
205
last = next;
206
i++;
207
}
208
iterator = iterator->ai_next;
209
}
210
211
retLen = i;
212
iterator = resNew;
213
i = 0;
214
215
name = (*env)->NewStringUTF(env, hostname);
216
if (IS_NULL(name)) {
217
goto cleanupAndReturn;
218
}
219
220
ret = (*env)->NewObjectArray(env, retLen, ia_class, NULL);
221
if (IS_NULL(ret)) {
222
/* we may have memory to free at the end of this */
223
goto cleanupAndReturn;
224
}
225
226
while (iterator != NULL) {
227
/* We need 4 bytes to store ipv4 address; */
228
int len = 4;
229
230
jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
231
if (IS_NULL(iaObj)) {
232
/* we may have memory to free at the end of this */
233
ret = NULL;
234
goto cleanupAndReturn;
235
}
236
setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)(iterator->ai_addr))->sin_addr.s_addr));
237
if ((*env)->ExceptionCheck(env))
238
goto cleanupAndReturn;
239
setInetAddress_hostName(env, iaObj, name);
240
if ((*env)->ExceptionCheck(env))
241
goto cleanupAndReturn;
242
(*env)->SetObjectArrayElement(env, ret, retLen - i -1, iaObj);
243
i++;
244
iterator = iterator->ai_next;
245
}
246
}
247
248
cleanupAndReturn:
249
{
250
struct addrinfo *iterator, *tmp;
251
iterator = resNew;
252
while (iterator != NULL) {
253
tmp = iterator;
254
iterator = iterator->ai_next;
255
free(tmp);
256
}
257
JNU_ReleaseStringPlatformChars(env, host, hostname);
258
}
259
260
freeaddrinfo(res);
261
262
return ret;
263
264
}
265
266
/*
267
* Class: java_net_Inet4AddressImpl
268
* Method: getHostByAddr
269
* Signature: (I)Ljava/lang/String;
270
*/
271
JNIEXPORT jstring JNICALL
272
Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
273
jbyteArray addrArray) {
274
jstring ret = NULL;
275
276
char host[NI_MAXHOST+1];
277
jfieldID fid;
278
int error = 0;
279
jint family;
280
struct sockaddr *him ;
281
int len = 0;
282
jbyte caddr[4];
283
jint addr;
284
285
struct sockaddr_in him4;
286
struct sockaddr *sa;
287
288
/*
289
* For IPv4 addresses construct a sockaddr_in structure.
290
*/
291
(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
292
addr = ((caddr[0]<<24) & 0xff000000);
293
addr |= ((caddr[1] <<16) & 0xff0000);
294
addr |= ((caddr[2] <<8) & 0xff00);
295
addr |= (caddr[3] & 0xff);
296
memset((char *) &him4, 0, sizeof(him4));
297
him4.sin_addr.s_addr = (uint32_t) htonl(addr);
298
him4.sin_family = AF_INET;
299
sa = (struct sockaddr *) &him4;
300
len = sizeof(him4);
301
302
error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0,
303
NI_NAMEREQD);
304
305
if (!error) {
306
ret = (*env)->NewStringUTF(env, host);
307
}
308
309
if (ret == NULL) {
310
JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
311
}
312
313
return ret;
314
315
}
316
317
#else /* defined(_ALLBSD_SOURCE) && !defined(HAS_GLIBC_GETHOSTBY_R) */
318
319
/* the initial size of our hostent buffers */
320
#ifndef NI_MAXHOST
321
#define NI_MAXHOST 1025
322
#endif
323
324
/************************************************************************
325
* Inet4AddressImpl
326
*/
327
328
/*
329
* Class: java_net_Inet4AddressImpl
330
* Method: getLocalHostName
331
* Signature: ()Ljava/lang/String;
332
*/
333
JNIEXPORT jstring JNICALL
334
Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
335
char hostname[NI_MAXHOST+1];
336
337
hostname[0] = '\0';
338
if (JVM_GetHostName(hostname, sizeof(hostname))) {
339
/* Something went wrong, maybe networking is not setup? */
340
strcpy(hostname, "localhost");
341
} else {
342
struct addrinfo hints, *res;
343
int error;
344
345
hostname[NI_MAXHOST] = '\0';
346
memset(&hints, 0, sizeof(hints));
347
hints.ai_flags = AI_CANONNAME;
348
hints.ai_family = AF_INET;
349
350
error = getaddrinfo(hostname, NULL, &hints, &res);
351
352
if (error == 0) {/* host is known to name service */
353
getnameinfo(res->ai_addr,
354
res->ai_addrlen,
355
hostname,
356
NI_MAXHOST,
357
NULL,
358
0,
359
NI_NAMEREQD);
360
361
/* if getnameinfo fails hostname is still the value
362
from gethostname */
363
364
freeaddrinfo(res);
365
}
366
}
367
return (*env)->NewStringUTF(env, hostname);
368
}
369
370
/*
371
* Find an internet address for a given hostname. Note that this
372
* code only works for addresses of type INET. The translation
373
* of %d.%d.%d.%d to an address (int) occurs in java now, so the
374
* String "host" shouldn't *ever* be a %d.%d.%d.%d string
375
*
376
* Class: java_net_Inet4AddressImpl
377
* Method: lookupAllHostAddr
378
* Signature: (Ljava/lang/String;)[[B
379
*/
380
381
JNIEXPORT jobjectArray JNICALL
382
Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
383
jstring host) {
384
const char *hostname;
385
jobjectArray ret = 0;
386
int retLen = 0;
387
int error = 0;
388
struct addrinfo hints, *res, *resNew = NULL;
389
390
initInetAddressIDs(env);
391
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
392
393
if (IS_NULL(host)) {
394
JNU_ThrowNullPointerException(env, "host is null");
395
return 0;
396
}
397
hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
398
CHECK_NULL_RETURN(hostname, NULL);
399
400
/* Try once, with our static buffer. */
401
memset(&hints, 0, sizeof(hints));
402
hints.ai_flags = AI_CANONNAME;
403
hints.ai_family = AF_INET;
404
405
#ifdef __solaris__
406
/*
407
* Workaround for Solaris bug 4160367 - if a hostname contains a
408
* white space then 0.0.0.0 is returned
409
*/
410
if (isspace((unsigned char)hostname[0])) {
411
JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
412
(char *)hostname);
413
JNU_ReleaseStringPlatformChars(env, host, hostname);
414
return NULL;
415
}
416
#endif
417
418
error = getaddrinfo(hostname, NULL, &hints, &res);
419
420
if (error) {
421
/* report error */
422
ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
423
JNU_ReleaseStringPlatformChars(env, host, hostname);
424
return NULL;
425
} else {
426
int i = 0;
427
struct addrinfo *itr, *last = NULL, *iterator = res;
428
429
while (iterator != NULL) {
430
// remove the duplicate one
431
int skip = 0;
432
itr = resNew;
433
while (itr != NULL) {
434
struct sockaddr_in *addr1, *addr2;
435
addr1 = (struct sockaddr_in *)iterator->ai_addr;
436
addr2 = (struct sockaddr_in *)itr->ai_addr;
437
if (addr1->sin_addr.s_addr ==
438
addr2->sin_addr.s_addr) {
439
skip = 1;
440
break;
441
}
442
itr = itr->ai_next;
443
}
444
445
if (!skip) {
446
struct addrinfo *next
447
= (struct addrinfo*) malloc(sizeof(struct addrinfo));
448
if (!next) {
449
JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
450
ret = NULL;
451
goto cleanupAndReturn;
452
}
453
memcpy(next, iterator, sizeof(struct addrinfo));
454
next->ai_next = NULL;
455
if (resNew == NULL) {
456
resNew = next;
457
} else {
458
last->ai_next = next;
459
}
460
last = next;
461
i++;
462
}
463
iterator = iterator->ai_next;
464
}
465
466
retLen = i;
467
iterator = resNew;
468
469
ret = (*env)->NewObjectArray(env, retLen, ia_class, NULL);
470
471
if (IS_NULL(ret)) {
472
/* we may have memory to free at the end of this */
473
goto cleanupAndReturn;
474
}
475
476
i = 0;
477
while (iterator != NULL) {
478
jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
479
if (IS_NULL(iaObj)) {
480
ret = NULL;
481
goto cleanupAndReturn;
482
}
483
setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
484
if ((*env)->ExceptionCheck(env))
485
goto cleanupAndReturn;
486
setInetAddress_hostName(env, iaObj, host);
487
if ((*env)->ExceptionCheck(env))
488
goto cleanupAndReturn;
489
(*env)->SetObjectArrayElement(env, ret, i++, iaObj);
490
iterator = iterator->ai_next;
491
}
492
}
493
494
cleanupAndReturn:
495
{
496
struct addrinfo *iterator, *tmp;
497
iterator = resNew;
498
while (iterator != NULL) {
499
tmp = iterator;
500
iterator = iterator->ai_next;
501
free(tmp);
502
}
503
JNU_ReleaseStringPlatformChars(env, host, hostname);
504
}
505
506
freeaddrinfo(res);
507
508
return ret;
509
}
510
511
/*
512
* Class: java_net_Inet4AddressImpl
513
* Method: getHostByAddr
514
* Signature: (I)Ljava/lang/String;
515
*/
516
JNIEXPORT jstring JNICALL
517
Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
518
jbyteArray addrArray) {
519
jstring ret = NULL;
520
521
char host[NI_MAXHOST+1];
522
int error = 0;
523
int len = 0;
524
jbyte caddr[4];
525
526
struct sockaddr_in him4;
527
struct sockaddr *sa;
528
529
jint addr;
530
(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
531
addr = ((caddr[0]<<24) & 0xff000000);
532
addr |= ((caddr[1] <<16) & 0xff0000);
533
addr |= ((caddr[2] <<8) & 0xff00);
534
addr |= (caddr[3] & 0xff);
535
memset((void *) &him4, 0, sizeof(him4));
536
him4.sin_addr.s_addr = (uint32_t) htonl(addr);
537
him4.sin_family = AF_INET;
538
sa = (struct sockaddr *) &him4;
539
len = sizeof(him4);
540
541
error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0,
542
NI_NAMEREQD);
543
544
if (!error) {
545
ret = (*env)->NewStringUTF(env, host);
546
}
547
548
if (ret == NULL) {
549
JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
550
}
551
552
return ret;
553
}
554
555
#endif /* _ALLBSD_SOURCE */
556
557
#define SET_NONBLOCKING(fd) { \
558
int flags = fcntl(fd, F_GETFL); \
559
flags |= O_NONBLOCK; \
560
fcntl(fd, F_SETFL, flags); \
561
}
562
563
/**
564
* ping implementation.
565
* Send a ICMP_ECHO_REQUEST packet every second until either the timeout
566
* expires or a answer is received.
567
* Returns true is an ECHO_REPLY is received, otherwise, false.
568
*/
569
static jboolean
570
ping4(JNIEnv *env, jint fd, struct sockaddr_in* him, jint timeout,
571
struct sockaddr_in* netif, jint ttl) {
572
jint size;
573
jint n, hlen1, icmplen;
574
socklen_t len;
575
char sendbuf[1500];
576
char recvbuf[1500];
577
struct icmp *icmp;
578
struct ip *ip;
579
struct sockaddr_in sa_recv;
580
jchar pid;
581
jint tmout2, seq = 1;
582
struct timeval tv;
583
size_t plen;
584
585
/* icmp_id is a 16 bit data type, therefore down cast the pid */
586
pid = (jchar)getpid();
587
size = 60*1024;
588
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
589
/*
590
* sets the ttl (max number of hops)
591
*/
592
if (ttl > 0) {
593
setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
594
}
595
/*
596
* a specific interface was specified, so let's bind the socket
597
* to that interface to ensure the requests are sent only through it.
598
*/
599
if (netif != NULL) {
600
if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
601
NET_ThrowNew(env, errno, "Can't bind socket");
602
close(fd);
603
return JNI_FALSE;
604
}
605
}
606
/*
607
* Make the socket non blocking so we can use select
608
*/
609
SET_NONBLOCKING(fd);
610
do {
611
/*
612
* create the ICMP request
613
*/
614
icmp = (struct icmp *) sendbuf;
615
icmp->icmp_type = ICMP_ECHO;
616
icmp->icmp_code = 0;
617
icmp->icmp_id = htons(pid);
618
icmp->icmp_seq = htons(seq);
619
seq++;
620
gettimeofday(&tv, NULL);
621
memcpy(icmp->icmp_data, &tv, sizeof(tv));
622
plen = ICMP_ADVLENMIN + sizeof(tv);
623
icmp->icmp_cksum = 0;
624
icmp->icmp_cksum = in_cksum((u_short *)icmp, plen);
625
/*
626
* send it
627
*/
628
n = sendto(fd, sendbuf, plen, 0, (struct sockaddr *)him,
629
sizeof(struct sockaddr));
630
if (n < 0 && errno != EINPROGRESS ) {
631
#ifdef __linux__
632
if (errno != EINVAL && errno != EHOSTUNREACH)
633
/*
634
* On some Linux versions, when a socket is bound to the loopback
635
* interface, sendto will fail and errno will be set to
636
* EINVAL or EHOSTUNREACH. When that happens, don't throw an
637
* exception, just return false.
638
*/
639
#endif /*__linux__ */
640
NET_ThrowNew(env, errno, "Can't send ICMP packet");
641
close(fd);
642
return JNI_FALSE;
643
}
644
645
tmout2 = timeout > 1000 ? 1000 : timeout;
646
do {
647
tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
648
if (tmout2 >= 0) {
649
len = sizeof(sa_recv);
650
n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&sa_recv, &len);
651
ip = (struct ip*) recvbuf;
652
hlen1 = (ip->ip_hl) << 2;
653
icmp = (struct icmp *) (recvbuf + hlen1);
654
icmplen = n - hlen1;
655
/*
656
* We did receive something, but is it what we were expecting?
657
* I.E.: A ICMP_ECHOREPLY packet with the proper PID.
658
*/
659
if (icmplen >= 8 && icmp->icmp_type == ICMP_ECHOREPLY
660
&& (ntohs(icmp->icmp_id) == pid)) {
661
if ((him->sin_addr.s_addr == sa_recv.sin_addr.s_addr)) {
662
close(fd);
663
return JNI_TRUE;
664
}
665
666
if (him->sin_addr.s_addr == 0) {
667
close(fd);
668
return JNI_TRUE;
669
}
670
}
671
672
}
673
} while (tmout2 > 0);
674
timeout -= 1000;
675
} while (timeout >0);
676
close(fd);
677
return JNI_FALSE;
678
}
679
680
/*
681
* Class: java_net_Inet4AddressImpl
682
* Method: isReachable0
683
* Signature: ([bI[bI)Z
684
*/
685
JNIEXPORT jboolean JNICALL
686
Java_java_net_Inet4AddressImpl_isReachable0(JNIEnv *env, jobject this,
687
jbyteArray addrArray,
688
jint timeout,
689
jbyteArray ifArray,
690
jint ttl) {
691
jint addr;
692
jbyte caddr[4];
693
jint fd;
694
struct sockaddr_in him;
695
struct sockaddr_in* netif = NULL;
696
struct sockaddr_in inf;
697
int len = 0;
698
int connect_rv = -1;
699
int sz;
700
701
memset((char *) caddr, 0, sizeof(caddr));
702
memset((char *) &him, 0, sizeof(him));
703
memset((char *) &inf, 0, sizeof(inf));
704
sz = (*env)->GetArrayLength(env, addrArray);
705
if (sz != 4) {
706
return JNI_FALSE;
707
}
708
(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
709
addr = ((caddr[0]<<24) & 0xff000000);
710
addr |= ((caddr[1] <<16) & 0xff0000);
711
addr |= ((caddr[2] <<8) & 0xff00);
712
addr |= (caddr[3] & 0xff);
713
addr = htonl(addr);
714
him.sin_addr.s_addr = addr;
715
him.sin_family = AF_INET;
716
len = sizeof(him);
717
/*
718
* If a network interface was specified, let's create the address
719
* for it.
720
*/
721
if (!(IS_NULL(ifArray))) {
722
memset((char *) caddr, 0, sizeof(caddr));
723
(*env)->GetByteArrayRegion(env, ifArray, 0, 4, caddr);
724
addr = ((caddr[0]<<24) & 0xff000000);
725
addr |= ((caddr[1] <<16) & 0xff0000);
726
addr |= ((caddr[2] <<8) & 0xff00);
727
addr |= (caddr[3] & 0xff);
728
addr = htonl(addr);
729
inf.sin_addr.s_addr = addr;
730
inf.sin_family = AF_INET;
731
inf.sin_port = 0;
732
netif = &inf;
733
}
734
735
/*
736
* Let's try to create a RAW socket to send ICMP packets
737
* This usually requires "root" privileges, so it's likely to fail.
738
*/
739
fd = JVM_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
740
if (fd != -1) {
741
/*
742
* It didn't fail, so we can use ICMP_ECHO requests.
743
*/
744
return ping4(env, fd, &him, timeout, netif, ttl);
745
}
746
747
/*
748
* Can't create a raw socket, so let's try a TCP socket
749
*/
750
fd = JVM_Socket(AF_INET, SOCK_STREAM, 0);
751
if (fd == JVM_IO_ERR) {
752
/* note: if you run out of fds, you may not be able to load
753
* the exception class, and get a NoClassDefFoundError
754
* instead.
755
*/
756
NET_ThrowNew(env, errno, "Can't create socket");
757
return JNI_FALSE;
758
}
759
if (ttl > 0) {
760
setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
761
}
762
763
/*
764
* A network interface was specified, so let's bind to it.
765
*/
766
if (netif != NULL) {
767
if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
768
NET_ThrowNew(env, errno, "Can't bind socket");
769
close(fd);
770
return JNI_FALSE;
771
}
772
}
773
774
/*
775
* Make the socket non blocking so we can use select/poll.
776
*/
777
SET_NONBLOCKING(fd);
778
779
/* no need to use NET_Connect as non-blocking */
780
him.sin_port = htons(7); /* Echo */
781
connect_rv = JVM_Connect(fd, (struct sockaddr *)&him, len);
782
783
/**
784
* connection established or refused immediately, either way it means
785
* we were able to reach the host!
786
*/
787
if (connect_rv == 0 || errno == ECONNREFUSED) {
788
close(fd);
789
return JNI_TRUE;
790
} else {
791
int optlen;
792
793
switch (errno) {
794
case ENETUNREACH: /* Network Unreachable */
795
case EAFNOSUPPORT: /* Address Family not supported */
796
case EADDRNOTAVAIL: /* address is not available on the remote machine */
797
#ifdef __linux__
798
case EINVAL:
799
case EHOSTUNREACH:
800
/*
801
* On some Linux versions, when a socket is bound to the loopback
802
* interface, connect will fail and errno will be set to EINVAL
803
* or EHOSTUNREACH. When that happens, don't throw an exception,
804
* just return false.
805
*/
806
#endif /* __linux__ */
807
close(fd);
808
return JNI_FALSE;
809
}
810
811
if (errno != EINPROGRESS) {
812
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
813
"connect failed");
814
close(fd);
815
return JNI_FALSE;
816
}
817
818
timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
819
if (timeout >= 0) {
820
/* has connection been established? */
821
optlen = sizeof(connect_rv);
822
if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
823
&optlen) <0) {
824
connect_rv = errno;
825
}
826
if (connect_rv == 0 || connect_rv == ECONNREFUSED) {
827
close(fd);
828
return JNI_TRUE;
829
}
830
}
831
close(fd);
832
return JNI_FALSE;
833
}
834
}
835
836