getifaddrs2.patch

Akira Tanaka, 05/06/2013 08:33 PM

Download (32.7 KB)

View differences:

ext/socket/extconf.rb
302 302
  netinet/tcp.h
303 303
  netinet/udp.h
304 304
  arpa/inet.h
305
  netpacket/packet.h
306
  net/ethernet.h
305 307
  sys/un.h
306 308
  ifaddrs.h
307 309
  sys/ioctl.h
......
310 312
  sys/param.h
311 313
  sys/ucred.h
312 314
  ucred.h
315
  net/if_dl.h
313 316
  arpa/nameser.h
314 317
  resolv.h
315 318
].each {|h|
......
325 328
  have_struct_member("struct sockaddr_un", "sun_len", headers) # 4.4BSD
326 329
end
327 330

  
331
have_type("struct sockaddr_dl", headers) # AF_LINK address.  4.4BSD since Net2
332

  
328 333
have_type("struct sockaddr_storage", headers)
329 334

  
330 335
have_type("struct addrinfo", headers)
......
550 555
    "unixserver.#{$OBJEXT}",
551 556
    "option.#{$OBJEXT}",
552 557
    "ancdata.#{$OBJEXT}",
553
    "raddrinfo.#{$OBJEXT}"
558
    "raddrinfo.#{$OBJEXT}",
559
    "ifaddr.#{$OBJEXT}"
554 560
  ]
555 561

  
556 562
  if getaddr_info_ok == :wide
ext/socket/ifaddr.c
1
#include "rubysocket.h"
2

  
3
#ifdef HAVE_GETIFADDRS
4
VALUE rb_cSockIfaddr;
5

  
6
typedef struct rb_ifaddr_tag rb_ifaddr_t;
7
typedef struct rb_ifaddr_root_tag rb_ifaddr_root_t;
8

  
9
struct rb_ifaddr_tag {
10
    int ord;
11
    struct ifaddrs *ifaddr;
12
    rb_ifaddr_root_t *root;
13
};
14

  
15
struct rb_ifaddr_root_tag {
16
    int refcount;
17
    int numifaddrs;
18
    rb_ifaddr_t ary[1];
19
};
20

  
21
static rb_ifaddr_root_t *
22
get_root(const rb_ifaddr_t *ifaddr)
23
{
24
    return (rb_ifaddr_root_t *)((char *)&ifaddr[-ifaddr->ord] -
25
                                offsetof(rb_ifaddr_root_t, ary));
26
}
27

  
28
static void
29
ifaddr_mark(void *ptr)
30
{
31
}
32

  
33
static void
34
ifaddr_free(void *ptr)
35
{
36
    rb_ifaddr_t *ifaddr = ptr;
37
    rb_ifaddr_root_t *root = get_root(ifaddr);
38
    root->refcount--;
39
    if (root->refcount == 0) {
40
        freeifaddrs(root->ary[0].ifaddr);
41
        xfree(root);
42
    }
43
}
44

  
45
static size_t
46
ifaddr_memsize(const void *ptr)
47
{
48
    const rb_ifaddr_t *ifaddr;
49
    const rb_ifaddr_root_t *root;
50
    if (ptr == NULL)
51
        return 0;
52
    ifaddr = ptr;
53
    root = get_root(ifaddr);
54
    return sizeof(rb_ifaddr_root_t) + (root->numifaddrs - 1) * sizeof(rb_ifaddr_t);
55
}
56

  
57
static const rb_data_type_t ifaddr_type = {
58
    "socket/ifaddr",
59
    {ifaddr_mark, ifaddr_free, ifaddr_memsize,},
60
};
61

  
62
#define IS_IFADDRS(obj) rb_typeddata_is_kind_of((obj), &ifaddr_type)
63
static inline rb_ifaddr_t *
64
check_ifaddr(VALUE self)
65
{
66
      return rb_check_typeddata(self, &ifaddr_type);
67
}
68

  
69
static rb_ifaddr_t *
70
get_ifaddr(VALUE self)
71
{
72
    rb_ifaddr_t *rifaddr = check_ifaddr(self);
73

  
74
    if (!rifaddr) {
75
        rb_raise(rb_eTypeError, "uninitialized ifaddr");
76
    }
77
    return rifaddr;
78
}
79

  
80
static VALUE
81
rsock_getifaddrs(void)
82
{
83
    int ret;
84
    int numifaddrs, i;
85
    struct ifaddrs *ifaddrs, *ifa;
86
    rb_ifaddr_root_t *root;
87
    VALUE result;
88

  
89
    ret = getifaddrs(&ifaddrs);
90
    if (ret == -1)
91
        rb_sys_fail("getifaddrs");
92

  
93
    numifaddrs = 0;
94
    for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
95
        numifaddrs++;
96

  
97
    root = xmalloc(sizeof(rb_ifaddr_root_t) + (numifaddrs-1) * sizeof(rb_ifaddr_t));
98
    root->refcount = root->numifaddrs = numifaddrs;
99

  
100
    ifa = ifaddrs;
101
    for (i = 0; i < numifaddrs; i++) {
102
        root->ary[i].ord = i;
103
        root->ary[i].ifaddr = ifa;
104
        root->ary[i].root = root;
105
        ifa = ifa->ifa_next;
106
    }
107

  
108
    result = rb_ary_new2(numifaddrs);
109
    for (i = 0; i < numifaddrs; i++) {
110
        rb_ary_push(result, TypedData_Wrap_Struct(rb_cSockIfaddr, &ifaddr_type, &root->ary[i]));
111
    }
112

  
113
    return result;
114
}
115

  
116
/*
117
 * call-seq:
118
 *   getifaddr.name => string
119
 *
120
 * Returns the interface name of _getifaddr_.
121
 */
