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 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 "JNIHelp.h" 49 50#define NATIVE_METHOD(className, functionName, signature) \ 51{ #functionName, signature, (void*)(className ## _ ## functionName) } 52 53//#if defined(__GLIBC__) || (defined(__FreeBSD__) && (__FreeBSD_version >= 601104)) 54#define HAS_GLIBC_GETHOSTBY_R 1 55//#endif 56 57#define SET_NONBLOCKING(fd) { \ 58 int flags = fcntl(fd, F_GETFL); \ 59 flags |= O_NONBLOCK; \ 60 fcntl(fd, F_SETFL, flags); \ 61} 62 63/** 64 * ping implementation. 65 * Send a ICMP_ECHO_REQUEST packet every second until either the timeout 66 * expires or a answer is received. 67 * Returns true is an ECHO_REPLY is received, otherwise, false. 68 */ 69static jboolean 70ping4(JNIEnv *env, jint fd, struct sockaddr_in* him, jint timeout, 71 struct sockaddr_in* netif, jint ttl) { 72 jint size; 73 jint n, hlen1, icmplen; 74 socklen_t len; 75 char sendbuf[1500]; 76 char recvbuf[1500]; 77 struct icmp *icmp; 78 struct ip *ip; 79 struct sockaddr_in sa_recv; 80 jchar pid; 81 jint tmout2, seq = 1; 82 struct timeval tv; 83 size_t plen; 84 85 /* icmp_id is a 16 bit data type, therefore down cast the pid */ 86 pid = (jchar)getpid(); 87 size = 60*1024; 88 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); 89 /* 90 * sets the ttl (max number of hops) 91 */ 92 if (ttl > 0) { 93 setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); 94 } 95 /* 96 * a specific interface was specified, so let's bind the socket 97 * to that interface to ensure the requests are sent only through it. 98 */ 99 if (netif != NULL) { 100 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) { 101 NET_ThrowNew(env, errno, "Can't bind socket"); 102 untagSocket(env, fd); 103 close(fd); 104 return JNI_FALSE; 105 } 106 } 107 /* 108 * Make the socket non blocking so we can use select 109 */ 110 SET_NONBLOCKING(fd); 111 do { 112 /* 113 * create the ICMP request 114 */ 115 icmp = (struct icmp *) sendbuf; 116 icmp->icmp_type = ICMP_ECHO; 117 icmp->icmp_code = 0; 118 icmp->icmp_id = htons(pid); 119 icmp->icmp_seq = htons(seq); 120 seq++; 121 gettimeofday(&tv, NULL); 122 memcpy(icmp->icmp_data, &tv, sizeof(tv)); 123 plen = ICMP_ADVLENMIN + sizeof(tv); 124 icmp->icmp_cksum = 0; 125 icmp->icmp_cksum = in_cksum((u_short *)icmp, plen); 126 /* 127 * send it 128 */ 129 n = sendto(fd, sendbuf, plen, 0, (struct sockaddr *)him, 130 sizeof(struct sockaddr)); 131 if (n < 0 && errno != EINPROGRESS ) { 132#ifdef __linux__ 133 if (errno != EINVAL && errno != EHOSTUNREACH) 134 /* 135 * On some Linuxes, when bound to the loopback interface, sendto 136 * will fail and errno will be set to EINVAL or EHOSTUNREACH. 137 * When that happens, don't throw an exception, just return false. 138 */ 139#endif /*__linux__ */ 140 NET_ThrowNew(env, errno, "Can't send ICMP packet"); 141 untagSocket(env, fd); 142 close(fd); 143 return JNI_FALSE; 144 } 145 146 tmout2 = timeout > 1000 ? 1000 : timeout; 147 do { 148 tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2); 149 if (tmout2 >= 0) { 150 len = sizeof(sa_recv); 151 n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&sa_recv, &len); 152 ip = (struct ip*) recvbuf; 153 hlen1 = (ip->ip_hl) << 2; 154 icmp = (struct icmp *) (recvbuf + hlen1); 155 icmplen = n - hlen1; 156 /* 157 * We did receive something, but is it what we were expecting? 158 * I.E.: A ICMP_ECHOREPLY packet with the proper PID. 159 */ 160 if (icmplen >= 8 && icmp->icmp_type == ICMP_ECHOREPLY 161 && (ntohs(icmp->icmp_id) == pid)) { 162 if ((him->sin_addr.s_addr == sa_recv.sin_addr.s_addr)) { 163 untagSocket(env, fd); 164 close(fd); 165 return JNI_TRUE; 166 } 167 168 if (him->sin_addr.s_addr == 0) { 169 untagSocket(env, fd); 170 close(fd); 171 return JNI_TRUE; 172 } 173 } 174 175 } 176 } while (tmout2 > 0); 177 timeout -= 1000; 178 } while (timeout >0); 179 untagSocket(env, fd); 180 close(fd); 181 return JNI_FALSE; 182} 183 184/* 185 * Class: java_net_Inet4AddressImpl 186 * Method: isReachable0 187 * Signature: ([bI[bI)Z 188 */ 189JNIEXPORT jboolean JNICALL 190Inet4AddressImpl_isReachable0(JNIEnv *env, jobject this, 191 jbyteArray addrArray, 192 jint timeout, 193 jbyteArray ifArray, 194 jint ttl) { 195 jint addr; 196 jbyte caddr[4]; 197 jint fd; 198 struct sockaddr_in him; 199 struct sockaddr_in* netif = NULL; 200 struct sockaddr_in inf; 201 int len = 0; 202 int connect_rv = -1; 203 int sz; 204 205 memset((char *) caddr, 0, sizeof(caddr)); 206 memset((char *) &him, 0, sizeof(him)); 207 memset((char *) &inf, 0, sizeof(inf)); 208 sz = (*env)->GetArrayLength(env, addrArray); 209 if (sz != 4) { 210 return JNI_FALSE; 211 } 212 (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr); 213 addr = ((caddr[0]<<24) & 0xff000000); 214 addr |= ((caddr[1] <<16) & 0xff0000); 215 addr |= ((caddr[2] <<8) & 0xff00); 216 addr |= (caddr[3] & 0xff); 217 addr = htonl(addr); 218 him.sin_addr.s_addr = addr; 219 him.sin_family = AF_INET; 220 len = sizeof(him); 221 /* 222 * If a network interface was specified, let's create the address 223 * for it. 224 */ 225 if (!(IS_NULL(ifArray))) { 226 memset((char *) caddr, 0, sizeof(caddr)); 227 (*env)->GetByteArrayRegion(env, ifArray, 0, 4, caddr); 228 addr = ((caddr[0]<<24) & 0xff000000); 229 addr |= ((caddr[1] <<16) & 0xff0000); 230 addr |= ((caddr[2] <<8) & 0xff00); 231 addr |= (caddr[3] & 0xff); 232 addr = htonl(addr); 233 inf.sin_addr.s_addr = addr; 234 inf.sin_family = AF_INET; 235 inf.sin_port = 0; 236 netif = &inf; 237 } 238 239 /* 240 * Let's try to create a RAW socket to send ICMP packets 241 * This usually requires "root" privileges, so it's likely to fail. 242 */ 243 fd = JVM_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 244 if (fd != -1) { 245 /* 246 * It didn't fail, so we can use ICMP_ECHO requests. 247 */ 248 tagSocket(env, fd); 249 return ping4(env, fd, &him, timeout, netif, ttl); 250 } 251 252 /* 253 * Can't create a raw socket, so let's try a TCP socket 254 */ 255 fd = JVM_Socket(AF_INET, SOCK_STREAM, 0); 256 if (fd == JVM_IO_ERR) { 257 /* note: if you run out of fds, you may not be able to load 258 * the exception class, and get a NoClassDefFoundError 259 * instead. 260 */ 261 NET_ThrowNew(env, errno, "Can't create socket"); 262 return JNI_FALSE; 263 } 264 tagSocket(env, fd); 265 266 if (ttl > 0) { 267 setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); 268 } 269 270 /* 271 * A network interface was specified, so let's bind to it. 272 */ 273 if (netif != NULL) { 274 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) { 275 NET_ThrowNew(env, errno, "Can't bind socket"); 276 untagSocket(env, fd); 277 close(fd); 278 return JNI_FALSE; 279 } 280 } 281 282 /* 283 * Make the socket non blocking so we can use select/poll. 284 */ 285 SET_NONBLOCKING(fd); 286 287 /* no need to use NET_Connect as non-blocking */ 288 him.sin_port = htons(7); /* Echo */ 289 connect_rv = JVM_Connect(fd, (struct sockaddr *)&him, len); 290 291 /** 292 * connection established or refused immediately, either way it means 293 * we were able to reach the host! 294 */ 295 if (connect_rv == 0 || errno == ECONNREFUSED) { 296 untagSocket(env, fd); 297 close(fd); 298 return JNI_TRUE; 299 } else { 300 int optlen; 301 302 switch (errno) { 303 case ENETUNREACH: /* Network Unreachable */ 304 case EAFNOSUPPORT: /* Address Family not supported */ 305 case EADDRNOTAVAIL: /* address is not available on the remote machine */ 306#ifdef __linux__ 307 case EINVAL: 308 case EHOSTUNREACH: 309 /* 310 * On some Linuxes, when bound to the loopback interface, connect 311 * will fail and errno will be set to EINVAL or EHOSTUNREACH. 312 * When that happens, don't throw an exception, just return false. 313 */ 314#endif /* __linux__ */ 315 untagSocket(env, fd); 316 close(fd); 317 return JNI_FALSE; 318 } 319 320 if (errno != EINPROGRESS) { 321 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException", 322 "connect failed"); 323 untagSocket(env, fd); 324 close(fd); 325 return JNI_FALSE; 326 } 327 328 timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout); 329 if (timeout >= 0) { 330 /* has connection been established? */ 331 optlen = sizeof(connect_rv); 332 if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv, 333 &optlen) <0) { 334 connect_rv = errno; 335 } 336 if (connect_rv == 0 || connect_rv == ECONNREFUSED) { 337 untagSocket(env, fd); 338 close(fd); 339 return JNI_TRUE; 340 } 341 } 342 untagSocket(env, fd); 343 close(fd); 344 return JNI_FALSE; 345 } 346} 347