Ruby 2.1.5p273(2014-11-13revision48405)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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)
202 return rsock_sockaddr_obj(ifa->ifa_addr, rsock_sockaddr_len(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)
220 return rsock_sockaddr_obj(ifa->ifa_netmask, rsock_sockaddr_len(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)
238 return rsock_sockaddr_obj(ifa->ifa_broadaddr, rsock_sockaddr_len(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)
256 return rsock_sockaddr_obj(ifa->ifa_dstaddr, rsock_sockaddr_len(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, " ");
356 rsock_inspect_sockaddr(ifa->ifa_addr,
357 rsock_sockaddr_len(ifa->ifa_addr),
358 result);
359 }
360 if (ifa->ifa_netmask) {
361 rb_str_cat2(result, " netmask=");
362 rsock_inspect_sockaddr(ifa->ifa_netmask,
363 rsock_sockaddr_len(ifa->ifa_netmask),
364 result);
365 }
366
367 if ((ifa->ifa_flags & IFF_BROADCAST) && ifa->ifa_broadaddr) {
368 rb_str_cat2(result, " broadcast=");
369 rsock_inspect_sockaddr(ifa->ifa_broadaddr,
370 rsock_sockaddr_len(ifa->ifa_broadaddr),
371 result);
372 }
373
374 if ((ifa->ifa_flags & IFF_POINTOPOINT) && ifa->ifa_dstaddr) {
375 rb_str_cat2(result, " dstaddr=");
376 rsock_inspect_sockaddr(ifa->ifa_dstaddr,
377 rsock_sockaddr_len(ifa->ifa_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
428 socket_s_getifaddrs(VALUE self)
429 {
430 return rsock_getifaddrs();
431 }
432 #else
433 #define socket_s_getifaddrs rb_f_notimplement
434 #endif
435
436 void
437 rsock_init_sockifaddr(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
456 rb_define_singleton_method(rb_cSocket, "getifaddrs", socket_s_getifaddrs, 0);
457 }
rb_cData
RUBY_EXTERN VALUE rb_cData
Definition: ruby.h:1560
rsock_inspect_sockaddr
VALUE rsock_inspect_sockaddr(struct sockaddr *sockaddr_arg, socklen_t socklen, VALUE ret)
Definition: raddrinfo.c:1089
rb_define_singleton_method
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1655
rsock_sockaddr_obj
VALUE rsock_sockaddr_obj(struct sockaddr *addr, socklen_t len)
CLASS_OF
#define CLASS_OF(v)
Definition: ruby.h:440
ifaddrs::ifa_broadaddr
struct sockaddr * ifa_broadaddr
Definition: win32.h:252
TypedData_Wrap_Struct
#define TypedData_Wrap_Struct(klass, data_type, sval)
Definition: ruby.h:1027
rb_eTypeError
VALUE rb_eTypeError
Definition: error.c:548
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:896
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:676
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
rsock_init_sockifaddr
void rsock_init_sockifaddr(void)
Definition: ifaddr.c:437
ifaddrs::ifa_addr
struct sockaddr * ifa_addr
Definition: win32.h:250
socket_s_getifaddrs
#define socket_s_getifaddrs
Definition: ifaddr.c:433
freeifaddrs
void freeifaddrs(struct ifaddrs *)
Definition: win32.c:3979
rb_ary_new2
#define rb_ary_new2
Definition: intern.h:90
rsock_sockaddr_len
socklen_t rsock_sockaddr_len(struct sockaddr *addr)
getifaddrs
int getifaddrs(struct ifaddrs **)
Definition: win32.c:3888
rb_class_name
VALUE rb_class_name(VALUE)
Definition: variable.c:391
ifaddrs::ifa_next
struct ifaddrs * ifa_next
Definition: win32.h:247
rb_str_cat2
VALUE rb_str_cat2(VALUE, const char *)
Definition: string.c:2159
rb_ary_new
VALUE rb_ary_new(void)
Definition: array.c:495
UINT2NUM
#define UINT2NUM(x)
Definition: ruby.h:1298
ifaddrs::ifa_flags
u_int ifa_flags
Definition: win32.h:249
offsetof
#define offsetof(p_type, field)
Definition: addrinfo.h:186
ifaddrs::ifa_dstaddr
struct sockaddr * ifa_dstaddr
Definition: win32.h:253
rb_cSocket
VALUE rb_cSocket
Definition: init.c:22
Qnil
#define Qnil
Definition: ruby.h:427
VALUE
unsigned long VALUE
Definition: ruby.h:88
result
static VALUE result
Definition: nkf.c:40
rb_str_new_cstr
VALUE rb_str_new_cstr(const char *)
Definition: string.c:560
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:1976
rubysocket.h
rb_check_typeddata
void * rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
Definition: error.c:520
xmalloc
#define xmalloc
Definition: defines.h:108
rb_data_type_struct
Definition: ruby.h:966
rb_str_catf
VALUE rb_str_catf(VALUE str, const char *format,...)
Definition: sprintf.c:1290
ifaddrs::ifa_netmask
struct sockaddr * ifa_netmask
Definition: win32.h:251
xfree
void void xfree(void *)
NULL
#define NULL
Definition: _sdbm.c:103
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1488
rb_str_append
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:2298
rb_eArgError
VALUE rb_eArgError
Definition: error.c:549
ifaddrs::ifa_name
char * ifa_name
Definition: win32.h:248
ifaddrs
Definition: win32.h:246