122

  
123
static VALUE
124
ifaddr_name(VALUE self)
125
{
126
    rb_ifaddr_t *rifaddr = get_ifaddr(self);
127
    struct ifaddrs *ifa = rifaddr->ifaddr;
128
    return rb_str_new_cstr(ifa->ifa_name);
129
}
130

  
131
/*
132
 * call-seq:
133
 *   getifaddr.ifindex => integer
134
 *
135
 * Returns the interface index of _getifaddr_.
136
 */
137

  
138
static VALUE
139
ifaddr_ifindex(VALUE self)
140
{
141
    rb_ifaddr_t *rifaddr = get_ifaddr(self);
142
    struct ifaddrs *ifa = rifaddr->ifaddr;
143
    unsigned int ifindex = if_nametoindex(ifa->ifa_name);
144
    if (ifindex == 0) {
145
        rb_raise(rb_eArgError, "invalid interface name: %s", ifa->ifa_name);
146
    }
147
    return UINT2NUM(ifindex);
148
}
149

  
150
/*
151
 * call-seq:
152
 *   getifaddr.flags => integer
153
 *
154
 * Returns the flags of _getifaddr_.
155
 */
156

  
157
static VALUE
158
ifaddr_flags(VALUE self)
159
{
160
    rb_ifaddr_t *rifaddr = get_ifaddr(self);
161
    struct ifaddrs *ifa = rifaddr->ifaddr;
162
    return UINT2NUM(ifa->ifa_flags);
163
}
164

  
165
/*
166
 * call-seq:
167
 *   getifaddr.addr => addrinfo
168
 *
169
 * Returns the address of _getifaddr_.
170
 * nil is returned if address is not available in _getifaddr_.
171
 */
172

  
173
static VALUE
174
ifaddr_addr(VALUE self)
175
{
176
    rb_ifaddr_t *rifaddr = get_ifaddr(self);
177
    struct ifaddrs *ifa = rifaddr->ifaddr;
178
    if (ifa->ifa_addr)
179
        return rsock_sockaddr_obj(ifa->ifa_addr, rsock_sockaddr_len(ifa->ifa_addr));
180
    return Qnil;
181
}
182

  
183
/*
184
 * call-seq:
185
 *   getifaddr.netmask => addrinfo
186
 *
187
 * Returns the netmask address of _getifaddr_.
188
 * nil is returned if netmask is not available in _getifaddr_.
189
 */
190

  
191
static VALUE
192
ifaddr_netmask(VALUE self)
193
{
194
    rb_ifaddr_t *rifaddr = get_ifaddr(self);
195
    struct ifaddrs *ifa = rifaddr->ifaddr;
196
    if (ifa->ifa_netmask)
197
        return rsock_sockaddr_obj(ifa->ifa_netmask, rsock_sockaddr_len(ifa->ifa_netmask));
198
    return Qnil;
199
}
200

  
201
/*
202
 * call-seq:
203
 *   getifaddr.broadaddr => addrinfo
204
 *
205
 * Returns the broadcast address of _getifaddr_.
206
 * nil is returned if the flags doesn't have IFF_BROADCAST.
207
 */
208

  
209
static VALUE
210
ifaddr_broadaddr(VALUE self)
211
{
212
    rb_ifaddr_t *rifaddr = get_ifaddr(self);
213
    struct ifaddrs *ifa = rifaddr->ifaddr;
214
    if ((ifa->ifa_flags & IFF_BROADCAST) && ifa->ifa_broadaddr)
215
        return rsock_sockaddr_obj(ifa->ifa_broadaddr, rsock_sockaddr_len(ifa->ifa_broadaddr));
216
    return Qnil;
217
}
218

  
219
/*
220
 * call-seq:
221
 *   getifaddr.dstaddr => addrinfo
222
 *
223
 * Returns the destination address of _getifaddr_.
224
 * nil is returned if the flags doesn't have IFF_POINTOPOINT.
225
 */
