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