Class: Socket::AncillaryData
- Inherits:
-
Object
- Object
- Socket::AncillaryData
- Defined in:
- ancdata.c,
ancdata.c
Overview
Socket::AncillaryData represents the ancillary data (control information) used by sendmsg and recvmsg system call. It contains socket #family, control message (cmsg) #level, cmsg #type and cmsg #data.
Class Method Summary collapse
-
.Socket::AncillaryData.int(family, cmsg_level, cmsg_type, integer) ⇒ Object
Creates a new Socket::AncillaryData object which contains a int as data.
-
.ip_pktinfo ⇒ Object
Returns new ancillary data for IP_PKTINFO.
-
.Socket::AncillaryData.ipv6_pktinfo(addr, ifindex) ⇒ Object
Returns new ancillary data for IPV6_PKTINFO.
-
.Socket::AncillaryData.unix_rights(io1, io2, ...) ⇒ Object
Creates a new Socket::AncillaryData object which contains file descriptors as data.
Instance Method Summary collapse
-
#cmsg_is?(level, type) ⇒ Boolean
tests the level and type of ancillarydata.
-
#data ⇒ String
returns the cmsg data as a string.
-
#family ⇒ Integer
returns the socket family as an integer.
-
#Socket::AncillaryData.new(family, cmsg_level, cmsg_type, cmsg_data) ⇒ Object
constructor
family should be an integer, a string or a symbol.
-
#inspect ⇒ String
returns a string which shows ancillarydata in human-readable form.
-
#int ⇒ Integer
Returns the data in ancillarydata as an int.
-
#ip_pktinfo ⇒ Array
Extracts addr, ifindex and spec_dst from IP_PKTINFO ancillary data.
-
#ipv6_pktinfo ⇒ Array
Extracts addr and ifindex from IPV6_PKTINFO ancillary data.
-
#ipv6_pktinfo_addr ⇒ Object
Extracts addr from IPV6_PKTINFO ancillary data.
-
#ipv6_pktinfo_ifindex ⇒ Object
Extracts ifindex from IPV6_PKTINFO ancillary data.
-
#level ⇒ Integer
returns the cmsg level as an integer.
-
#timestamp ⇒ Time
returns the timestamp as a time object.
-
#type ⇒ Integer
returns the cmsg type as an integer.
-
#unix_rights ⇒ array-of-IOs?
returns the array of IO objects for SCM_RIGHTS control message in UNIX domain socket.
Constructor Details
#Socket::AncillaryData.new(family, cmsg_level, cmsg_type, cmsg_data) ⇒ Object
family should be an integer, a string or a symbol.
-
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 should be an integer, a string or a symbol. If a string/symbol is specified, it is interpreted depend on 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 should be a string.
p Socket::AncillaryData.new(:INET, :TCP, :NODELAY, "")
#=> #<Socket::AncillaryData: INET TCP NODELAY "">
p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "")
#=> #<Socket::AncillaryData: INET6 IPV6 PKTINFO "">
72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'ancdata.c', line 72
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;
}
|
Class Method Details
.Socket::AncillaryData.int(family, cmsg_level, cmsg_type, integer) ⇒ Object
Creates a new Socket::AncillaryData object which contains a int as data.
The size and endian is dependent on the host.
p Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, STDERR.fileno)
#=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 2>
363 364 365 366 367 368 369 370 371 |
# File 'ancdata.c', line 363
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) ⇒ Object .Socket::AncillaryData.ip_pktinfo(addr, ifindex, spec_dst) ⇒ Object
Returns new ancillary data for IP_PKTINFO.
If spec_dst is not given, addr is used.
IP_PKTINFO is not standard.
Supported platform: 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>
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 |
# File 'ancdata.c', line 417
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) ⇒ Object
Returns new ancillary data for IPV6_PKTINFO.
IPV6_PKTINFO is defined by RFC 3542.
addr = Addrinfo.ip("::1")
ifindex = 0
p Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
#=> #<Socket::AncillaryData: INET6 IPV6 PKTINFO ::1 ifindex:0>
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 |
# File 'ancdata.c', line 530
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.unix_rights(io1, io2, ...) ⇒ Object
Creates a new Socket::AncillaryData object which contains file descriptors as data.
p Socket::AncillaryData.unix_rights(STDERR)
#=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 2>
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'ancdata.c', line 188
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_PTR(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;
}
|
Instance Method Details
#cmsg_is?(level, type) ⇒ Boolean
tests the level and type of ancillarydata.
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
1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 |
# File 'ancdata.c', line 1087
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
returns the cmsg data as a string.
p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").data
#=> ""
170 171 172 173 174 175 176 |
# File 'ancdata.c', line 170
static VALUE
ancillary_data(VALUE self)
{
VALUE v = rb_attr_get(self, rb_intern("data"));
StringValue(v);
return v;
}
|
#family ⇒ Integer
returns the socket family as an integer.
p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").family
#=> 10
111 112 113 114 115 |
# File 'ancdata.c', line 111
static VALUE
ancillary_family_m(VALUE self)
{
return INT2NUM(ancillary_family(self));
}
|
#inspect ⇒ String
returns a string which shows ancillarydata in human-readable form.
p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").inspect
#=> "#<Socket::AncillaryData: INET6 IPV6 PKTINFO \"\">"
949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 |
# File 'ancdata.c', line 949
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, " %s", rb_id2name(SYM2ID(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
Returns the data in ancillarydata as an int.
The size and endian is dependent on the host.
ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, STDERR.fileno)
p ancdata.int #=> 2
384 385 386 387 388 389 390 391 392 393 394 |
# File 'ancdata.c', line 384
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 ⇒ Array
Extracts addr, ifindex and spec_dst from IP_PKTINFO ancillary data.
IP_PKTINFO is not standard.
Supported platform: 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>]
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 |
# File 'ancdata.c', line 480
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 ⇒ Array
Extracts addr and ifindex from IPV6_PKTINFO ancillary data.
IPV6_PKTINFO is defined by RFC 3542.
addr = Addrinfo.ip("::1")
ifindex = 0
ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
p ancdata.ipv6_pktinfo #=> [#<Addrinfo: ::1>, 0]
598 599 600 601 602 603 604 605 606 607 608 |
# File 'ancdata.c', line 598
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 ⇒ Object
Extracts addr from IPV6_PKTINFO ancillary data.
IPV6_PKTINFO is defined by RFC 3542.
addr = Addrinfo.ip("::1")
ifindex = 0
ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
p ancdata.ipv6_pktinfo_addr #=> #<Addrinfo: ::1>
628 629 630 631 632 633 634 635 |
# File 'ancdata.c', line 628
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 ⇒ Object
Extracts ifindex from IPV6_PKTINFO ancillary data.
IPV6_PKTINFO is defined by RFC 3542.
addr = Addrinfo.ip("::1")
ifindex = 0
ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
p ancdata.ipv6_pktinfo_ifindex #=> 0
655 656 657 658 659 660 661 662 |
# File 'ancdata.c', line 655
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
returns the cmsg level as an integer.
p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").level
#=> 41
133 134 135 136 137 |
# File 'ancdata.c', line 133
static VALUE
ancillary_level_m(VALUE self)
{
return INT2NUM(ancillary_level(self));
}
|
#timestamp ⇒ Time
returns the timestamp as a time object.
ancillarydata should be one of following type:
-
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. p t #=> 2009-02-24 17:35:46 +0900 p t.usec #=> 775581 p t.nsec #=> 775581000 }
}
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 |
# File 'ancdata.c', line 297
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
returns the cmsg type as an integer.
p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").type
#=> 2
155 156 157 158 159 |
# File 'ancdata.c', line 155
static VALUE
ancillary_type_m(VALUE self)
{
return INT2NUM(ancillary_type(self));
}
|
#unix_rights ⇒ array-of-IOs?
returns the array of IO objects for SCM_RIGHTS control message in UNIX domain socket.
The class of the IO objects in the array is IO or Socket.
The array is attached to ancillarydata when it is instantiated. For example, BasicSocket#recvmsg attach the array when receives a SCM_RIGHTS control message and :scm_rights=>true option is given.
# 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
254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'ancdata.c', line 254
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"));
}
|