我正在使用
Ruby和bit-struct在测试设置中配置我的网络接口.这适用于大多数IOCTL调用,但我无法弄清楚如何调用SIOCGIFCONF
这是一个例子:
如果我想获取接口的MAC地址,我会写这样的东西:
class LinuxIfreqMacAddr < BitStruct
char :name, 128
unsigned :type, 16, :endian => :native
hex_octets :macaddr, 48
pad :padding, 64
end
ifr = LinuxIfreqMacAddr.new
ifr.name = "eth0"
s.ioctl(SIOCGIFHWADDR, ifr) # s is a socket
puts ifr.macaddr
这很好,并将打印eth0的MAC地址.但是“struct ifconf”(与SIOCGIFCONF一起使用)的签名需要传递缓冲区.
这是签名:
struct ifconf {
int ifc_len;
char __user *ifcu_buf;
};
我如何从ruby调用SIOCGIFCONF ioctl命令,缓冲区为4096字节?
最佳答案 使用
Array#pack的“P”说明符存储指向a的指针
缓冲:
require 'socket'
sock = UDPSocket.new
ifreqs = ' ' * 4096
ifconf = [ifreqs.size, ifreqs].pack("l!P")
SIOCGIFCONF = 0x8912
sock.ioctl(SIOCGIFCONF, ifconf)
data_size = ifconf.unpack('l!').first
p data_size # => 120
这是如何工作的
创建ioctl将存储接口信息数组的缓冲区:
ifreqs = ' ' * 4096
现在创建缓冲区以传递给ioctl调用.缓冲区将是一个
表示ifconf struct的字符串:
struct ifconf {
int ifc_len; /* size of buffer */
union {
char *ifc_buf; /* buffer address */
struct ifreq *ifc_req; /* array of structures */
};
};
我们使用Array#pack来做到这一点:
ifconf = [ifreqs.size, ifreqs].pack("l!P")
格式说明符分解为:
>“我!” – 签名长的平台原生大小.这编码ifreqs.size.
>“P” – 指向固定长度缓冲区的指针.这编码地址
存储在ifreqs字符串中的缓冲区.
现在我们可以打电话:
SIOCGIFCONF = 0x8912
sock.ioctl(SIOCGIFCONF, ifconf)
SIOCGIFCONF调用修改ifconf缓冲区,将ifc_len更新为
实际存储在ifreqs bufffer中的数据字节数.我们
通过解压缩数组中的元素可以看到:
data_size = ifconf.unpack('l!').first
p data_size # => 120
将存储在ifreqs中的数据解码为一个练习
读者.