Feature #8368 » getifaddrs.patch
| ext/socket/extconf.rb | ||
|---|---|---|
|   netinet/tcp.h | ||
|   netinet/udp.h | ||
|   arpa/inet.h | ||
|   netpacket/packet.h | ||
|   net/ethernet.h | ||
|   sys/un.h | ||
|   ifaddrs.h | ||
|   sys/ioctl.h | ||
| ... | ... | |
|   sys/param.h | ||
|   sys/ucred.h | ||
|   ucred.h | ||
|   net/if_dl.h | ||
|   arpa/nameser.h | ||
|   resolv.h | ||
| ].each {|h| | ||
| ... | ... | |
|   have_struct_member("struct sockaddr_un", "sun_len", headers) # 4.4BSD | ||
| end | ||
| have_type("struct sockaddr_dl", headers) # AF_LINK address.  4.4BSD since Net2 | ||
| have_type("struct sockaddr_storage", headers) | ||
| have_type("struct addrinfo", headers) | ||
| ... | ... | |
|     "unixserver.#{$OBJEXT}", | ||
|     "option.#{$OBJEXT}", | ||
|     "ancdata.#{$OBJEXT}", | ||
|     "raddrinfo.#{$OBJEXT}" | ||
|     "raddrinfo.#{$OBJEXT}", | ||
|     "ifaddr.#{$OBJEXT}" | ||
|   ] | ||
|   if getaddr_info_ok == :wide | ||
| ext/socket/ifaddr.c | ||
|---|---|---|
| #include "rubysocket.h" | ||
| VALUE rb_cSockIfaddr; | ||
| typedef struct rb_ifaddr_tag rb_ifaddr_t; | ||
| typedef struct rb_ifaddr_root_tag rb_ifaddr_root_t; | ||
| struct rb_ifaddr_tag { | ||
|     int ord; | ||
|     struct ifaddrs *ifaddr; | ||
|     rb_ifaddr_root_t *root; | ||
| }; | ||
| struct rb_ifaddr_root_tag { | ||
|     int refcount; | ||
|     int numifaddrs; | ||
|     rb_ifaddr_t ary[1]; | ||
| }; | ||
| static rb_ifaddr_root_t * | ||
| get_root(const rb_ifaddr_t *ifaddr) | ||
| { | ||
|     return (rb_ifaddr_root_t *)((char *)&ifaddr[-ifaddr->ord] - | ||
|                                 offsetof(rb_ifaddr_root_t, ary)); | ||
| } | ||
| static void | ||
| ifaddr_mark(void *ptr) | ||
| { | ||
| } | ||
| static void | ||
| ifaddr_free(void *ptr) | ||
| { | ||
|     rb_ifaddr_t *ifaddr = ptr; | ||
|     rb_ifaddr_root_t *root = get_root(ifaddr); | ||
|     root->refcount--; | ||
|     if (root->refcount == 0) { | ||
|         freeifaddrs(root->ary[0].ifaddr); | ||
|         xfree(root); | ||
|     } | ||
| } | ||
| static size_t | ||
| ifaddr_memsize(const void *ptr) | ||
| { | ||
|     const rb_ifaddr_t *ifaddr; | ||
|     const rb_ifaddr_root_t *root; | ||
|     if (ptr == NULL) | ||
|         return 0; | ||
|     ifaddr = ptr; | ||
|     root = get_root(ifaddr); | ||
|     return sizeof(rb_ifaddr_root_t) + (root->numifaddrs - 1) * sizeof(rb_ifaddr_t); | ||
| } | ||
| static const rb_data_type_t ifaddr_type = { | ||
|     "socket/ifaddr", | ||
|     {ifaddr_mark, ifaddr_free, ifaddr_memsize,}, | ||
| }; | ||
| #define IS_IFADDRS(obj) rb_typeddata_is_kind_of((obj), &ifaddr_type) | ||
| static inline rb_ifaddr_t * | ||
| check_ifaddr(VALUE self) | ||
| { | ||
|       return rb_check_typeddata(self, &ifaddr_type); | ||
| } | ||
| static rb_ifaddr_t * | ||
| get_ifaddr(VALUE self) | ||
| { | ||
|     rb_ifaddr_t *rifaddr = check_ifaddr(self); | ||
|     if (!rifaddr) { | ||
|         rb_raise(rb_eTypeError, "uninitialized ifaddr"); | ||
|     } | ||
|     return rifaddr; | ||
| } | ||
| static VALUE | ||
| rsock_getifaddrs(void) | ||
| { | ||
|     int ret; | ||
|     int numifaddrs, i; | ||
|     struct ifaddrs *ifaddrs, *ifa; | ||
|     rb_ifaddr_root_t *root; | ||
|     VALUE result; | ||
|     ret = getifaddrs(&ifaddrs); | ||
|     if (ret == -1) | ||
|         rb_sys_fail("getifaddrs"); | ||
|     numifaddrs = 0; | ||
|     for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) | ||
|         numifaddrs++; | ||
|     root = xmalloc(sizeof(rb_ifaddr_root_t) + (numifaddrs-1) * sizeof(rb_ifaddr_t)); | ||
|     root->refcount = root->numifaddrs = numifaddrs; | ||
|     ifa = ifaddrs; | ||
|     for (i = 0; i < numifaddrs; i++) { | ||
|         root->ary[i].ord = i; | ||
|         root->ary[i].ifaddr = ifa; | ||
|         root->ary[i].root = root; | ||
|         ifa = ifa->ifa_next; | ||
|     } | ||
|     result = rb_ary_new2(numifaddrs); | ||
|     for (i = 0; i < numifaddrs; i++) { | ||
|         rb_ary_push(result, TypedData_Wrap_Struct(rb_cSockIfaddr, &ifaddr_type, &root->ary[i])); | ||
|     } | ||
|     return result; | ||
| } | ||
| /* | ||
|  * call-seq: | ||
|  *   getifaddr.name => string | ||
|  * | ||
|  * Returns the interface name of _getifaddr_. | ||
|  */ | ||
| static VALUE | ||
| ifaddr_name(VALUE self) | ||
| { | ||
|     rb_ifaddr_t *rifaddr = get_ifaddr(self); | ||
|     struct ifaddrs *ifa = rifaddr->ifaddr; | ||
|     return rb_str_new_cstr(ifa->ifa_name); | ||
| } | ||
| /* | ||
|  * call-seq: | ||
|  *   getifaddr.ifindex => integer | ||
|  * | ||
|  * Returns the interface index of _getifaddr_. | ||
|  */ | ||
| static VALUE | ||
| ifaddr_ifindex(VALUE self) | ||
| { | ||
|     rb_ifaddr_t *rifaddr = get_ifaddr(self); | ||
|     struct ifaddrs *ifa = rifaddr->ifaddr; | ||
|     unsigned int ifindex = if_nametoindex(ifa->ifa_name); | ||
|     if (ifindex == 0) { | ||
|         rb_raise(rb_eArgError, "invalid interface name: %s", ifa->ifa_name); | ||
|     } | ||
|     return UINT2NUM(ifindex); | ||
| } | ||
| /* | ||
|  * call-seq: | ||
|  *   getifaddr.flags => integer | ||
|  * | ||
|  * Returns the flags of _getifaddr_. | ||
|  */ | ||
| static VALUE | ||
| ifaddr_flags(VALUE self) | ||
| { | ||
|     rb_ifaddr_t *rifaddr = get_ifaddr(self); | ||
|     struct ifaddrs *ifa = rifaddr->ifaddr; | ||
|     return UINT2NUM(ifa->ifa_flags); | ||
| } | ||
| /* | ||
|  * call-seq: | ||
|  *   getifaddr.addr => addrinfo | ||
|  * | ||
|  * Returns the address of _getifaddr_. | ||
|  * nil is returned if address is not available in _getifaddr_. | ||
|  */ | ||
| static VALUE | ||
| ifaddr_addr(VALUE self) | ||
| { | ||
|     rb_ifaddr_t *rifaddr = get_ifaddr(self); | ||
|     struct ifaddrs *ifa = rifaddr->ifaddr; | ||
|     if (ifa->ifa_addr) | ||
|         return rsock_sockaddr_obj(ifa->ifa_addr, rsock_sockaddr_len(ifa->ifa_addr)); | ||
|     return Qnil; | ||
| } | ||
| /* | ||
|  * call-seq: | ||
|  *   getifaddr.netmask => addrinfo | ||
|  * | ||
|  * Returns the netmask address of _getifaddr_. | ||
|  * nil is returned if netmask is not available in _getifaddr_. | ||
|  */ | ||
| static VALUE | ||
| ifaddr_netmask(VALUE self) | ||
| { | ||
|     rb_ifaddr_t *rifaddr = get_ifaddr(self); | ||
|     struct ifaddrs *ifa = rifaddr->ifaddr; | ||
|     if (ifa->ifa_netmask) | ||
|         return rsock_sockaddr_obj(ifa->ifa_netmask, rsock_sockaddr_len(ifa->ifa_netmask)); | ||
|     return Qnil; | ||
| } | ||
| /* | ||
|  * call-seq: | ||
|  *   getifaddr.broadaddr => addrinfo | ||
|  * | ||
|  * Returns the broadcast address of _getifaddr_. | ||
|  * nil is returned if the flags doesn't have IFF_BROADCAST. | ||
|  */ | ||
| static VALUE | ||
| ifaddr_broadaddr(VALUE self) | ||
| { | ||
|     rb_ifaddr_t *rifaddr = get_ifaddr(self); | ||
|     struct ifaddrs *ifa = rifaddr->ifaddr; | ||
|     if ((ifa->ifa_flags & IFF_BROADCAST) && ifa->ifa_broadaddr) | ||
|         return rsock_sockaddr_obj(ifa->ifa_broadaddr, rsock_sockaddr_len(ifa->ifa_broadaddr)); | ||
|     return Qnil; | ||
| } | ||
| /* | ||
|  * call-seq: | ||
|  *   getifaddr.dstaddr => addrinfo | ||
|  * | ||
|  * Returns the destination address of _getifaddr_. | ||
|  * nil is returned if the flags doesn't have IFF_POINTOPOINT. | ||
|  */ | ||
| static VALUE | ||
| ifaddr_dstaddr(VALUE self) | ||
| { | ||
|     rb_ifaddr_t *rifaddr = get_ifaddr(self); | ||
|     struct ifaddrs *ifa = rifaddr->ifaddr; | ||
|     if ((ifa->ifa_flags & IFF_POINTOPOINT) && ifa->ifa_dstaddr) | ||
|         return rsock_sockaddr_obj(ifa->ifa_dstaddr, rsock_sockaddr_len(ifa->ifa_dstaddr)); | ||
|     return Qnil; | ||
| } | ||
| static void | ||
| ifaddr_inspect_flags(unsigned int flags, VALUE result) | ||
| { | ||
|     char *sep = " "; | ||
| #define INSPECT_BIT(bit, name) \ | ||
|     if (flags & (bit)) { rb_str_catf(result, "%s" name, sep); flags &= ~(bit); sep = ","; } | ||
| #ifdef IFF_UP | ||
|     INSPECT_BIT(IFF_UP, "UP") | ||
| #endif | ||
| #ifdef IFF_BROADCAST | ||
|     INSPECT_BIT(IFF_BROADCAST, "BROADCAST") | ||
| #endif | ||
| #ifdef IFF_DEBUG | ||
|     INSPECT_BIT(IFF_DEBUG, "DEBUG") | ||
| #endif | ||
| #ifdef IFF_LOOPBACK | ||
|     INSPECT_BIT(IFF_LOOPBACK, "LOOPBACK") | ||
| #endif | ||
| #ifdef IFF_POINTOPOINT | ||
|     INSPECT_BIT(IFF_POINTOPOINT, "POINTOPOINT") | ||
| #endif | ||
| #ifdef IFF_RUNNING | ||
|     INSPECT_BIT(IFF_RUNNING, "RUNNING") | ||
| #endif | ||
| #ifdef IFF_NOARP | ||
|     INSPECT_BIT(IFF_NOARP, "NOARP") | ||
| #endif | ||
| #ifdef IFF_PROMISC | ||
|     INSPECT_BIT(IFF_PROMISC, "PROMISC") | ||
| #endif | ||
| #ifdef IFF_NOTRAILERS | ||
|     INSPECT_BIT(IFF_NOTRAILERS, "NOTRAILERS") | ||
| #endif | ||
| #ifdef IFF_ALLMULTI | ||
|     INSPECT_BIT(IFF_ALLMULTI, "ALLMULTI") | ||
| #endif | ||
| #ifdef IFF_MASTER | ||
|     INSPECT_BIT(IFF_MASTER, "MASTER") | ||
| #endif | ||
| #ifdef IFF_SLAVE | ||
|     INSPECT_BIT(IFF_SLAVE, "SLAVE") | ||
| #endif | ||
| #ifdef IFF_MULTICAST | ||
|     INSPECT_BIT(IFF_MULTICAST, "MULTICAST") | ||
| #endif | ||
| #ifdef IFF_PORTSEL | ||
|     INSPECT_BIT(IFF_PORTSEL, "PORTSEL") | ||
| #endif | ||
| #ifdef IFF_AUTOMEDIA | ||
|     INSPECT_BIT(IFF_AUTOMEDIA, "AUTOMEDIA") | ||
| #endif | ||
| #ifdef IFF_DYNAMIC | ||
|     INSPECT_BIT(IFF_DYNAMIC, "DYNAMIC") | ||
| #endif | ||
| #ifdef IFF_LOWER_UP | ||
|     INSPECT_BIT(IFF_LOWER_UP, "LOWER_UP") | ||
| #endif | ||
| #ifdef IFF_DORMANT | ||
|     INSPECT_BIT(IFF_DORMANT, "DORMANT") | ||
| #endif | ||
| #ifdef IFF_ECHO | ||
|     INSPECT_BIT(IFF_ECHO, "ECHO") | ||
| #endif | ||
| #undef INSPECT_BIT | ||
|     if (flags) { | ||
|         rb_str_catf(result, "%s%#x", sep, flags); | ||
|     } | ||
| } | ||
| /* | ||
|  * call-seq: | ||
|  *   getifaddr.inspect => string | ||
|  * | ||
|  * Returns a string to show contents of _getifaddr_. | ||
|  */ | ||
| static VALUE | ||
| ifaddr_inspect(VALUE self) | ||
| { | ||
|     rb_ifaddr_t *rifaddr = get_ifaddr(self); | ||
|     struct ifaddrs *ifa; | ||
|     VALUE result; | ||
|     ifa = rifaddr->ifaddr; | ||
|     result = rb_str_new_cstr("#<"); | ||
|     rb_str_append(result, rb_class_name(CLASS_OF(self))); | ||
|     rb_str_cat2(result, " "); | ||
|     rb_str_cat2(result, ifa->ifa_name); | ||
|     if (ifa->ifa_flags) | ||
|         ifaddr_inspect_flags(ifa->ifa_flags, result); | ||
|     if (ifa->ifa_addr) { | ||
|       rb_str_cat2(result, " ["); | ||
|       rsock_inspect_sockaddr(ifa->ifa_addr, | ||
|           rsock_sockaddr_len(ifa->ifa_addr), | ||
|           result); | ||
|       rb_str_cat2(result, "]"); | ||
|     } | ||
|     if (ifa->ifa_netmask) { | ||
|       rb_str_cat2(result, " netmask:["); | ||
|       rsock_inspect_sockaddr(ifa->ifa_netmask, | ||
|           rsock_sockaddr_len(ifa->ifa_netmask), | ||
|           result); | ||
|       rb_str_cat2(result, "]"); | ||
|     } | ||
|     if ((ifa->ifa_flags & IFF_BROADCAST) && ifa->ifa_broadaddr) { | ||
|       rb_str_cat2(result, " broadcast:["); | ||
|       rsock_inspect_sockaddr(ifa->ifa_broadaddr, | ||
|           rsock_sockaddr_len(ifa->ifa_broadaddr), | ||
|           result); | ||
|       rb_str_cat2(result, "]"); | ||
|     } | ||
|     if ((ifa->ifa_flags & IFF_POINTOPOINT) && ifa->ifa_dstaddr) { | ||
|       rb_str_cat2(result, " dstaddr:["); | ||
|       rsock_inspect_sockaddr(ifa->ifa_dstaddr, | ||
|           rsock_sockaddr_len(ifa->ifa_dstaddr), | ||
|           result); | ||
|       rb_str_cat2(result, "]"); | ||
|     } | ||
|     rb_str_cat2(result, ">"); | ||
|     return result; | ||
| } | ||
| /* | ||
|  * call-seq: | ||
|  *   Socket.getifaddrs => [ifaddr1, ...] | ||
|  * | ||
|  * Returns an array of interface addresses. | ||
|  * An element of the array is an instance of Socket::Ifaddr. | ||
|  * | ||
|  * This method can be used to find multicast-enabled interfaces: | ||
|  * | ||
|  *   pp Socket.getifaddrs.reject {|ifaddr| | ||
|  *     !ifaddr.addr.ip? || (ifaddr.flags & Socket::IFF_MULTICAST == 0) | ||
|  *   }.map {|ifaddr| [ifaddr.name, ifaddr.ifindex, ifaddr.addr] } | ||
|  *   #=> [["eth0", 2, #<Addrinfo: 221.186.184.67>], | ||
|  *   #    ["eth0", 2, #<Addrinfo: fe80::216:3eff:fe95:88bb%eth0>]] | ||
|  * | ||
|  * Example result on GNU/Linux: | ||
|  *   pp Socket.getifaddrs | ||
|  *   #=> [#<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 [PACKET protocol:0 lo hatype:772 HOST hwaddr:00:00:00:00:00:00]>, | ||
|  *   #    #<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]>, | ||
|  *   #    #<Socket::Ifaddr sit0 NOARP [PACKET protocol:0 sit0 hatype:776 HOST hwaddr:00:00:00:00]>, | ||
|  *   #    #<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 [127.0.0.1] netmask:[255.0.0.0]>, | ||
|  *   #    #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 [221.186.184.67] netmask:[255.255.255.240] broadcast:[221.186.184.79]>, | ||
|  *   #    #<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 [::1] netmask:[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]>, | ||
|  *   #    #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 [fe80::216:3eff:fe95:88bb%eth0] netmask:[ffff:ffff:ffff:ffff::]>] | ||
|  * | ||
|  * Example result on FreeBSD: | ||
|  *   pp Socket.getifaddrs' | ||
|  *   #=> [#<Socket::Ifaddr usbus0 UP,0x10000 [LINK usbus0]>, | ||
|  *   #    #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 [LINK re0 3a:d0:40:9a:fe:e8]>, | ||
|  *   #    #<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]>, | ||
|  *   #    #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 [fe80:2::38d0:40ff:fe9a:fee8] netmask:[ffff:ffff:ffff:ffff::]>, | ||
|  *   #    #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 [2001:2e8:408:10::12] netmask:[UNSPEC]>, | ||
|  *   #    #<Socket::Ifaddr plip0 POINTOPOINT,MULTICAST,0x800 [LINK plip0]>, | ||
|  *   #    #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST [LINK lo0]>, | ||
|  *   #    #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST [::1] netmask:[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]>, | ||
|  *   #    #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST [fe80:4::1] netmask:[ffff:ffff:ffff:ffff::]>, | ||
|  *   #    #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST [127.0.0.1] netmask:[255.?.?.? (5 bytes for 16 bytes sockaddr_in)]>] | ||
|  */ | ||
| static VALUE | ||
| socket_s_getifaddrs(VALUE self) | ||
| { | ||
|     return rsock_getifaddrs(); | ||
| } | ||
| void | ||
| rsock_init_sockifaddr(void) | ||
| { | ||
|     /* | ||
|      * Document-class: Socket::Ifaddr | ||
|      * | ||
|      * Socket::Ifaddr represents a result of getifaddrs() function. | ||
|      */ | ||
|     rb_cSockIfaddr = rb_define_class_under(rb_cSocket, "Ifaddr", rb_cData); | ||
|     rb_define_method(rb_cSockIfaddr, "inspect", ifaddr_inspect, 0); | ||
|     rb_define_method(rb_cSockIfaddr, "name", ifaddr_name, 0); | ||
|     rb_define_method(rb_cSockIfaddr, "ifindex", ifaddr_ifindex, 0); | ||
|     rb_define_method(rb_cSockIfaddr, "flags", ifaddr_flags, 0); | ||
|     rb_define_method(rb_cSockIfaddr, "addr", ifaddr_addr, 0); | ||
|     rb_define_method(rb_cSockIfaddr, "netmask", ifaddr_netmask, 0); | ||
|     rb_define_method(rb_cSockIfaddr, "broadaddr", ifaddr_broadaddr, 0); | ||
|     rb_define_method(rb_cSockIfaddr, "dstaddr", ifaddr_dstaddr, 0); | ||
|     rb_define_singleton_method(rb_cSocket, "getifaddrs", socket_s_getifaddrs, 0); | ||
| } | ||
| ext/socket/init.c | ||
|---|---|---|
|     rsock_init_sockopt(); | ||
|     rsock_init_ancdata(); | ||
|     rsock_init_addrinfo(); | ||
|     rsock_init_sockifaddr(); | ||
|     rsock_init_socket_constants(); | ||
| } | ||
| ext/socket/mkconstants.rb | ||
|---|---|---|
| LOCAL_PEERCRED	nil	Retrieve peer credentials | ||
| LOCAL_CREDS	nil	Pass credentials to receiver | ||
| LOCAL_CONNWAIT	nil	Connect blocks until accepted | ||
| IFF_802_1Q_VLAN      nil 802.1Q VLAN device | ||
| IFF_ALLMULTI         nil receive all multicast packets | ||
| IFF_ALTPHYS          nil use alternate physical connection | ||
| IFF_AUTOMEDIA        nil auto media select active | ||
| IFF_BONDING          nil bonding master or slave | ||
| IFF_BRIDGE_PORT      nil device used as bridge port | ||
| IFF_BROADCAST        nil broadcast address valid | ||
| IFF_CANTCONFIG       nil unconfigurable using ioctl(2) | ||
| IFF_DEBUG            nil turn on debugging | ||
| IFF_DISABLE_NETPOLL  nil disable netpoll at run-time | ||
| IFF_DONT_BRIDGE      nil disallow bridging this ether dev | ||
| IFF_DORMANT          nil driver signals dormant | ||
| IFF_DRV_OACTIVE      nil tx hardware queue is full | ||
| IFF_DRV_RUNNING      nil resources allocated | ||
| IFF_DYING            nil interface is winding down | ||
| IFF_DYNAMIC          nil dialup device with changing addresses | ||
| IFF_EBRIDGE          nil ethernet bridging device | ||
| IFF_ECHO             nil echo sent packets | ||
| IFF_ISATAP           nil ISATAP interface (RFC4214) | ||
| IFF_LINK0            nil per link layer defined bit 0 | ||
| IFF_LINK1            nil per link layer defined bit 1 | ||
| IFF_LINK2            nil per link layer defined bit 2 | ||
| IFF_LIVE_ADDR_CHANGE nil hardware address change when it's running | ||
| IFF_LOOPBACK         nil loopback net | ||
| IFF_LOWER_UP         nil driver signals L1 up | ||
| IFF_MACVLAN_PORT     nil device used as macvlan port | ||
| IFF_MASTER           nil master of a load balancer | ||
| IFF_MASTER_8023AD    nil bonding master, 802.3ad. | ||
| IFF_MASTER_ALB       nil bonding master, balance-alb. | ||
| IFF_MASTER_ARPMON    nil bonding master, ARP mon in use | ||
| IFF_MONITOR          nil user-requested monitor mode | ||
| IFF_MULTICAST        nil supports multicast | ||
| IFF_NOARP            nil no address resolution protocol | ||
| IFF_NOTRAILERS       nil avoid use of trailers | ||
| IFF_OACTIVE          nil transmission in progress | ||
| IFF_OVS_DATAPATH     nil device used as Open vSwitch datapath port | ||
| IFF_POINTOPOINT      nil point-to-point link | ||
| IFF_PORTSEL          nil can set media type | ||
| IFF_PPROMISC         nil user-requested promisc mode | ||
| IFF_PROMISC          nil receive all packets | ||
| IFF_RENAMING         nil interface is being renamed | ||
| IFF_ROUTE            nil routing entry installed | ||
| IFF_RUNNING          nil resources allocated | ||
| IFF_SIMPLEX          nil can't hear own transmissions | ||
| IFF_SLAVE            nil slave of a load balancer | ||
| IFF_SLAVE_INACTIVE   nil bonding slave not the curr. active | ||
| IFF_SLAVE_NEEDARP    nil need ARPs for validation | ||
| IFF_SMART            nil interface manages own routes | ||
| IFF_STATICARP        nil static ARP | ||
| IFF_SUPP_NOFCS       nil sending custom FCS | ||
| IFF_TEAM_PORT        nil used as team port | ||
| IFF_TX_SKB_SHARING   nil sharing skbs on transmit | ||
| IFF_UNICAST_FLT      nil unicast filtering | ||
| IFF_UP               nil interface is up | ||
| IFF_WAN_HDLC         nil WAN HDLC device | ||
| IFF_XMIT_DST_RELEASE nil dev_hard_start_xmit() is allowed to release skb->dst | ||
| IFF_VOLATILE         nil volatile flags | ||
| IFF_CANTCHANGE       nil flags not changeable | ||
| ext/socket/raddrinfo.c | ||
|---|---|---|
| inspect_sockaddr(VALUE addrinfo, VALUE ret) | ||
| { | ||
|     rb_addrinfo_t *rai = get_addrinfo(addrinfo); | ||
|     union_sockaddr *sockaddr = &rai->addr; | ||
|     socklen_t socklen = rai->sockaddr_len; | ||
|     return rsock_inspect_sockaddr((struct sockaddr *)sockaddr, socklen, ret); | ||
| } | ||
|     if (rai->sockaddr_len == 0) { | ||
| VALUE | ||
| rsock_inspect_sockaddr(struct sockaddr *sockaddr_arg, socklen_t socklen, VALUE ret) | ||
| { | ||
|     union_sockaddr *sockaddr = (union_sockaddr *)sockaddr_arg; | ||
|     if (socklen == 0) { | ||
|         rb_str_cat2(ret, "empty-sockaddr"); | ||
|     } | ||
|     else if ((long)rai->sockaddr_len < ((char*)&rai->addr.addr.sa_family + sizeof(rai->addr.addr.sa_family)) - (char*)&rai->addr) | ||
|     else if ((long)socklen < ((char*)&sockaddr->addr.sa_family + sizeof(sockaddr->addr.sa_family)) - (char*)sockaddr) | ||
|         rb_str_cat2(ret, "too-short-sockaddr"); | ||
|     else { | ||
|         switch (rai->addr.addr.sa_family) { | ||
|         switch (sockaddr->addr.sa_family) { | ||
|           case AF_UNSPEC: | ||
| 	  { | ||
| 	    rb_str_cat2(ret, "UNSPEC"); | ||
|             break; | ||
| 	  } | ||
|           case AF_INET: | ||
|           { | ||
|             struct sockaddr_in *addr; | ||
|             int port; | ||
|             if (rai->sockaddr_len < (socklen_t)sizeof(struct sockaddr_in)) { | ||
|                 rb_str_cat2(ret, "too-short-AF_INET-sockaddr"); | ||
|             } | ||
|             else { | ||
|                 addr = &rai->addr.in; | ||
|                 rb_str_catf(ret, "%d.%d.%d.%d", | ||
|                             ((unsigned char*)&addr->sin_addr)[0], | ||
|                             ((unsigned char*)&addr->sin_addr)[1], | ||
|                             ((unsigned char*)&addr->sin_addr)[2], | ||
|                             ((unsigned char*)&addr->sin_addr)[3]); | ||
|                 port = ntohs(addr->sin_port); | ||
|                 if (port) | ||
|                     rb_str_catf(ret, ":%d", port); | ||
|                 if ((socklen_t)sizeof(struct sockaddr_in) < rai->sockaddr_len) | ||
|                     rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(rai->sockaddr_len - sizeof(struct sockaddr_in))); | ||
|             } | ||
| 	    addr = &sockaddr->in; | ||
| 	    if (((char*)&addr->sin_addr)-(char*)addr+0+1 <= socklen) | ||
| 		rb_str_catf(ret, "%d", ((unsigned char*)&addr->sin_addr)[0]); | ||
| 	    else | ||
| 		rb_str_cat2(ret, "?"); | ||
| 	    if (((char*)&addr->sin_addr)-(char*)addr+1+1 <= socklen) | ||
| 		rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[1]); | ||
| 	    else | ||
| 		rb_str_cat2(ret, ".?"); | ||
| 	    if (((char*)&addr->sin_addr)-(char*)addr+2+1 <= socklen) | ||
| 		rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[2]); | ||
| 	    else | ||
| 		rb_str_cat2(ret, ".?"); | ||
| 	    if (((char*)&addr->sin_addr)-(char*)addr+3+1 <= socklen) | ||
| 		rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[3]); | ||
| 	    else | ||
| 		rb_str_cat2(ret, ".?"); | ||
| 	    if (((char*)&addr->sin_port)-(char*)addr+sizeof(addr->sin_port) < socklen) { | ||
| 		port = ntohs(addr->sin_port); | ||
| 		if (port) | ||
| 		    rb_str_catf(ret, ":%d", port); | ||
| 	    } | ||
| 	    else { | ||
| 		rb_str_cat2(ret, ":?"); | ||
| 	    } | ||
| 	    if ((socklen_t)sizeof(struct sockaddr_in) != socklen) | ||
| 		rb_str_catf(ret, " (%d bytes for %d bytes sockaddr_in)", | ||
| 		  (int)socklen, | ||
| 		  (int)sizeof(struct sockaddr_in)); | ||
|             break; | ||
|           } | ||
| ... | ... | |
|             char hbuf[1024]; | ||
|             int port; | ||
|             int error; | ||
|             if (rai->sockaddr_len < (socklen_t)sizeof(struct sockaddr_in6)) { | ||
|                 rb_str_cat2(ret, "too-short-AF_INET6-sockaddr"); | ||
|             if (socklen < (socklen_t)sizeof(struct sockaddr_in6)) { | ||
|                 rb_str_catf(ret, "too-short-AF_INET6-sockaddr %d bytes", (int)socklen); | ||
|             } | ||
|             else { | ||
|                 addr = &rai->addr.in6; | ||
|                 addr = &sockaddr->in6; | ||
|                 /* use getnameinfo for scope_id. | ||
|                  * RFC 4007: IPv6 Scoped Address Architecture | ||
|                  * draft-ietf-ipv6-scope-api-00.txt: Scoped Address Extensions to the IPv6 Basic Socket API | ||
|                  */ | ||
|                 error = getnameinfo(&rai->addr.addr, rai->sockaddr_len, | ||
|                 error = getnameinfo(&sockaddr->addr, socklen, | ||
|                                     hbuf, (socklen_t)sizeof(hbuf), NULL, 0, | ||
|                                     NI_NUMERICHOST|NI_NUMERICSERV); | ||
|                 if (error) { | ||
| ... | ... | |
|                     port = ntohs(addr->sin6_port); | ||
|                     rb_str_catf(ret, "[%s]:%d", hbuf, port); | ||
|                 } | ||
|                 if ((socklen_t)sizeof(struct sockaddr_in6) < rai->sockaddr_len) | ||
|                     rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(rai->sockaddr_len - sizeof(struct sockaddr_in6))); | ||
|                 if ((socklen_t)sizeof(struct sockaddr_in6) < socklen) | ||
|                     rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(socklen - sizeof(struct sockaddr_in6))); | ||
|             } | ||
|             break; | ||
|           } | ||
| ... | ... | |
| #ifdef HAVE_SYS_UN_H | ||
|           case AF_UNIX: | ||
|           { | ||
|             struct sockaddr_un *addr = &rai->addr.un; | ||
|             struct sockaddr_un *addr = &sockaddr->un; | ||
|             char *p, *s, *e; | ||
|             s = addr->sun_path; | ||
|             e = (char*)addr + rai->sockaddr_len; | ||
|             e = (char*)addr + socklen; | ||
|             while (s < e && *(e-1) == '\0') | ||
|                 e--; | ||
|             if (e < s) | ||
| ... | ... | |
|                 } | ||
|                 if (printable_only) { /* only printable, no space */ | ||
|                     if (s[0] != '/') /* relative path */ | ||
|                         rb_str_cat2(ret, "AF_UNIX "); | ||
|                         rb_str_cat2(ret, "UNIX "); | ||
|                     rb_str_cat(ret, s, p - s); | ||
|                 } | ||
|                 else { | ||
|                     rb_str_cat2(ret, "AF_UNIX"); | ||
|                     rb_str_cat2(ret, "UNIX"); | ||
|                     while (s < e) | ||
|                         rb_str_catf(ret, ":%02x", (unsigned char)*s++); | ||
|                 } | ||
| ... | ... | |
|           } | ||
| #endif | ||
| #ifdef AF_PACKET | ||
|           /* GNU/Linux */ | ||
|           case AF_PACKET: | ||
|           { | ||
|             struct sockaddr_ll *addr; | ||
|             addr = (struct sockaddr_ll *)sockaddr; | ||
|             rb_str_cat2(ret, "PACKET"); | ||
|             if (offsetof(struct sockaddr_ll, sll_protocol) + sizeof(addr->sll_protocol) <= socklen) { | ||
|                 rb_str_catf(ret, " protocol:%d", ntohs(addr->sll_protocol)); | ||
|             } | ||
|             if (offsetof(struct sockaddr_ll, sll_ifindex) + sizeof(addr->sll_ifindex) <= socklen) { | ||
|                 char buf[IFNAMSIZ]; | ||
|                 if (if_indextoname(addr->sll_ifindex, buf) == NULL) | ||
|                     rb_str_catf(ret, " ifindex:%d", addr->sll_ifindex); | ||
|                 else | ||
|                     rb_str_catf(ret, " %s", buf); | ||
|             } | ||
|             if (offsetof(struct sockaddr_ll, sll_hatype) + sizeof(addr->sll_hatype) <= socklen) { | ||
|                 rb_str_catf(ret, " hatype:%d", addr->sll_hatype); | ||
|             } | ||
|             if (offsetof(struct sockaddr_ll, sll_pkttype) + sizeof(addr->sll_pkttype) <= socklen) { | ||
|                 if (addr->sll_pkttype == PACKET_HOST) | ||
|                     rb_str_cat2(ret, " HOST"); | ||
|                 else if (addr->sll_pkttype == PACKET_BROADCAST) | ||
|                     rb_str_cat2(ret, " BROADCAST"); | ||
|                 else if (addr->sll_pkttype == PACKET_MULTICAST) | ||
|                     rb_str_cat2(ret, " MULTICAST"); | ||
|                 else if (addr->sll_pkttype == PACKET_OTHERHOST) | ||
|                     rb_str_cat2(ret, " OTHERHOST"); | ||
|                 else if (addr->sll_pkttype == PACKET_OUTGOING) | ||
|                     rb_str_cat2(ret, " OUTGOING"); | ||
|                 else | ||
|                     rb_str_catf(ret, " pkttype:%d", addr->sll_pkttype); | ||
|             } | ||
|             if (socklen != (socklen_t)(offsetof(struct sockaddr_ll, sll_addr) + addr->sll_halen)) { | ||
|                 if (offsetof(struct sockaddr_ll, sll_halen) + sizeof(addr->sll_halen) <= socklen) { | ||
|                     rb_str_catf(ret, " halen:%d", addr->sll_halen); | ||
|                 } | ||
|             } | ||
|             if (offsetof(struct sockaddr_ll, sll_addr) < socklen) { | ||
|                 socklen_t len, i; | ||
|                 rb_str_cat2(ret, " hwaddr"); | ||
|                 len = addr->sll_halen; | ||
|                 if (socklen < offsetof(struct sockaddr_ll, sll_addr) + len) | ||
|                     len = socklen - offsetof(struct sockaddr_ll, sll_addr); | ||
|                 for (i = 0; i < len; i++) { | ||
|                     rb_str_catf(ret, ":%02x", addr->sll_addr[i]); | ||
|                 } | ||
|             } | ||
|             if (socklen < (socklen_t)(offsetof(struct sockaddr_ll, sll_halen) + sizeof(addr->sll_halen)) || | ||
|                 (socklen_t)(offsetof(struct sockaddr_ll, sll_addr) + addr->sll_halen) != socklen) | ||
|                 rb_str_catf(ret, " (%d bytes for %d bytes sockaddr_ll)", | ||
|                     (int)socklen, (int)sizeof(struct sockaddr_ll)); | ||
|             break; | ||
|           } | ||
| #endif | ||
| #ifdef AF_LINK | ||
| 	  /* AF_LINK is defined in 4.4BSD derivations since Net2. | ||
| 	     link_ntoa is also defined at Net2. | ||
|              However Debian GNU/kFreeBSD defines AF_LINK but | ||
|              don't have link_ntoa.  */ | ||
|           case AF_LINK: | ||
| 	  { | ||
| 	    /* | ||
| 	     * Simple implementation using link_ntoa(): | ||
| 	     * This doesn't work on Debian GNU/kFreeBSD 6.0.7 (squeeze). | ||
|              * Also, the format is bit different. | ||
| 	     * | ||
| 	     * rb_str_catf(ret, "LINK %s", link_ntoa(&sockaddr->dl)); | ||
| 	     * break; | ||
| 	     */ | ||
|             struct sockaddr_dl *addr = &sockaddr->dl; | ||
|             char *np = NULL, *ap = NULL, *endp; | ||
|             int nlen = 0, alen = 0; | ||
|             int i, off; | ||
|             endp = ((char *)addr) + socklen; | ||
|             rb_str_cat2(ret, "LINK"); | ||
|             if (offsetof(struct sockaddr_dl, sdl_data) < socklen) { | ||
|                 np = addr->sdl_data; | ||
|                 nlen = addr->sdl_nlen; | ||
|                 if (endp - np < nlen) | ||
|                     nlen = endp - np; | ||
|             } | ||
|             off = addr->sdl_nlen; | ||
|             if (offsetof(struct sockaddr_dl, sdl_data) + off < socklen) { | ||
|                 ap = addr->sdl_data + off; | ||
|                 alen = addr->sdl_alen; | ||
|                 if (endp - ap < alen) | ||
|                     alen = endp - ap; | ||
|             } | ||
|             if (np) | ||
|                 rb_str_catf(ret, " %.*s", nlen, np); | ||
|             else | ||
|                 rb_str_cat2(ret, " ?"); | ||
|             if (ap) { | ||
|                 for (i = 0; i < alen; i++) | ||
|                     rb_str_catf(ret, "%s%02x", i == 0 ? " " : ":", (unsigned char)ap[i]); | ||
|             } | ||
|             if (socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_nlen) + sizeof(addr->sdl_nlen)) || | ||
|                 socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_alen) + sizeof(addr->sdl_alen)) || | ||
|                 socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_slen) + sizeof(addr->sdl_slen)) || | ||
|                 /* longer length is possible behavior because struct sockaddr_dl has "minimum work area, can be larger" as the last field. | ||
|                  * cf. Net2:/usr/src/sys/net/if_dl.h. */ | ||
|                 socklen < (socklen_t)(offsetof(struct sockaddr_dl, sdl_data) + addr->sdl_nlen + addr->sdl_alen + addr->sdl_slen)) | ||
|                 rb_str_catf(ret, " (%d bytes for %d bytes sockaddr_dl)", | ||
|                     (int)socklen, (int)sizeof(struct sockaddr_dl)); | ||
|             break; | ||
|           } | ||
| #endif | ||
|           default: | ||
|           { | ||
|             ID id = rsock_intern_family(rai->addr.addr.sa_family); | ||
|             ID id = rsock_intern_family(sockaddr->addr.sa_family); | ||
|             if (id == 0) | ||
|                 rb_str_catf(ret, "unknown address family %d", rai->addr.addr.sa_family); | ||
|                 rb_str_catf(ret, "unknown address family %d", sockaddr->addr.sa_family); | ||
|             else | ||
|                 rb_str_catf(ret, "%s address format unknown", rb_id2name(id)); | ||
|             break; | ||
| ext/socket/rubysocket.h | ||
|---|---|---|
| #  include <netdb.h> | ||
| #endif | ||
| #ifdef HAVE_NETPACKET_PACKET_H | ||
| #  include <netpacket/packet.h> | ||
| #endif | ||
| #ifdef HAVE_NET_ETHERNET_H | ||
| #  include <net/ethernet.h> | ||
| #endif | ||
| #include <errno.h> | ||
| #ifdef HAVE_SYS_UN_H | ||
| ... | ... | |
| #ifdef HAVE_UCRED_H | ||
| #  include <ucred.h> | ||
| #endif | ||
| #ifdef HAVE_NET_IF_DL_H | ||
| #  include <net/if_dl.h> | ||
| #endif | ||
| #ifndef HAVE_TYPE_SOCKLEN_T | ||
| typedef int socklen_t; | ||
| ... | ... | |
| #ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN | ||
|   struct sockaddr_un un; | ||
| #endif | ||
| #ifdef HAVE_TYPE_STRUCT_SOCKADDR_DL | ||
|   struct sockaddr_dl dl; /* AF_LINK */ | ||
| #endif | ||
|   struct sockaddr_storage storage; | ||
|   char place_holder[2048]; /* sockaddr_storage is not enough for Unix domain sockets on SunOS and Darwin. */ | ||
| } union_sockaddr; | ||
| ... | ... | |
| VALUE rsock_make_ipaddr(struct sockaddr *addr, socklen_t addrlen); | ||
| VALUE rsock_ipaddr(struct sockaddr *sockaddr, socklen_t sockaddrlen, int norevlookup); | ||
| VALUE rsock_make_hostent(VALUE host, struct addrinfo *addr, VALUE (*ipaddr)(struct sockaddr *, socklen_t)); | ||
| VALUE rsock_inspect_sockaddr(struct sockaddr *addr, socklen_t socklen, VALUE ret); | ||
| socklen_t rsock_sockaddr_len(struct sockaddr *addr); | ||
| VALUE rsock_sockaddr_obj(struct sockaddr *addr, socklen_t len); | ||
| int rsock_revlookup_flag(VALUE revlookup, int *norevlookup); | ||
| ... | ... | |
| void rsock_init_ancdata(void); | ||
| void rsock_init_addrinfo(void); | ||
| void rsock_init_sockopt(void); | ||
| void rsock_init_sockifaddr(void); | ||
| void rsock_init_socket_init(void); | ||
| NORETURN(void rsock_sys_fail_host_port(const char *, VALUE, VALUE)); | ||
| ext/socket/socket.c | ||
|---|---|---|
|         return (socklen_t)sizeof(struct sockaddr_un); | ||
| #endif | ||
| #ifdef AF_PACKET | ||
|       case AF_PACKET: | ||
|         return (socklen_t)(offsetof(struct sockaddr_ll, sll_addr) + ((struct sockaddr_ll *)addr)->sll_halen); | ||
| #endif | ||
|       default: | ||
|         return (socklen_t)(offsetof(struct sockaddr, sa_family) + sizeof(addr->sa_family)); | ||
|     } | ||
| } | ||
| socklen_t | ||
| rsock_sockaddr_len(struct sockaddr *addr) | ||
| { | ||
|     return sockaddr_len(addr); | ||
| } | ||
| static VALUE | ||
| sockaddr_obj(struct sockaddr *addr, socklen_t len) | ||
| { | ||
| ... | ... | |
|     return rsock_addrinfo_new(addr, len, addr->sa_family, 0, 0, Qnil, Qnil); | ||
| } | ||
| VALUE | ||
| rsock_sockaddr_obj(struct sockaddr *addr, socklen_t len) | ||
| { | ||
|     return sockaddr_obj(addr, len); | ||
| } | ||
| #endif | ||
| #if defined(HAVE_GETIFADDRS) || (defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && !defined(__hpux)) || defined(SIOCGIFCONF) ||  defined(_WIN32) | ||