Socket::AncillaryData
class Socket::AncillaryData
Parent:Object
Socket :: AncillaryData表示sendmsg和recvmsg系统调用使用的辅助数据(控制信息)。它包含套接字系列,控制消息(cmsg)级别,cmsg类型和cmsg数据。
公共类方法
Socket :: AncillaryData.int(family,cmsg_level,cmsg_type,integer)→ancillarydata显示源代码
创建一个新的包含int作为数据的Socket :: AncillaryData对象。
大小和endian依赖于主机。
require 'socket'
p Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, STDERR.fileno)
#=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 2>
static VALUE
ancillary_s_int(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE vtype, VALUE integer)
{
int family = rsock_family_arg(vfamily
int level = rsock_level_arg(family, vlevel
int type = rsock_cmsg_type_arg(family, level, vtype
int i = NUM2INT(integer
return ancdata_new(family, level, type, rb_str_new((char*)&i, sizeof(i))
}
Socket :: AncillaryData.ip_pktinfo(addr,ifindex)→ancdata显示源文件
Socket :: AncillaryData.ip_pktinfo(addr,ifindex,spec_dst)→ancdata
返回IP_PKTINFO的新辅助数据。
如果没有给出spec_dst,则使用addr。
IP_PKTINFO不是标准的。
支持的平台:GNU / Linux
addr = Addrinfo.ip("127.0.0.1")
ifindex = 0
spec_dst = Addrinfo.ip("127.0.0.1")
p Socket::AncillaryData.ip_pktinfo(addr, ifindex, spec_dst)
#=> #<Socket::AncillaryData: INET IP PKTINFO 127.0.0.1 ifindex:0 spec_dst:127.0.0.1>
static VALUE
ancillary_s_ip_pktinfo(int argc, VALUE *argv, VALUE self)
{
VALUE v_addr, v_ifindex, v_spec_dst;
unsigned int ifindex;
struct sockaddr_in sa;
struct in_pktinfo pktinfo;
rb_scan_args(argc, argv, "21", &v_addr, &v_ifindex, &v_spec_dst
SockAddrStringValue(v_addr
ifindex = NUM2UINT(v_ifindex
if (NIL_P(v_spec_dst))
v_spec_dst = v_addr;
else
SockAddrStringValue(v_spec_dst
memset(&pktinfo, 0, sizeof(pktinfo)
memset(&sa, 0, sizeof(sa)
if (RSTRING_LEN(v_addr) != sizeof(sa))
rb_raise(rb_eArgError, "addr size different to AF_INET sockaddr"
memcpy(&sa, RSTRING_PTR(v_addr), sizeof(sa)
if (sa.sin_family != AF_INET)
rb_raise(rb_eArgError, "addr is not AF_INET sockaddr"
memcpy(&pktinfo.ipi_addr, &sa.sin_addr, sizeof(pktinfo.ipi_addr)
pktinfo.ipi_ifindex = ifindex;
memset(&sa, 0, sizeof(sa)
if (RSTRING_LEN(v_spec_dst) != sizeof(sa))
rb_raise(rb_eArgError, "spec_dat size different to AF_INET sockaddr"
memcpy(&sa, RSTRING_PTR(v_spec_dst), sizeof(sa)
if (sa.sin_family != AF_INET)
rb_raise(rb_eArgError, "spec_dst is not AF_INET sockaddr"
memcpy(&pktinfo.ipi_spec_dst, &sa.sin_addr, sizeof(pktinfo.ipi_spec_dst)
return ancdata_new(AF_INET, IPPROTO_IP, IP_PKTINFO, rb_str_new((char *)&pktinfo, sizeof(pktinfo))
}
Socket :: AncillaryData.ipv6_pktinfo(addr,ifindex)→ancdata显示源文件
返回IPV6_PKTINFO的新辅助数据。
IPV6_PKTINFO由RFC 3542定义。
addr = Addrinfo.ip("::1")
ifindex = 0
p Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
#=> #<Socket::AncillaryData: INET6 IPV6 PKTINFO ::1 ifindex:0>
static VALUE
ancillary_s_ipv6_pktinfo(VALUE self, VALUE v_addr, VALUE v_ifindex)
{
unsigned int ifindex;
struct sockaddr_in6 sa;
struct in6_pktinfo pktinfo;
SockAddrStringValue(v_addr
ifindex = NUM2UINT(v_ifindex
memset(&pktinfo, 0, sizeof(pktinfo)
memset(&sa, 0, sizeof(sa)
if (RSTRING_LEN(v_addr) != sizeof(sa))
rb_raise(rb_eArgError, "addr size different to AF_INET6 sockaddr"
memcpy(&sa, RSTRING_PTR(v_addr), sizeof(sa)
if (sa.sin6_family != AF_INET6)
rb_raise(rb_eArgError, "addr is not AF_INET6 sockaddr"
memcpy(&pktinfo.ipi6_addr, &sa.sin6_addr, sizeof(pktinfo.ipi6_addr)
pktinfo.ipi6_ifindex = ifindex;
return ancdata_new(AF_INET6, IPPROTO_IPV6, IPV6_PKTINFO, rb_str_new((char *)&pktinfo, sizeof(pktinfo))
}
Socket :: AncillaryData.new(family,cmsg_level,cmsg_type,cmsg_data)→ancillarydata显示源代码
家庭
应该是一个整数,一个字符串或一个符号。
- Socket::AF_INET, “AF_INET”, “INET”, :AF_INET, :INET
- Socket::AF_UNIX, “AF_UNIX”, “UNIX”, :AF_UNIX, :UNIX
- etc.
cmsg
_
level
should be an integer, a string or a symbol.
- Socket::SOL_SOCKET, “SOL_SOCKET”, “SOCKET”, :SOL_SOCKET and :SOCKET
- Socket::IPPROTO_IP, “IP” and :IP
- Socket::IPPROTO_IPV6, “IPV6” and :IPV6
- Socket::IPPROTO_TCP, “TCP” and :TCP
- etc.
cmsg_type
应该是一个整数,一个字符串或一个符号。如果指定了字符串/符号,则会根据cmsg_level进行
解释。
- Socket::SCM_RIGHTS, “SCM_RIGHTS”, “RIGHTS”, :SCM_RIGHTS, :RIGHTS for SOL_SOCKET
- Socket::IP_RECVTTL, “RECVTTL” and :RECVTTL for IPPROTO_IP
- Socket::IPV6_PKTINFO, “PKTINFO” and :PKTINFO for IPPROTO_IPV6
- etc.
cmsg_data
应该是一个字符串。
p Socket::AncillaryData.new(:INET, :TCP, :NODELAY, "")
#=> #<Socket::AncillaryData: INET TCP NODELAY "">
p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "")
#=> #<Socket::AncillaryData: INET6 IPV6 PKTINFO "">
static VALUE
ancillary_initialize(VALUE self, VALUE vfamily, VALUE vlevel, VALUE vtype, VALUE data)
{
int family = rsock_family_arg(vfamily
int level = rsock_level_arg(family, vlevel
int type = rsock_cmsg_type_arg(family, level, vtype
StringValue(data
rb_ivar_set(self, rb_intern("family"), INT2NUM(family)
rb_ivar_set(self, rb_intern("level"), INT2NUM(level)
rb_ivar_set(self, rb_intern("type"), INT2NUM(type)
rb_ivar_set(self, rb_intern("data"), data
return self;
}
Socket::AncillaryData.unix_rights(io1, io2, ...) → ancillarydata Show source
创建一个新的包含文件描述符作为数据的Socket :: AncillaryData对象。
p Socket::AncillaryData.unix_rights(STDERR)
#=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 2>
static VALUE
ancillary_s_unix_rights(int argc, VALUE *argv, VALUE klass)
{
VALUE result, str, ary;
int i;
ary = rb_ary_new(
for (i = 0 ; i < argc; i++) {
VALUE obj = argv[i];
if (!RB_TYPE_P(obj, T_FILE)) {
rb_raise(rb_eTypeError, "IO expected"
}
rb_ary_push(ary, obj
}
str = rb_str_buf_new(sizeof(int) * argc
for (i = 0 ; i < argc; i++) {
VALUE obj = RARRAY_AREF(ary, i
rb_io_t *fptr;
int fd;
GetOpenFile(obj, fptr
fd = fptr->fd;
rb_str_buf_cat(str, (char *)&fd, sizeof(int)
}
result = ancdata_new(AF_UNIX, SOL_SOCKET, SCM_RIGHTS, str
rb_ivar_set(result, rb_intern("unix_rights"), ary
return result;
}
Public Instance Methods
cmsg_is?(level, type) → true or false Show source
测试辅助数据
的级别和类型。
ancdata = Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "")
ancdata.cmsg_is?(Socket::IPPROTO_IPV6, Socket::IPV6_PKTINFO) #=> true
ancdata.cmsg_is?(:IPV6, :PKTINFO) #=> true
ancdata.cmsg_is?(:IP, :PKTINFO) #=> false
ancdata.cmsg_is?(:SOCKET, :RIGHTS) #=> false
static VALUE
ancillary_cmsg_is_p(VALUE self, VALUE vlevel, VALUE vtype)
{
int family = ancillary_family(self
int level = rsock_level_arg(family, vlevel
int type = rsock_cmsg_type_arg(family, level, vtype
if (ancillary_level(self) == level &&
ancillary_type(self) == type)
return Qtrue;
else
return Qfalse;
}
data → string Show source
以字符串形式返回cmsg数据。
p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").data
#=> ""
static VALUE
ancillary_data(VALUE self)
{
VALUE v = rb_attr_get(self, rb_intern("data")
StringValue(v
return v;
}
family → integer Show source
以整数形式返回套接字系列。
p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").family
#=> 10
static VALUE
ancillary_family_m(VALUE self)
{
return INT2NUM(ancillary_family(self)
}
inspect → string Show source
返回一个以可读形式显示辅助数据的字符串。
p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").inspect
#=> "#<Socket::AncillaryData: INET6 IPV6 PKTINFO \"\">"
static VALUE
ancillary_inspect(VALUE self)
{
VALUE ret;
int family, level, type;
VALUE data;
ID family_id, level_id, type_id;
VALUE vtype;
int inspected;
family = ancillary_family(self
level = ancillary_level(self
type = ancillary_type(self
data = ancillary_data(self
ret = rb_sprintf("#<%s:", rb_obj_classname(self)
family_id = rsock_intern_family_noprefix(family
if (family_id)
rb_str_catf(ret, " %s", rb_id2name(family_id)
else
rb_str_catf(ret, " family:%d", family
if (level == SOL_SOCKET) {
rb_str_cat2(ret, " SOCKET"
type_id = rsock_intern_scm_optname(type
if (type_id)
rb_str_catf(ret, " %s", rb_id2name(type_id)
else
rb_str_catf(ret, " cmsg_type:%d", type
}
else if (IS_IP_FAMILY(family)) {
level_id = rsock_intern_iplevel(level
if (level_id)
rb_str_catf(ret, " %s", rb_id2name(level_id)
else
rb_str_catf(ret, " cmsg_level:%d", level
vtype = ip_cmsg_type_to_sym(level, type
if (SYMBOL_P(vtype))
rb_str_catf(ret, " %"PRIsVALUE, rb_sym2str(vtype)
else
rb_str_catf(ret, " cmsg_type:%d", type
}
else {
rb_str_catf(ret, " cmsg_level:%d", level
rb_str_catf(ret, " cmsg_type:%d", type
}
inspected = 0;
if (level == SOL_SOCKET)
family = AF_UNSPEC;
switch (family) {
case AF_UNSPEC:
switch (level) {
# if defined(SOL_SOCKET)
case SOL_SOCKET:
switch (type) {
# if defined(SCM_TIMESTAMP) /* GNU/Linux, FreeBSD, NetBSD, OpenBSD, MacOS X, Solaris */
case SCM_TIMESTAMP: inspected = inspect_timeval_as_abstime(level, type, data, ret break;
# endif
# if defined(SCM_TIMESTAMPNS) /* GNU/Linux */
case SCM_TIMESTAMPNS: inspected = inspect_timespec_as_abstime(level, type, data, ret break;
# endif
# if defined(SCM_BINTIME) /* FreeBSD */
case SCM_BINTIME: inspected = inspect_bintime_as_abstime(level, type, data, ret break;
# endif
# if defined(SCM_RIGHTS) /* 4.4BSD */
case SCM_RIGHTS: inspected = anc_inspect_socket_rights(level, type, data, ret break;
# endif
# if defined(SCM_CREDENTIALS) /* GNU/Linux */
case SCM_CREDENTIALS: inspected = anc_inspect_passcred_credentials(level, type, data, ret break;
# endif
# if defined(INSPECT_SCM_CREDS) /* NetBSD */
case SCM_CREDS: inspected = anc_inspect_socket_creds(level, type, data, ret break;
# endif
}
break;
# endif
}
break;
case AF_INET:
#ifdef INET6
case AF_INET6:
#endif
switch (level) {
# if defined(IPPROTO_IP)
case IPPROTO_IP:
switch (type) {
# if defined(IP_RECVDSTADDR) /* 4.4BSD */
case IP_RECVDSTADDR: inspected = anc_inspect_ip_recvdstaddr(level, type, data, ret break;
# endif
# if defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST) /* GNU/Linux */
case IP_PKTINFO: inspected = anc_inspect_ip_pktinfo(level, type, data, ret break;
# endif
}
break;
# endif
# if defined(IPPROTO_IPV6)
case IPPROTO_IPV6:
switch (type) {
# if defined(IPV6_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN6_PKTINFO) /* RFC 3542 */
case IPV6_PKTINFO: inspected = anc_inspect_ipv6_pktinfo(level, type, data, ret break;
# endif
}
break;
# endif
}
break;
}
if (!inspected) {
rb_str_cat2(ret, " "
rb_str_append(ret, rb_str_dump(data)
}
rb_str_cat2(ret, ">"
return ret;
}
int → integer Show source
以int形式返回ancillarydata
中的数据。
大小和endian依赖于主机。
ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, STDERR.fileno)
p ancdata.int #=> 2
static VALUE
ancillary_int(VALUE self)
{
VALUE data;
int i;
data = ancillary_data(self
if (RSTRING_LEN(data) != sizeof(int))
rb_raise(rb_eTypeError, "size differ. expected as sizeof(int)=%d but %ld", (int)sizeof(int), (long)RSTRING_LEN(data)
memcpy((char*)&i, RSTRING_PTR(data), sizeof(int)
return INT2NUM(i
}
ip_pktinfo → addr, ifindex, spec_dst()
从IP_PKTINFO辅助数据中提取addr,ifindex和spec_dst。
IP_PKTINFO不是标准的。
支持的平台:GNU / Linux
addr = Addrinfo.ip("127.0.0.1")
ifindex = 0
spec_dest = Addrinfo.ip("127.0.0.1")
ancdata = Socket::AncillaryData.ip_pktinfo(addr, ifindex, spec_dest)
p ancdata.ip_pktinfo
#=> [#<Addrinfo: 127.0.0.1>, 0, #<Addrinfo: 127.0.0.1>]
static VALUE
ancillary_ip_pktinfo(VALUE self)
{
int level, type;
VALUE data;
struct in_pktinfo pktinfo;
struct sockaddr_in sa;
VALUE v_spec_dst, v_addr;
level = ancillary_level(self
type = ancillary_type(self
data = ancillary_data(self
if (level != IPPROTO_IP || type != IP_PKTINFO ||
RSTRING_LEN(data) != sizeof(struct in_pktinfo)) {
rb_raise(rb_eTypeError, "IP_PKTINFO ancillary data expected"
}
memcpy(&pktinfo, RSTRING_PTR(data), sizeof(struct in_pktinfo)
memset(&sa, 0, sizeof(sa)
sa.sin_family = AF_INET;
memcpy(&sa.sin_addr, &pktinfo.ipi_addr, sizeof(sa.sin_addr)
v_addr = rsock_addrinfo_new((struct sockaddr *)&sa, sizeof(sa), PF_INET, 0, 0, Qnil, Qnil
sa.sin_family = AF_INET;
memcpy(&sa.sin_addr, &pktinfo.ipi_spec_dst, sizeof(sa.sin_addr)
v_spec_dst = rsock_addrinfo_new((struct sockaddr *)&sa, sizeof(sa), PF_INET, 0, 0, Qnil, Qnil
return rb_ary_new3(3, v_addr, UINT2NUM(pktinfo.ipi_ifindex), v_spec_dst
}
ipv6_pktinfo → addr, ifindex()
从IPV6_PKTINFO辅助数据中提取addr和ifindex。
IPV6_PKTINFO由RFC 3542定义。
addr = Addrinfo.ip("::1")
ifindex = 0
ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
p ancdata.ipv6_pktinfo #=> [#<Addrinfo: ::1>, 0]
static VALUE
ancillary_ipv6_pktinfo(VALUE self)
{
struct in6_pktinfo pktinfo;
struct sockaddr_in6 sa;
VALUE v_addr;
extract_ipv6_pktinfo(self, &pktinfo, &sa
v_addr = rsock_addrinfo_new((struct sockaddr *)&sa, (socklen_t)sizeof(sa), PF_INET6, 0, 0, Qnil, Qnil
return rb_ary_new3(2, v_addr, UINT2NUM(pktinfo.ipi6_ifindex)
}
ipv6_pktinfo_addr → addr Show source
从IPV6_PKTINFO辅助数据中提取addr。
IPV6_PKTINFO由RFC 3542定义。
addr = Addrinfo.ip("::1")
ifindex = 0
ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
p ancdata.ipv6_pktinfo_addr #=> #<Addrinfo: ::1>
static VALUE
ancillary_ipv6_pktinfo_addr(VALUE self)
{
struct in6_pktinfo pktinfo;
struct sockaddr_in6 sa;
extract_ipv6_pktinfo(self, &pktinfo, &sa
return rsock_addrinfo_new((struct sockaddr *)&sa, (socklen_t)sizeof(sa), PF_INET6, 0, 0, Qnil, Qnil
}
ipv6_pktinfo_ifindex → addr Show source
从IPV6_PKTINFO辅助数据中提取ifindex。
IPV6_PKTINFO由RFC 3542定义。
addr = Addrinfo.ip("::1")
ifindex = 0
ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
p ancdata.ipv6_pktinfo_ifindex #=> 0
static VALUE
ancillary_ipv6_pktinfo_ifindex(VALUE self)
{
struct in6_pktinfo pktinfo;
struct sockaddr_in6 sa;
extract_ipv6_pktinfo(self, &pktinfo, &sa
return UINT2NUM(pktinfo.ipi6_ifindex
}
level → integer Show source
以整数形式返回cmsg级别。
p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").level
#=> 41
static VALUE
ancillary_level_m(VALUE self)
{
return INT2NUM(ancillary_level(self)
}
timestamp → time Show source
作为时间对象返回时间戳。
ancillarydata
应该是以下类型之一:
- SOL_SOCKET/SCM_TIMESTAMP (microsecond) GNU/Linux, FreeBSD, NetBSD, OpenBSD, Solaris, MacOS X
- SOL_SOCKET/SCM_TIMESTAMPNS (nanosecond) GNU/Linux
- SOL_SOCKET/SCM_BINTIME (2**(-64) second) FreeBSD
Addrinfo.udp(“127.0.0.1”, 0).bind {|s1|
Addrinfo.udp("127.0.0.1", 0).bind {|s2| s1.setsockopt(:SOCKET, :TIMESTAMP, true) s2.send "a", 0, s1.local_address ctl = s1.recvmsg.last p ctl #=> #<Socket::AncillaryData: INET SOCKET TIMESTAMP 2009-02-24 17:35:46.775581> t = ctl.timestamp p t #=> 2009-02-24 17:35:46 +0900 p t.usec #=> 775581 p t.nsec #=> 775581000 }
}
static VALUE
ancillary_timestamp(VALUE self)
{
int level, type;
VALUE data;
VALUE result = Qnil;
level = ancillary_level(self
type = ancillary_type(self
data = ancillary_data(self
# ifdef SCM_TIMESTAMP
if (level == SOL_SOCKET && type == SCM_TIMESTAMP &&
RSTRING_LEN(data) == sizeof(struct timeval)) {
struct timeval tv;
memcpy((char*)&tv, RSTRING_PTR(data), sizeof(tv)
result = rb_time_new(tv.tv_sec, tv.tv_usec
}
# endif
# ifdef SCM_TIMESTAMPNS
if (level == SOL_SOCKET && type == SCM_TIMESTAMPNS &&
RSTRING_LEN(data) == sizeof(struct timespec)) {
struct timespec ts;
memcpy((char*)&ts, RSTRING_PTR(data), sizeof(ts)
result = rb_time_nano_new(ts.tv_sec, ts.tv_nsec
}
# endif
#define add(x,y) (rb_funcall((x), '+', 1, (y)))
#define mul(x,y) (rb_funcall((x), '*', 1, (y)))
#define quo(x,y) (rb_funcall((x), rb_intern("quo"), 1, (y)))
# ifdef SCM_BINTIME
if (level == SOL_SOCKET && type == SCM_BINTIME &&
RSTRING_LEN(data) == sizeof(struct bintime)) {
struct bintime bt;
VALUE d, timev;
memcpy((char*)&bt, RSTRING_PTR(data), sizeof(bt)
d = ULL2NUM(0x100000000ULL
d = mul(d,d
timev = add(TIMET2NUM(bt.sec), quo(ULL2NUM(bt.frac), d)
result = rb_time_num_new(timev, Qnil
}
# endif
if (result == Qnil)
rb_raise(rb_eTypeError, "timestamp ancillary data expected"
return result;
}
type → integer Show source
以整数形式返回cmsg类型。
p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").type
#=> 2
static VALUE
ancillary_type_m(VALUE self)
{
return INT2NUM(ancillary_type(self)
}
unix_rights → array-of-IOs or nil Show source
在UNIX域套接字中返回SCM_RIGHTS控制消息的IO对象数组。
数组中IO对象的类是IO或套接字。
数组在实例化时附加到辅助数据。例如,BasicSocket#recvmsg在收到SCM_RIGHTS控制消息时附加数组,并且:给出scm_rights => true选项。
# recvmsg needs :scm_rights=>true for unix_rights
s1, s2 = UNIXSocket.pair
p s1 #=> #<UNIXSocket:fd 3>
s1.sendmsg "stdin and a socket", 0, nil, Socket::AncillaryData.unix_rights(STDIN, s1)
_, _, _, ctl = s2.recvmsg(:scm_rights=>true)
p ctl #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 6 7>
p ctl.unix_rights #=> [#<IO:fd 6>, #<Socket:fd 7>]
p File.identical?(STDIN, ctl.unix_rights[0]) #=> true
p File.identical?(s1, ctl.unix_rights[1]) #=> true
# If :scm_rights=>true is not given, unix_rights returns nil
s1, s2 = UNIXSocket.pair
s1.sendmsg "stdin and a socket", 0, nil, Socket::AncillaryData.unix_rights(STDIN, s1)
_, _, _, ctl = s2.recvmsg
p ctl #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 6 7>
p ctl.unix_rights #=> nil
static VALUE
ancillary_unix_rights(VALUE self)
{
int level, type;
level = ancillary_level(self
type = ancillary_type(self
if (level != SOL_SOCKET || type != SCM_RIGHTS)
rb_raise(rb_eTypeError, "SCM_RIGHTS ancillary data expected"
return rb_attr_get(self, rb_intern("unix_rights")
}