PageRenderTime 54ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/java-1.7.0-openjdk/openjdk/jdk/src/solaris/native/java/net/Inet4AddressImpl.c

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