summaryrefslogtreecommitdiff
path: root/libjava/java/net/natVMNetworkInterfacePosix.cc
blob: 8238d9c1fa6c6537165b9246c91d5d28cb754b85 (plain)
1
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/* 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/Inet4Address.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);
      Inet4Address* address =
        new java::net::Inet4Address (baddr, JvNewStringLatin1 (""));
      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;
}