natVMNetworkInterfacePosix.cc 4.21 KB
Newer Older
1
/* Copyright (C) 2003, 2005, 2006  Free Software Foundation
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36

   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
37 38 39
#ifdef HAVE_IFADDRS_H
#include <ifaddrs.h>
#endif
40 41 42

#include <gcj/cni.h>
#include <jvm.h>
43
#include <java/net/InetAddress.h>
44
#include <java/net/NetworkInterface.h>
45
#include <java/net/SocketException.h>
46
#include <java/net/VMNetworkInterface.h>
47 48 49
#include <java/util/Vector.h>

::java::util::Vector*
50
java::net::VMNetworkInterface::getInterfaces ()
51
{
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
  ::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 */

101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
  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;
    }
129
  while (if_data.ifc_len >= (int) (sizeof (struct ifreq) * num_interfaces));
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150

  // 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);
151
      InetAddress* address = java::net::InetAddress::getByAddress (baddr);
152 153 154 155 156 157 158 159
      ht->add (new NetworkInterface (if_name, address));
      if_record++;
    }

  _Jv_Free (if_data.ifc_buf);
  
  if (fd >= 0)
    _Jv_close (fd);
160 161
#endif /* HAVE_GETIFADDRS */ 

162 163
  return ht;
}