226

  
227
static VALUE
228
ifaddr_dstaddr(VALUE self)
229
{
230
    rb_ifaddr_t *rifaddr = get_ifaddr(self);
231
    struct ifaddrs *ifa = rifaddr->ifaddr;
232
    if ((ifa->ifa_flags & IFF_POINTOPOINT) && ifa->ifa_dstaddr)
233
        return rsock_sockaddr_obj(ifa->ifa_dstaddr, rsock_sockaddr_len(ifa->ifa_dstaddr));
234
    return Qnil;
235
}
236

  
237
static void
238
ifaddr_inspect_flags(unsigned int flags, VALUE result)
239
{
240
    const char *sep = " ";
241
#define INSPECT_BIT(bit, name) \
242
    if (flags & (bit)) { rb_str_catf(result, "%s" name, sep); flags &= ~(bit); sep = ","; }
243
#ifdef IFF_UP
244
    INSPECT_BIT(IFF_UP, "UP")
245
#endif
246
#ifdef IFF_BROADCAST
247
    INSPECT_BIT(IFF_BROADCAST, "BROADCAST")
248
#endif
249
#ifdef IFF_DEBUG
250
    INSPECT_BIT(IFF_DEBUG, "DEBUG")
251
#endif
252
#ifdef IFF_LOOPBACK
253
    INSPECT_BIT(IFF_LOOPBACK, "LOOPBACK")
254
#endif
255
#ifdef IFF_POINTOPOINT
256
    INSPECT_BIT(IFF_POINTOPOINT, "POINTOPOINT")
257
#endif
258
#ifdef IFF_RUNNING
259
    INSPECT_BIT(IFF_RUNNING, "RUNNING")
260
#endif
261
#ifdef IFF_NOARP
262
    INSPECT_BIT(IFF_NOARP, "NOARP")
263
#endif
264
#ifdef IFF_PROMISC
265
    INSPECT_BIT(IFF_PROMISC, "PROMISC")
266
#endif
267
#ifdef IFF_NOTRAILERS
268
    INSPECT_BIT(IFF_NOTRAILERS, "NOTRAILERS")
269
#endif
270
#ifdef IFF_ALLMULTI
271
    INSPECT_BIT(IFF_ALLMULTI, "ALLMULTI")
272
#endif
273
#ifdef IFF_MASTER
274
    INSPECT_BIT(IFF_MASTER, "MASTER")
275
#endif
276
#ifdef IFF_SLAVE
277
    INSPECT_BIT(IFF_SLAVE, "SLAVE")
278
#endif
279
#ifdef IFF_MULTICAST
280
    INSPECT_BIT(IFF_MULTICAST, "MULTICAST")
281
#endif
282
#ifdef IFF_PORTSEL
283
    INSPECT_BIT(IFF_PORTSEL, "PORTSEL")
284
#endif
285
#ifdef IFF_AUTOMEDIA
286
    INSPECT_BIT(IFF_AUTOMEDIA, "AUTOMEDIA")
287
#endif
288
#ifdef IFF_DYNAMIC
289
    INSPECT_BIT(IFF_DYNAMIC, "DYNAMIC")
290
#endif
291
#ifdef IFF_LOWER_UP
292
    INSPECT_BIT(IFF_LOWER_UP, "LOWER_UP")
293
#endif
294
#ifdef IFF_DORMANT
295
    INSPECT_BIT(IFF_DORMANT, "DORMANT")
296
#endif
297
#ifdef IFF_ECHO
298
    INSPECT_BIT(IFF_ECHO, "ECHO")
299
#endif
300
#undef INSPECT_BIT
301
    if (flags) {
302
        rb_str_catf(result, "%s%#x", sep, flags);
303
    }
304
}
305

  
306
/*
307
 * call-seq:
308
 *   getifaddr.inspect => string
309
 *
310
 * Returns a string to show contents of _getifaddr_.
311
 */
312

  
313
static VALUE
314
ifaddr_inspect(VALUE self)
315
{
316
    rb_ifaddr_t *rifaddr = get_ifaddr(self);
317
    struct ifaddrs *ifa;
318
    VALUE result;
319

  
320
    ifa = rifaddr->ifaddr;
321

  
322
    result = rb_str_new_cstr("#<");
323

  
324
    rb_str_append(result, rb_class_name(CLASS_OF(self)));
325
    rb_str_cat2(result, " ");
326
    rb_str_cat2(result, ifa->ifa_name);
327

  
328
    if (ifa->ifa_flags)
329
        ifaddr_inspect_flags(ifa->ifa_flags, result);
330

  
331
    if (ifa->ifa_addr) {
332
      rb_str_cat2(result, " ");
333
      rsock_inspect_sockaddr(ifa->ifa_addr,
334
          rsock_sockaddr_len(ifa->ifa_addr),
335
          result);
336
    }
337
    if (ifa->ifa_netmask) {
338
      rb_str_cat2(result, " netmask=");
339
      rsock_inspect_sockaddr(ifa->ifa_netmask,
340
          rsock_sockaddr_len(ifa->ifa_netmask),
341
          result);
342
    }
343

  
344
    if ((ifa->ifa_flags & IFF_BROADCAST) && ifa->ifa_broadaddr) {
345
      rb_str_cat2(result, " broadcast=");
346
      rsock_inspect_sockaddr(ifa->ifa_broadaddr,
347
          rsock_sockaddr_len(ifa->ifa_broadaddr),
348
          result);
349
    }
350

  
351
    if ((ifa->ifa_flags & IFF_POINTOPOINT) && ifa->ifa_dstaddr) {
352
      rb_str_cat2(result, " dstaddr=");
353
      rsock_inspect_sockaddr(ifa->ifa_dstaddr,
354
          rsock_sockaddr_len(ifa->ifa_dstaddr),
355
          result);
356
    }
357

  
358
    rb_str_cat2(result, ">");
359
    return result;
360
}
361
#endif
362

  
363
#ifdef HAVE_GETIFADDRS
364
/*
365
 * call-seq:
366
 *   Socket.getifaddrs => [ifaddr1, ...]
367
 *
368
 * Returns an array of interface addresses.
369
 * An element of the array is an instance of Socket::Ifaddr.
370
 *
371
 * This method can be used to find multicast-enabled interfaces:
372
 *
373
 *   pp Socket.getifaddrs.reject {|ifaddr|
374
 *     !ifaddr.addr.ip? || (ifaddr.flags & Socket::IFF_MULTICAST == 0)
375
 *   }.map {|ifaddr| [ifaddr.name, ifaddr.ifindex, ifaddr.addr] }
376
 *   #=> [["eth0", 2, #<Addrinfo: 221.186.184.67>],
377
 *   #    ["eth0", 2, #<Addrinfo: fe80::216:3eff:fe95:88bb%eth0>]]
378
 *
379
 * Example result on GNU/Linux:
380
 *   pp Socket.getifaddrs
381
 *   #=> [#<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 PACKET[protocol=0 lo hatype=772 HOST hwaddr=00:00:00:00:00:00]>,
382
 *   #    #<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]>,
383
 *   #    #<Socket::Ifaddr sit0 NOARP PACKET[protocol=0 sit0 hatype=776 HOST hwaddr=00:00:00:00]>,
384
 *   #    #<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 127.0.0.1 netmask=255.0.0.0>,
385
 *   #    #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 221.186.184.67 netmask=255.255.255.240 broadcast=221.186.184.79>,
386
 *   #    #<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 ::1 netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>,
387
 *   #    #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 fe80::216:3eff:fe95:88bb%eth0 netmask=ffff:ffff:ffff:ffff::>]
388
 *
389
 * Example result on FreeBSD:
390
 *   pp Socket.getifaddrs
391
 *   #=> [#<Socket::Ifaddr usbus0 UP,0x10000 LINK[usbus0]>,
392
 *   #    #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 LINK[re0 3a:d0:40:9a:fe:e8]>,
393
 *   #    #<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>,
394
 *   #    #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 fe80:2::38d0:40ff:fe9a:fee8 netmask=ffff:ffff:ffff:ffff::>,
395
 *   #    #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 2001:2e8:408:10::12 netmask=UNSPEC>,
396
 *   #    #<Socket::Ifaddr plip0 POINTOPOINT,MULTICAST,0x800 LINK[plip0]>,
397
 *   #    #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST LINK[lo0]>,
398
 *   #    #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST ::1 netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>,
399
 *   #    #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST fe80:4::1 netmask=ffff:ffff:ffff:ffff::>,
400
 *   #    #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST 127.0.0.1 netmask=255.?.?.? (5 bytes for 16 bytes sockaddr_in)>]
401
 *
402
 */
