1#include "rubysocket.h" 2 3#include <time.h> 4 5#if defined(HAVE_ST_MSG_CONTROL) 6static VALUE rb_cAncillaryData; 7 8static VALUE 9constant_to_sym(int constant, ID (*intern_const)(int)) 10{ 11 ID name = intern_const(constant); 12 if (name) { 13 return ID2SYM(name); 14 } 15 16 return INT2NUM(constant); 17} 18 19static VALUE 20ip_cmsg_type_to_sym(int level, int cmsg_type) 21{ 22 switch (level) { 23 case SOL_SOCKET: 24 return constant_to_sym(cmsg_type, rsock_intern_scm_optname); 25 case IPPROTO_IP: 26 return constant_to_sym(cmsg_type, rsock_intern_ip_optname); 27#ifdef IPPROTO_IPV6 28 case IPPROTO_IPV6: 29 return constant_to_sym(cmsg_type, rsock_intern_ipv6_optname); 30#endif 31 case IPPROTO_TCP: 32 return constant_to_sym(cmsg_type, rsock_intern_tcp_optname); 33 case IPPROTO_UDP: 34 return constant_to_sym(cmsg_type, rsock_intern_udp_optname); 35 default: 36 return INT2NUM(cmsg_type); 37 } 38} 39 40/* 41 * call-seq: 42 * Socket::AncillaryData.new(family, cmsg_level, cmsg_type, cmsg_data) -> ancillarydata 43 * 44 * _family_ should be an integer, a string or a symbol. 45 * - Socket::AF_INET, "AF_INET", "INET", :AF_INET, :INET 46 * - Socket::AF_UNIX, "AF_UNIX", "UNIX", :AF_UNIX, :UNIX 47 * - etc. 48 * 49 * _cmsg_level_ should be an integer, a string or a symbol. 50 * - Socket::SOL_SOCKET, "SOL_SOCKET", "SOCKET", :SOL_SOCKET and :SOCKET 51 * - Socket::IPPROTO_IP, "IP" and :IP 52 * - Socket::IPPROTO_IPV6, "IPV6" and :IPV6 53 * - Socket::IPPROTO_TCP, "TCP" and :TCP 54 * - etc. 55 * 56 * _cmsg_type_ should be an integer, a string or a symbol. 57 * If a string/symbol is specified, it is interpreted depend on _cmsg_level_. 58 * - Socket::SCM_RIGHTS, "SCM_RIGHTS", "RIGHTS", :SCM_RIGHTS, :RIGHTS for SOL_SOCKET 59 * - Socket::IP_RECVTTL, "RECVTTL" and :RECVTTL for IPPROTO_IP 60 * - Socket::IPV6_PKTINFO, "PKTINFO" and :PKTINFO for IPPROTO_IPV6 61 * - etc. 62 * 63 * _cmsg_data_ should be a string. 64 * 65 * p Socket::AncillaryData.new(:INET, :TCP, :NODELAY, "") 66 * #=> #<Socket::AncillaryData: INET TCP NODELAY ""> 67 * 68 * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "") 69 * #=> #<Socket::AncillaryData: INET6 IPV6 PKTINFO ""> 70 * 71 */ 72static VALUE 73ancillary_initialize(VALUE self, VALUE vfamily, VALUE vlevel, VALUE vtype, VALUE data) 74{ 75 int family = rsock_family_arg(vfamily); 76 int level = rsock_level_arg(family, vlevel); 77 int type = rsock_cmsg_type_arg(family, level, vtype); 78 StringValue(data); 79 rb_ivar_set(self, rb_intern("family"), INT2NUM(family)); 80 rb_ivar_set(self, rb_intern("level"), INT2NUM(level)); 81 rb_ivar_set(self, rb_intern("type"), INT2NUM(type)); 82 rb_ivar_set(self, rb_intern("data"), data); 83 return self; 84} 85 86static VALUE 87ancdata_new(int family, int level, int type, VALUE data) 88{ 89 NEWOBJ_OF(obj, struct RObject, rb_cAncillaryData, T_OBJECT); 90 StringValue(data); 91 ancillary_initialize((VALUE)obj, INT2NUM(family), INT2NUM(level), INT2NUM(type), data); 92 return (VALUE)obj; 93} 94 95static int 96ancillary_family(VALUE self) 97{ 98 VALUE v = rb_attr_get(self, rb_intern("family")); 99 return NUM2INT(v); 100} 101 102/* 103 * call-seq: 104 * ancillarydata.family => integer 105 * 106 * returns the socket family as an integer. 107 * 108 * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").family 109 * #=> 10 110 */ 111static VALUE 112ancillary_family_m(VALUE self) 113{ 114 return INT2NUM(ancillary_family(self)); 115} 116 117static int 118ancillary_level(VALUE self) 119{ 120 VALUE v = rb_attr_get(self, rb_intern("level")); 121 return NUM2INT(v); 122} 123 124/* 125 * call-seq: 126 * ancillarydata.level => integer 127 * 128 * returns the cmsg level as an integer. 129 * 130 * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").level 131 * #=> 41 132 */ 133static VALUE 134ancillary_level_m(VALUE self) 135{ 136 return INT2NUM(ancillary_level(self)); 137} 138 139static int 140ancillary_type(VALUE self) 141{ 142 VALUE v = rb_attr_get(self, rb_intern("type")); 143 return NUM2INT(v); 144} 145 146/* 147 * call-seq: 148 * ancillarydata.type => integer 149 * 150 * returns the cmsg type as an integer. 151 * 152 * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").type 153 * #=> 2 154 */ 155static VALUE 156ancillary_type_m(VALUE self) 157{ 158 return INT2NUM(ancillary_type(self)); 159} 160 161/* 162 * call-seq: 163 * ancillarydata.data => string 164 * 165 * returns the cmsg data as a string. 166 * 167 * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").data 168 * #=> "" 169 */ 170static VALUE 171ancillary_data(VALUE self) 172{ 173 VALUE v = rb_attr_get(self, rb_intern("data")); 174 StringValue(v); 175 return v; 176} 177 178#ifdef SCM_RIGHTS 179/* 180 * call-seq: 181 * Socket::AncillaryData.unix_rights(io1, io2, ...) => ancillarydata 182 * 183 * Creates a new Socket::AncillaryData object which contains file descriptors as data. 184 * 185 * p Socket::AncillaryData.unix_rights(STDERR) 186 * #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 2> 187 */ 188static VALUE 189ancillary_s_unix_rights(int argc, VALUE *argv, VALUE klass) 190{ 191 VALUE result, str, ary; 192 int i; 193 194 ary = rb_ary_new(); 195 196 for (i = 0 ; i < argc; i++) { 197 VALUE obj = argv[i]; 198 if (!RB_TYPE_P(obj, T_FILE)) { 199 rb_raise(rb_eTypeError, "IO expected"); 200 } 201 rb_ary_push(ary, obj); 202 } 203 204 str = rb_str_buf_new(sizeof(int) * argc); 205 206 for (i = 0 ; i < argc; i++) { 207 VALUE obj = RARRAY_PTR(ary)[i]; 208 rb_io_t *fptr; 209 int fd; 210 GetOpenFile(obj, fptr); 211 fd = fptr->fd; 212 rb_str_buf_cat(str, (char *)&fd, sizeof(int)); 213 } 214 215 result = ancdata_new(AF_UNIX, SOL_SOCKET, SCM_RIGHTS, str); 216 rb_ivar_set(result, rb_intern("unix_rights"), ary); 217 return result; 218} 219#else 220#define ancillary_s_unix_rights rb_f_notimplement 221#endif 222 223#ifdef SCM_RIGHTS 224/* 225 * call-seq: 226 * ancillarydata.unix_rights => array-of-IOs or nil 227 * 228 * returns the array of IO objects for SCM_RIGHTS control message in UNIX domain socket. 229 * 230 * The class of the IO objects in the array is IO or Socket. 231 * 232 * The array is attached to _ancillarydata_ when it is instantiated. 233 * For example, BasicSocket#recvmsg attach the array when 234 * receives a SCM_RIGHTS control message and :scm_rights=>true option is given. 235 * 236 * # recvmsg needs :scm_rights=>true for unix_rights 237 * s1, s2 = UNIXSocket.pair 238 * p s1 #=> #<UNIXSocket:fd 3> 239 * s1.sendmsg "stdin and a socket", 0, nil, Socket::AncillaryData.unix_rights(STDIN, s1) 240 * _, _, _, ctl = s2.recvmsg(:scm_rights=>true) 241 * p ctl #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 6 7> 242 * p ctl.unix_rights #=> [#<IO:fd 6>, #<Socket:fd 7>] 243 * p File.identical?(STDIN, ctl.unix_rights[0]) #=> true 244 * p File.identical?(s1, ctl.unix_rights[1]) #=> true 245 * 246 * # If :scm_rights=>true is not given, unix_rights returns nil 247 * s1, s2 = UNIXSocket.pair 248 * s1.sendmsg "stdin and a socket", 0, nil, Socket::AncillaryData.unix_rights(STDIN, s1) 249 * _, _, _, ctl = s2.recvmsg 250 * p ctl #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 6 7> 251 * p ctl.unix_rights #=> nil 252 * 253 */ 254static VALUE 255ancillary_unix_rights(VALUE self) 256{ 257 int level, type; 258 259 level = ancillary_level(self); 260 type = ancillary_type(self); 261 262 if (level != SOL_SOCKET || type != SCM_RIGHTS) 263 rb_raise(rb_eTypeError, "SCM_RIGHTS ancillary data expected"); 264 265 return rb_attr_get(self, rb_intern("unix_rights")); 266} 267#else 268#define ancillary_unix_rights rb_f_notimplement 269#endif 270 271#if defined(SCM_TIMESTAMP) || defined(SCM_TIMESTAMPNS) || defined(SCM_BINTIME) 272/* 273 * call-seq: 274 * ancillarydata.timestamp => time 275 * 276 * returns the timestamp as a time object. 277 * 278 * _ancillarydata_ should be one of following type: 279 * - SOL_SOCKET/SCM_TIMESTAMP (micro second) GNU/Linux, FreeBSD, NetBSD, OpenBSD, Solaris, MacOS X 280 * - SOL_SOCKET/SCM_TIMESTAMPNS (nano second) GNU/Linux 281 * - SOL_SOCKET/SCM_BINTIME (2**(-64) second) FreeBSD 282 * 283 * Addrinfo.udp("127.0.0.1", 0).bind {|s1| 284 * Addrinfo.udp("127.0.0.1", 0).bind {|s2| 285 * s1.setsockopt(:SOCKET, :TIMESTAMP, true) 286 * s2.send "a", 0, s1.local_address 287 * ctl = s1.recvmsg.last 288 * p ctl #=> #<Socket::AncillaryData: INET SOCKET TIMESTAMP 2009-02-24 17:35:46.775581> 289 * t = ctl.timestamp 290 * p t #=> 2009-02-24 17:35:46 +0900 291 * p t.usec #=> 775581 292 * p t.nsec #=> 775581000 293 * } 294 * } 295 * 296 */ 297static VALUE 298ancillary_timestamp(VALUE self) 299{ 300 int level, type; 301 VALUE data; 302 VALUE result = Qnil; 303 304 level = ancillary_level(self); 305 type = ancillary_type(self); 306 data = ancillary_data(self); 307 308# ifdef SCM_TIMESTAMP 309 if (level == SOL_SOCKET && type == SCM_TIMESTAMP && 310 RSTRING_LEN(data) == sizeof(struct timeval)) { 311 struct timeval tv; 312 memcpy((char*)&tv, RSTRING_PTR(data), sizeof(tv)); 313 result = rb_time_new(tv.tv_sec, tv.tv_usec); 314 } 315# endif 316 317# ifdef SCM_TIMESTAMPNS 318 if (level == SOL_SOCKET && type == SCM_TIMESTAMPNS && 319 RSTRING_LEN(data) == sizeof(struct timespec)) { 320 struct timespec ts; 321 memcpy((char*)&ts, RSTRING_PTR(data), sizeof(ts)); 322 result = rb_time_nano_new(ts.tv_sec, ts.tv_nsec); 323 } 324# endif 325 326#define add(x,y) (rb_funcall((x), '+', 1, (y))) 327#define mul(x,y) (rb_funcall((x), '*', 1, (y))) 328#define quo(x,y) (rb_funcall((x), rb_intern("quo"), 1, (y))) 329 330# ifdef SCM_BINTIME 331 if (level == SOL_SOCKET && type == SCM_BINTIME && 332 RSTRING_LEN(data) == sizeof(struct bintime)) { 333 struct bintime bt; 334 VALUE d, timev; 335 memcpy((char*)&bt, RSTRING_PTR(data), sizeof(bt)); 336 d = ULL2NUM(0x100000000ULL); 337 d = mul(d,d); 338 timev = add(TIMET2NUM(bt.sec), quo(ULL2NUM(bt.frac), d)); 339 result = rb_time_num_new(timev, Qnil); 340 } 341# endif 342 343 if (result == Qnil) 344 rb_raise(rb_eTypeError, "timestamp ancillary data expected"); 345 346 return result; 347} 348#else 349#define ancillary_timestamp rb_f_notimplement 350#endif 351 352/* 353 * call-seq: 354 * Socket::AncillaryData.int(family, cmsg_level, cmsg_type, integer) => ancillarydata 355 * 356 * Creates a new Socket::AncillaryData object which contains a int as data. 357 * 358 * The size and endian is dependent on the host. 359 * 360 * p Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, STDERR.fileno) 361 * #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 2> 362 */ 363static VALUE 364ancillary_s_int(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE vtype, VALUE integer) 365{ 366 int family = rsock_family_arg(vfamily); 367 int level = rsock_level_arg(family, vlevel); 368 int type = rsock_cmsg_type_arg(family, level, vtype); 369 int i = NUM2INT(integer); 370 return ancdata_new(family, level, type, rb_str_new((char*)&i, sizeof(i))); 371} 372 373/* 374 * call-seq: 375 * ancillarydata.int => integer 376 * 377 * Returns the data in _ancillarydata_ as an int. 378 * 379 * The size and endian is dependent on the host. 380 * 381 * ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, STDERR.fileno) 382 * p ancdata.int #=> 2 383 */ 384static VALUE 385ancillary_int(VALUE self) 386{ 387 VALUE data; 388 int i; 389 data = ancillary_data(self); 390 if (RSTRING_LEN(data) != sizeof(int)) 391 rb_raise(rb_eTypeError, "size differ. expected as sizeof(int)=%d but %ld", (int)sizeof(int), (long)RSTRING_LEN(data)); 392 memcpy((char*)&i, RSTRING_PTR(data), sizeof(int)); 393 return INT2NUM(i); 394} 395 396#if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST) /* GNU/Linux */ 397/* 398 * call-seq: 399 * Socket::AncillaryData.ip_pktinfo(addr, ifindex) => ancdata 400 * Socket::AncillaryData.ip_pktinfo(addr, ifindex, spec_dst) => ancdata 401 * 402 * Returns new ancillary data for IP_PKTINFO. 403 * 404 * If spec_dst is not given, addr is used. 405 * 406 * IP_PKTINFO is not standard. 407 * 408 * Supported platform: GNU/Linux 409 * 410 * addr = Addrinfo.ip("127.0.0.1") 411 * ifindex = 0 412 * spec_dst = Addrinfo.ip("127.0.0.1") 413 * p Socket::AncillaryData.ip_pktinfo(addr, ifindex, spec_dst) 414 * #=> #<Socket::AncillaryData: INET IP PKTINFO 127.0.0.1 ifindex:0 spec_dst:127.0.0.1> 415 * 416 */ 417static VALUE 418ancillary_s_ip_pktinfo(int argc, VALUE *argv, VALUE self) 419{ 420 VALUE v_addr, v_ifindex, v_spec_dst; 421 unsigned int ifindex; 422 struct sockaddr_in sa; 423 struct in_pktinfo pktinfo; 424 425 rb_scan_args(argc, argv, "21", &v_addr, &v_ifindex, &v_spec_dst); 426 427 SockAddrStringValue(v_addr); 428 ifindex = NUM2UINT(v_ifindex); 429 if (NIL_P(v_spec_dst)) 430 v_spec_dst = v_addr; 431 else 432 SockAddrStringValue(v_spec_dst); 433 434 memset(&pktinfo, 0, sizeof(pktinfo)); 435 436 memset(&sa, 0, sizeof(sa)); 437 if (RSTRING_LEN(v_addr) != sizeof(sa)) 438 rb_raise(rb_eArgError, "addr size different to AF_INET sockaddr"); 439 memcpy(&sa, RSTRING_PTR(v_addr), sizeof(sa)); 440 if (sa.sin_family != AF_INET) 441 rb_raise(rb_eArgError, "addr is not AF_INET sockaddr"); 442 memcpy(&pktinfo.ipi_addr, &sa.sin_addr, sizeof(pktinfo.ipi_addr)); 443 444 pktinfo.ipi_ifindex = ifindex; 445 446 memset(&sa, 0, sizeof(sa)); 447 if (RSTRING_LEN(v_spec_dst) != sizeof(sa)) 448 rb_raise(rb_eArgError, "spec_dat size different to AF_INET sockaddr"); 449 memcpy(&sa, RSTRING_PTR(v_spec_dst), sizeof(sa)); 450 if (sa.sin_family != AF_INET) 451 rb_raise(rb_eArgError, "spec_dst is not AF_INET sockaddr"); 452 memcpy(&pktinfo.ipi_spec_dst, &sa.sin_addr, sizeof(pktinfo.ipi_spec_dst)); 453 454 return ancdata_new(AF_INET, IPPROTO_IP, IP_PKTINFO, rb_str_new((char *)&pktinfo, sizeof(pktinfo))); 455} 456#else 457#define ancillary_s_ip_pktinfo rb_f_notimplement 458#endif 459 460#if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST) /* GNU/Linux */ 461/* 462 * call-seq: 463 * ancdata.ip_pktinfo => [addr, ifindex, spec_dst] 464 * 465 * Extracts addr, ifindex and spec_dst from IP_PKTINFO ancillary data. 466 * 467 * IP_PKTINFO is not standard. 468 * 469 * Supported platform: GNU/Linux 470 * 471 * addr = Addrinfo.ip("127.0.0.1") 472 * ifindex = 0 473 * spec_dest = Addrinfo.ip("127.0.0.1") 474 * ancdata = Socket::AncillaryData.ip_pktinfo(addr, ifindex, spec_dest) 475 * p ancdata.ip_pktinfo 476 * #=> [#<Addrinfo: 127.0.0.1>, 0, #<Addrinfo: 127.0.0.1>] 477 * 478 * 479 */ 480static VALUE 481ancillary_ip_pktinfo(VALUE self) 482{ 483 int level, type; 484 VALUE data; 485 struct in_pktinfo pktinfo; 486 struct sockaddr_in sa; 487 VALUE v_spec_dst, v_addr; 488 489 level = ancillary_level(self); 490 type = ancillary_type(self); 491 data = ancillary_data(self); 492 493 if (level != IPPROTO_IP || type != IP_PKTINFO || 494 RSTRING_LEN(data) != sizeof(struct in_pktinfo)) { 495 rb_raise(rb_eTypeError, "IP_PKTINFO ancillary data expected"); 496 } 497 498 memcpy(&pktinfo, RSTRING_PTR(data), sizeof(struct in_pktinfo)); 499 memset(&sa, 0, sizeof(sa)); 500 501 sa.sin_family = AF_INET; 502 memcpy(&sa.sin_addr, &pktinfo.ipi_addr, sizeof(sa.sin_addr)); 503 v_addr = rsock_addrinfo_new((struct sockaddr *)&sa, sizeof(sa), PF_INET, 0, 0, Qnil, Qnil); 504 505 sa.sin_family = AF_INET; 506 memcpy(&sa.sin_addr, &pktinfo.ipi_spec_dst, sizeof(sa.sin_addr)); 507 v_spec_dst = rsock_addrinfo_new((struct sockaddr *)&sa, sizeof(sa), PF_INET, 0, 0, Qnil, Qnil); 508 509 return rb_ary_new3(3, v_addr, UINT2NUM(pktinfo.ipi_ifindex), v_spec_dst); 510} 511#else 512#define ancillary_ip_pktinfo rb_f_notimplement 513#endif 514 515#if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */ 516/* 517 * call-seq: 518 * Socket::AncillaryData.ipv6_pktinfo(addr, ifindex) => ancdata 519 * 520 * Returns new ancillary data for IPV6_PKTINFO. 521 * 522 * IPV6_PKTINFO is defined by RFC 3542. 523 * 524 * addr = Addrinfo.ip("::1") 525 * ifindex = 0 526 * p Socket::AncillaryData.ipv6_pktinfo(addr, ifindex) 527 * #=> #<Socket::AncillaryData: INET6 IPV6 PKTINFO ::1 ifindex:0> 528 * 529 */ 530static VALUE 531ancillary_s_ipv6_pktinfo(VALUE self, VALUE v_addr, VALUE v_ifindex) 532{ 533 unsigned int ifindex; 534 struct sockaddr_in6 sa; 535 struct in6_pktinfo pktinfo; 536 537 SockAddrStringValue(v_addr); 538 ifindex = NUM2UINT(v_ifindex); 539 540 memset(&pktinfo, 0, sizeof(pktinfo)); 541 542 memset(&sa, 0, sizeof(sa)); 543 if (RSTRING_LEN(v_addr) != sizeof(sa)) 544 rb_raise(rb_eArgError, "addr size different to AF_INET6 sockaddr"); 545 memcpy(&sa, RSTRING_PTR(v_addr), sizeof(sa)); 546 if (sa.sin6_family != AF_INET6) 547 rb_raise(rb_eArgError, "addr is not AF_INET6 sockaddr"); 548 memcpy(&pktinfo.ipi6_addr, &sa.sin6_addr, sizeof(pktinfo.ipi6_addr)); 549 550 pktinfo.ipi6_ifindex = ifindex; 551 552 return ancdata_new(AF_INET6, IPPROTO_IPV6, IPV6_PKTINFO, rb_str_new((char *)&pktinfo, sizeof(pktinfo))); 553} 554#else 555#define ancillary_s_ipv6_pktinfo rb_f_notimplement 556#endif 557 558#if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */ 559static void 560extract_ipv6_pktinfo(VALUE self, struct in6_pktinfo *pktinfo_ptr, struct sockaddr_in6 *sa_ptr) 561{ 562 int level, type; 563 VALUE data; 564 565 level = ancillary_level(self); 566 type = ancillary_type(self); 567 data = ancillary_data(self); 568 569 if (level != IPPROTO_IPV6 || type != IPV6_PKTINFO || 570 RSTRING_LEN(data) != sizeof(struct in6_pktinfo)) { 571 rb_raise(rb_eTypeError, "IPV6_PKTINFO ancillary data expected"); 572 } 573 574 memcpy(pktinfo_ptr, RSTRING_PTR(data), sizeof(*pktinfo_ptr)); 575 576 memset(sa_ptr, 0, sizeof(*sa_ptr)); 577 SET_SA_LEN((struct sockaddr *)sa_ptr, sizeof(struct sockaddr_in6)); 578 sa_ptr->sin6_family = AF_INET6; 579 memcpy(&sa_ptr->sin6_addr, &pktinfo_ptr->ipi6_addr, sizeof(sa_ptr->sin6_addr)); 580 if (IN6_IS_ADDR_LINKLOCAL(&sa_ptr->sin6_addr)) 581 sa_ptr->sin6_scope_id = pktinfo_ptr->ipi6_ifindex; 582} 583#endif 584 585#if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */ 586/* 587 * call-seq: 588 * ancdata.ipv6_pktinfo => [addr, ifindex] 589 * 590 * Extracts addr and ifindex from IPV6_PKTINFO ancillary data. 591 * 592 * IPV6_PKTINFO is defined by RFC 3542. 593 * 594 * addr = Addrinfo.ip("::1") 595 * ifindex = 0 596 * ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex) 597 * p ancdata.ipv6_pktinfo #=> [#<Addrinfo: ::1>, 0] 598 * 599 */ 600static VALUE 601ancillary_ipv6_pktinfo(VALUE self) 602{ 603 struct in6_pktinfo pktinfo; 604 struct sockaddr_in6 sa; 605 VALUE v_addr; 606 607 extract_ipv6_pktinfo(self, &pktinfo, &sa); 608 v_addr = rsock_addrinfo_new((struct sockaddr *)&sa, (socklen_t)sizeof(sa), PF_INET6, 0, 0, Qnil, Qnil); 609 return rb_ary_new3(2, v_addr, UINT2NUM(pktinfo.ipi6_ifindex)); 610} 611#else 612#define ancillary_ipv6_pktinfo rb_f_notimplement 613#endif 614 615#if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */ 616/* 617 * call-seq: 618 * ancdata.ipv6_pktinfo_addr => addr 619 * 620 * Extracts addr from IPV6_PKTINFO ancillary data. 621 * 622 * IPV6_PKTINFO is defined by RFC 3542. 623 * 624 * addr = Addrinfo.ip("::1") 625 * ifindex = 0 626 * ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex) 627 * p ancdata.ipv6_pktinfo_addr #=> #<Addrinfo: ::1> 628 * 629 */ 630static VALUE 631ancillary_ipv6_pktinfo_addr(VALUE self) 632{ 633 struct in6_pktinfo pktinfo; 634 struct sockaddr_in6 sa; 635 extract_ipv6_pktinfo(self, &pktinfo, &sa); 636 return rsock_addrinfo_new((struct sockaddr *)&sa, (socklen_t)sizeof(sa), PF_INET6, 0, 0, Qnil, Qnil); 637} 638#else 639#define ancillary_ipv6_pktinfo_addr rb_f_notimplement 640#endif 641 642#if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */ 643/* 644 * call-seq: 645 * ancdata.ipv6_pktinfo_ifindex => addr 646 * 647 * Extracts ifindex from IPV6_PKTINFO ancillary data. 648 * 649 * IPV6_PKTINFO is defined by RFC 3542. 650 * 651 * addr = Addrinfo.ip("::1") 652 * ifindex = 0 653 * ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex) 654 * p ancdata.ipv6_pktinfo_ifindex #=> 0 655 * 656 */ 657static VALUE 658ancillary_ipv6_pktinfo_ifindex(VALUE self) 659{ 660 struct in6_pktinfo pktinfo; 661 struct sockaddr_in6 sa; 662 extract_ipv6_pktinfo(self, &pktinfo, &sa); 663 return UINT2NUM(pktinfo.ipi6_ifindex); 664} 665#else 666#define ancillary_ipv6_pktinfo_ifindex rb_f_notimplement 667#endif 668 669#if defined(SOL_SOCKET) && defined(SCM_RIGHTS) /* 4.4BSD */ 670static int 671anc_inspect_socket_rights(int level, int type, VALUE data, VALUE ret) 672{ 673 if (level == SOL_SOCKET && type == SCM_RIGHTS && 674 0 < RSTRING_LEN(data) && (RSTRING_LEN(data) % sizeof(int) == 0)) { 675 long off; 676 for (off = 0; off < RSTRING_LEN(data); off += sizeof(int)) { 677 int fd; 678 memcpy((char*)&fd, RSTRING_PTR(data)+off, sizeof(int)); 679 rb_str_catf(ret, " %d", fd); 680 } 681 return 1; 682 } 683 else { 684 return 0; 685 } 686} 687#endif 688 689#if defined(SCM_CREDENTIALS) /* GNU/Linux */ 690static int 691anc_inspect_passcred_credentials(int level, int type, VALUE data, VALUE ret) 692{ 693 if (level == SOL_SOCKET && type == SCM_CREDENTIALS && 694 RSTRING_LEN(data) == sizeof(struct ucred)) { 695 struct ucred cred; 696 memcpy(&cred, RSTRING_PTR(data), sizeof(struct ucred)); 697 rb_str_catf(ret, " pid=%u uid=%u gid=%u", cred.pid, cred.uid, cred.gid); 698 rb_str_cat2(ret, " (ucred)"); 699 return 1; 700 } 701 else { 702 return 0; 703 } 704} 705#endif 706 707#if defined(SCM_CREDS) 708#define INSPECT_SCM_CREDS 709static int 710anc_inspect_socket_creds(int level, int type, VALUE data, VALUE ret) 711{ 712 if (level != SOL_SOCKET && type != SCM_CREDS) 713 return 0; 714 715 /* 716 * FreeBSD has struct cmsgcred and struct sockcred. 717 * They use both SOL_SOCKET/SCM_CREDS in the ancillary message. 718 * They are not ambiguous from the view of the caller 719 * because struct sockcred is sent if and only if the caller sets LOCAL_CREDS socket option. 720 * But inspect method doesn't know it. 721 * So they are ambiguous from the view of inspect. 722 * This function distinguish them by the size of the ancillary message. 723 * This heuristics works well except when sc_ngroups == CMGROUP_MAX. 724 */ 725 726#if defined(HAVE_TYPE_STRUCT_CMSGCRED) /* FreeBSD */ 727 if (RSTRING_LEN(data) == sizeof(struct cmsgcred)) { 728 struct cmsgcred cred; 729 memcpy(&cred, RSTRING_PTR(data), sizeof(struct cmsgcred)); 730 rb_str_catf(ret, " pid=%u", cred.cmcred_pid); 731 rb_str_catf(ret, " uid=%u", cred.cmcred_uid); 732 rb_str_catf(ret, " euid=%u", cred.cmcred_euid); 733 rb_str_catf(ret, " gid=%u", cred.cmcred_gid); 734 if (cred.cmcred_ngroups) { 735 int i; 736 const char *sep = " groups="; 737 for (i = 0; i < cred.cmcred_ngroups; i++) { 738 rb_str_catf(ret, "%s%u", sep, cred.cmcred_groups[i]); 739 sep = ","; 740 } 741 } 742 rb_str_cat2(ret, " (cmsgcred)"); 743 return 1; 744 } 745#endif 746#if defined(HAVE_TYPE_STRUCT_SOCKCRED) /* FreeBSD, NetBSD */ 747 if ((size_t)RSTRING_LEN(data) >= SOCKCREDSIZE(0)) { 748 struct sockcred cred0, *cred; 749 memcpy(&cred0, RSTRING_PTR(data), SOCKCREDSIZE(0)); 750 if ((size_t)RSTRING_LEN(data) == SOCKCREDSIZE(cred0.sc_ngroups)) { 751 cred = (struct sockcred *)ALLOCA_N(char, SOCKCREDSIZE(cred0.sc_ngroups)); 752 memcpy(cred, RSTRING_PTR(data), SOCKCREDSIZE(cred0.sc_ngroups)); 753 rb_str_catf(ret, " uid=%u", cred->sc_uid); 754 rb_str_catf(ret, " euid=%u", cred->sc_euid); 755 rb_str_catf(ret, " gid=%u", cred->sc_gid); 756 rb_str_catf(ret, " egid=%u", cred->sc_egid); 757 if (cred0.sc_ngroups) { 758 int i; 759 const char *sep = " groups="; 760 for (i = 0; i < cred0.sc_ngroups; i++) { 761 rb_str_catf(ret, "%s%u", sep, cred->sc_groups[i]); 762 sep = ","; 763 } 764 } 765 rb_str_cat2(ret, " (sockcred)"); 766 return 1; 767 } 768 } 769#endif 770 return 0; 771} 772#endif 773 774#if defined(IPPROTO_IP) && defined(IP_RECVDSTADDR) /* 4.4BSD */ 775static int 776anc_inspect_ip_recvdstaddr(int level, int type, VALUE data, VALUE ret) 777{ 778 if (level == IPPROTO_IP && type == IP_RECVDSTADDR && 779 RSTRING_LEN(data) == sizeof(struct in_addr)) { 780 struct in_addr addr; 781 char addrbuf[INET_ADDRSTRLEN]; 782 memcpy(&addr, RSTRING_PTR(data), sizeof(addr)); 783 if (inet_ntop(AF_INET, &addr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL) 784 rb_str_cat2(ret, " invalid-address"); 785 else 786 rb_str_catf(ret, " %s", addrbuf); 787 return 1; 788 } 789 else { 790 return 0; 791 } 792} 793#endif 794 795#if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST) /* GNU/Linux */ 796static int 797anc_inspect_ip_pktinfo(int level, int type, VALUE data, VALUE ret) 798{ 799 if (level == IPPROTO_IP && type == IP_PKTINFO && 800 RSTRING_LEN(data) == sizeof(struct in_pktinfo)) { 801 struct in_pktinfo pktinfo; 802 char buf[INET_ADDRSTRLEN > IFNAMSIZ ? INET_ADDRSTRLEN : IFNAMSIZ]; 803 memcpy(&pktinfo, RSTRING_PTR(data), sizeof(pktinfo)); 804 if (inet_ntop(AF_INET, &pktinfo.ipi_addr, buf, sizeof(buf)) == NULL) 805 rb_str_cat2(ret, " invalid-address"); 806 else 807 rb_str_catf(ret, " %s", buf); 808 if (if_indextoname(pktinfo.ipi_ifindex, buf) == NULL) 809 rb_str_catf(ret, " ifindex:%d", pktinfo.ipi_ifindex); 810 else 811 rb_str_catf(ret, " %s", buf); 812 if (inet_ntop(AF_INET, &pktinfo.ipi_spec_dst, buf, sizeof(buf)) == NULL) 813 rb_str_cat2(ret, " spec_dst:invalid-address"); 814 else 815 rb_str_catf(ret, " spec_dst:%s", buf); 816 return 1; 817 } 818 else { 819 return 0; 820 } 821} 822#endif 823 824#if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN6_PKTINFO) /* IPv6 RFC3542 */ 825static int 826anc_inspect_ipv6_pktinfo(int level, int type, VALUE data, VALUE ret) 827{ 828 if (level == IPPROTO_IPV6 && type == IPV6_PKTINFO && 829 RSTRING_LEN(data) == sizeof(struct in6_pktinfo)) { 830 struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)RSTRING_PTR(data); 831 struct in6_addr addr; 832 unsigned int ifindex; 833 char addrbuf[INET6_ADDRSTRLEN], ifbuf[IFNAMSIZ]; 834 memcpy(&addr, &pktinfo->ipi6_addr, sizeof(addr)); 835 memcpy(&ifindex, &pktinfo->ipi6_ifindex, sizeof(ifindex)); 836 if (inet_ntop(AF_INET6, &addr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL) 837 rb_str_cat2(ret, " invalid-address"); 838 else 839 rb_str_catf(ret, " %s", addrbuf); 840 if (if_indextoname(ifindex, ifbuf) == NULL) 841 rb_str_catf(ret, " ifindex:%d", ifindex); 842 else 843 rb_str_catf(ret, " %s", ifbuf); 844 return 1; 845 } 846 else { 847 return 0; 848 } 849} 850#endif 851 852#if defined(SCM_TIMESTAMP) /* GNU/Linux, FreeBSD, NetBSD, OpenBSD, MacOS X, Solaris */ 853static int 854inspect_timeval_as_abstime(int level, int optname, VALUE data, VALUE ret) 855{ 856 if (RSTRING_LEN(data) == sizeof(struct timeval)) { 857 struct timeval tv; 858 time_t time; 859 struct tm tm; 860 char buf[32]; 861 memcpy((char*)&tv, RSTRING_PTR(data), sizeof(tv)); 862 time = tv.tv_sec; 863 tm = *localtime(&time); 864 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm); 865 rb_str_catf(ret, " %s.%06ld", buf, (long)tv.tv_usec); 866 return 1; 867 } 868 else { 869 return 0; 870 } 871} 872#endif 873 874#if defined(SCM_TIMESTAMPNS) /* GNU/Linux */ 875static int 876inspect_timespec_as_abstime(int level, int optname, VALUE data, VALUE ret) 877{ 878 if (RSTRING_LEN(data) == sizeof(struct timespec)) { 879 struct timespec ts; 880 struct tm tm; 881 char buf[32]; 882 memcpy((char*)&ts, RSTRING_PTR(data), sizeof(ts)); 883 tm = *localtime(&ts.tv_sec); 884 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm); 885 rb_str_catf(ret, " %s.%09ld", buf, (long)ts.tv_nsec); 886 return 1; 887 } 888 else { 889 return 0; 890 } 891} 892#endif 893 894#if defined(SCM_BINTIME) /* FreeBSD */ 895static int 896inspect_bintime_as_abstime(int level, int optname, VALUE data, VALUE ret) 897{ 898 if (RSTRING_LEN(data) == sizeof(struct bintime)) { 899 struct bintime bt; 900 struct tm tm; 901 uint64_t frac_h, frac_l; 902 uint64_t scale_h, scale_l; 903 uint64_t tmp1, tmp2; 904 uint64_t res_h, res_l; 905 char buf[32]; 906 memcpy((char*)&bt, RSTRING_PTR(data), sizeof(bt)); 907 tm = *localtime(&bt.sec); 908 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm); 909 910 /* res_h = frac * 10**19 / 2**64 */ 911 912 frac_h = bt.frac >> 32; 913 frac_l = bt.frac & 0xffffffff; 914 915 scale_h = 0x8ac72304; /* 0x8ac7230489e80000 == 10**19 */ 916 scale_l = 0x89e80000; 917 918 res_h = frac_h * scale_h; 919 res_l = frac_l * scale_l; 920 921 tmp1 = frac_h * scale_l; 922 res_h += tmp1 >> 32; 923 tmp2 = res_l; 924 res_l += tmp1 & 0xffffffff; 925 if (res_l < tmp2) res_h++; 926 927 tmp1 = frac_l * scale_h; 928 res_h += tmp1 >> 32; 929 tmp2 = res_l; 930 res_l += tmp1 & 0xffffffff; 931 if (res_l < tmp2) res_h++; 932 933 rb_str_catf(ret, " %s.%019"PRIu64, buf, res_h); 934 return 1; 935 } 936 else { 937 return 0; 938 } 939} 940#endif 941 942/* 943 * call-seq: 944 * ancillarydata.inspect => string 945 * 946 * returns a string which shows ancillarydata in human-readable form. 947 * 948 * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").inspect 949 * #=> "#<Socket::AncillaryData: INET6 IPV6 PKTINFO \"\">" 950 */ 951static VALUE 952ancillary_inspect(VALUE self) 953{ 954 VALUE ret; 955 int family, level, type; 956 VALUE data; 957 ID family_id, level_id, type_id; 958 VALUE vtype; 959 int inspected; 960 961 family = ancillary_family(self); 962 level = ancillary_level(self); 963 type = ancillary_type(self); 964 data = ancillary_data(self); 965 966 ret = rb_sprintf("#<%s:", rb_obj_classname(self)); 967 968 family_id = rsock_intern_family_noprefix(family); 969 if (family_id) 970 rb_str_catf(ret, " %s", rb_id2name(family_id)); 971 else 972 rb_str_catf(ret, " family:%d", family); 973 974 if (level == SOL_SOCKET) { 975 rb_str_cat2(ret, " SOCKET"); 976 977 type_id = rsock_intern_scm_optname(type); 978 if (type_id) 979 rb_str_catf(ret, " %s", rb_id2name(type_id)); 980 else 981 rb_str_catf(ret, " cmsg_type:%d", type); 982 } 983 else if (IS_IP_FAMILY(family)) { 984 level_id = rsock_intern_iplevel(level); 985 if (level_id) 986 rb_str_catf(ret, " %s", rb_id2name(level_id)); 987 else 988 rb_str_catf(ret, " cmsg_level:%d", level); 989 990 vtype = ip_cmsg_type_to_sym(level, type); 991 if (SYMBOL_P(vtype)) 992 rb_str_catf(ret, " %s", rb_id2name(SYM2ID(vtype))); 993 else 994 rb_str_catf(ret, " cmsg_type:%d", type); 995 } 996 else { 997 rb_str_catf(ret, " cmsg_level:%d", level); 998 rb_str_catf(ret, " cmsg_type:%d", type); 999 } 1000 1001 inspected = 0; 1002 1003 if (level == SOL_SOCKET) 1004 family = AF_UNSPEC; 1005 1006 switch (family) { 1007 case AF_UNSPEC: 1008 switch (level) { 1009# if defined(SOL_SOCKET) 1010 case SOL_SOCKET: 1011 switch (type) { 1012# if defined(SCM_TIMESTAMP) /* GNU/Linux, FreeBSD, NetBSD, OpenBSD, MacOS X, Solaris */ 1013 case SCM_TIMESTAMP: inspected = inspect_timeval_as_abstime(level, type, data, ret); break; 1014# endif 1015# if defined(SCM_TIMESTAMPNS) /* GNU/Linux */ 1016 case SCM_TIMESTAMPNS: inspected = inspect_timespec_as_abstime(level, type, data, ret); break; 1017# endif 1018# if defined(SCM_BINTIME) /* FreeBSD */ 1019 case SCM_BINTIME: inspected = inspect_bintime_as_abstime(level, type, data, ret); break; 1020# endif 1021# if defined(SCM_RIGHTS) /* 4.4BSD */ 1022 case SCM_RIGHTS: inspected = anc_inspect_socket_rights(level, type, data, ret); break; 1023# endif 1024# if defined(SCM_CREDENTIALS) /* GNU/Linux */ 1025 case SCM_CREDENTIALS: inspected = anc_inspect_passcred_credentials(level, type, data, ret); break; 1026# endif 1027# if defined(INSPECT_SCM_CREDS) /* NetBSD */ 1028 case SCM_CREDS: inspected = anc_inspect_socket_creds(level, type, data, ret); break; 1029# endif 1030 } 1031 break; 1032# endif 1033 } 1034 break; 1035 1036 case AF_INET: 1037#ifdef INET6 1038 case AF_INET6: 1039#endif 1040 switch (level) { 1041# if defined(IPPROTO_IP) 1042 case IPPROTO_IP: 1043 switch (type) { 1044# if defined(IP_RECVDSTADDR) /* 4.4BSD */ 1045 case IP_RECVDSTADDR: inspected = anc_inspect_ip_recvdstaddr(level, type, data, ret); break; 1046# endif 1047# if defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST) /* GNU/Linux */ 1048 case IP_PKTINFO: inspected = anc_inspect_ip_pktinfo(level, type, data, ret); break; 1049# endif 1050 } 1051 break; 1052# endif 1053 1054# if defined(IPPROTO_IPV6) 1055 case IPPROTO_IPV6: 1056 switch (type) { 1057# if defined(IPV6_PKTINFO) /* RFC 3542 */ 1058 case IPV6_PKTINFO: inspected = anc_inspect_ipv6_pktinfo(level, type, data, ret); break; 1059# endif 1060 } 1061 break; 1062# endif 1063 } 1064 break; 1065 } 1066 1067 if (!inspected) { 1068 rb_str_cat2(ret, " "); 1069 rb_str_append(ret, rb_str_dump(data)); 1070 } 1071 1072 rb_str_cat2(ret, ">"); 1073 1074 return ret; 1075} 1076 1077/* 1078 * call-seq: 1079 * ancillarydata.cmsg_is?(level, type) => true or false 1080 * 1081 * tests the level and type of _ancillarydata_. 1082 * 1083 * ancdata = Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "") 1084 * ancdata.cmsg_is?(Socket::IPPROTO_IPV6, Socket::IPV6_PKTINFO) #=> true 1085 * ancdata.cmsg_is?(:IPV6, :PKTINFO) #=> true 1086 * ancdata.cmsg_is?(:IP, :PKTINFO) #=> false 1087 * ancdata.cmsg_is?(:SOCKET, :RIGHTS) #=> false 1088 */ 1089static VALUE 1090ancillary_cmsg_is_p(VALUE self, VALUE vlevel, VALUE vtype) 1091{ 1092 int family = ancillary_family(self); 1093 int level = rsock_level_arg(family, vlevel); 1094 int type = rsock_cmsg_type_arg(family, level, vtype); 1095 1096 if (ancillary_level(self) == level && 1097 ancillary_type(self) == type) 1098 return Qtrue; 1099 else 1100 return Qfalse; 1101} 1102 1103#endif 1104 1105#if defined(HAVE_SENDMSG) 1106struct sendmsg_args_struct { 1107 int fd; 1108 const struct msghdr *msg; 1109 int flags; 1110}; 1111 1112static void * 1113nogvl_sendmsg_func(void *ptr) 1114{ 1115 struct sendmsg_args_struct *args = ptr; 1116 return (void *)(VALUE)sendmsg(args->fd, args->msg, args->flags); 1117} 1118 1119static ssize_t 1120rb_sendmsg(int fd, const struct msghdr *msg, int flags) 1121{ 1122 struct sendmsg_args_struct args; 1123 args.fd = fd; 1124 args.msg = msg; 1125 args.flags = flags; 1126 return (ssize_t)rb_thread_call_without_gvl(nogvl_sendmsg_func, &args, RUBY_UBF_IO, 0); 1127} 1128 1129static VALUE 1130bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock) 1131{ 1132 rb_io_t *fptr; 1133 VALUE data, vflags, dest_sockaddr; 1134 VALUE *controls_ptr; 1135 int controls_num; 1136 struct msghdr mh; 1137 struct iovec iov; 1138#if defined(HAVE_ST_MSG_CONTROL) 1139 volatile VALUE controls_str = 0; 1140#endif 1141 int flags; 1142 ssize_t ss; 1143 int family; 1144 1145 rb_secure(4); 1146 GetOpenFile(sock, fptr); 1147 family = rsock_getfamily(fptr->fd); 1148 1149 data = vflags = dest_sockaddr = Qnil; 1150 controls_ptr = NULL; 1151 controls_num = 0; 1152 1153 if (argc == 0) 1154 rb_raise(rb_eArgError, "mesg argument required"); 1155 data = argv[0]; 1156 if (1 < argc) vflags = argv[1]; 1157 if (2 < argc) dest_sockaddr = argv[2]; 1158 if (3 < argc) { controls_ptr = &argv[3]; controls_num = argc - 3; } 1159 1160 StringValue(data); 1161 1162 if (controls_num) { 1163#if defined(HAVE_ST_MSG_CONTROL) 1164 int i; 1165 size_t last_pad = 0; 1166#if defined(__NetBSD__) 1167 int last_level = 0; 1168 int last_type = 0; 1169#endif 1170 controls_str = rb_str_tmp_new(0); 1171 for (i = 0; i < controls_num; i++) { 1172 VALUE elt = controls_ptr[i], v; 1173 VALUE vlevel, vtype; 1174 int level, type; 1175 VALUE cdata; 1176 long oldlen; 1177 struct cmsghdr cmh; 1178 char *cmsg; 1179 size_t cspace; 1180 v = rb_check_convert_type(elt, T_ARRAY, "Array", "to_ary"); 1181 if (!NIL_P(v)) { 1182 elt = v; 1183 if (RARRAY_LEN(elt) != 3) 1184 rb_raise(rb_eArgError, "an element of controls should be 3-elements array"); 1185 vlevel = rb_ary_entry(elt, 0); 1186 vtype = rb_ary_entry(elt, 1); 1187 cdata = rb_ary_entry(elt, 2); 1188 } 1189 else { 1190 vlevel = rb_funcall(elt, rb_intern("level"), 0); 1191 vtype = rb_funcall(elt, rb_intern("type"), 0); 1192 cdata = rb_funcall(elt, rb_intern("data"), 0); 1193 } 1194 level = rsock_level_arg(family, vlevel); 1195 type = rsock_cmsg_type_arg(family, level, vtype); 1196 StringValue(cdata); 1197 oldlen = RSTRING_LEN(controls_str); 1198 cspace = CMSG_SPACE(RSTRING_LEN(cdata)); 1199 rb_str_resize(controls_str, oldlen + cspace); 1200 cmsg = RSTRING_PTR(controls_str)+oldlen; 1201 memset((char *)cmsg, 0, cspace); 1202 memset((char *)&cmh, 0, sizeof(cmh)); 1203 cmh.cmsg_level = level; 1204 cmh.cmsg_type = type; 1205 cmh.cmsg_len = (socklen_t)CMSG_LEN(RSTRING_LEN(cdata)); 1206 MEMCPY(cmsg, &cmh, char, sizeof(cmh)); 1207 MEMCPY(cmsg+((char*)CMSG_DATA(&cmh)-(char*)&cmh), RSTRING_PTR(cdata), char, RSTRING_LEN(cdata)); 1208#if defined(__NetBSD__) 1209 last_level = cmh.cmsg_level; 1210 last_type = cmh.cmsg_type; 1211#endif 1212 last_pad = cspace - cmh.cmsg_len; 1213 } 1214 if (last_pad) { 1215 /* 1216 * This code removes the last padding from msg_controllen. 1217 * 1218 * 4.3BSD-Reno reject the padding for SCM_RIGHTS. (There was no 64bit environments in those days?) 1219 * RFC 2292 require the padding. 1220 * RFC 3542 relaxes the condition - implementation must accept both as valid. 1221 * 1222 * Actual problems: 1223 * 1224 * - NetBSD 4.0.1 1225 * SCM_RIGHTS with padding causes EINVAL 1226 * IPV6_PKTINFO without padding causes "page fault trap" 1227 * http://www.netbsd.org/cgi-bin/query-pr-single.pl?number=40661 1228 * 1229 * - OpenBSD 4.4 1230 * IPV6_PKTINFO without padding causes EINVAL 1231 * 1232 * Basically, msg_controllen should contains the padding. 1233 * So the padding is removed only if a problem really exists. 1234 */ 1235#if defined(__NetBSD__) 1236 if (last_level == SOL_SOCKET && last_type == SCM_RIGHTS) 1237 rb_str_set_len(controls_str, RSTRING_LEN(controls_str)-last_pad); 1238#endif 1239 } 1240#else 1241 rb_raise(rb_eNotImpError, "control message for sendmsg is unimplemented"); 1242#endif 1243 } 1244 1245 flags = NIL_P(vflags) ? 0 : NUM2INT(vflags); 1246#ifdef MSG_DONTWAIT 1247 if (nonblock) 1248 flags |= MSG_DONTWAIT; 1249#endif 1250 1251 if (!NIL_P(dest_sockaddr)) 1252 SockAddrStringValue(dest_sockaddr); 1253 1254 rb_io_check_closed(fptr); 1255 1256 retry: 1257 memset(&mh, 0, sizeof(mh)); 1258 if (!NIL_P(dest_sockaddr)) { 1259 mh.msg_name = RSTRING_PTR(dest_sockaddr); 1260 mh.msg_namelen = RSTRING_LENINT(dest_sockaddr); 1261 } 1262 mh.msg_iovlen = 1; 1263 mh.msg_iov = &iov; 1264 iov.iov_base = RSTRING_PTR(data); 1265 iov.iov_len = RSTRING_LEN(data); 1266#if defined(HAVE_ST_MSG_CONTROL) 1267 if (controls_str) { 1268 mh.msg_control = RSTRING_PTR(controls_str); 1269 mh.msg_controllen = RSTRING_LENINT(controls_str); 1270 } 1271 else { 1272 mh.msg_control = NULL; 1273 mh.msg_controllen = 0; 1274 } 1275#endif 1276 1277 rb_io_check_closed(fptr); 1278 if (nonblock) 1279 rb_io_set_nonblock(fptr); 1280 1281 ss = rb_sendmsg(fptr->fd, &mh, flags); 1282 1283 if (ss == -1) { 1284 if (!nonblock && rb_io_wait_writable(fptr->fd)) { 1285 rb_io_check_closed(fptr); 1286 goto retry; 1287 } 1288 if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN)) 1289 rb_mod_sys_fail(rb_mWaitWritable, "sendmsg(2) would block"); 1290 rb_sys_fail("sendmsg(2)"); 1291 } 1292 1293 return SSIZET2NUM(ss); 1294} 1295#endif 1296 1297#if defined(HAVE_SENDMSG) 1298/* 1299 * call-seq: 1300 * basicsocket.sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent 1301 * 1302 * sendmsg sends a message using sendmsg(2) system call in blocking manner. 1303 * 1304 * _mesg_ is a string to send. 1305 * 1306 * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_OOB. 1307 * 1308 * _dest_sockaddr_ is a destination socket address for connection-less socket. 1309 * It should be a sockaddr such as a result of Socket.sockaddr_in. 1310 * An Addrinfo object can be used too. 1311 * 1312 * _controls_ is a list of ancillary data. 1313 * The element of _controls_ should be Socket::AncillaryData or 1314 * 3-elements array. 1315 * The 3-element array should contains cmsg_level, cmsg_type and data. 1316 * 1317 * The return value, _numbytes_sent_ is an integer which is the number of bytes sent. 1318 * 1319 * sendmsg can be used to implement send_io as follows: 1320 * 1321 * # use Socket::AncillaryData. 1322 * ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, io.fileno) 1323 * sock.sendmsg("a", 0, nil, ancdata) 1324 * 1325 * # use 3-element array. 1326 * ancdata = [:SOCKET, :RIGHTS, [io.fileno].pack("i!")] 1327 * sock.sendmsg("\0", 0, nil, ancdata) 1328 * 1329 */ 1330VALUE 1331rsock_bsock_sendmsg(int argc, VALUE *argv, VALUE sock) 1332{ 1333 return bsock_sendmsg_internal(argc, argv, sock, 0); 1334} 1335#endif 1336 1337#if defined(HAVE_SENDMSG) 1338/* 1339 * call-seq: 1340 * basicsocket.sendmsg_nonblock(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent 1341 * 1342 * sendmsg_nonblock sends a message using sendmsg(2) system call in non-blocking manner. 1343 * 1344 * It is similar to BasicSocket#sendmsg 1345 * but the non-blocking flag is set before the system call 1346 * and it doesn't retry the system call. 1347 * 1348 */ 1349VALUE 1350rsock_bsock_sendmsg_nonblock(int argc, VALUE *argv, VALUE sock) 1351{ 1352 return bsock_sendmsg_internal(argc, argv, sock, 1); 1353} 1354#endif 1355 1356#if defined(HAVE_RECVMSG) 1357struct recvmsg_args_struct { 1358 int fd; 1359 struct msghdr *msg; 1360 int flags; 1361}; 1362 1363ssize_t 1364rsock_recvmsg(int socket, struct msghdr *message, int flags) 1365{ 1366#ifdef MSG_CMSG_CLOEXEC 1367 /* MSG_CMSG_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */ 1368 flags |= MSG_CMSG_CLOEXEC; 1369#endif 1370 return recvmsg(socket, message, flags); 1371} 1372 1373static void * 1374nogvl_recvmsg_func(void *ptr) 1375{ 1376 struct recvmsg_args_struct *args = ptr; 1377 int flags = args->flags; 1378 return (void *)rsock_recvmsg(args->fd, args->msg, flags); 1379} 1380 1381static ssize_t 1382rb_recvmsg(int fd, struct msghdr *msg, int flags) 1383{ 1384 struct recvmsg_args_struct args; 1385 args.fd = fd; 1386 args.msg = msg; 1387 args.flags = flags; 1388 return (ssize_t)rb_thread_call_without_gvl(nogvl_recvmsg_func, &args, RUBY_UBF_IO, 0); 1389} 1390 1391#if defined(HAVE_ST_MSG_CONTROL) 1392static void 1393discard_cmsg(struct cmsghdr *cmh, char *msg_end, int msg_peek_p) 1394{ 1395# if !defined(FD_PASSING_WORK_WITH_RECVMSG_MSG_PEEK) 1396 /* 1397 * FreeBSD 8.2.0, NetBSD 5 and MacOS X Snow Leopard doesn't 1398 * allocate fds by recvmsg with MSG_PEEK. 1399 * [ruby-dev:44189] 1400 * http://bugs.ruby-lang.org/issues/5075 1401 * 1402 * Linux 2.6.38 allocate fds by recvmsg with MSG_PEEK. 1403 */ 1404 if (msg_peek_p) 1405 return; 1406# endif 1407 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) { 1408 int *fdp = (int *)CMSG_DATA(cmh); 1409 int *end = (int *)((char *)cmh + cmh->cmsg_len); 1410 while ((char *)fdp + sizeof(int) <= (char *)end && 1411 (char *)fdp + sizeof(int) <= msg_end) { 1412 rb_fd_fix_cloexec(*fdp); 1413 close(*fdp); 1414 fdp++; 1415 } 1416 } 1417} 1418#endif 1419 1420void 1421rsock_discard_cmsg_resource(struct msghdr *mh, int msg_peek_p) 1422{ 1423#if defined(HAVE_ST_MSG_CONTROL) 1424 struct cmsghdr *cmh; 1425 char *msg_end; 1426 1427 if (mh->msg_controllen == 0) 1428 return; 1429 1430 msg_end = (char *)mh->msg_control + mh->msg_controllen; 1431 1432 for (cmh = CMSG_FIRSTHDR(mh); cmh != NULL; cmh = CMSG_NXTHDR(mh, cmh)) { 1433 discard_cmsg(cmh, msg_end, msg_peek_p); 1434 } 1435#endif 1436} 1437 1438#if defined(HAVE_ST_MSG_CONTROL) 1439static void 1440make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end) 1441{ 1442 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) { 1443 int *fdp, *end; 1444 VALUE ary = rb_ary_new(); 1445 rb_ivar_set(ctl, rb_intern("unix_rights"), ary); 1446 fdp = (int *)CMSG_DATA(cmh); 1447 end = (int *)((char *)cmh + cmh->cmsg_len); 1448 while ((char *)fdp + sizeof(int) <= (char *)end && 1449 (char *)fdp + sizeof(int) <= msg_end) { 1450 int fd = *fdp; 1451 struct stat stbuf; 1452 VALUE io; 1453 if (fstat(fd, &stbuf) == -1) 1454 rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS"); 1455 rb_fd_fix_cloexec(fd); 1456 if (S_ISSOCK(stbuf.st_mode)) 1457 io = rsock_init_sock(rb_obj_alloc(rb_cSocket), fd); 1458 else 1459 io = rb_io_fdopen(fd, O_RDWR, NULL); 1460 ary = rb_attr_get(ctl, rb_intern("unix_rights")); 1461 rb_ary_push(ary, io); 1462 fdp++; 1463 } 1464 OBJ_FREEZE(ary); 1465 } 1466} 1467#endif 1468 1469static VALUE 1470bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock) 1471{ 1472 rb_io_t *fptr; 1473 VALUE vmaxdatlen, vmaxctllen, vflags, vopts; 1474 int grow_buffer; 1475 size_t maxdatlen; 1476 int flags, orig_flags; 1477 int request_scm_rights; 1478 struct msghdr mh; 1479 struct iovec iov; 1480 struct sockaddr_storage namebuf; 1481 char datbuf0[4096], *datbuf; 1482 VALUE dat_str = Qnil; 1483 VALUE ret; 1484 ssize_t ss; 1485#if defined(HAVE_ST_MSG_CONTROL) 1486 struct cmsghdr *cmh; 1487 size_t maxctllen; 1488 union { 1489 char bytes[4096]; 1490 struct cmsghdr align; 1491 } ctlbuf0; 1492 char *ctlbuf; 1493 VALUE ctl_str = Qnil; 1494 int family; 1495 int gc_done = 0; 1496#endif 1497 1498 rb_secure(4); 1499 1500 vopts = Qnil; 1501 if (0 < argc && RB_TYPE_P(argv[argc-1], T_HASH)) 1502 vopts = argv[--argc]; 1503 1504 rb_scan_args(argc, argv, "03", &vmaxdatlen, &vflags, &vmaxctllen); 1505 1506 maxdatlen = NIL_P(vmaxdatlen) ? sizeof(datbuf0) : NUM2SIZET(vmaxdatlen); 1507#if defined(HAVE_ST_MSG_CONTROL) 1508 maxctllen = NIL_P(vmaxctllen) ? sizeof(ctlbuf0) : NUM2SIZET(vmaxctllen); 1509#else 1510 if (!NIL_P(vmaxctllen)) 1511 rb_raise(rb_eArgError, "control message not supported"); 1512#endif 1513 flags = NIL_P(vflags) ? 0 : NUM2INT(vflags); 1514#ifdef MSG_DONTWAIT 1515 if (nonblock) 1516 flags |= MSG_DONTWAIT; 1517#endif 1518 orig_flags = flags; 1519 1520 grow_buffer = NIL_P(vmaxdatlen) || NIL_P(vmaxctllen); 1521 1522 request_scm_rights = 0; 1523 if (!NIL_P(vopts) && RTEST(rb_hash_aref(vopts, ID2SYM(rb_intern("scm_rights"))))) 1524 request_scm_rights = 1; 1525 1526 GetOpenFile(sock, fptr); 1527 if (rb_io_read_pending(fptr)) { 1528 rb_raise(rb_eIOError, "recvmsg for buffered IO"); 1529 } 1530 1531#if !defined(HAVE_ST_MSG_CONTROL) 1532 if (grow_buffer) { 1533 int socktype; 1534 socklen_t optlen = (socklen_t)sizeof(socktype); 1535 if (getsockopt(fptr->fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen) == -1) { 1536 rb_sys_fail("getsockopt(SO_TYPE)"); 1537 } 1538 if (socktype == SOCK_STREAM) 1539 grow_buffer = 0; 1540 } 1541#endif 1542 1543 retry: 1544 if (maxdatlen <= sizeof(datbuf0)) 1545 datbuf = datbuf0; 1546 else { 1547 if (NIL_P(dat_str)) 1548 dat_str = rb_str_tmp_new(maxdatlen); 1549 else 1550 rb_str_resize(dat_str, maxdatlen); 1551 datbuf = RSTRING_PTR(dat_str); 1552 } 1553 1554#if defined(HAVE_ST_MSG_CONTROL) 1555 if (maxctllen <= sizeof(ctlbuf0)) 1556 ctlbuf = ctlbuf0.bytes; 1557 else { 1558 if (NIL_P(ctl_str)) 1559 ctl_str = rb_str_tmp_new(maxctllen); 1560 else 1561 rb_str_resize(ctl_str, maxctllen); 1562 ctlbuf = RSTRING_PTR(ctl_str); 1563 } 1564#endif 1565 1566 memset(&mh, 0, sizeof(mh)); 1567 1568 memset(&namebuf, 0, sizeof(namebuf)); 1569 mh.msg_name = (struct sockaddr *)&namebuf; 1570 mh.msg_namelen = (socklen_t)sizeof(namebuf); 1571 1572 mh.msg_iov = &iov; 1573 mh.msg_iovlen = 1; 1574 iov.iov_base = datbuf; 1575 iov.iov_len = maxdatlen; 1576 1577#if defined(HAVE_ST_MSG_CONTROL) 1578 mh.msg_control = ctlbuf; 1579 mh.msg_controllen = (socklen_t)maxctllen; 1580#endif 1581 1582 if (grow_buffer) 1583 flags |= MSG_PEEK; 1584 1585 rb_io_check_closed(fptr); 1586 if (nonblock) 1587 rb_io_set_nonblock(fptr); 1588 1589 ss = rb_recvmsg(fptr->fd, &mh, flags); 1590 1591 if (ss == -1) { 1592 if (!nonblock && rb_io_wait_readable(fptr->fd)) { 1593 rb_io_check_closed(fptr); 1594 goto retry; 1595 } 1596 if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN)) 1597 rb_mod_sys_fail(rb_mWaitReadable, "recvmsg(2) would block"); 1598#if defined(HAVE_ST_MSG_CONTROL) 1599 if (!gc_done && (errno == EMFILE || errno == EMSGSIZE)) { 1600 /* 1601 * When SCM_RIGHTS hit the file descriptors limit: 1602 * - Linux 2.6.18 causes success with MSG_CTRUNC 1603 * - MacOS X 10.4 causes EMSGSIZE (and lost file descriptors?) 1604 * - Solaris 11 causes EMFILE 1605 */ 1606 gc_and_retry: 1607 rb_gc(); 1608 gc_done = 1; 1609 goto retry; 1610 } 1611#endif 1612 rb_sys_fail("recvmsg(2)"); 1613 } 1614 1615 if (grow_buffer) { 1616 int grown = 0; 1617#if defined(HAVE_ST_MSG_CONTROL) 1618 if (NIL_P(vmaxdatlen) && (mh.msg_flags & MSG_TRUNC)) { 1619 if (SIZE_MAX/2 < maxdatlen) 1620 rb_raise(rb_eArgError, "max data length too big"); 1621 maxdatlen *= 2; 1622 grown = 1; 1623 } 1624 if (NIL_P(vmaxctllen) && (mh.msg_flags & MSG_CTRUNC)) { 1625#define BIG_ENOUGH_SPACE 65536 1626 if (BIG_ENOUGH_SPACE < maxctllen && 1627 mh.msg_controllen < (socklen_t)(maxctllen - BIG_ENOUGH_SPACE)) { 1628 /* there are big space bug truncated. 1629 * file descriptors limit? */ 1630 if (!gc_done) { 1631 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0); 1632 goto gc_and_retry; 1633 } 1634 } 1635 else { 1636 if (SIZE_MAX/2 < maxctllen) 1637 rb_raise(rb_eArgError, "max control message length too big"); 1638 maxctllen *= 2; 1639 grown = 1; 1640 } 1641#undef BIG_ENOUGH_SPACE 1642 } 1643#else 1644 if (NIL_P(vmaxdatlen) && ss != -1 && ss == (ssize_t)iov.iov_len) { 1645 if (SIZE_MAX/2 < maxdatlen) 1646 rb_raise(rb_eArgError, "max data length too big"); 1647 maxdatlen *= 2; 1648 grown = 1; 1649 } 1650#endif 1651 if (grown) { 1652 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0); 1653 goto retry; 1654 } 1655 else { 1656 grow_buffer = 0; 1657 if (flags != orig_flags) { 1658 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0); 1659 flags = orig_flags; 1660 goto retry; 1661 } 1662 } 1663 } 1664 1665 if (NIL_P(dat_str)) 1666 dat_str = rb_tainted_str_new(datbuf, ss); 1667 else { 1668 rb_str_resize(dat_str, ss); 1669 OBJ_TAINT(dat_str); 1670 RBASIC(dat_str)->klass = rb_cString; 1671 } 1672 1673 ret = rb_ary_new3(3, dat_str, 1674 rsock_io_socket_addrinfo(sock, mh.msg_name, mh.msg_namelen), 1675#if defined(HAVE_ST_MSG_CONTROL) 1676 INT2NUM(mh.msg_flags) 1677#else 1678 Qnil 1679#endif 1680 ); 1681 1682#if defined(HAVE_ST_MSG_CONTROL) 1683 family = rsock_getfamily(fptr->fd); 1684 if (mh.msg_controllen) { 1685 char *msg_end = (char *)mh.msg_control + mh.msg_controllen; 1686 for (cmh = CMSG_FIRSTHDR(&mh); cmh != NULL; cmh = CMSG_NXTHDR(&mh, cmh)) { 1687 VALUE ctl; 1688 char *ctl_end; 1689 size_t clen; 1690 if (cmh->cmsg_len == 0) { 1691 rb_raise(rb_eTypeError, "invalid control message (cmsg_len == 0)"); 1692 } 1693 ctl_end = (char*)cmh + cmh->cmsg_len; 1694 clen = (ctl_end <= msg_end ? ctl_end : msg_end) - (char*)CMSG_DATA(cmh); 1695 ctl = ancdata_new(family, cmh->cmsg_level, cmh->cmsg_type, rb_tainted_str_new((char*)CMSG_DATA(cmh), clen)); 1696 if (request_scm_rights) 1697 make_io_for_unix_rights(ctl, cmh, msg_end); 1698 else 1699 discard_cmsg(cmh, msg_end, (flags & MSG_PEEK) != 0); 1700 rb_ary_push(ret, ctl); 1701 } 1702 } 1703#endif 1704 1705 return ret; 1706} 1707#endif 1708 1709#if defined(HAVE_RECVMSG) 1710/* 1711 * call-seq: 1712 * basicsocket.recvmsg(maxmesglen=nil, flags=0, maxcontrollen=nil, opts={}) => [mesg, sender_addrinfo, rflags, *controls] 1713 * 1714 * recvmsg receives a message using recvmsg(2) system call in blocking manner. 1715 * 1716 * _maxmesglen_ is the maximum length of mesg to receive. 1717 * 1718 * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_PEEK. 1719 * 1720 * _maxcontrollen_ is the maximum length of controls (ancillary data) to receive. 1721 * 1722 * _opts_ is option hash. 1723 * Currently :scm_rights=>bool is the only option. 1724 * 1725 * :scm_rights option specifies that application expects SCM_RIGHTS control message. 1726 * If the value is nil or false, application don't expects SCM_RIGHTS control message. 1727 * In this case, recvmsg closes the passed file descriptors immediately. 1728 * This is the default behavior. 1729 * 1730 * If :scm_rights value is neither nil nor false, application expects SCM_RIGHTS control message. 1731 * In this case, recvmsg creates IO objects for each file descriptors for 1732 * Socket::AncillaryData#unix_rights method. 1733 * 1734 * The return value is 4-elements array. 1735 * 1736 * _mesg_ is a string of the received message. 1737 * 1738 * _sender_addrinfo_ is a sender socket address for connection-less socket. 1739 * It is an Addrinfo object. 1740 * For connection-oriented socket such as TCP, sender_addrinfo is platform dependent. 1741 * 1742 * _rflags_ is a flags on the received message which is bitwise OR of MSG_* constants such as Socket::MSG_TRUNC. 1743 * It will be nil if the system uses 4.3BSD style old recvmsg system call. 1744 * 1745 * _controls_ is ancillary data which is an array of Socket::AncillaryData objects such as: 1746 * 1747 * #<Socket::AncillaryData: AF_UNIX SOCKET RIGHTS 7> 1748 * 1749 * _maxmesglen_ and _maxcontrollen_ can be nil. 1750 * In that case, the buffer will be grown until the message is not truncated. 1751 * Internally, MSG_PEEK is used and MSG_TRUNC/MSG_CTRUNC are checked. 1752 * 1753 * recvmsg can be used to implement recv_io as follows: 1754 * 1755 * mesg, sender_sockaddr, rflags, *controls = sock.recvmsg(:scm_rights=>true) 1756 * controls.each {|ancdata| 1757 * if ancdata.cmsg_is?(:SOCKET, :RIGHTS) 1758 * return ancdata.unix_rights[0] 1759 * end 1760 * } 1761 * 1762 */ 1763VALUE 1764rsock_bsock_recvmsg(int argc, VALUE *argv, VALUE sock) 1765{ 1766 return bsock_recvmsg_internal(argc, argv, sock, 0); 1767} 1768#endif 1769 1770#if defined(HAVE_RECVMSG) 1771/* 1772 * call-seq: 1773 * basicsocket.recvmsg_nonblock(maxdatalen=nil, flags=0, maxcontrollen=nil, opts={}) => [data, sender_addrinfo, rflags, *controls] 1774 * 1775 * recvmsg receives a message using recvmsg(2) system call in non-blocking manner. 1776 * 1777 * It is similar to BasicSocket#recvmsg 1778 * but non-blocking flag is set before the system call 1779 * and it doesn't retry the system call. 1780 * 1781 */ 1782VALUE 1783rsock_bsock_recvmsg_nonblock(int argc, VALUE *argv, VALUE sock) 1784{ 1785 return bsock_recvmsg_internal(argc, argv, sock, 1); 1786} 1787#endif 1788 1789void 1790rsock_init_ancdata(void) 1791{ 1792#if defined(HAVE_ST_MSG_CONTROL) 1793 /* 1794 * Document-class: Socket::AncillaryData 1795 * 1796 * Socket::AncillaryData represents the ancillary data (control information) 1797 * used by sendmsg and recvmsg system call. It contains socket #family, 1798 * control message (cmsg) #level, cmsg #type and cmsg #data. 1799 */ 1800 rb_cAncillaryData = rb_define_class_under(rb_cSocket, "AncillaryData", rb_cObject); 1801 rb_define_method(rb_cAncillaryData, "initialize", ancillary_initialize, 4); 1802 rb_define_method(rb_cAncillaryData, "inspect", ancillary_inspect, 0); 1803 rb_define_method(rb_cAncillaryData, "family", ancillary_family_m, 0); 1804 rb_define_method(rb_cAncillaryData, "level", ancillary_level_m, 0); 1805 rb_define_method(rb_cAncillaryData, "type", ancillary_type_m, 0); 1806 rb_define_method(rb_cAncillaryData, "data", ancillary_data, 0); 1807 1808 rb_define_method(rb_cAncillaryData, "cmsg_is?", ancillary_cmsg_is_p, 2); 1809 1810 rb_define_singleton_method(rb_cAncillaryData, "int", ancillary_s_int, 4); 1811 rb_define_method(rb_cAncillaryData, "int", ancillary_int, 0); 1812 1813 rb_define_singleton_method(rb_cAncillaryData, "unix_rights", ancillary_s_unix_rights, -1); 1814 rb_define_method(rb_cAncillaryData, "unix_rights", ancillary_unix_rights, 0); 1815 1816 rb_define_method(rb_cAncillaryData, "timestamp", ancillary_timestamp, 0); 1817 1818 rb_define_singleton_method(rb_cAncillaryData, "ip_pktinfo", ancillary_s_ip_pktinfo, -1); 1819 rb_define_method(rb_cAncillaryData, "ip_pktinfo", ancillary_ip_pktinfo, 0); 1820 1821 rb_define_singleton_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_s_ipv6_pktinfo, 2); 1822 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_ipv6_pktinfo, 0); 1823 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_addr", ancillary_ipv6_pktinfo_addr, 0); 1824 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_ifindex", ancillary_ipv6_pktinfo_ifindex, 0); 1825#endif 1826} 1827