/* * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/ #include <ctype.h> #include <errno.h> #include <sys/types.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/ip_icmp.h> #include <stdlib.h> #include <string.h> #include <sys/time.h>
hostname[0] = '\0'; if (gethostname(hostname, sizeof(hostname)) != 0) {
strcpy(hostname, "localhost");
} else { // make sure string is null-terminated
hostname[NI_MAXHOST] = '\0';
} return (*env)->NewStringUTF(env, hostname);
}
/* * Find an internet address for a given hostname. Note that this * code only works for addresses of type INET. The translation * of %d.%d.%d.%d to an address (int) occurs in java now, so the * String "host" shouldn't be a %d.%d.%d.%d string. The only * exception should be when any of the %d are out of range and * we fallback to a lookup. * * Class: java_net_Inet4AddressImpl * Method: lookupAllHostAddr * Signature: (Ljava/lang/String;)[[B
*/
JNIEXPORT jobjectArray JNICALL
Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
jstring host) {
jobjectArray ret = NULL; constchar *hostname; int error = 0; struct addrinfo hints, *res = NULL, *resNew = NULL, *last = NULL,
*iterator;
// allocate array - at this point i contains the number of addresses
ret = (*env)->NewObjectArray(env, i, ia_class, NULL); if (IS_NULL(ret)) { goto cleanupAndReturn;
}
i = 0;
iterator = resNew; while (iterator != NULL) {
jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID); if (IS_NULL(iaObj)) {
ret = NULL; goto cleanupAndReturn;
}
setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in *)
(iterator->ai_addr))->sin_addr.s_addr)); if ((*env)->ExceptionCheck(env)) goto cleanupAndReturn;
setInetAddress_hostName(env, iaObj, host); if ((*env)->ExceptionCheck(env)) goto cleanupAndReturn;
(*env)->SetObjectArrayElement(env, ret, i++, iaObj);
iterator = iterator->ai_next;
}
}
cleanupAndReturn:
JNU_ReleaseStringPlatformChars(env, host, hostname); while (resNew != NULL) {
last = resNew;
resNew = resNew->ai_next;
free(last);
} if (res != NULL) {
freeaddrinfo(res);
} return ret;
}
/* * Class: java_net_Inet4AddressImpl * Method: getHostByAddr * Signature: ([B)Ljava/lang/String; * * Theoretically the UnknownHostException could be enriched with gai error * information. But as it is silently ignored anyway, there's no need for this. * It's only important that either a valid hostname is returned or an * UnknownHostException is thrown.
*/
JNIEXPORT jstring JNICALL
Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
jbyteArray addrArray) {
jstring ret = NULL; char host[NI_MAXHOST + 1];
jbyte caddr[4];
jint addr; struct sockaddr_in sa;
/** * ping implementation using tcp port 7 (echo)
*/ static jboolean
tcp_ping4(JNIEnv *env, SOCKETADDRESS *sa, SOCKETADDRESS *netif, jint timeout,
jint ttl)
{
jint fd; int connect_rv = -1;
// open a TCP socket
fd = socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead.
NET_ThrowNew(env, errno, "Can't create socket"); return JNI_FALSE;
}
// set TTL if (ttl > 0) {
setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
}
// A network interface was specified, so let's bind to it. if (netif != NULL) { if (bind(fd, &netif->sa, sizeof(struct sockaddr_in)) < 0) {
NET_ThrowNew(env, errno, "Can't bind socket");
close(fd); return JNI_FALSE;
}
}
// Make the socket non blocking so we can use select/poll.
SET_NONBLOCKING(fd);
// connection established or refused immediately, either way it means // we were able to reach the host! if (connect_rv == 0 || errno == ECONNREFUSED) {
close(fd); return JNI_TRUE;
}
switch (errno) { case ENETUNREACH: // Network Unreachable case EAFNOSUPPORT: // Address Family not supported case EADDRNOTAVAIL: // address is not available on the remote machine #ifdefined(__linux__) || defined(_AIX) // On some Linux versions, when a socket is bound to the loopback // interface, connect will fail and errno will be set to EINVAL // or EHOSTUNREACH. When that happens, don't throw an exception, // just return false. case EINVAL: case EHOSTUNREACH: // No route to host #endif
close(fd); return JNI_FALSE; case EINPROGRESS: // this is expected as we'll probably have to wait break; default:
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException", "connect failed");
close(fd); return JNI_FALSE;
}
timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout); if (timeout >= 0) { // connection has been established, check for error condition
socklen_t optlen = (socklen_t)sizeof(connect_rv); if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
&optlen) <0)
{
connect_rv = errno;
} if (connect_rv == 0 || connect_rv == ECONNREFUSED) {
close(fd); return JNI_TRUE;
}
}
close(fd); return JNI_FALSE;
}
/** * ping implementation. * Send an ICMP_ECHO_REQUEST packet every second until either the timeout * expires or an answer is received. * Returns true if an ECHO_REPLY is received, false otherwise.
*/ static jboolean
ping4(JNIEnv *env, jint fd, SOCKETADDRESS *sa, SOCKETADDRESS *netif,
jint timeout, jint ttl)
{
jint n, size = 60 * 1024, hlen, tmout2, seq = 1;
socklen_t len; unsignedchar sendbuf[1500], recvbuf[1500]; struct icmp *icmp; struct ip *ip; struct sockaddr_in sa_recv;
jchar pid; struct timeval tv;
size_t plen = ICMP_ADVLENMIN + sizeof(tv);
// sets the ttl (max number of hops) if (ttl > 0) {
setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
}
// a specific interface was specified, so let's bind the socket // to that interface to ensure the requests are sent only through it. if (netif != NULL) { if (bind(fd, &netif->sa, sizeof(struct sockaddr_in)) < 0) {
NET_ThrowNew(env, errno, "Can't bind socket");
close(fd); return JNI_FALSE;
}
}
// icmp_id is a 16 bit data type, therefore down cast the pid
pid = (jchar)getpid();
// Make the socket non blocking so we can use select
SET_NONBLOCKING(fd); do { // create the ICMP request
icmp = (struct icmp *)sendbuf;
icmp->icmp_type = ICMP_ECHO;
icmp->icmp_code = 0; // let's tag the ECHO packet with our pid so we can identify it
icmp->icmp_id = htons(pid);
icmp->icmp_seq = htons(seq);
seq++;
gettimeofday(&tv, NULL);
memcpy(icmp->icmp_data, &tv, sizeof(tv));
icmp->icmp_cksum = 0; // manually calculate checksum
icmp->icmp_cksum = in_cksum((u_short *)icmp, plen); // send it
n = sendto(fd, sendbuf, plen, 0, &sa->sa, sizeof(struct sockaddr_in)); if (n < 0 && errno != EINPROGRESS) { #ifdefined(__linux__) /* * On some Linux versions, when a socket is bound to the loopback * interface, sendto will fail and errno will be set to * EINVAL or EHOSTUNREACH. When that happens, don't throw an * exception, just return false.
*/ if (errno != EINVAL && errno != EHOSTUNREACH) {
NET_ThrowNew(env, errno, "Can't send ICMP packet");
} #else
NET_ThrowNew(env, errno, "Can't send ICMP packet"); #endif
close(fd); return JNI_FALSE;
}
tmout2 = timeout > 1000 ? 1000 : timeout; do {
tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2); if (tmout2 >= 0) {
len = sizeof(sa_recv);
n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0,
(struct sockaddr *)&sa_recv, &len); // check if we received enough data if (n < (jint)sizeof(struct ip)) { continue;
}
ip = (struct ip *)recvbuf;
hlen = ((jint)(unsignedint)(ip->ip_hl)) << 2; // check if we received enough data if (n < (jint)(hlen + sizeof(struct icmp))) { continue;
}
icmp = (struct icmp *)(recvbuf + hlen); // We did receive something, but is it what we were expecting? // I.E.: An ICMP_ECHO_REPLY packet with the proper PID and // from the host that we are trying to determine is reachable. if (icmp->icmp_type == ICMP_ECHOREPLY &&
(ntohs(icmp->icmp_id) == pid))
{ if (sa->sa4.sin_addr.s_addr == sa_recv.sin_addr.s_addr) {
close(fd); return JNI_TRUE;
} elseif (sa->sa4.sin_addr.s_addr == 0) {
close(fd); return JNI_TRUE;
}
}
}
} while (tmout2 > 0);
timeout -= 1000;
} while (timeout > 0);
close(fd); return JNI_FALSE;
}
// Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail.
fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (fd == -1) { return tcp_ping4(env, &sa, netif, timeout, ttl);
} else { // It didn't fail, so we can use ICMP_ECHO requests. return ping4(env, fd, &sa, netif, timeout, ttl);
}
}
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.