403

  
404
static VALUE
405
socket_s_getifaddrs(VALUE self)
406
{
407
    return rsock_getifaddrs();
408
}
409
#else
410
#define socket_s_getifaddrs rb_f_notimplement
411
#endif
412

  
413
void
414
rsock_init_sockifaddr(void)
415
{
416
#ifdef HAVE_GETIFADDRS
417
    /*
418
     * Document-class: Socket::Ifaddr
419
     *
420
     * Socket::Ifaddr represents a result of getifaddrs() function.
421
     */
422
    rb_cSockIfaddr = rb_define_class_under(rb_cSocket, "Ifaddr", rb_cData);
423
    rb_define_method(rb_cSockIfaddr, "inspect", ifaddr_inspect, 0);
424
    rb_define_method(rb_cSockIfaddr, "name", ifaddr_name, 0);
425
    rb_define_method(rb_cSockIfaddr, "ifindex", ifaddr_ifindex, 0);
426
    rb_define_method(rb_cSockIfaddr, "flags", ifaddr_flags, 0);
427
    rb_define_method(rb_cSockIfaddr, "addr", ifaddr_addr, 0);
428
    rb_define_method(rb_cSockIfaddr, "netmask", ifaddr_netmask, 0);
429
    rb_define_method(rb_cSockIfaddr, "broadaddr", ifaddr_broadaddr, 0);
430
    rb_define_method(rb_cSockIfaddr, "dstaddr", ifaddr_dstaddr, 0);
431
#endif
432

  
433
    rb_define_singleton_method(rb_cSocket, "getifaddrs", socket_s_getifaddrs, 0);
434
}
ext/socket/init.c
627 627
    rsock_init_sockopt();
628 628
    rsock_init_ancdata();
629 629
    rsock_init_addrinfo();
630
    rsock_init_sockifaddr();
630 631
    rsock_init_socket_constants();
