| /* Copyright (C) 2003, 2005, 2006 Free Software Foundation |
| |
| This file is part of libgcj. |
| |
| This software is copyrighted work licensed under the terms of the |
| Libgcj License. Please consult the file "LIBGCJ_LICENSE" for |
| details. */ |
| |
| #include <config.h> |
| #include <platform.h> |
| |
| #ifdef HAVE_UNISTD_H |
| #include <unistd.h> |
| #endif |
| #include <string.h> |
| #include <errno.h> |
| #include <stdlib.h> |
| |
| #include <sys/param.h> |
| #include <sys/types.h> |
| #ifdef HAVE_NETINET_IN_H |
| #include <netinet/in.h> |
| #endif |
| #ifdef HAVE_ARPA_INET_H |
| #include <arpa/inet.h> |
| #endif |
| #ifdef HAVE_NETDB_H |
| #include <netdb.h> |
| #endif |
| #ifdef HAVE_SYS_IOCTL_H |
| #define BSD_COMP /* Get FIONREAD on Solaris2. */ |
| #include <sys/ioctl.h> |
| #endif |
| #ifdef HAVE_NET_IF_H |
| #include <net/if.h> |
| #endif |
| #ifdef HAVE_IFADDRS_H |
| #include <ifaddrs.h> |
| #endif |
| |
| #include <gcj/cni.h> |
| #include <jvm.h> |
| #include <java/net/InetAddress.h> |
| #include <java/net/NetworkInterface.h> |
| #include <java/net/SocketException.h> |
| #include <java/net/VMNetworkInterface.h> |
| #include <java/util/Vector.h> |
| |
| ::java::util::Vector* |
| java::net::VMNetworkInterface::getInterfaces () |
| { |
| ::java::util::Vector* ht = new ::java::util::Vector (); |
| |
| #ifdef HAVE_GETIFADDRS |
| |
| struct ifaddrs *addrs; |
| if (::getifaddrs (&addrs) == -1) |
| throw new ::java::net::SocketException(JvNewStringUTF (strerror (errno))); |
| |
| for (struct ifaddrs *work = addrs; work != NULL; work = work->ifa_next) |
| { |
| // Sometimes the address can be NULL; I don't know why but |
| // there's nothing we can do with this. |
| if (! work->ifa_addr) |
| continue; |
| // We only return Inet4 or Inet6 addresses. |
| jbyteArray laddr; |
| if (work->ifa_addr->sa_family == AF_INET) |
| { |
| sockaddr_in *real = reinterpret_cast<sockaddr_in *> (work->ifa_addr); |
| laddr = JvNewByteArray(4); |
| memcpy (elements (laddr), &real->sin_addr, 4); |
| } |
| #ifdef HAVE_INET6 |
| else if (work->ifa_addr->sa_family == AF_INET6) |
| { |
| sockaddr_in6 *real |
| = reinterpret_cast<sockaddr_in6 *> (work->ifa_addr); |
| laddr = JvNewByteArray(16); |
| memcpy (elements (laddr), &real->sin6_addr, 16); |
| } |
| #endif |
| else |
| continue; |
| |
| ::java::net::InetAddress *inaddr |
| = ::java::net::InetAddress::getByAddress(laddr); |
| |
| // It is ok to make a new NetworkInterface for each struct; the |
| // java code will unify these as necessary; see |
| // NetworkInterface.condense(). |
| jstring name = JvNewStringUTF (work->ifa_name); |
| |
| ht->add (new NetworkInterface (name, inaddr)); |
| } |
| |
| freeifaddrs (addrs); |
| |
| #else /* ! HAVE_GETIFADDRS */ |
| |
| int fd; |
| int num_interfaces = 0; |
| struct ifconf if_data; |
| struct ifreq* if_record; |
| |
| if_data.ifc_len = 0; |
| if_data.ifc_buf = NULL; |
| |
| // Open a (random) socket to have a file descriptor for the ioctl calls. |
| fd = _Jv_socket (PF_INET, SOCK_DGRAM, htons (IPPROTO_IP)); |
| |
| if (fd < 0) |
| throw new ::java::net::SocketException; |
| |
| // Get all interfaces. If not enough buffers are available try it |
| // with a bigger buffer size. |
| do |
| { |
| num_interfaces += 16; |
| |
| if_data.ifc_len = sizeof (struct ifreq) * num_interfaces; |
| if_data.ifc_buf = |
| (char*) _Jv_Realloc (if_data.ifc_buf, if_data.ifc_len); |
| |
| // Try to get all local interfaces. |
| if (::ioctl (fd, SIOCGIFCONF, &if_data) < 0) |
| throw new java::net::SocketException; |
| } |
| while (if_data.ifc_len >= (int) (sizeof (struct ifreq) * num_interfaces)); |
| |
| // Get addresses of all interfaces. |
| if_record = if_data.ifc_req; |
| |
| for (int n = 0; n < if_data.ifc_len; n += sizeof (struct ifreq)) |
| { |
| struct ifreq ifr; |
| |
| memset (&ifr, 0, sizeof (ifr)); |
| strcpy (ifr.ifr_name, if_record->ifr_name); |
| |
| // Try to get the IPv4-address of the local interface |
| if (::ioctl (fd, SIOCGIFADDR, &ifr) < 0) |
| throw new java::net::SocketException; |
| |
| int len = 4; |
| struct sockaddr_in sa = *((sockaddr_in*) &(ifr.ifr_addr)); |
| |
| jbyteArray baddr = JvNewByteArray (len); |
| memcpy (elements (baddr), &(sa.sin_addr), len); |
| jstring if_name = JvNewStringLatin1 (if_record->ifr_name); |
| InetAddress* address = java::net::InetAddress::getByAddress (baddr); |
| ht->add (new NetworkInterface (if_name, address)); |
| if_record++; |
| } |
| |
| _Jv_Free (if_data.ifc_buf); |
| |
| if (fd >= 0) |
| _Jv_close (fd); |
| #endif /* HAVE_GETIFADDRS */ |
| |
| return ht; |
| } |