* ext/socket: New method, Socket.getifaddrs, implemented.
[ruby-core:54777] [Feature #8368] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40639 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
fade664f91
commit
b323d7d54c
@ -1,3 +1,8 @@
|
|||||||
|
Sat May 11 17:28:51 2013 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
|
* ext/socket: New method, Socket.getifaddrs, implemented.
|
||||||
|
[ruby-core:54777] [Feature #8368]
|
||||||
|
|
||||||
Sat May 11 00:47:22 2013 Tanaka Akira <akr@fsij.org>
|
Sat May 11 00:47:22 2013 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
* gc.h (SET_MACHINE_STACK_END): Add !defined(_ILP32) to a defining
|
* gc.h (SET_MACHINE_STACK_END): Add !defined(_ILP32) to a defining
|
||||||
|
@ -306,6 +306,8 @@ end
|
|||||||
netinet/tcp.h
|
netinet/tcp.h
|
||||||
netinet/udp.h
|
netinet/udp.h
|
||||||
arpa/inet.h
|
arpa/inet.h
|
||||||
|
netpacket/packet.h
|
||||||
|
net/ethernet.h
|
||||||
sys/un.h
|
sys/un.h
|
||||||
ifaddrs.h
|
ifaddrs.h
|
||||||
sys/ioctl.h
|
sys/ioctl.h
|
||||||
@ -314,6 +316,7 @@ end
|
|||||||
sys/param.h
|
sys/param.h
|
||||||
sys/ucred.h
|
sys/ucred.h
|
||||||
ucred.h
|
ucred.h
|
||||||
|
net/if_dl.h
|
||||||
arpa/nameser.h
|
arpa/nameser.h
|
||||||
resolv.h
|
resolv.h
|
||||||
].each {|h|
|
].each {|h|
|
||||||
@ -329,6 +332,8 @@ if have_type("struct sockaddr_un", headers) # POSIX
|
|||||||
have_struct_member("struct sockaddr_un", "sun_len", headers) # 4.4BSD
|
have_struct_member("struct sockaddr_un", "sun_len", headers) # 4.4BSD
|
||||||
end
|
end
|
||||||
|
|
||||||
|
have_type("struct sockaddr_dl", headers) # AF_LINK address. 4.4BSD since Net2
|
||||||
|
|
||||||
have_type("struct sockaddr_storage", headers)
|
have_type("struct sockaddr_storage", headers)
|
||||||
|
|
||||||
have_type("struct addrinfo", headers)
|
have_type("struct addrinfo", headers)
|
||||||
@ -554,7 +559,8 @@ EOS
|
|||||||
"unixserver.#{$OBJEXT}",
|
"unixserver.#{$OBJEXT}",
|
||||||
"option.#{$OBJEXT}",
|
"option.#{$OBJEXT}",
|
||||||
"ancdata.#{$OBJEXT}",
|
"ancdata.#{$OBJEXT}",
|
||||||
"raddrinfo.#{$OBJEXT}"
|
"raddrinfo.#{$OBJEXT}",
|
||||||
|
"ifaddr.#{$OBJEXT}"
|
||||||
]
|
]
|
||||||
|
|
||||||
if getaddr_info_ok == :wide
|
if getaddr_info_ok == :wide
|
||||||
|
434
ext/socket/ifaddr.c
Normal file
434
ext/socket/ifaddr.c
Normal file
@ -0,0 +1,434 @@
|
|||||||
|
#include "rubysocket.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_GETIFADDRS
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
const 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);
|
||||||
|
}
|
||||||
|
if (ifa->ifa_netmask) {
|
||||||
|
rb_str_cat2(result, " netmask=");
|
||||||
|
rsock_inspect_sockaddr(ifa->ifa_netmask,
|
||||||
|
rsock_sockaddr_len(ifa->ifa_netmask),
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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, ">");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_GETIFADDRS
|
||||||
|
/*
|
||||||
|
* 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();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define socket_s_getifaddrs rb_f_notimplement
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
rsock_init_sockifaddr(void)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_GETIFADDRS
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rb_define_singleton_method(rb_cSocket, "getifaddrs", socket_s_getifaddrs, 0);
|
||||||
|
}
|
@ -627,5 +627,6 @@ rsock_init_socket_init()
|
|||||||
rsock_init_sockopt();
|
rsock_init_sockopt();
|
||||||
rsock_init_ancdata();
|
rsock_init_ancdata();
|
||||||
rsock_init_addrinfo();
|
rsock_init_addrinfo();
|
||||||
|
rsock_init_sockifaddr();
|
||||||
rsock_init_socket_constants();
|
rsock_init_socket_constants();
|
||||||
}
|
}
|
||||||
|
@ -703,3 +703,62 @@ SCM_UCRED nil User credentials
|
|||||||
LOCAL_PEERCRED nil Retrieve peer credentials
|
LOCAL_PEERCRED nil Retrieve peer credentials
|
||||||
LOCAL_CREDS nil Pass credentials to receiver
|
LOCAL_CREDS nil Pass credentials to receiver
|
||||||
LOCAL_CONNWAIT nil Connect blocks until accepted
|
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
|
||||||
|
@ -953,34 +953,62 @@ static VALUE
|
|||||||
inspect_sockaddr(VALUE addrinfo, VALUE ret)
|
inspect_sockaddr(VALUE addrinfo, VALUE ret)
|
||||||
{
|
{
|
||||||
rb_addrinfo_t *rai = get_addrinfo(addrinfo);
|
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");
|
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");
|
rb_str_cat2(ret, "too-short-sockaddr");
|
||||||
else {
|
else {
|
||||||
switch (rai->addr.addr.sa_family) {
|
switch (sockaddr->addr.sa_family) {
|
||||||
|
case AF_UNSPEC:
|
||||||
|
{
|
||||||
|
rb_str_cat2(ret, "UNSPEC");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
{
|
{
|
||||||
struct sockaddr_in *addr;
|
struct sockaddr_in *addr;
|
||||||
int port;
|
int port;
|
||||||
if (rai->sockaddr_len < (socklen_t)sizeof(struct sockaddr_in)) {
|
addr = &sockaddr->in;
|
||||||
rb_str_cat2(ret, "too-short-AF_INET-sockaddr");
|
if (((char*)&addr->sin_addr)-(char*)addr+0+1 <= socklen)
|
||||||
}
|
rb_str_catf(ret, "%d", ((unsigned char*)&addr->sin_addr)[0]);
|
||||||
else {
|
else
|
||||||
addr = &rai->addr.in;
|
rb_str_cat2(ret, "?");
|
||||||
rb_str_catf(ret, "%d.%d.%d.%d",
|
if (((char*)&addr->sin_addr)-(char*)addr+1+1 <= socklen)
|
||||||
((unsigned char*)&addr->sin_addr)[0],
|
rb_str_catf(ret, ".%d", ((unsigned char*)&addr->sin_addr)[1]);
|
||||||
((unsigned char*)&addr->sin_addr)[1],
|
else
|
||||||
((unsigned char*)&addr->sin_addr)[2],
|
rb_str_cat2(ret, ".?");
|
||||||
((unsigned char*)&addr->sin_addr)[3]);
|
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+(int)sizeof(addr->sin_port) < socklen) {
|
||||||
port = ntohs(addr->sin_port);
|
port = ntohs(addr->sin_port);
|
||||||
if (port)
|
if (port)
|
||||||
rb_str_catf(ret, ":%d", 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)));
|
|
||||||
}
|
}
|
||||||
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -991,16 +1019,16 @@ inspect_sockaddr(VALUE addrinfo, VALUE ret)
|
|||||||
char hbuf[1024];
|
char hbuf[1024];
|
||||||
int port;
|
int port;
|
||||||
int error;
|
int error;
|
||||||
if (rai->sockaddr_len < (socklen_t)sizeof(struct sockaddr_in6)) {
|
if (socklen < (socklen_t)sizeof(struct sockaddr_in6)) {
|
||||||
rb_str_cat2(ret, "too-short-AF_INET6-sockaddr");
|
rb_str_catf(ret, "too-short-AF_INET6-sockaddr %d bytes", (int)socklen);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
addr = &rai->addr.in6;
|
addr = &sockaddr->in6;
|
||||||
/* use getnameinfo for scope_id.
|
/* use getnameinfo for scope_id.
|
||||||
* RFC 4007: IPv6 Scoped Address Architecture
|
* RFC 4007: IPv6 Scoped Address Architecture
|
||||||
* draft-ietf-ipv6-scope-api-00.txt: Scoped Address Extensions to the IPv6 Basic Socket API
|
* 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,
|
hbuf, (socklen_t)sizeof(hbuf), NULL, 0,
|
||||||
NI_NUMERICHOST|NI_NUMERICSERV);
|
NI_NUMERICHOST|NI_NUMERICSERV);
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -1013,8 +1041,8 @@ inspect_sockaddr(VALUE addrinfo, VALUE ret)
|
|||||||
port = ntohs(addr->sin6_port);
|
port = ntohs(addr->sin6_port);
|
||||||
rb_str_catf(ret, "[%s]:%d", hbuf, port);
|
rb_str_catf(ret, "[%s]:%d", hbuf, port);
|
||||||
}
|
}
|
||||||
if ((socklen_t)sizeof(struct sockaddr_in6) < rai->sockaddr_len)
|
if ((socklen_t)sizeof(struct sockaddr_in6) < socklen)
|
||||||
rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(rai->sockaddr_len - sizeof(struct sockaddr_in6)));
|
rb_str_catf(ret, "(sockaddr %d bytes too long)", (int)(socklen - sizeof(struct sockaddr_in6)));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1023,10 +1051,10 @@ inspect_sockaddr(VALUE addrinfo, VALUE ret)
|
|||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_SYS_UN_H
|
||||||
case AF_UNIX:
|
case AF_UNIX:
|
||||||
{
|
{
|
||||||
struct sockaddr_un *addr = &rai->addr.un;
|
struct sockaddr_un *addr = &sockaddr->un;
|
||||||
char *p, *s, *e;
|
char *p, *s, *e;
|
||||||
s = addr->sun_path;
|
s = addr->sun_path;
|
||||||
e = (char*)addr + rai->sockaddr_len;
|
e = (char*)addr + socklen;
|
||||||
while (s < e && *(e-1) == '\0')
|
while (s < e && *(e-1) == '\0')
|
||||||
e--;
|
e--;
|
||||||
if (e < s)
|
if (e < s)
|
||||||
@ -1042,11 +1070,11 @@ inspect_sockaddr(VALUE addrinfo, VALUE ret)
|
|||||||
}
|
}
|
||||||
if (printable_only) { /* only printable, no space */
|
if (printable_only) { /* only printable, no space */
|
||||||
if (s[0] != '/') /* relative path */
|
if (s[0] != '/') /* relative path */
|
||||||
rb_str_cat2(ret, "AF_UNIX ");
|
rb_str_cat2(ret, "UNIX ");
|
||||||
rb_str_cat(ret, s, p - s);
|
rb_str_cat(ret, s, p - s);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rb_str_cat2(ret, "AF_UNIX");
|
rb_str_cat2(ret, "UNIX");
|
||||||
while (s < e)
|
while (s < e)
|
||||||
rb_str_catf(ret, ":%02x", (unsigned char)*s++);
|
rb_str_catf(ret, ":%02x", (unsigned char)*s++);
|
||||||
}
|
}
|
||||||
@ -1055,11 +1083,157 @@ inspect_sockaddr(VALUE addrinfo, VALUE ret)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef AF_PACKET
|
||||||
|
/* GNU/Linux */
|
||||||
|
case AF_PACKET:
|
||||||
|
{
|
||||||
|
struct sockaddr_ll *addr;
|
||||||
|
const char *sep = "[";
|
||||||
|
#define CATSEP do { rb_str_cat2(ret, sep); sep = " "; } while (0);
|
||||||
|
|
||||||
|
addr = (struct sockaddr_ll *)sockaddr;
|
||||||
|
|
||||||
|
rb_str_cat2(ret, "PACKET");
|
||||||
|
|
||||||
|
if (offsetof(struct sockaddr_ll, sll_protocol) + sizeof(addr->sll_protocol) <= socklen) {
|
||||||
|
CATSEP;
|
||||||
|
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];
|
||||||
|
CATSEP;
|
||||||
|
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) {
|
||||||
|
CATSEP;
|
||||||
|
rb_str_catf(ret, "hatype=%d", addr->sll_hatype);
|
||||||
|
}
|
||||||
|
if (offsetof(struct sockaddr_ll, sll_pkttype) + sizeof(addr->sll_pkttype) <= socklen) {
|
||||||
|
CATSEP;
|
||||||
|
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)) {
|
||||||
|
CATSEP;
|
||||||
|
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;
|
||||||
|
CATSEP;
|
||||||
|
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_cat2(ret, i == 0 ? "=" : ":");
|
||||||
|
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) {
|
||||||
|
CATSEP;
|
||||||
|
rb_str_catf(ret, "(%d bytes for %d bytes sockaddr_ll)",
|
||||||
|
(int)socklen, (int)sizeof(struct sockaddr_ll));
|
||||||
|
}
|
||||||
|
|
||||||
|
rb_str_cat2(ret, "]");
|
||||||
|
#undef CATSEP
|
||||||
|
|
||||||
|
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;
|
||||||
|
const char *sep = "[";
|
||||||
|
#define CATSEP do { rb_str_cat2(ret, sep); sep = " "; } while (0);
|
||||||
|
|
||||||
|
rb_str_cat2(ret, "LINK");
|
||||||
|
|
||||||
|
endp = ((char *)addr) + socklen;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
CATSEP;
|
||||||
|
if (np)
|
||||||
|
rb_str_catf(ret, "%.*s", nlen, np);
|
||||||
|
else
|
||||||
|
rb_str_cat2(ret, "?");
|
||||||
|
|
||||||
|
if (ap && 0 < alen) {
|
||||||
|
CATSEP;
|
||||||
|
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)) {
|
||||||
|
CATSEP;
|
||||||
|
rb_str_catf(ret, "(%d bytes for %d bytes sockaddr_dl)",
|
||||||
|
(int)socklen, (int)sizeof(struct sockaddr_dl));
|
||||||
|
}
|
||||||
|
|
||||||
|
rb_str_cat2(ret, "]");
|
||||||
|
#undef CATSEP
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
ID id = rsock_intern_family(rai->addr.addr.sa_family);
|
ID id = rsock_intern_family(sockaddr->addr.sa_family);
|
||||||
if (id == 0)
|
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
|
else
|
||||||
rb_str_catf(ret, "%s address format unknown", rb_id2name(id));
|
rb_str_catf(ret, "%s address format unknown", rb_id2name(id));
|
||||||
break;
|
break;
|
||||||
|
@ -44,6 +44,13 @@
|
|||||||
# include <netdb.h>
|
# include <netdb.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_NETPACKET_PACKET_H
|
||||||
|
# include <netpacket/packet.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_NET_ETHERNET_H
|
||||||
|
# include <net/ethernet.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#ifdef HAVE_SYS_UN_H
|
#ifdef HAVE_SYS_UN_H
|
||||||
@ -87,6 +94,9 @@
|
|||||||
#ifdef HAVE_UCRED_H
|
#ifdef HAVE_UCRED_H
|
||||||
# include <ucred.h>
|
# include <ucred.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_NET_IF_DL_H
|
||||||
|
# include <net/if_dl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef HAVE_TYPE_SOCKLEN_T
|
#ifndef HAVE_TYPE_SOCKLEN_T
|
||||||
typedef int socklen_t;
|
typedef int socklen_t;
|
||||||
@ -168,6 +178,9 @@ typedef union {
|
|||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
|
||||||
struct sockaddr_un un;
|
struct sockaddr_un un;
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_DL
|
||||||
|
struct sockaddr_dl dl; /* AF_LINK */
|
||||||
#endif
|
#endif
|
||||||
struct sockaddr_storage storage;
|
struct sockaddr_storage storage;
|
||||||
char place_holder[2048]; /* sockaddr_storage is not enough for Unix domain sockets on SunOS and Darwin. */
|
char place_holder[2048]; /* sockaddr_storage is not enough for Unix domain sockets on SunOS and Darwin. */
|
||||||
@ -267,6 +280,9 @@ VALUE rsock_addrinfo_inspect_sockaddr(VALUE rai);
|
|||||||
VALUE rsock_make_ipaddr(struct sockaddr *addr, socklen_t addrlen);
|
VALUE rsock_make_ipaddr(struct sockaddr *addr, socklen_t addrlen);
|
||||||
VALUE rsock_ipaddr(struct sockaddr *sockaddr, socklen_t sockaddrlen, int norevlookup);
|
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_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);
|
int rsock_revlookup_flag(VALUE revlookup, int *norevlookup);
|
||||||
|
|
||||||
@ -344,6 +360,7 @@ void rsock_init_socket_constants(void);
|
|||||||
void rsock_init_ancdata(void);
|
void rsock_init_ancdata(void);
|
||||||
void rsock_init_addrinfo(void);
|
void rsock_init_addrinfo(void);
|
||||||
void rsock_init_sockopt(void);
|
void rsock_init_sockopt(void);
|
||||||
|
void rsock_init_sockifaddr(void);
|
||||||
void rsock_init_socket_init(void);
|
void rsock_init_socket_init(void);
|
||||||
|
|
||||||
NORETURN(void rsock_sys_fail_host_port(const char *, VALUE, VALUE));
|
NORETURN(void rsock_sys_fail_host_port(const char *, VALUE, VALUE));
|
||||||
|
@ -1584,11 +1584,22 @@ sockaddr_len(struct sockaddr *addr)
|
|||||||
return (socklen_t)sizeof(struct sockaddr_un);
|
return (socklen_t)sizeof(struct sockaddr_un);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef AF_PACKET
|
||||||
|
case AF_PACKET:
|
||||||
|
return (socklen_t)(offsetof(struct sockaddr_ll, sll_addr) + ((struct sockaddr_ll *)addr)->sll_halen);
|
||||||
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return (socklen_t)(offsetof(struct sockaddr, sa_family) + sizeof(addr->sa_family));
|
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
|
static VALUE
|
||||||
sockaddr_obj(struct sockaddr *addr, socklen_t len)
|
sockaddr_obj(struct sockaddr *addr, socklen_t len)
|
||||||
{
|
{
|
||||||
@ -1622,6 +1633,12 @@ sockaddr_obj(struct sockaddr *addr, socklen_t len)
|
|||||||
return rsock_addrinfo_new(addr, len, addr->sa_family, 0, 0, Qnil, Qnil);
|
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
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_GETIFADDRS) || (defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && !defined(__hpux)) || defined(SIOCGIFCONF) || defined(_WIN32)
|
#if defined(HAVE_GETIFADDRS) || (defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && !defined(__hpux)) || defined(SIOCGIFCONF) || defined(_WIN32)
|
||||||
|
@ -564,4 +564,15 @@ class TestSocket < Test::Unit::TestCase
|
|||||||
accepted.close if accepted
|
accepted.close if accepted
|
||||||
sock.close if sock && ! sock.closed?
|
sock.close if sock && ! sock.closed?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_getifaddrs
|
||||||
|
begin
|
||||||
|
list = Socket.getifaddrs
|
||||||
|
rescue NotImplementedError
|
||||||
|
return
|
||||||
|
end
|
||||||
|
list.each {|ifaddr|
|
||||||
|
assert_instance_of(Socket::Ifaddr, ifaddr)
|
||||||
|
}
|
||||||
|
end
|
||||||
end if defined?(Socket)
|
end if defined?(Socket)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user