631 632
}
ext/socket/mkconstants.rb
703 703
LOCAL_PEERCRED	nil	Retrieve peer credentials
704 704
LOCAL_CREDS	nil	Pass credentials to receiver
705 705
LOCAL_CONNWAIT	nil	Connect blocks until accepted
706

  
707
IFF_802_1Q_VLAN      nil 802.1Q VLAN device
708
IFF_ALLMULTI         nil receive all multicast packets
709
IFF_ALTPHYS          nil use alternate physical connection
710
IFF_AUTOMEDIA        nil auto media select active
711
IFF_BONDING          nil bonding master or slave
712
IFF_BRIDGE_PORT      nil device used as bridge port
713
IFF_BROADCAST        nil broadcast address valid
714
IFF_CANTCONFIG       nil unconfigurable using ioctl(2)
715
IFF_DEBUG            nil turn on debugging
716
IFF_DISABLE_NETPOLL  nil disable netpoll at run-time
717
IFF_DONT_BRIDGE      nil disallow bridging this ether dev
718
IFF_DORMANT          nil driver signals dormant
719
IFF_DRV_OACTIVE      nil tx hardware queue is full
720
IFF_DRV_RUNNING      nil resources allocated
721
IFF_DYING            nil interface is winding down
722
IFF_DYNAMIC          nil dialup device with changing addresses
723
IFF_EBRIDGE          nil ethernet bridging device
724
IFF_ECHO             nil echo sent packets
725
IFF_ISATAP           nil ISATAP interface (RFC4214)
726
IFF_LINK0            nil per link layer defined bit 0
727
IFF_LINK1            nil per link layer defined bit 1
728
IFF_LINK2            nil per link layer defined bit 2
729
IFF_LIVE_ADDR_CHANGE nil hardware address change when it's running
730
IFF_LOOPBACK         nil loopback net
731
IFF_LOWER_UP         nil driver signals L1 up
732
IFF_MACVLAN_PORT     nil device used as macvlan port
733
IFF_MASTER           nil master of a load balancer
734
IFF_MASTER_8023AD    nil bonding master, 802.3ad.
735
IFF_MASTER_ALB       nil bonding master, balance-alb.
736
IFF_MASTER_ARPMON    nil bonding master, ARP mon in use
737
IFF_MONITOR          nil user-requested monitor mode
738
IFF_MULTICAST        nil supports multicast
739
IFF_NOARP            nil no address resolution protocol
740
IFF_NOTRAILERS       nil avoid use of trailers
741
IFF_OACTIVE          nil transmission in progress
742
IFF_OVS_DATAPATH     nil device used as Open vSwitch datapath port
743
IFF_POINTOPOINT      nil point-to-point link
744
IFF_PORTSEL          nil can set media type
745
IFF_PPROMISC         nil user-requested promisc mode
746
IFF_PROMISC          nil receive all packets
747
IFF_RENAMING         nil interface is being renamed
748
IFF_ROUTE            nil routing entry installed
749
IFF_RUNNING          nil resources allocated
750
IFF_SIMPLEX          nil can't hear own transmissions
751
IFF_SLAVE            nil slave of a load balancer
752
IFF_SLAVE_INACTIVE   nil bonding slave not the curr. active
753
IFF_SLAVE_NEEDARP    nil need ARPs for validation
754
IFF_SMART            nil interface manages own routes
755
IFF_STATICARP        nil static ARP
756
IFF_SUPP_NOFCS       nil sending custom FCS
757
IFF_TEAM_PORT        nil used as team port
758
IFF_TX_SKB_SHARING   nil sharing skbs on transmit
759
IFF_UNICAST_FLT      nil unicast filtering
760
IFF_UP               nil interface is up
761
IFF_WAN_HDLC         nil WAN HDLC device
762
IFF_XMIT_DST_RELEASE nil dev_hard_start_xmit() is allowed to release skb->dst
763
IFF_VOLATILE         nil volatile flags
764
IFF_CANTCHANGE       nil flags not changeable
ext/socket/raddrinfo.c
953 953
inspect_sockaddr(VALUE addrinfo, VALUE ret)
954 954
{
955 955
    rb_addrinfo_t *rai = get_addrinfo(addrinfo);
956
    union_sockaddr *sockaddr = &rai->addr;
957
    socklen_t socklen = rai->sockaddr_len;
958
    return rsock_inspect_sockaddr((struct sockaddr *)sockaddr, socklen, ret);
959
}
956 960

  
957
    if (rai->sockaddr_len == 0) {
961
VALUE
962
rsock_inspect_sockaddr(struct sockaddr *sockaddr_arg, socklen_t socklen, VALUE ret)
963
{
964
    union_sockaddr *sockaddr = (union_sockaddr *)sockaddr_arg;
965
    if (socklen == 0) {
958 966
        rb_str_cat2(ret, "empty-sockaddr");
959 967
    }
960
    else if ((long)rai->sockaddr_len < ((char*)&rai->addr.addr.sa_family + sizeof(rai->addr.addr.sa_family)) - (char*)&rai->addr)
968
    else if ((long)socklen < ((char*)&sockaddr->addr.sa_family + sizeof(sockaddr->addr.sa_family)) - (char*)sockaddr)
961 969
        rb_str_cat2(ret, "too-short-sockaddr");
962 970
    else {
963
        switch (rai->addr.addr.sa_family) {
971
        switch (sockaddr->addr.sa_family) {
972
          case AF_UNSPEC:
973
	  {
974
	    rb_str_cat2(ret, "UNSPEC");
975
            break;
976
	  }
977

  
964 978
          case AF_INET:
965 979
          {
966 980
            struct sockaddr_in *addr;
967 981
            int port;
968
            if (rai->sockaddr_len < (socklen_t)sizeof(struct sockaddr_in)) {
969
                rb_str_cat2(ret, "too-short-AF_INET-sockaddr");
970
            }
971
            else {
972
                addr = &rai->addr.in;
973
                rb_str_catf(ret, "%d.%d.%d.%d",
974
                            ((unsigned char*)&addr->sin_addr)[0],
975
                            ((unsigned char*)&addr->sin_addr)[1],
976
                            ((unsigned char*)&addr->sin_addr)[2],
977
                            ((unsigned char*)&addr->sin_addr)[3]);
978
                port = ntohs(addr->sin_port);
979
                if (port)
980
                    rb_str_catf(ret, ":%d", port);
981
                if ((socklen_t)sizeof(struct sockaddr_in) < rai->sockaddr_len)
982
                    rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(rai->sockaddr_len - sizeof(struct sockaddr_in)));
983
            }
982
	    addr = &sockaddr->in;
983
	    if (((char*)&addr->sin_addr)-(char*)addr+0+1 <= socklen)
984
		rb_str_catf(ret, "%d", ((unsigned char*)&addr->sin_addr)[0]);
985
	    else
986
		rb_str_cat2(ret, "?");
987
	    if (((char*)&addr->sin_addr)-(char*)addr+1+1 <= socklen)
988
		rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[1]);
989
	    else
990
		rb_str_cat2(ret, ".?");
991
	    if (((char*)&addr->sin_addr)-(char*)addr+2+1 <= socklen)
992
		rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[2]);
993
	    else
994
		rb_str_cat2(ret, ".?");
995
	    if (((char*)&addr->sin_addr)-(char*)addr+3+1 <= socklen)
996
		rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[3]);
997
	    else
998
		rb_str_cat2(ret, ".?");
999

  
1000
	    if (((char*)&addr->sin_port)-(char*)addr+(int)sizeof(addr->sin_port) < socklen) {
1001
		port = ntohs(addr->sin_port);
1002
		if (port)
1003
		    rb_str_catf(ret, ":%d", port);
1004
	    }
1005
	    else {
1006
		rb_str_cat2(ret, ":?");
1007
	    }
1008
	    if ((socklen_t)sizeof(struct sockaddr_in) != socklen)
1009
		rb_str_catf(ret, " (%d bytes for %d bytes sockaddr_in)",
1010
		  (int)socklen,
1011
		  (int)sizeof(struct sockaddr_in));
984 1012
            break;
985 1013
          }
986 1014

  
......
991 1019
            char hbuf[1024];
992 1020
            int port;
993 1021
            int error;
994
            if (rai->sockaddr_len < (socklen_t)sizeof(struct sockaddr_in6)) {
995
                rb_str_cat2(ret, "too-short-AF_INET6-sockaddr");
1022
            if (socklen < (socklen_t)sizeof(struct sockaddr_in6)) {
1023
                rb_str_catf(ret, "too-short-AF_INET6-sockaddr %d bytes", (int)socklen);
996 1024
            }
997 1025
            else {
998
                addr = &rai->addr.in6;
1026
                addr = &sockaddr->in6;
999 1027
                /* use getnameinfo for scope_id.
1000 1028
                 * RFC 4007: IPv6 Scoped Address Architecture
1001 1029
                 * draft-ietf-ipv6-scope-api-00.txt: Scoped Address Extensions to the IPv6 Basic Socket API
1002 1030
                 */
1003
                error = getnameinfo(&rai->addr.addr, rai->sockaddr_len,
1031
                error = getnameinfo(&sockaddr->addr, socklen,
1004 1032
                                    hbuf, (socklen_t)sizeof(hbuf), NULL, 0,
1005 1033
                                    NI_NUMERICHOST|NI_NUMERICSERV);
1006 1034
                if (error) {
......
1013 1041
                    port = ntohs(addr->sin6_port);
1014 1042
                    rb_str_catf(ret, "[%s]:%d", hbuf, port);
1015 1043
                }
1016
                if ((socklen_t)sizeof(struct sockaddr_in6) < rai->sockaddr_len)
1017
                    rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(rai->sockaddr_len - sizeof(struct sockaddr_in6)));
1044
                if ((socklen_t)sizeof(struct sockaddr_in6) < socklen)
1045
                    rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(socklen - sizeof(struct sockaddr_in6)));
1018 1046
            }
1019 1047
            break;
1020 1048
          }
