Ruby  2.1.10p492(2016-04-01revision54464)
ifaddr.c
Go to the documentation of this file.
1 #include "rubysocket.h"
2 
3 #ifdef HAVE_GETIFADDRS
4 
5 /*
6  * ifa_flags is usually unsigned int.
7  * However it is uint64_t on SunOS 5.11 (OpenIndiana).
8  */
9 #ifdef HAVE_LONG_LONG
10 typedef unsigned LONG_LONG ifa_flags_t;
11 #define PRIxIFAFLAGS PRI_LL_PREFIX"x"
12 #define IFAFLAGS2NUM(flags) ULL2NUM(flags)
13 #else
14 typedef unsigned int ifa_flags_t;
15 #define PRIxIFAFLAGS "x"
16 #define IFAFLAGS2NUM(flags) UINT2NUM(flags)
17 #endif
18 
19 VALUE rb_cSockIfaddr;
20 
21 typedef struct rb_ifaddr_tag rb_ifaddr_t;
22 typedef struct rb_ifaddr_root_tag rb_ifaddr_root_t;
23 
24 struct rb_ifaddr_tag {
25  int ord;
26  struct ifaddrs *ifaddr;
27  rb_ifaddr_root_t *root;
28 };
29 
30 struct rb_ifaddr_root_tag {
31  int refcount;
32  int numifaddrs;
33  rb_ifaddr_t ary[1];
34 };
35 
36 static rb_ifaddr_root_t *
37 get_root(const rb_ifaddr_t *ifaddr)
38 {
39  return (rb_ifaddr_root_t *)((char *)&ifaddr[-ifaddr->ord] -
40  offsetof(rb_ifaddr_root_t, ary));
41 }
42 
43 static void
44 ifaddr_mark(void *ptr)
45 {
46 }
47 
48 static void
49 ifaddr_free(void *ptr)
50 {
51  rb_ifaddr_t *ifaddr = ptr;
52  rb_ifaddr_root_t *root = get_root(ifaddr);
53  root->refcount--;
54  if (root->refcount == 0) {
55  freeifaddrs(root->ary[0].ifaddr);
56  xfree(root);
57  }
58 }
59 
60 static size_t
61 ifaddr_memsize(const void *ptr)
62 {
63  const rb_ifaddr_t *ifaddr;
64  const rb_ifaddr_root_t *root;
65  if (ptr == NULL)
66  return 0;
67  ifaddr = ptr;
68  root = get_root(ifaddr);
69  return sizeof(rb_ifaddr_root_t) + (root->numifaddrs - 1) * sizeof(rb_ifaddr_t);
70 }
71 
72 static const rb_data_type_t ifaddr_type = {
73  "socket/ifaddr",
74  {ifaddr_mark, ifaddr_free, ifaddr_memsize,},
75 };
76 
77 #define IS_IFADDRS(obj) rb_typeddata_is_kind_of((obj), &ifaddr_type)
78 static inline rb_ifaddr_t *
79 check_ifaddr(VALUE self)
80 {
81  return rb_check_typeddata(self, &ifaddr_type);
82 }
83 
84 static rb_ifaddr_t *
85 get_ifaddr(VALUE self)
86 {
87  rb_ifaddr_t *rifaddr = check_ifaddr(self);
88 
89  if (!rifaddr) {
90  rb_raise(rb_eTypeError, "uninitialized ifaddr");
91  }
92  return rifaddr;
93 }
94 
95 static VALUE
96 rsock_getifaddrs(void)
97 {
98  int ret;
99  int numifaddrs, i;
100  struct ifaddrs *ifaddrs, *ifa;
101  rb_ifaddr_root_t *root;
102  VALUE result;
103 
104  ret = getifaddrs(&ifaddrs);
105  if (ret == -1)
106  rb_sys_fail("getifaddrs");
107 
108  if (!ifaddrs) {
109  return rb_ary_new();
110  }
111 
112  numifaddrs = 0;
113  for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
114  numifaddrs++;
115 
116  root = xmalloc(sizeof(rb_ifaddr_root_t) + (numifaddrs-1) * sizeof(rb_ifaddr_t));
117  root->refcount = root->numifaddrs = numifaddrs;
118 
119  ifa = ifaddrs;
120  for (i = 0; i < numifaddrs; i++) {
121  root->ary[i].ord = i;
122  root->ary[i].ifaddr = ifa;
123  root->ary[i].root = root;
124  ifa = ifa->ifa_next;
125  }
126 
127  result = rb_ary_new2(numifaddrs);
128  for (i = 0; i < numifaddrs; i++) {
129  rb_ary_push(result, TypedData_Wrap_Struct(rb_cSockIfaddr, &ifaddr_type, &root->ary[i]));
130  }
131 
132  return result;
133 }
134 
135 /*
136  * call-seq:
137  * ifaddr.name => string
138  *
139  * Returns the interface name of _ifaddr_.
140  */
141 
142 static VALUE
143 ifaddr_name(VALUE self)
144 {
145  rb_ifaddr_t *rifaddr = get_ifaddr(self);
146  struct ifaddrs *ifa = rifaddr->ifaddr;
147  return rb_str_new_cstr(ifa->ifa_name);
148 }
149 
150 #ifdef HAVE_IF_NAMETOINDEX
151 /*
152  * call-seq:
153  * ifaddr.ifindex => integer
154  *
155  * Returns the interface index of _ifaddr_.
156  */
157 
158 static VALUE
159 ifaddr_ifindex(VALUE self)
160 {
161  rb_ifaddr_t *rifaddr = get_ifaddr(self);
162  struct ifaddrs *ifa = rifaddr->ifaddr;
163  unsigned int ifindex = if_nametoindex(ifa->ifa_name);
164  if (ifindex == 0) {
165  rb_raise(rb_eArgError, "invalid interface name: %s", ifa->ifa_name);
166  }
167  return UINT2NUM(ifindex);
168 }
169 #else
170 #define ifaddr_ifindex rb_f_notimplement
171 #endif
172 
173 /*
174  * call-seq:
175  * ifaddr.flags => integer
176  *
177  * Returns the flags of _ifaddr_.
178  */
179 
180 static VALUE
181 ifaddr_flags(VALUE self)
182 {
183  rb_ifaddr_t *rifaddr = get_ifaddr(self);
184  struct ifaddrs *ifa = rifaddr->ifaddr;
185  return IFAFLAGS2NUM(ifa->ifa_flags);
186 }
187 
188 /*
189  * call-seq:
190  * ifaddr.addr => addrinfo
191  *
192  * Returns the address of _ifaddr_.
193  * nil is returned if address is not available in _ifaddr_.
194  */
195 
196 static VALUE
197 ifaddr_addr(VALUE self)
198 {
199  rb_ifaddr_t *rifaddr = get_ifaddr(self);
200  struct ifaddrs *ifa = rifaddr->ifaddr;
201  if (ifa->ifa_addr)
203  return Qnil;
204 }
205 
206 /*
207  * call-seq:
208  * ifaddr.netmask => addrinfo
209  *
210  * Returns the netmask address of _ifaddr_.
211  * nil is returned if netmask is not available in _ifaddr_.
212  */
213 
214 static VALUE
215 ifaddr_netmask(VALUE self)
216 {
217  rb_ifaddr_t *rifaddr = get_ifaddr(self);
218  struct ifaddrs *ifa = rifaddr->ifaddr;
219  if (ifa->ifa_netmask)
221  return Qnil;
222 }
223 
224 /*
225  * call-seq:
226  * ifaddr.broadaddr => addrinfo
227  *
228  * Returns the broadcast address of _ifaddr_.
229  * nil is returned if the flags doesn't have IFF_BROADCAST.
230  */
231 
232 static VALUE
233 ifaddr_broadaddr(VALUE self)
234 {
235  rb_ifaddr_t *rifaddr = get_ifaddr(self);
236  struct ifaddrs *ifa = rifaddr->ifaddr;
237  if ((ifa->ifa_flags & IFF_BROADCAST) && ifa->ifa_broadaddr)
239  return Qnil;
240 }
241 
242 /*
243  * call-seq:
244  * ifaddr.dstaddr => addrinfo
245  *
246  * Returns the destination address of _ifaddr_.
247  * nil is returned if the flags doesn't have IFF_POINTOPOINT.
248  */
249 
250 static VALUE
251 ifaddr_dstaddr(VALUE self)
252 {
253  rb_ifaddr_t *rifaddr = get_ifaddr(self);
254  struct ifaddrs *ifa = rifaddr->ifaddr;
255  if ((ifa->ifa_flags & IFF_POINTOPOINT) && ifa->ifa_dstaddr)
257  return Qnil;
258 }
259 
260 static void
261 ifaddr_inspect_flags(ifa_flags_t flags, VALUE result)
262 {
263  const char *sep = " ";
264 #define INSPECT_BIT(bit, name) \
265  if (flags & (bit)) { rb_str_catf(result, "%s" name, sep); flags &= ~(ifa_flags_t)(bit); sep = ","; }
266 #ifdef IFF_UP
267  INSPECT_BIT(IFF_UP, "UP")
268 #endif
269 #ifdef IFF_BROADCAST
270  INSPECT_BIT(IFF_BROADCAST, "BROADCAST")
271 #endif
272 #ifdef IFF_DEBUG
273  INSPECT_BIT(IFF_DEBUG, "DEBUG")
274 #endif
275 #ifdef IFF_LOOPBACK
276  INSPECT_BIT(IFF_LOOPBACK, "LOOPBACK")
277 #endif
278 #ifdef IFF_POINTOPOINT
279  INSPECT_BIT(IFF_POINTOPOINT, "POINTOPOINT")
280 #endif
281 #ifdef IFF_RUNNING
282  INSPECT_BIT(IFF_RUNNING, "RUNNING")
283 #endif
284 #ifdef IFF_NOARP
285  INSPECT_BIT(IFF_NOARP, "NOARP")
286 #endif
287 #ifdef IFF_PROMISC
288  INSPECT_BIT(IFF_PROMISC, "PROMISC")
289 #endif
290 #ifdef IFF_NOTRAILERS
291  INSPECT_BIT(IFF_NOTRAILERS, "NOTRAILERS")
292 #endif
293 #ifdef IFF_ALLMULTI
294  INSPECT_BIT(IFF_ALLMULTI, "ALLMULTI")
295 #endif
296 #ifdef IFF_MASTER
297  INSPECT_BIT(IFF_MASTER, "MASTER")
298 #endif
299 #ifdef IFF_SLAVE
300  INSPECT_BIT(IFF_SLAVE, "SLAVE")
301 #endif
302 #ifdef IFF_MULTICAST
303  INSPECT_BIT(IFF_MULTICAST, "MULTICAST")
304 #endif
305 #ifdef IFF_PORTSEL
306  INSPECT_BIT(IFF_PORTSEL, "PORTSEL")
307 #endif
308 #ifdef IFF_AUTOMEDIA
309  INSPECT_BIT(IFF_AUTOMEDIA, "AUTOMEDIA")
310 #endif
311 #ifdef IFF_DYNAMIC
312  INSPECT_BIT(IFF_DYNAMIC, "DYNAMIC")
313 #endif
314 #ifdef IFF_LOWER_UP
315  INSPECT_BIT(IFF_LOWER_UP, "LOWER_UP")
316 #endif
317 #ifdef IFF_DORMANT
318  INSPECT_BIT(IFF_DORMANT, "DORMANT")
319 #endif
320 #ifdef IFF_ECHO
321  INSPECT_BIT(IFF_ECHO, "ECHO")
322 #endif
323 #undef INSPECT_BIT
324  if (flags) {
325  rb_str_catf(result, "%s%#"PRIxIFAFLAGS, sep, flags);
326  }
327 }
328 
329 /*
330  * call-seq:
331  * ifaddr.inspect => string
332  *
333  * Returns a string to show contents of _ifaddr_.
334  */
335 
336 static VALUE
337 ifaddr_inspect(VALUE self)
338 {
339  rb_ifaddr_t *rifaddr = get_ifaddr(self);
340  struct ifaddrs *ifa;
341  VALUE result;
342 
343  ifa = rifaddr->ifaddr;
344 
345  result = rb_str_new_cstr("#<");
346 
347  rb_str_append(result, rb_class_name(CLASS_OF(self)));
348  rb_str_cat2(result, " ");
349  rb_str_cat2(result, ifa->ifa_name);
350 
351  if (ifa->ifa_flags)
352  ifaddr_inspect_flags(ifa->ifa_flags, result);
353 
354  if (ifa->ifa_addr) {
355  rb_str_cat2(result, " ");
358  result);
359  }
360  if (ifa->ifa_netmask) {
361  rb_str_cat2(result, " netmask=");
364  result);
365  }
366 
367  if ((ifa->ifa_flags & IFF_BROADCAST) && ifa->ifa_broadaddr) {
368  rb_str_cat2(result, " broadcast=");
371  result);
372  }
373 
374  if ((ifa->ifa_flags & IFF_POINTOPOINT) && ifa->ifa_dstaddr) {
375  rb_str_cat2(result, " dstaddr=");
378  result);
379  }
380 
381  rb_str_cat2(result, ">");
382  return result;
383 }
384 #endif
385 
386 #ifdef HAVE_GETIFADDRS
387 /*
388  * call-seq:
389  * Socket.getifaddrs => [ifaddr1, ...]
390  *
391  * Returns an array of interface addresses.
392  * An element of the array is an instance of Socket::Ifaddr.
393  *
394  * This method can be used to find multicast-enabled interfaces:
395  *
396  * pp Socket.getifaddrs.reject {|ifaddr|
397  * !ifaddr.addr.ip? || (ifaddr.flags & Socket::IFF_MULTICAST == 0)
398  * }.map {|ifaddr| [ifaddr.name, ifaddr.ifindex, ifaddr.addr] }
399  * #=> [["eth0", 2, #<Addrinfo: 221.186.184.67>],
400  * # ["eth0", 2, #<Addrinfo: fe80::216:3eff:fe95:88bb%eth0>]]
401  *
402  * Example result on GNU/Linux:
403  * pp Socket.getifaddrs
404  * #=> [#<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 PACKET[protocol=0 lo hatype=772 HOST hwaddr=00:00:00:00:00:00]>,
405  * # #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 PACKET[protocol=0 eth0 hatype=1 HOST hwaddr=00:16:3e:95:88:bb] broadcast=PACKET[protocol=0 eth0 hatype=1 HOST hwaddr=ff:ff:ff:ff:ff:ff]>,
406  * # #<Socket::Ifaddr sit0 NOARP PACKET[protocol=0 sit0 hatype=776 HOST hwaddr=00:00:00:00]>,
407  * # #<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 127.0.0.1 netmask=255.0.0.0>,
408  * # #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 221.186.184.67 netmask=255.255.255.240 broadcast=221.186.184.79>,
409  * # #<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 ::1 netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>,
410  * # #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 fe80::216:3eff:fe95:88bb%eth0 netmask=ffff:ffff:ffff:ffff::>]
411  *
412  * Example result on FreeBSD:
413  * pp Socket.getifaddrs
414  * #=> [#<Socket::Ifaddr usbus0 UP,0x10000 LINK[usbus0]>,
415  * # #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 LINK[re0 3a:d0:40:9a:fe:e8]>,
416  * # #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 10.250.10.18 netmask=255.255.255.? (7 bytes for 16 bytes sockaddr_in) broadcast=10.250.10.255>,
417  * # #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 fe80:2::38d0:40ff:fe9a:fee8 netmask=ffff:ffff:ffff:ffff::>,
418  * # #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 2001:2e8:408:10::12 netmask=UNSPEC>,
419  * # #<Socket::Ifaddr plip0 POINTOPOINT,MULTICAST,0x800 LINK[plip0]>,
420  * # #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST LINK[lo0]>,
421  * # #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST ::1 netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>,
422  * # #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST fe80:4::1 netmask=ffff:ffff:ffff:ffff::>,
423  * # #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST 127.0.0.1 netmask=255.?.?.? (5 bytes for 16 bytes sockaddr_in)>]
424  *
425  */
426 
427 static VALUE
429 {
430  return rsock_getifaddrs();
431 }
432 #else
433 #define socket_s_getifaddrs rb_f_notimplement
434 #endif
435 
436 void
438 {
439 #ifdef HAVE_GETIFADDRS
440  /*
441  * Document-class: Socket::Ifaddr
442  *
443  * Socket::Ifaddr represents a result of getifaddrs() function.
444  */
445  rb_cSockIfaddr = rb_define_class_under(rb_cSocket, "Ifaddr", rb_cData);
446  rb_define_method(rb_cSockIfaddr, "inspect", ifaddr_inspect, 0);
447  rb_define_method(rb_cSockIfaddr, "name", ifaddr_name, 0);
448  rb_define_method(rb_cSockIfaddr, "ifindex", ifaddr_ifindex, 0);
449  rb_define_method(rb_cSockIfaddr, "flags", ifaddr_flags, 0);
450  rb_define_method(rb_cSockIfaddr, "addr", ifaddr_addr, 0);
451  rb_define_method(rb_cSockIfaddr, "netmask", ifaddr_netmask, 0);
452  rb_define_method(rb_cSockIfaddr, "broadaddr", ifaddr_broadaddr, 0);
453  rb_define_method(rb_cSockIfaddr, "dstaddr", ifaddr_dstaddr, 0);
454 #endif
455 
457 }
VALUE rsock_inspect_sockaddr(struct sockaddr *sockaddr_arg, socklen_t socklen, VALUE ret)
Definition: raddrinfo.c:1090
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1646
VALUE rsock_sockaddr_obj(struct sockaddr *addr, socklen_t len)
struct sockaddr * ifa_broadaddr
Definition: win32.h:252
VALUE rb_str_new_cstr(const char *)
Definition: string.c:560
int ret
Definition: tcltklib.c:285
VALUE rb_eTypeError
Definition: error.c:548
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:900
rb_str_append(str, i)
#define CLASS_OF(v)
#define xfree
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:657
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
VALUE rb_class_name(VALUE)
Definition: variable.c:391
void rsock_init_sockifaddr(void)
Definition: ifaddr.c:437
struct sockaddr * ifa_addr
Definition: win32.h:250
#define socket_s_getifaddrs
Definition: ifaddr.c:433
#define rb_ary_new2
void freeifaddrs(struct ifaddrs *)
Definition: win32.c:3983
i
Definition: enum.c:446
VALUE ary
Definition: enum.c:674
socklen_t rsock_sockaddr_len(struct sockaddr *addr)
int getifaddrs(struct ifaddrs **)
Definition: win32.c:3892
struct ifaddrs * ifa_next
Definition: win32.h:247
#define Qnil
Definition: enum.c:67
VALUE rb_ary_new(void)
Definition: array.c:499
int flags
Definition: tcltklib.c:3015
u_int ifa_flags
Definition: win32.h:249
VALUE rb_str_cat2(VALUE, const char *)
Definition: string.c:2158
#define offsetof(p_type, field)
Definition: addrinfo.h:186
#define xmalloc
#define TypedData_Wrap_Struct(klass, data_type, sval)
struct sockaddr * ifa_dstaddr
Definition: win32.h:253
VALUE rb_cSocket
Definition: init.c:22
void rb_sys_fail(const char *mesg)
Definition: error.c:1976
return ptr
Definition: tcltklib.c:789
void * rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
Definition: error.c:520
VALUE rb_str_catf(VALUE str, const char *format,...)
Definition: sprintf.c:1290
#define UINT2NUM(x)
struct sockaddr * ifa_netmask
Definition: win32.h:251
unsigned long VALUE
Definition: ripper.y:88
RUBY_EXTERN VALUE rb_cData
Definition: ripper.y:1568
#define NULL
Definition: _sdbm.c:102
volatile VALUE result
Definition: enum.c:1989
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1479
VALUE rb_eArgError
Definition: error.c:549
char * ifa_name
Definition: win32.h:248
Definition: win32.h:246