summaryrefslogtreecommitdiff
path: root/libjava/java/net/natVMNetworkInterfacePosix.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/java/net/natVMNetworkInterfacePosix.cc')
-rw-r--r--libjava/java/net/natVMNetworkInterfacePosix.cc163
1 files changed, 163 insertions, 0 deletions
diff --git a/libjava/java/net/natVMNetworkInterfacePosix.cc b/libjava/java/net/natVMNetworkInterfacePosix.cc
new file mode 100644
index 000000000..bfb11d21c
--- /dev/null
+++ b/libjava/java/net/natVMNetworkInterfacePosix.cc
@@ -0,0 +1,163 @@
+/* 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;
+}