......
1023 1051
#ifdef HAVE_SYS_UN_H
1024 1052
          case AF_UNIX:
1025 1053
          {
1026
            struct sockaddr_un *addr = &rai->addr.un;
1054
            struct sockaddr_un *addr = &sockaddr->un;
1027 1055
            char *p, *s, *e;
1028 1056
            s = addr->sun_path;
1029
            e = (char*)addr + rai->sockaddr_len;
1057
            e = (char*)addr + socklen;
1030 1058
            while (s < e && *(e-1) == '\0')
1031 1059
                e--;
1032 1060
            if (e < s)
......
1042 1070
                }
1043 1071
                if (printable_only) { /* only printable, no space */
1044 1072
                    if (s[0] != '/') /* relative path */
1045
                        rb_str_cat2(ret, "AF_UNIX ");
1073
                        rb_str_cat2(ret, "UNIX ");
1046 1074
                    rb_str_cat(ret, s, p - s);
1047 1075
                }
1048 1076
                else {
1049
                    rb_str_cat2(ret, "AF_UNIX");
1077
                    rb_str_cat2(ret, "UNIX");
1050 1078
                    while (s < e)
1051 1079
                        rb_str_catf(ret, ":%02x", (unsigned char)*s++);
1052 1080
                }
......
1055 1083
          }
1056 1084
#endif
1057 1085

  
1086
#ifdef AF_PACKET
1087
          /* GNU/Linux */
1088
          case AF_PACKET:
