6 static VALUE sym_wait_readable, sym_wait_writable;
8 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
9 static VALUE rb_cAncillaryData;
12 constant_to_sym(
int constant,
ID (*intern_const)(
int))
14 ID name = intern_const(constant);
23 ip_cmsg_type_to_sym(
int level,
int cmsg_type)
90 ancdata_new(
int family,
int level,
int type,
VALUE data)
99 ancillary_family(
VALUE self)
115 ancillary_family_m(
VALUE self)
117 return INT2NUM(ancillary_family(
self));
121 ancillary_level(
VALUE self)
137 ancillary_level_m(
VALUE self)
139 return INT2NUM(ancillary_level(
self));
143 ancillary_type(
VALUE self)
159 ancillary_type_m(
VALUE self)
161 return INT2NUM(ancillary_type(
self));
174 ancillary_data(
VALUE self)
218 result = ancdata_new(AF_UNIX, SOL_SOCKET, SCM_RIGHTS,
str);
223 #define ancillary_s_unix_rights rb_f_notimplement
258 ancillary_unix_rights(
VALUE self)
262 level = ancillary_level(
self);
263 type = ancillary_type(
self);
265 if (level != SOL_SOCKET ||
type != SCM_RIGHTS)
271 #define ancillary_unix_rights rb_f_notimplement
274 #if defined(SCM_TIMESTAMP) || defined(SCM_TIMESTAMPNS) || defined(SCM_BINTIME)
301 ancillary_timestamp(
VALUE self)
307 level = ancillary_level(
self);
308 type = ancillary_type(
self);
309 data = ancillary_data(
self);
311 # ifdef SCM_TIMESTAMP
312 if (level == SOL_SOCKET &&
type == SCM_TIMESTAMP &&
320 # ifdef SCM_TIMESTAMPNS
321 if (level == SOL_SOCKET &&
type == SCM_TIMESTAMPNS &&
329 #define add(x,y) (rb_funcall((x), '+', 1, (y)))
330 #define mul(x,y) (rb_funcall((x), '*', 1, (y)))
331 #define quo(x,y) (rb_funcall((x), rb_intern("quo"), 1, (y)))
334 if (level == SOL_SOCKET &&
type == SCM_BINTIME &&
352 #define ancillary_timestamp rb_f_notimplement
390 ancillary_int(
VALUE self)
394 data = ancillary_data(
self);
401 #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST)
425 VALUE v_addr, v_ifindex, v_spec_dst;
426 unsigned int ifindex;
427 struct sockaddr_in sa;
428 struct in_pktinfo pktinfo;
434 if (
NIL_P(v_spec_dst))
439 memset(&pktinfo, 0,
sizeof(pktinfo));
441 memset(&sa, 0,
sizeof(sa));
445 if (sa.sin_family != AF_INET)
447 memcpy(&pktinfo.ipi_addr, &sa.sin_addr,
sizeof(pktinfo.ipi_addr));
449 pktinfo.ipi_ifindex = ifindex;
451 memset(&sa, 0,
sizeof(sa));
455 if (sa.sin_family != AF_INET)
457 memcpy(&pktinfo.ipi_spec_dst, &sa.sin_addr,
sizeof(pktinfo.ipi_spec_dst));
459 return ancdata_new(AF_INET,
IPPROTO_IP, IP_PKTINFO,
rb_str_new((
char *)&pktinfo,
sizeof(pktinfo)));
462 #define ancillary_s_ip_pktinfo rb_f_notimplement
465 #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST)
486 ancillary_ip_pktinfo(
VALUE self)
490 struct in_pktinfo pktinfo;
491 struct sockaddr_in sa;
492 VALUE v_spec_dst, v_addr;
494 level = ancillary_level(
self);
495 type = ancillary_type(
self);
496 data = ancillary_data(
self);
504 memset(&sa, 0,
sizeof(sa));
506 sa.sin_family = AF_INET;
507 memcpy(&sa.sin_addr, &pktinfo.ipi_addr,
sizeof(sa.sin_addr));
510 sa.sin_family = AF_INET;
511 memcpy(&sa.sin_addr, &pktinfo.ipi_spec_dst,
sizeof(sa.sin_addr));
517 #define ancillary_ip_pktinfo rb_f_notimplement
520 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)
538 unsigned int ifindex;
539 struct sockaddr_in6 sa;
540 struct in6_pktinfo pktinfo;
545 memset(&pktinfo, 0,
sizeof(pktinfo));
547 memset(&sa, 0,
sizeof(sa));
551 if (sa.sin6_family != AF_INET6)
553 memcpy(&pktinfo.ipi6_addr, &sa.sin6_addr,
sizeof(pktinfo.ipi6_addr));
555 pktinfo.ipi6_ifindex = ifindex;
557 return ancdata_new(AF_INET6, IPPROTO_IPV6, IPV6_PKTINFO,
rb_str_new((
char *)&pktinfo,
sizeof(pktinfo)));
560 #define ancillary_s_ipv6_pktinfo rb_f_notimplement
563 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)
565 extract_ipv6_pktinfo(
VALUE self,
struct in6_pktinfo *pktinfo_ptr,
struct sockaddr_in6 *sa_ptr)
570 level = ancillary_level(
self);
571 type = ancillary_type(
self);
572 data = ancillary_data(
self);
574 if (level != IPPROTO_IPV6 ||
type != IPV6_PKTINFO ||
581 INIT_SOCKADDR((
struct sockaddr *)sa_ptr, AF_INET6,
sizeof(*sa_ptr));
582 memcpy(&sa_ptr->sin6_addr, &pktinfo_ptr->ipi6_addr,
sizeof(sa_ptr->sin6_addr));
583 if (IN6_IS_ADDR_LINKLOCAL(&sa_ptr->sin6_addr))
584 sa_ptr->sin6_scope_id = pktinfo_ptr->ipi6_ifindex;
588 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)
604 ancillary_ipv6_pktinfo(
VALUE self)
606 struct in6_pktinfo pktinfo;
607 struct sockaddr_in6 sa;
610 extract_ipv6_pktinfo(
self, &pktinfo, &sa);
615 #define ancillary_ipv6_pktinfo rb_f_notimplement
618 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)
634 ancillary_ipv6_pktinfo_addr(
VALUE self)
636 struct in6_pktinfo pktinfo;
637 struct sockaddr_in6 sa;
638 extract_ipv6_pktinfo(
self, &pktinfo, &sa);
642 #define ancillary_ipv6_pktinfo_addr rb_f_notimplement
645 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)
661 ancillary_ipv6_pktinfo_ifindex(
VALUE self)
663 struct in6_pktinfo pktinfo;
664 struct sockaddr_in6 sa;
665 extract_ipv6_pktinfo(
self, &pktinfo, &sa);
666 return UINT2NUM(pktinfo.ipi6_ifindex);
669 #define ancillary_ipv6_pktinfo_ifindex rb_f_notimplement
672 #if defined(SOL_SOCKET) && defined(SCM_RIGHTS)
674 anc_inspect_socket_rights(
int level,
int type,
VALUE data,
VALUE ret)
676 if (level == SOL_SOCKET &&
type == SCM_RIGHTS &&
692 #if defined(SCM_CREDENTIALS)
694 anc_inspect_passcred_credentials(
int level,
int type,
VALUE data,
VALUE ret)
696 if (level == SOL_SOCKET &&
type == SCM_CREDENTIALS &&
700 rb_str_catf(ret,
" pid=%u uid=%u gid=%u", cred.pid, cred.uid, cred.gid);
710 #if defined(SCM_CREDS)
711 #define INSPECT_SCM_CREDS
713 anc_inspect_socket_creds(
int level,
int type,
VALUE data,
VALUE ret)
715 if (level != SOL_SOCKET &&
type != SCM_CREDS)
729 #if defined(HAVE_TYPE_STRUCT_CMSGCRED)
730 if (
RSTRING_LEN(data) ==
sizeof(
struct cmsgcred)) {
731 struct cmsgcred cred;
737 if (cred.cmcred_ngroups) {
739 const char *sep =
" groups=";
740 for (
i = 0;
i < cred.cmcred_ngroups;
i++) {
749 #if defined(HAVE_TYPE_STRUCT_SOCKCRED)
750 if ((
size_t)
RSTRING_LEN(data) >= SOCKCREDSIZE(0)) {
751 struct sockcred cred0, *cred;
753 if ((
size_t)
RSTRING_LEN(data) == SOCKCREDSIZE(cred0.sc_ngroups)) {
754 cred = (
struct sockcred *)
ALLOCA_N(
char, SOCKCREDSIZE(cred0.sc_ngroups));
760 if (cred0.sc_ngroups) {
762 const char *sep =
" groups=";
763 for (
i = 0;
i < cred0.sc_ngroups;
i++) {
777 #if defined(IPPROTO_IP) && defined(IP_RECVDSTADDR)
779 anc_inspect_ip_recvdstaddr(
int level,
int type,
VALUE data,
VALUE ret)
798 #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST)
800 anc_inspect_ip_pktinfo(
int level,
int type,
VALUE data,
VALUE ret)
804 struct in_pktinfo pktinfo;
811 if (if_indextoname(pktinfo.ipi_ifindex,
buf) ==
NULL)
812 rb_str_catf(ret,
" ifindex:%d", pktinfo.ipi_ifindex);
827 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN6_PKTINFO)
829 anc_inspect_ipv6_pktinfo(
int level,
int type,
VALUE data,
VALUE ret)
831 if (level == IPPROTO_IPV6 &&
type == IPV6_PKTINFO &&
833 struct in6_pktinfo *pktinfo = (
struct in6_pktinfo *)
RSTRING_PTR(data);
834 struct in6_addr addr;
835 unsigned int ifindex;
837 memcpy(&addr, &pktinfo->ipi6_addr,
sizeof(addr));
838 memcpy(&ifindex, &pktinfo->ipi6_ifindex,
sizeof(ifindex));
843 if (if_indextoname(ifindex, ifbuf) ==
NULL)
855 #if defined(SCM_TIMESTAMP)
857 inspect_timeval_as_abstime(
int level,
int optname,
VALUE data,
VALUE ret)
877 #if defined(SCM_TIMESTAMPNS)
879 inspect_timespec_as_abstime(
int level,
int optname,
VALUE data,
VALUE ret)
897 #if defined(SCM_BINTIME)
899 inspect_bintime_as_abstime(
int level,
int optname,
VALUE data,
VALUE ret)
915 frac_h = bt.frac >> 32;
916 frac_l = bt.frac & 0xffffffff;
918 scale_h = 0x8ac72304;
919 scale_l = 0x89e80000;
921 res_h = frac_h * scale_h;
922 res_l = frac_l * scale_l;
924 tmp1 = frac_h * scale_l;
927 res_l += tmp1 & 0xffffffff;
928 if (res_l < tmp2) res_h++;
930 tmp1 = frac_l * scale_h;
933 res_l += tmp1 & 0xffffffff;
934 if (res_l < tmp2) res_h++;
955 ancillary_inspect(
VALUE self)
958 int family, level,
type;
960 ID family_id, level_id, type_id;
964 family = ancillary_family(
self);
965 level = ancillary_level(
self);
966 type = ancillary_type(
self);
967 data = ancillary_data(
self);
977 if (level == SOL_SOCKET) {
993 vtype = ip_cmsg_type_to_sym(level,
type);
1006 if (level == SOL_SOCKET)
1012 # if defined(SOL_SOCKET)
1015 # if defined(SCM_TIMESTAMP)
1016 case SCM_TIMESTAMP: inspected = inspect_timeval_as_abstime(level,
type, data, ret);
break;
1018 # if defined(SCM_TIMESTAMPNS)
1019 case SCM_TIMESTAMPNS: inspected = inspect_timespec_as_abstime(level,
type, data, ret);
break;
1021 # if defined(SCM_BINTIME)
1022 case SCM_BINTIME: inspected = inspect_bintime_as_abstime(level,
type, data, ret);
break;
1024 # if defined(SCM_RIGHTS)
1025 case SCM_RIGHTS: inspected = anc_inspect_socket_rights(level,
type, data, ret);
break;
1027 # if defined(SCM_CREDENTIALS)
1028 case SCM_CREDENTIALS: inspected = anc_inspect_passcred_credentials(level,
type, data, ret);
break;
1030 # if defined(INSPECT_SCM_CREDS)
1031 case SCM_CREDS: inspected = anc_inspect_socket_creds(level,
type, data, ret);
break;
1044 # if defined(IPPROTO_IP)
1047 # if defined(IP_RECVDSTADDR)
1048 case IP_RECVDSTADDR: inspected = anc_inspect_ip_recvdstaddr(level,
type, data, ret);
break;
1050 # if defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST)
1051 case IP_PKTINFO: inspected = anc_inspect_ip_pktinfo(level,
type, data, ret);
break;
1057 # if defined(IPPROTO_IPV6)
1060 # if defined(IPV6_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN6_PKTINFO)
1061 case IPV6_PKTINFO: inspected = anc_inspect_ipv6_pktinfo(level,
type, data, ret);
break;
1095 int family = ancillary_family(
self);
1099 if (ancillary_level(
self) == level &&
1100 ancillary_type(
self) ==
type)
1108 #if defined(HAVE_SENDMSG)
1109 struct sendmsg_args_struct {
1112 const struct msghdr *msg;
1116 nogvl_sendmsg_func(
void *
ptr)
1118 struct sendmsg_args_struct *args =
ptr;
1119 return (
void *)(
VALUE)
sendmsg(args->fd, args->msg, args->flags);
1123 rb_sendmsg(
int fd,
const struct msghdr *msg,
int flags)
1125 struct sendmsg_args_struct args;
1142 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1143 VALUE controls_str = 0;
1150 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1163 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1165 size_t last_pad = 0;
1167 #if defined(__NetBSD__)
1172 for (
i = 0;
i < controls_num;
i++) {
1173 VALUE elt = controls_ptr[
i],
v;
1174 VALUE vlevel, vtype;
1202 memset((
char *)cmsg, 0, cspace);
1203 memset((
char *)&cmh, 0,
sizeof(cmh));
1204 cmh.cmsg_level = level;
1205 cmh.cmsg_type =
type;
1207 MEMCPY(cmsg, &cmh,
char,
sizeof(cmh));
1209 #if defined(__NetBSD__)
1210 last_level = cmh.cmsg_level;
1211 last_type = cmh.cmsg_type;
1213 last_pad = cspace - cmh.cmsg_len;
1236 #if defined(__NetBSD__)
1237 if (last_level == SOL_SOCKET && last_type == SCM_RIGHTS)
1250 flags |= MSG_DONTWAIT;
1253 if (!
NIL_P(dest_sockaddr))
1259 memset(&mh, 0,
sizeof(mh));
1260 if (!
NIL_P(dest_sockaddr)) {
1268 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1279 ss = rb_sendmsg(fptr->
fd, &mh, flags);
1290 return sym_wait_writable;
1293 "sendmsg(2) would block");
1297 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1306 #if defined(HAVE_SENDMSG)
1311 return bsock_sendmsg_internal(sock, data, flags, dest_sockaddr, controls,
1316 #if defined(HAVE_SENDMSG)
1321 return bsock_sendmsg_internal(sock, data, flags, dest_sockaddr,
1326 #if defined(HAVE_RECVMSG)
1327 struct recvmsg_args_struct {
1334 rsock_recvmsg(
int socket,
struct msghdr *message,
int flags)
1338 #ifdef MSG_CMSG_CLOEXEC
1340 flags |= MSG_CMSG_CLOEXEC;
1343 ret =
recvmsg(socket, message, flags);
1350 nogvl_recvmsg_func(
void *
ptr)
1352 struct recvmsg_args_struct *args =
ptr;
1353 int flags = args->flags;
1354 return (
void *)rsock_recvmsg(args->fd, args->msg, flags);
1358 rb_recvmsg(
int fd,
struct msghdr *msg,
int flags)
1360 struct recvmsg_args_struct args;
1367 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1369 discard_cmsg(
struct cmsghdr *cmh,
char *msg_end,
int msg_peek_p)
1371 # if !defined(FD_PASSING_WORK_WITH_RECVMSG_MSG_PEEK)
1383 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
1384 int *fdp = (
int *)CMSG_DATA(cmh);
1385 int *end = (
int *)((
char *)cmh + cmh->cmsg_len);
1386 while ((
char *)fdp +
sizeof(
int) <= (
char *)end &&
1387 (
char *)fdp +
sizeof(
int) <= msg_end) {
1397 rsock_discard_cmsg_resource(
struct msghdr *mh,
int msg_peek_p)
1399 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1400 struct cmsghdr *cmh;
1408 for (cmh = CMSG_FIRSTHDR(mh); cmh !=
NULL; cmh = CMSG_NXTHDR(mh, cmh)) {
1409 discard_cmsg(cmh, msg_end, msg_peek_p);
1414 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1416 make_io_for_unix_rights(
VALUE ctl,
struct cmsghdr *cmh,
char *msg_end)
1418 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
1422 fdp = (
int *)CMSG_DATA(cmh);
1423 end = (
int *)((
char *)cmh + cmh->cmsg_len);
1424 while ((
char *)fdp +
sizeof(
int) <= (
char *)end &&
1425 (
char *)fdp +
sizeof(
int) <= msg_end) {
1429 if (
fstat(fd, &stbuf) == -1)
1450 bsock_recvmsg_internal(
VALUE sock,
1457 int flags, orig_flags;
1465 int request_scm_rights;
1466 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1467 struct cmsghdr *cmh;
1476 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1479 if (!
NIL_P(vmaxctllen))
1485 flags |= MSG_DONTWAIT;
1489 grow_buffer =
NIL_P(vmaxdatlen) ||
NIL_P(vmaxctllen);
1491 request_scm_rights = 0;
1492 if (
RTEST(scm_rights))
1493 request_scm_rights = 1;
1494 #if !defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1495 if (request_scm_rights)
1504 #if !defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1508 if (getsockopt(fptr->
fd, SOL_SOCKET, SO_TYPE, (
void*)&socktype, &optlen) == -1) {
1511 if (socktype == SOCK_STREAM)
1523 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1531 memset(&mh, 0,
sizeof(mh));
1533 memset(&namebuf, 0,
sizeof(namebuf));
1539 iov.iov_base = datbuf;
1540 iov.iov_len = maxdatlen;
1542 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1554 ss = rb_recvmsg(fptr->
fd, &mh, flags);
1565 return sym_wait_readable;
1569 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1592 if (
NIL_P(vmaxdatlen) && ss != -1 && ss == (
ssize_t)iov.iov_len) {
1598 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1600 #define BIG_ENOUGH_SPACE 65536
1601 if (BIG_ENOUGH_SPACE < maxctllen &&
1606 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
1616 #undef BIG_ENOUGH_SPACE
1620 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
1625 if (flags != orig_flags) {
1626 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
1642 #
if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1649 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1653 for (cmh = CMSG_FIRSTHDR(&mh); cmh !=
NULL; cmh = CMSG_NXTHDR(&mh, cmh)) {
1657 if (cmh->cmsg_len == 0) {
1660 ctl_end = (
char*)cmh + cmh->cmsg_len;
1661 clen = (ctl_end <= msg_end ? ctl_end : msg_end) - (
char*)CMSG_DATA(cmh);
1662 ctl = ancdata_new(family, cmh->cmsg_level, cmh->cmsg_type,
rb_str_new((
char*)CMSG_DATA(cmh), clen));
1663 if (request_scm_rights)
1664 make_io_for_unix_rights(ctl, cmh, msg_end);
1666 discard_cmsg(cmh, msg_end, (flags & MSG_PEEK) != 0);
1677 #if defined(HAVE_RECVMSG)
1683 return bsock_recvmsg_internal(sock, dlen, flags, clen, scm_rights, ex, 0);
1687 #if defined(HAVE_RECVMSG)
1692 return bsock_recvmsg_internal(sock, dlen, flags, clen, scm_rights, ex, 1);
1699 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1708 rb_define_method(rb_cAncillaryData,
"initialize", ancillary_initialize, 4);
1721 rb_define_method(rb_cAncillaryData,
"unix_rights", ancillary_unix_rights, 0);
1726 rb_define_method(rb_cAncillaryData,
"ip_pktinfo", ancillary_ip_pktinfo, 0);
1729 rb_define_method(rb_cAncillaryData,
"ipv6_pktinfo", ancillary_ipv6_pktinfo, 0);
1730 rb_define_method(rb_cAncillaryData,
"ipv6_pktinfo_addr", ancillary_ipv6_pktinfo_addr, 0);
1731 rb_define_method(rb_cAncillaryData,
"ipv6_pktinfo_ifindex", ancillary_ipv6_pktinfo_ifindex, 0);