1089
          {
1090
            struct sockaddr_ll *addr;
1091
            const char *sep = "[";
1092
#define CATSEP do { rb_str_cat2(ret, sep); sep = " "; } while (0);
1093

  
1094
            addr = (struct sockaddr_ll *)sockaddr;
1095

  
1096
            rb_str_cat2(ret, "PACKET");
1097

  
1098
            if (offsetof(struct sockaddr_ll, sll_protocol) + sizeof(addr->sll_protocol) <= socklen) {
1099
                CATSEP;
1100
                rb_str_catf(ret, "protocol=%d", ntohs(addr->sll_protocol));
1101
            }
1102
            if (offsetof(struct sockaddr_ll, sll_ifindex) + sizeof(addr->sll_ifindex) <= socklen) {
1103
                char buf[IFNAMSIZ];
1104
                CATSEP;
1105
                if (if_indextoname(addr->sll_ifindex, buf) == NULL)
1106
                    rb_str_catf(ret, "ifindex=%d", addr->sll_ifindex);
1107
                else
1108
                    rb_str_catf(ret, "%s", buf);
1109
            }
1110
            if (offsetof(struct sockaddr_ll, sll_hatype) + sizeof(addr->sll_hatype) <= socklen) {
1111
                CATSEP;
1112
                rb_str_catf(ret, "hatype=%d", addr->sll_hatype);
1113
            }
1114
            if (offsetof(struct sockaddr_ll, sll_pkttype) + sizeof(addr->sll_pkttype) <= socklen) {
1115
                CATSEP;
1116
                if (addr->sll_pkttype == PACKET_HOST)
1117
                    rb_str_cat2(ret, "HOST");
1118
                else if (addr->sll_pkttype == PACKET_BROADCAST)
1119
                    rb_str_cat2(ret, "BROADCAST");
1120
                else if (addr->sll_pkttype == PACKET_MULTICAST)
1121
                    rb_str_cat2(ret, "MULTICAST");
1122
                else if (addr->sll_pkttype == PACKET_OTHERHOST)
1123
                    rb_str_cat2(ret, "OTHERHOST");
1124
                else if (addr->sll_pkttype == PACKET_OUTGOING)
1125
                    rb_str_cat2(ret, "OUTGOING");
1126
                else
1127
                    rb_str_catf(ret, "pkttype=%d", addr->sll_pkttype);
1128
            }
1129
            if (socklen != (socklen_t)(offsetof(struct sockaddr_ll, sll_addr) + addr->sll_halen)) {
1130
                CATSEP;
1131
                if (offsetof(struct sockaddr_ll, sll_halen) + sizeof(addr->sll_halen) <= socklen) {
1132
                    rb_str_catf(ret, "halen=%d", addr->sll_halen);
1133
                }
1134
            }
1135
            if (offsetof(struct sockaddr_ll, sll_addr) < socklen) {
1136
                socklen_t len, i;
1137
                CATSEP;
1138
                rb_str_cat2(ret, "hwaddr");
1139
                len = addr->sll_halen;
1140
                if (socklen < offsetof(struct sockaddr_ll, sll_addr) + len)
1141
                    len = socklen - offsetof(struct sockaddr_ll, sll_addr);
1142
                for (i = 0; i < len; i++) {
1143
                    rb_str_cat2(ret, i == 0 ? "=" : ":");
1144
                    rb_str_catf(ret, "%02x", addr->sll_addr[i]);
1145
                }
1146
            }
1147

  
1148
            if (socklen < (socklen_t)(offsetof(struct sockaddr_ll, sll_halen) + sizeof(addr->sll_halen)) ||
1149
                (socklen_t)(offsetof(struct sockaddr_ll, sll_addr) + addr->sll_halen) != socklen) {
1150
                CATSEP;
1151
                rb_str_catf(ret, "(%d bytes for %d bytes sockaddr_ll)",
1152
                    (int)socklen, (int)sizeof(struct sockaddr_ll));
1153
            }
1154

  
1155
            rb_str_cat2(ret, "]");
1156
#undef CATSEP
1157

  
1158
            break;
1159
          }
1160
#endif
1161

  
1162
#ifdef AF_LINK
1163
	  /* AF_LINK is defined in 4.4BSD derivations since Net2.
1164
	     link_ntoa is also defined at Net2.
1165
             However Debian GNU/kFreeBSD defines AF_LINK but
1166
             don't have link_ntoa.  */
1167
          case AF_LINK:
1168
	  {
1169
	    /*
1170
	     * Simple implementation using link_ntoa():
1171
	     * This doesn't work on Debian GNU/kFreeBSD 6.0.7 (squeeze).
1172
             * Also, the format is bit different.
1173
	     *
1174
	     * rb_str_catf(ret, "LINK %s", link_ntoa(&sockaddr->dl));
1175
	     * break;
1176
	     */
1177
            struct sockaddr_dl *addr = &sockaddr->dl;
1178
            char *np = NULL, *ap = NULL, *endp;
1179
            int nlen = 0, alen = 0;
1180
            int i, off;
1181
            const char *sep = "[";
1182
#define CATSEP do { rb_str_cat2(ret, sep); sep = " "; } while (0);
1183

  
1184
            rb_str_cat2(ret, "LINK");
1185

  
1186
            endp = ((char *)addr) + socklen;
1187

  
1188
            if (offsetof(struct sockaddr_dl, sdl_data) < socklen) {
1189
                np = addr->sdl_data;
1190
                nlen = addr->sdl_nlen;
1191
                if (endp - np < nlen)
1192
                    nlen = endp - np;
1193
            }
1194
            off = addr->sdl_nlen;
1195

  
1196
            if (offsetof(struct sockaddr_dl, sdl_data) + off < socklen) {
1197
                ap = addr->sdl_data + off;
1198
                alen = addr->sdl_alen;
1199
                if (endp - ap < alen)
1200
                    alen = endp - ap;
1201
            }
1202

  
1203
	    CATSEP;
1204
            if (np)
1205
                rb_str_catf(ret, "%.*s", nlen, np);
1206
            else
1207
                rb_str_cat2(ret, "?");
1208

  
1209
            if (ap && 0 < alen) {
1210
		CATSEP;
1211
                for (i = 0; i < alen; i++)
1212
                    rb_str_catf(ret, "%s%02x", i == 0 ? "" : ":", (unsigned char)ap[i]);
1213
            }
1214

  
1215
            if (socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_nlen) + sizeof(addr->sdl_nlen)) ||
1216
                socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_alen) + sizeof(addr->sdl_alen)) ||
1217
                socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_slen) + sizeof(addr->sdl_slen)) ||
1218
                /* longer length is possible behavior because struct sockaddr_dl has "minimum work area, can be larger" as the last field.
1219
                 * cf. Net2:/usr/src/sys/net/if_dl.h. */
1220
                socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_data) + addr->sdl_nlen + addr->sdl_alen + addr->sdl_slen)) {
1221
		CATSEP;
1222
                rb_str_catf(ret, "(%d bytes for %d bytes sockaddr_dl)",
1223
                    (int)socklen, (int)sizeof(struct sockaddr_dl));
1224
	    }
1225

  
1226
            rb_str_cat2(ret, "]");
1227
#undef CATSEP
1228
            break;
1229
          }
1230
#endif
1231

  
1058 1232
          default:
1059 1233
          {
1060
            ID id = rsock_intern_family(rai->addr.addr.sa_family);
1234
            ID id = rsock_intern_family(sockaddr->addr.sa_family);
1061 1235
            if (id == 0)
1062
                rb_str_catf(ret, "unknown address family %d", rai->addr.addr.sa_family);
1236
                rb_str_catf(ret, "unknown address family %d", sockaddr->addr.sa_family);
1063 1237
            else
1064 1238
                rb_str_catf(ret, "%s address format unknown", rb_id2name(id));
1065 1239
            break;
ext/socket/rubysocket.h
44 44
#  include <netdb.h>
45 45
#endif
46 46

  
47
#ifdef HAVE_NETPACKET_PACKET_H
48
#  include <netpacket/packet.h>
49
#endif
50
#ifdef HAVE_NET_ETHERNET_H
51
#  include <net/ethernet.h>
52
#endif
53

  
47 54
#include <errno.h>
48 55

  
49 56
#ifdef HAVE_SYS_UN_H
......
87 94
#ifdef HAVE_UCRED_H
88 95
#  include <ucred.h>
89 96
#endif
97
#ifdef HAVE_NET_IF_DL_H
98
#  include <net/if_dl.h>
99
#endif
90 100

  
91 101
#ifndef HAVE_TYPE_SOCKLEN_T
92 102
typedef int socklen_t;
......
169 179
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
170 180
  struct sockaddr_un un;
171 181
#endif
182
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_DL
183
  struct sockaddr_dl dl; /* AF_LINK */
184
#endif
172 185
  struct sockaddr_storage storage;
173 186
  char place_holder[2048]; /* sockaddr_storage is not enough for Unix domain sockets on SunOS and Darwin. */
174 187
} union_sockaddr;
......
267 280
VALUE rsock_make_ipaddr(struct sockaddr *addr, socklen_t addrlen);
268 281
VALUE rsock_ipaddr(struct sockaddr *sockaddr, socklen_t sockaddrlen, int norevlookup);
269 282
VALUE rsock_make_hostent(VALUE host, struct addrinfo *addr, VALUE (*ipaddr)(struct sockaddr *, socklen_t));
283
VALUE rsock_inspect_sockaddr(struct sockaddr *addr, socklen_t socklen, VALUE ret);
284
socklen_t rsock_sockaddr_len(struct sockaddr *addr);
285
VALUE rsock_sockaddr_obj(struct sockaddr *addr, socklen_t len);
270 286

  
271 287
int rsock_revlookup_flag(VALUE revlookup, int *norevlookup);
272 288

  
......
344 360
void rsock_init_ancdata(void);
345 361
void rsock_init_addrinfo(void);
346 362
void rsock_init_sockopt(void);
363
void rsock_init_sockifaddr(void);
347 364
void rsock_init_socket_init(void);
348 365

  
349 366
NORETURN(void rsock_sys_fail_host_port(const char *, VALUE, VALUE));
ext/socket/socket.c
1584 1584
        return (socklen_t)sizeof(struct sockaddr_un);
1585 1585
#endif
1586 1586

  
1587
#ifdef AF_PACKET
1588
      case AF_PACKET:
1589
        return (socklen_t)(offsetof(struct sockaddr_ll, sll_addr) + ((struct sockaddr_ll *)addr)->sll_halen);
1590
#endif
1591

  
1587 1592
      default:
1588 1593
        return (socklen_t)(offsetof(struct sockaddr, sa_family) + sizeof(addr->sa_family));
1589 1594
    }
1590 1595
}
1591 1596

  
1597
socklen_t
1598
rsock_sockaddr_len(struct sockaddr *addr)
1599
{
1600
    return sockaddr_len(addr);
1601
}
1602

  
1592 1603
static VALUE
1593 1604
sockaddr_obj(struct sockaddr *addr, socklen_t len)
1594 1605
{
......
1622 1633
    return rsock_addrinfo_new(addr, len, addr->sa_family, 0, 0, Qnil, Qnil);
1623 1634
}
1624 1635

  
1636
VALUE
1637
rsock_sockaddr_obj(struct sockaddr *addr, socklen_t len)
1638
{
1639
    return sockaddr_obj(addr, len);
1640
}
1641

  
1625 1642
#endif
1626 1643

  
1627 1644
#if defined(HAVE_GETIFADDRS) || (defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && !defined(__hpux)) || defined(SIOCGIFCONF) ||  defined(_WIN32)
test/socket/test_socket.rb
564 564
    accepted.close if accepted
565 565
    sock.close if sock && ! sock.closed?
566 566
  end
567

  
568
  def test_getifaddrs
569
    begin
570
      list = Socket.getifaddrs
571
    rescue NotImplementedError
572
      return
573
    end
574
    list.each {|ifaddr|
575
      assert_instance_of(Socket::Ifaddr, ifaddr)
576
    }
577
  end
567 578
end if defined?(Socket)