Ruby  2.1.10p492(2016-04-01revision54464)
ancdata.c
Go to the documentation of this file.
1 #include "rubysocket.h"
2 
3 #include <time.h>
4 
5 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
6 static VALUE rb_cAncillaryData;
7 
8 static VALUE
9 constant_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 
19 static VALUE
20 ip_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  */
72 static VALUE
73 ancillary_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 
86 static VALUE
87 ancdata_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 
95 static int
96 ancillary_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  */
111 static VALUE
112 ancillary_family_m(VALUE self)
113 {
114  return INT2NUM(ancillary_family(self));
115 }
116 
117 static int
118 ancillary_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  */
133 static VALUE
134 ancillary_level_m(VALUE self)
135 {
136  return INT2NUM(ancillary_level(self));
137 }
138 
139 static int
140 ancillary_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  */
155 static VALUE
156 ancillary_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  */
170 static VALUE
171 ancillary_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  */
188 static VALUE
189 ancillary_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  */
254 static VALUE
255 ancillary_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 (microsecond) GNU/Linux, FreeBSD, NetBSD, OpenBSD, Solaris, MacOS X
280  * - SOL_SOCKET/SCM_TIMESTAMPNS (nanosecond) 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  */
297 static VALUE
298 ancillary_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  */
363 static VALUE
364 ancillary_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  */
384 static VALUE
385 ancillary_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  */
417 static VALUE
418 ancillary_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  */
480 static VALUE
481 ancillary_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  */
530 static VALUE
531 ancillary_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 */
559 static void
560 extract_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  INIT_SOCKADDR((struct sockaddr *)sa_ptr, AF_INET6, sizeof(*sa_ptr));
577  memcpy(&sa_ptr->sin6_addr, &pktinfo_ptr->ipi6_addr, sizeof(sa_ptr->sin6_addr));
578  if (IN6_IS_ADDR_LINKLOCAL(&sa_ptr->sin6_addr))
579  sa_ptr->sin6_scope_id = pktinfo_ptr->ipi6_ifindex;
580 }
581 #endif
582 
583 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */
584 /*
585  * call-seq:
586  * ancdata.ipv6_pktinfo => [addr, ifindex]
587  *
588  * Extracts addr and ifindex from IPV6_PKTINFO ancillary data.
589  *
590  * IPV6_PKTINFO is defined by RFC 3542.
591  *
592  * addr = Addrinfo.ip("::1")
593  * ifindex = 0
594  * ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
595  * p ancdata.ipv6_pktinfo #=> [#<Addrinfo: ::1>, 0]
596  *
597  */
598 static VALUE
599 ancillary_ipv6_pktinfo(VALUE self)
600 {
601  struct in6_pktinfo pktinfo;
602  struct sockaddr_in6 sa;
603  VALUE v_addr;
604 
605  extract_ipv6_pktinfo(self, &pktinfo, &sa);
606  v_addr = rsock_addrinfo_new((struct sockaddr *)&sa, (socklen_t)sizeof(sa), PF_INET6, 0, 0, Qnil, Qnil);
607  return rb_ary_new3(2, v_addr, UINT2NUM(pktinfo.ipi6_ifindex));
608 }
609 #else
610 #define ancillary_ipv6_pktinfo rb_f_notimplement
611 #endif
612 
613 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */
614 /*
615  * call-seq:
616  * ancdata.ipv6_pktinfo_addr => addr
617  *
618  * Extracts addr from IPV6_PKTINFO ancillary data.
619  *
620  * IPV6_PKTINFO is defined by RFC 3542.
621  *
622  * addr = Addrinfo.ip("::1")
623  * ifindex = 0
624  * ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
625  * p ancdata.ipv6_pktinfo_addr #=> #<Addrinfo: ::1>
626  *
627  */
628 static VALUE
629 ancillary_ipv6_pktinfo_addr(VALUE self)
630 {
631  struct in6_pktinfo pktinfo;
632  struct sockaddr_in6 sa;
633  extract_ipv6_pktinfo(self, &pktinfo, &sa);
634  return rsock_addrinfo_new((struct sockaddr *)&sa, (socklen_t)sizeof(sa), PF_INET6, 0, 0, Qnil, Qnil);
635 }
636 #else
637 #define ancillary_ipv6_pktinfo_addr rb_f_notimplement
638 #endif
639 
640 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */
641 /*
642  * call-seq:
643  * ancdata.ipv6_pktinfo_ifindex => addr
644  *
645  * Extracts ifindex from IPV6_PKTINFO ancillary data.
646  *
647  * IPV6_PKTINFO is defined by RFC 3542.
648  *
649  * addr = Addrinfo.ip("::1")
650  * ifindex = 0
651  * ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
652  * p ancdata.ipv6_pktinfo_ifindex #=> 0
653  *
654  */
655 static VALUE
656 ancillary_ipv6_pktinfo_ifindex(VALUE self)
657 {
658  struct in6_pktinfo pktinfo;
659  struct sockaddr_in6 sa;
660  extract_ipv6_pktinfo(self, &pktinfo, &sa);
661  return UINT2NUM(pktinfo.ipi6_ifindex);
662 }
663 #else
664 #define ancillary_ipv6_pktinfo_ifindex rb_f_notimplement
665 #endif
666 
667 #if defined(SOL_SOCKET) && defined(SCM_RIGHTS) /* 4.4BSD */
668 static int
669 anc_inspect_socket_rights(int level, int type, VALUE data, VALUE ret)
670 {
671  if (level == SOL_SOCKET && type == SCM_RIGHTS &&
672  0 < RSTRING_LEN(data) && (RSTRING_LEN(data) % sizeof(int) == 0)) {
673  long off;
674  for (off = 0; off < RSTRING_LEN(data); off += sizeof(int)) {
675  int fd;
676  memcpy((char*)&fd, RSTRING_PTR(data)+off, sizeof(int));
677  rb_str_catf(ret, " %d", fd);
678  }
679  return 1;
680  }
681  else {
682  return 0;
683  }
684 }
685 #endif
686 
687 #if defined(SCM_CREDENTIALS) /* GNU/Linux */
688 static int
689 anc_inspect_passcred_credentials(int level, int type, VALUE data, VALUE ret)
690 {
691  if (level == SOL_SOCKET && type == SCM_CREDENTIALS &&
692  RSTRING_LEN(data) == sizeof(struct ucred)) {
693  struct ucred cred;
694  memcpy(&cred, RSTRING_PTR(data), sizeof(struct ucred));
695  rb_str_catf(ret, " pid=%u uid=%u gid=%u", cred.pid, cred.uid, cred.gid);
696  rb_str_cat2(ret, " (ucred)");
697  return 1;
698  }
699  else {
700  return 0;
701  }
702 }
703 #endif
704 
705 #if defined(SCM_CREDS)
706 #define INSPECT_SCM_CREDS
707 static int
708 anc_inspect_socket_creds(int level, int type, VALUE data, VALUE ret)
709 {
710  if (level != SOL_SOCKET && type != SCM_CREDS)
711  return 0;
712 
713  /*
714  * FreeBSD has struct cmsgcred and struct sockcred.
715  * They use both SOL_SOCKET/SCM_CREDS in the ancillary message.
716  * They are not ambiguous from the view of the caller
717  * because struct sockcred is sent if and only if the caller sets LOCAL_CREDS socket option.
718  * But inspect method doesn't know it.
719  * So they are ambiguous from the view of inspect.
720  * This function distinguish them by the size of the ancillary message.
721  * This heuristics works well except when sc_ngroups == CMGROUP_MAX.
722  */
723 
724 #if defined(HAVE_TYPE_STRUCT_CMSGCRED) /* FreeBSD */
725  if (RSTRING_LEN(data) == sizeof(struct cmsgcred)) {
726  struct cmsgcred cred;
727  memcpy(&cred, RSTRING_PTR(data), sizeof(struct cmsgcred));
728  rb_str_catf(ret, " pid=%u", cred.cmcred_pid);
729  rb_str_catf(ret, " uid=%u", cred.cmcred_uid);
730  rb_str_catf(ret, " euid=%u", cred.cmcred_euid);
731  rb_str_catf(ret, " gid=%u", cred.cmcred_gid);
732  if (cred.cmcred_ngroups) {
733  int i;
734  const char *sep = " groups=";
735  for (i = 0; i < cred.cmcred_ngroups; i++) {
736  rb_str_catf(ret, "%s%u", sep, cred.cmcred_groups[i]);
737  sep = ",";
738  }
739  }
740  rb_str_cat2(ret, " (cmsgcred)");
741  return 1;
742  }
743 #endif
744 #if defined(HAVE_TYPE_STRUCT_SOCKCRED) /* FreeBSD, NetBSD */
745  if ((size_t)RSTRING_LEN(data) >= SOCKCREDSIZE(0)) {
746  struct sockcred cred0, *cred;
747  memcpy(&cred0, RSTRING_PTR(data), SOCKCREDSIZE(0));
748  if ((size_t)RSTRING_LEN(data) == SOCKCREDSIZE(cred0.sc_ngroups)) {
749  cred = (struct sockcred *)ALLOCA_N(char, SOCKCREDSIZE(cred0.sc_ngroups));
750  memcpy(cred, RSTRING_PTR(data), SOCKCREDSIZE(cred0.sc_ngroups));
751  rb_str_catf(ret, " uid=%u", cred->sc_uid);
752  rb_str_catf(ret, " euid=%u", cred->sc_euid);
753  rb_str_catf(ret, " gid=%u", cred->sc_gid);
754  rb_str_catf(ret, " egid=%u", cred->sc_egid);
755  if (cred0.sc_ngroups) {
756  int i;
757  const char *sep = " groups=";
758  for (i = 0; i < cred0.sc_ngroups; i++) {
759  rb_str_catf(ret, "%s%u", sep, cred->sc_groups[i]);
760  sep = ",";
761  }
762  }
763  rb_str_cat2(ret, " (sockcred)");
764  return 1;
765  }
766  }
767 #endif
768  return 0;
769 }
770 #endif
771 
772 #if defined(IPPROTO_IP) && defined(IP_RECVDSTADDR) /* 4.4BSD */
773 static int
774 anc_inspect_ip_recvdstaddr(int level, int type, VALUE data, VALUE ret)
775 {
776  if (level == IPPROTO_IP && type == IP_RECVDSTADDR &&
777  RSTRING_LEN(data) == sizeof(struct in_addr)) {
778  struct in_addr addr;
779  char addrbuf[INET_ADDRSTRLEN];
780  memcpy(&addr, RSTRING_PTR(data), sizeof(addr));
781  if (inet_ntop(AF_INET, &addr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
782  rb_str_cat2(ret, " invalid-address");
783  else
784  rb_str_catf(ret, " %s", addrbuf);
785  return 1;
786  }
787  else {
788  return 0;
789  }
790 }
791 #endif
792 
793 #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST) /* GNU/Linux */
794 static int
795 anc_inspect_ip_pktinfo(int level, int type, VALUE data, VALUE ret)
796 {
797  if (level == IPPROTO_IP && type == IP_PKTINFO &&
798  RSTRING_LEN(data) == sizeof(struct in_pktinfo)) {
799  struct in_pktinfo pktinfo;
800  char buf[INET_ADDRSTRLEN > IFNAMSIZ ? INET_ADDRSTRLEN : IFNAMSIZ];
801  memcpy(&pktinfo, RSTRING_PTR(data), sizeof(pktinfo));
802  if (inet_ntop(AF_INET, &pktinfo.ipi_addr, buf, sizeof(buf)) == NULL)
803  rb_str_cat2(ret, " invalid-address");
804  else
805  rb_str_catf(ret, " %s", buf);
806  if (if_indextoname(pktinfo.ipi_ifindex, buf) == NULL)
807  rb_str_catf(ret, " ifindex:%d", pktinfo.ipi_ifindex);
808  else
809  rb_str_catf(ret, " %s", buf);
810  if (inet_ntop(AF_INET, &pktinfo.ipi_spec_dst, buf, sizeof(buf)) == NULL)
811  rb_str_cat2(ret, " spec_dst:invalid-address");
812  else
813  rb_str_catf(ret, " spec_dst:%s", buf);
814  return 1;
815  }
816  else {
817  return 0;
818  }
819 }
820 #endif
821 
822 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN6_PKTINFO) /* IPv6 RFC3542 */
823 static int
824 anc_inspect_ipv6_pktinfo(int level, int type, VALUE data, VALUE ret)
825 {
826  if (level == IPPROTO_IPV6 && type == IPV6_PKTINFO &&
827  RSTRING_LEN(data) == sizeof(struct in6_pktinfo)) {
828  struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)RSTRING_PTR(data);
829  struct in6_addr addr;
830  unsigned int ifindex;
831  char addrbuf[INET6_ADDRSTRLEN], ifbuf[IFNAMSIZ];
832  memcpy(&addr, &pktinfo->ipi6_addr, sizeof(addr));
833  memcpy(&ifindex, &pktinfo->ipi6_ifindex, sizeof(ifindex));
834  if (inet_ntop(AF_INET6, &addr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
835  rb_str_cat2(ret, " invalid-address");
836  else
837  rb_str_catf(ret, " %s", addrbuf);
838  if (if_indextoname(ifindex, ifbuf) == NULL)
839  rb_str_catf(ret, " ifindex:%d", ifindex);
840  else
841  rb_str_catf(ret, " %s", ifbuf);
842  return 1;
843  }
844  else {
845  return 0;
846  }
847 }
848 #endif
849 
850 #if defined(SCM_TIMESTAMP) /* GNU/Linux, FreeBSD, NetBSD, OpenBSD, MacOS X, Solaris */
851 static int
852 inspect_timeval_as_abstime(int level, int optname, VALUE data, VALUE ret)
853 {
854  if (RSTRING_LEN(data) == sizeof(struct timeval)) {
855  struct timeval tv;
856  time_t time;
857  struct tm tm;
858  char buf[32];
859  memcpy((char*)&tv, RSTRING_PTR(data), sizeof(tv));
860  time = tv.tv_sec;
861  tm = *localtime(&time);
862  strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
863  rb_str_catf(ret, " %s.%06ld", buf, (long)tv.tv_usec);
864  return 1;
865  }
866  else {
867  return 0;
868  }
869 }
870 #endif
871 
872 #if defined(SCM_TIMESTAMPNS) /* GNU/Linux */
873 static int
874 inspect_timespec_as_abstime(int level, int optname, VALUE data, VALUE ret)
875 {
876  if (RSTRING_LEN(data) == sizeof(struct timespec)) {
877  struct timespec ts;
878  struct tm tm;
879  char buf[32];
880  memcpy((char*)&ts, RSTRING_PTR(data), sizeof(ts));
881  tm = *localtime(&ts.tv_sec);
882  strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
883  rb_str_catf(ret, " %s.%09ld", buf, (long)ts.tv_nsec);
884  return 1;
885  }
886  else {
887  return 0;
888  }
889 }
890 #endif
891 
892 #if defined(SCM_BINTIME) /* FreeBSD */
893 static int
894 inspect_bintime_as_abstime(int level, int optname, VALUE data, VALUE ret)
895 {
896  if (RSTRING_LEN(data) == sizeof(struct bintime)) {
897  struct bintime bt;
898  struct tm tm;
899  uint64_t frac_h, frac_l;
900  uint64_t scale_h, scale_l;
901  uint64_t tmp1, tmp2;
902  uint64_t res_h, res_l;
903  char buf[32];
904  memcpy((char*)&bt, RSTRING_PTR(data), sizeof(bt));
905  tm = *localtime(&bt.sec);
906  strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
907 
908  /* res_h = frac * 10**19 / 2**64 */
909 
910  frac_h = bt.frac >> 32;
911  frac_l = bt.frac & 0xffffffff;
912 
913  scale_h = 0x8ac72304; /* 0x8ac7230489e80000 == 10**19 */
914  scale_l = 0x89e80000;
915 
916  res_h = frac_h * scale_h;
917  res_l = frac_l * scale_l;
918 
919  tmp1 = frac_h * scale_l;
920  res_h += tmp1 >> 32;
921  tmp2 = res_l;
922  res_l += tmp1 & 0xffffffff;
923  if (res_l < tmp2) res_h++;
924 
925  tmp1 = frac_l * scale_h;
926  res_h += tmp1 >> 32;
927  tmp2 = res_l;
928  res_l += tmp1 & 0xffffffff;
929  if (res_l < tmp2) res_h++;
930 
931  rb_str_catf(ret, " %s.%019"PRIu64, buf, res_h);
932  return 1;
933  }
934  else {
935  return 0;
936  }
937 }
938 #endif
939 
940 /*
941  * call-seq:
942  * ancillarydata.inspect => string
943  *
944  * returns a string which shows ancillarydata in human-readable form.
945  *
946  * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").inspect
947  * #=> "#<Socket::AncillaryData: INET6 IPV6 PKTINFO \"\">"
948  */
949 static VALUE
950 ancillary_inspect(VALUE self)
951 {
952  VALUE ret;
953  int family, level, type;
954  VALUE data;
955  ID family_id, level_id, type_id;
956  VALUE vtype;
957  int inspected;
958 
959  family = ancillary_family(self);
960  level = ancillary_level(self);
961  type = ancillary_type(self);
962  data = ancillary_data(self);
963 
964  ret = rb_sprintf("#<%s:", rb_obj_classname(self));
965 
966  family_id = rsock_intern_family_noprefix(family);
967  if (family_id)
968  rb_str_catf(ret, " %s", rb_id2name(family_id));
969  else
970  rb_str_catf(ret, " family:%d", family);
971 
972  if (level == SOL_SOCKET) {
973  rb_str_cat2(ret, " SOCKET");
974 
975  type_id = rsock_intern_scm_optname(type);
976  if (type_id)
977  rb_str_catf(ret, " %s", rb_id2name(type_id));
978  else
979  rb_str_catf(ret, " cmsg_type:%d", type);
980  }
981  else if (IS_IP_FAMILY(family)) {
982  level_id = rsock_intern_iplevel(level);
983  if (level_id)
984  rb_str_catf(ret, " %s", rb_id2name(level_id));
985  else
986  rb_str_catf(ret, " cmsg_level:%d", level);
987 
988  vtype = ip_cmsg_type_to_sym(level, type);
989  if (SYMBOL_P(vtype))
990  rb_str_catf(ret, " %s", rb_id2name(SYM2ID(vtype)));
991  else
992  rb_str_catf(ret, " cmsg_type:%d", type);
993  }
994  else {
995  rb_str_catf(ret, " cmsg_level:%d", level);
996  rb_str_catf(ret, " cmsg_type:%d", type);
997  }
998 
999  inspected = 0;
1000 
1001  if (level == SOL_SOCKET)
1002  family = AF_UNSPEC;
1003 
1004  switch (family) {
1005  case AF_UNSPEC:
1006  switch (level) {
1007 # if defined(SOL_SOCKET)
1008  case SOL_SOCKET:
1009  switch (type) {
1010 # if defined(SCM_TIMESTAMP) /* GNU/Linux, FreeBSD, NetBSD, OpenBSD, MacOS X, Solaris */
1011  case SCM_TIMESTAMP: inspected = inspect_timeval_as_abstime(level, type, data, ret); break;
1012 # endif
1013 # if defined(SCM_TIMESTAMPNS) /* GNU/Linux */
1014  case SCM_TIMESTAMPNS: inspected = inspect_timespec_as_abstime(level, type, data, ret); break;
1015 # endif
1016 # if defined(SCM_BINTIME) /* FreeBSD */
1017  case SCM_BINTIME: inspected = inspect_bintime_as_abstime(level, type, data, ret); break;
1018 # endif
1019 # if defined(SCM_RIGHTS) /* 4.4BSD */
1020  case SCM_RIGHTS: inspected = anc_inspect_socket_rights(level, type, data, ret); break;
1021 # endif
1022 # if defined(SCM_CREDENTIALS) /* GNU/Linux */
1023  case SCM_CREDENTIALS: inspected = anc_inspect_passcred_credentials(level, type, data, ret); break;
1024 # endif
1025 # if defined(INSPECT_SCM_CREDS) /* NetBSD */
1026  case SCM_CREDS: inspected = anc_inspect_socket_creds(level, type, data, ret); break;
1027 # endif
1028  }
1029  break;
1030 # endif
1031  }
1032  break;
1033 
1034  case AF_INET:
1035 #ifdef INET6
1036  case AF_INET6:
1037 #endif
1038  switch (level) {
1039 # if defined(IPPROTO_IP)
1040  case IPPROTO_IP:
1041  switch (type) {
1042 # if defined(IP_RECVDSTADDR) /* 4.4BSD */
1043  case IP_RECVDSTADDR: inspected = anc_inspect_ip_recvdstaddr(level, type, data, ret); break;
1044 # endif
1045 # if defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST) /* GNU/Linux */
1046  case IP_PKTINFO: inspected = anc_inspect_ip_pktinfo(level, type, data, ret); break;
1047 # endif
1048  }
1049  break;
1050 # endif
1051 
1052 # if defined(IPPROTO_IPV6)
1053  case IPPROTO_IPV6:
1054  switch (type) {
1055 # if defined(IPV6_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN6_PKTINFO) /* RFC 3542 */
1056  case IPV6_PKTINFO: inspected = anc_inspect_ipv6_pktinfo(level, type, data, ret); break;
1057 # endif
1058  }
1059  break;
1060 # endif
1061  }
1062  break;
1063  }
1064 
1065  if (!inspected) {
1066  rb_str_cat2(ret, " ");
1067  rb_str_append(ret, rb_str_dump(data));
1068  }
1069 
1070  rb_str_cat2(ret, ">");
1071 
1072  return ret;
1073 }
1074 
1075 /*
1076  * call-seq:
1077  * ancillarydata.cmsg_is?(level, type) => true or false
1078  *
1079  * tests the level and type of _ancillarydata_.
1080  *
1081  * ancdata = Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "")
1082  * ancdata.cmsg_is?(Socket::IPPROTO_IPV6, Socket::IPV6_PKTINFO) #=> true
1083  * ancdata.cmsg_is?(:IPV6, :PKTINFO) #=> true
1084  * ancdata.cmsg_is?(:IP, :PKTINFO) #=> false
1085  * ancdata.cmsg_is?(:SOCKET, :RIGHTS) #=> false
1086  */
1087 static VALUE
1088 ancillary_cmsg_is_p(VALUE self, VALUE vlevel, VALUE vtype)
1089 {
1090  int family = ancillary_family(self);
1091  int level = rsock_level_arg(family, vlevel);
1092  int type = rsock_cmsg_type_arg(family, level, vtype);
1093 
1094  if (ancillary_level(self) == level &&
1095  ancillary_type(self) == type)
1096  return Qtrue;
1097  else
1098  return Qfalse;
1099 }
1100 
1101 #endif
1102 
1103 #if defined(HAVE_SENDMSG)
1104 struct sendmsg_args_struct {
1105  int fd;
1106  const struct msghdr *msg;
1107  int flags;
1108 };
1109 
1110 static void *
1111 nogvl_sendmsg_func(void *ptr)
1112 {
1113  struct sendmsg_args_struct *args = ptr;
1114  return (void *)(VALUE)sendmsg(args->fd, args->msg, args->flags);
1115 }
1116 
1117 static ssize_t
1118 rb_sendmsg(int fd, const struct msghdr *msg, int flags)
1119 {
1120  struct sendmsg_args_struct args;
1121  args.fd = fd;
1122  args.msg = msg;
1123  args.flags = flags;
1124  return (ssize_t)rb_thread_call_without_gvl(nogvl_sendmsg_func, &args, RUBY_UBF_IO, 0);
1125 }
1126 
1127 static VALUE
1128 bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
1129 {
1130  rb_io_t *fptr;
1131  VALUE data, vflags, dest_sockaddr;
1132  int controls_num;
1133  struct msghdr mh;
1134  struct iovec iov;
1135 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1136  VALUE controls_str = 0;
1137  VALUE *controls_ptr = NULL;
1138  int family;
1139 #endif
1140  int flags;
1141  ssize_t ss;
1142 
1143  GetOpenFile(sock, fptr);
1144 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1145  family = rsock_getfamily(fptr->fd);
1146 #endif
1147 
1148  data = vflags = dest_sockaddr = Qnil;
1149 
1150  if (argc == 0)
1151  rb_raise(rb_eArgError, "mesg argument required");
1152  data = argv[0];
1153  if (1 < argc) vflags = argv[1];
1154  if (2 < argc) dest_sockaddr = argv[2];
1155  controls_num = 3 < argc ? argc - 3 : 0;
1156 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1157  if (3 < argc) { controls_ptr = &argv[3]; }
1158 #endif
1159 
1160  StringValue(data);
1161 
1162  if (controls_num) {
1163 #if defined(HAVE_STRUCT_MSGHDR_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_SOCKLEN(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_STRUCT_MSGHDR_MSG_CONTROL)
1267  if (controls_str) {
1268  mh.msg_control = RSTRING_PTR(controls_str);
1269  mh.msg_controllen = RSTRING_SOCKLEN(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_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "sendmsg(2) would block");
1290  rb_sys_fail("sendmsg(2)");
1291  }
1292 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1293  RB_GC_GUARD(controls_str);
1294 #endif
1295 
1296  return SSIZET2NUM(ss);
1297 }
1298 #endif
1299 
1300 #if defined(HAVE_SENDMSG)
1301 /*
1302  * call-seq:
1303  * basicsocket.sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
1304  *
1305  * sendmsg sends a message using sendmsg(2) system call in blocking manner.
1306  *
1307  * _mesg_ is a string to send.
1308  *
1309  * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_OOB.
1310  *
1311  * _dest_sockaddr_ is a destination socket address for connection-less socket.
1312  * It should be a sockaddr such as a result of Socket.sockaddr_in.
1313  * An Addrinfo object can be used too.
1314  *
1315  * _controls_ is a list of ancillary data.
1316  * The element of _controls_ should be Socket::AncillaryData or
1317  * 3-elements array.
1318  * The 3-element array should contains cmsg_level, cmsg_type and data.
1319  *
1320  * The return value, _numbytes_sent_ is an integer which is the number of bytes sent.
1321  *
1322  * sendmsg can be used to implement send_io as follows:
1323  *
1324  * # use Socket::AncillaryData.
1325  * ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, io.fileno)
1326  * sock.sendmsg("a", 0, nil, ancdata)
1327  *
1328  * # use 3-element array.
1329  * ancdata = [:SOCKET, :RIGHTS, [io.fileno].pack("i!")]
1330  * sock.sendmsg("\0", 0, nil, ancdata)
1331  *
1332  */
1333 VALUE
1335 {
1336  return bsock_sendmsg_internal(argc, argv, sock, 0);
1337 }
1338 #endif
1339 
1340 #if defined(HAVE_SENDMSG)
1341 /*
1342  * call-seq:
1343  * basicsocket.sendmsg_nonblock(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
1344  *
1345  * sendmsg_nonblock sends a message using sendmsg(2) system call in non-blocking manner.
1346  *
1347  * It is similar to BasicSocket#sendmsg
1348  * but the non-blocking flag is set before the system call
1349  * and it doesn't retry the system call.
1350  *
1351  */
1352 VALUE
1354 {
1355  return bsock_sendmsg_internal(argc, argv, sock, 1);
1356 }
1357 #endif
1358 
1359 #if defined(HAVE_RECVMSG)
1360 struct recvmsg_args_struct {
1361  int fd;
1362  struct msghdr *msg;
1363  int flags;
1364 };
1365 
1366 ssize_t
1367 rsock_recvmsg(int socket, struct msghdr *message, int flags)
1368 {
1369  ssize_t ret;
1370  socklen_t len0;
1371 #ifdef MSG_CMSG_CLOEXEC
1372  /* MSG_CMSG_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
1373  flags |= MSG_CMSG_CLOEXEC;
1374 #endif
1375  len0 = message->msg_namelen;
1376  ret = recvmsg(socket, message, flags);
1377  if (ret != -1 && len0 < message->msg_namelen)
1378  message->msg_namelen = len0;
1379  return ret;
1380 }
1381 
1382 static void *
1383 nogvl_recvmsg_func(void *ptr)
1384 {
1385  struct recvmsg_args_struct *args = ptr;
1386  int flags = args->flags;
1387  return (void *)rsock_recvmsg(args->fd, args->msg, flags);
1388 }
1389 
1390 static ssize_t
1391 rb_recvmsg(int fd, struct msghdr *msg, int flags)
1392 {
1393  struct recvmsg_args_struct args;
1394  args.fd = fd;
1395  args.msg = msg;
1396  args.flags = flags;
1397  return (ssize_t)rb_thread_call_without_gvl(nogvl_recvmsg_func, &args, RUBY_UBF_IO, 0);
1398 }
1399 
1400 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1401 static void
1402 discard_cmsg(struct cmsghdr *cmh, char *msg_end, int msg_peek_p)
1403 {
1404 # if !defined(FD_PASSING_WORK_WITH_RECVMSG_MSG_PEEK)
1405  /*
1406  * FreeBSD 8.2.0, NetBSD 5 and MacOS X Snow Leopard doesn't
1407  * allocate fds by recvmsg with MSG_PEEK.
1408  * [ruby-dev:44189]
1409  * http://bugs.ruby-lang.org/issues/5075
1410  *
1411  * Linux 2.6.38 allocate fds by recvmsg with MSG_PEEK.
1412  */
1413  if (msg_peek_p)
1414  return;
1415 # endif
1416  if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
1417  int *fdp = (int *)CMSG_DATA(cmh);
1418  int *end = (int *)((char *)cmh + cmh->cmsg_len);
1419  while ((char *)fdp + sizeof(int) <= (char *)end &&
1420  (char *)fdp + sizeof(int) <= msg_end) {
1421  rb_fd_fix_cloexec(*fdp);
1422  close(*fdp);
1423  fdp++;
1424  }
1425  }
1426 }
1427 #endif
1428 
1429 void
1430 rsock_discard_cmsg_resource(struct msghdr *mh, int msg_peek_p)
1431 {
1432 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1433  struct cmsghdr *cmh;
1434  char *msg_end;
1435 
1436  if (mh->msg_controllen == 0)
1437  return;
1438 
1439  msg_end = (char *)mh->msg_control + mh->msg_controllen;
1440 
1441  for (cmh = CMSG_FIRSTHDR(mh); cmh != NULL; cmh = CMSG_NXTHDR(mh, cmh)) {
1442  discard_cmsg(cmh, msg_end, msg_peek_p);
1443  }
1444 #endif
1445 }
1446 
1447 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1448 static void
1449 make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end)
1450 {
1451  if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
1452  int *fdp, *end;
1453  VALUE ary = rb_ary_new();
1454  rb_ivar_set(ctl, rb_intern("unix_rights"), ary);
1455  fdp = (int *)CMSG_DATA(cmh);
1456  end = (int *)((char *)cmh + cmh->cmsg_len);
1457  while ((char *)fdp + sizeof(int) <= (char *)end &&
1458  (char *)fdp + sizeof(int) <= msg_end) {
1459  int fd = *fdp;
1460  struct stat stbuf;
1461  VALUE io;
1462  if (fstat(fd, &stbuf) == -1)
1463  rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");
1464  rb_fd_fix_cloexec(fd);
1465  if (S_ISSOCK(stbuf.st_mode))
1467  else
1468  io = rb_io_fdopen(fd, O_RDWR, NULL);
1469  ary = rb_attr_get(ctl, rb_intern("unix_rights"));
1470  rb_ary_push(ary, io);
1471  fdp++;
1472  }
1473  OBJ_FREEZE(ary);
1474  }
1475 }
1476 #endif
1477 
1478 static VALUE
1479 bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
1480 {
1481  rb_io_t *fptr;
1482  VALUE vmaxdatlen, vmaxctllen, vflags;
1483  VALUE vopts;
1484  int grow_buffer;
1485  size_t maxdatlen;
1486  int flags, orig_flags;
1487  struct msghdr mh;
1488  struct iovec iov;
1489  union_sockaddr namebuf;
1490  char datbuf0[4096], *datbuf;
1491  VALUE dat_str = Qnil;
1492  VALUE ret;
1493  ssize_t ss;
1494  int request_scm_rights;
1495 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1496  struct cmsghdr *cmh;
1497  size_t maxctllen;
1498  union {
1499  char bytes[4096];
1500  struct cmsghdr align;
1501  } ctlbuf0;
1502  char *ctlbuf;
1503  VALUE ctl_str = Qnil;
1504  int family;
1505  int gc_done = 0;
1506 #endif
1507 
1508 
1509  rb_scan_args(argc, argv, "03:", &vmaxdatlen, &vflags, &vmaxctllen, &vopts);
1510 
1511  maxdatlen = NIL_P(vmaxdatlen) ? sizeof(datbuf0) : NUM2SIZET(vmaxdatlen);
1512 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1513  maxctllen = NIL_P(vmaxctllen) ? sizeof(ctlbuf0) : NUM2SIZET(vmaxctllen);
1514 #else
1515  if (!NIL_P(vmaxctllen))
1516  rb_raise(rb_eArgError, "control message not supported");
1517 #endif
1518  flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
1519 #ifdef MSG_DONTWAIT
1520  if (nonblock)
1521  flags |= MSG_DONTWAIT;
1522 #endif
1523  orig_flags = flags;
1524 
1525  grow_buffer = NIL_P(vmaxdatlen) || NIL_P(vmaxctllen);
1526 
1527  request_scm_rights = 0;
1528  if (!NIL_P(vopts) && RTEST(rb_hash_aref(vopts, ID2SYM(rb_intern("scm_rights")))))
1529  request_scm_rights = 1;
1530 #if !defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1531  if (request_scm_rights)
1532  rb_raise(rb_eNotImpError, "control message for recvmsg is unimplemented");
1533 #endif
1534 
1535  GetOpenFile(sock, fptr);
1536  if (rb_io_read_pending(fptr)) {
1537  rb_raise(rb_eIOError, "recvmsg for buffered IO");
1538  }
1539 
1540 #if !defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1541  if (grow_buffer) {
1542  int socktype;
1543  socklen_t optlen = (socklen_t)sizeof(socktype);
1544  if (getsockopt(fptr->fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen) == -1) {
1545  rb_sys_fail("getsockopt(SO_TYPE)");
1546  }
1547  if (socktype == SOCK_STREAM)
1548  grow_buffer = 0;
1549  }
1550 #endif
1551 
1552  retry:
1553  if (maxdatlen <= sizeof(datbuf0))
1554  datbuf = datbuf0;
1555  else {
1556  if (NIL_P(dat_str))
1557  dat_str = rb_str_tmp_new(maxdatlen);
1558  else
1559  rb_str_resize(dat_str, maxdatlen);
1560  datbuf = RSTRING_PTR(dat_str);
1561  }
1562 
1563 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1564  if (maxctllen <= sizeof(ctlbuf0))
1565  ctlbuf = ctlbuf0.bytes;
1566  else {
1567  if (NIL_P(ctl_str))
1568  ctl_str = rb_str_tmp_new(maxctllen);
1569  else
1570  rb_str_resize(ctl_str, maxctllen);
1571  ctlbuf = RSTRING_PTR(ctl_str);
1572  }
1573 #endif
1574 
1575  memset(&mh, 0, sizeof(mh));
1576 
1577  memset(&namebuf, 0, sizeof(namebuf));
1578  mh.msg_name = &namebuf.addr;
1579  mh.msg_namelen = (socklen_t)sizeof(namebuf);
1580 
1581  mh.msg_iov = &iov;
1582  mh.msg_iovlen = 1;
1583  iov.iov_base = datbuf;
1584  iov.iov_len = maxdatlen;
1585 
1586 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1587  mh.msg_control = ctlbuf;
1588  mh.msg_controllen = (socklen_t)maxctllen;
1589 #endif
1590 
1591  if (grow_buffer)
1592  flags |= MSG_PEEK;
1593 
1594  rb_io_check_closed(fptr);
1595  if (nonblock)
1596  rb_io_set_nonblock(fptr);
1597 
1598  ss = rb_recvmsg(fptr->fd, &mh, flags);
1599 
1600  if (ss == -1) {
1601  if (!nonblock && rb_io_wait_readable(fptr->fd)) {
1602  rb_io_check_closed(fptr);
1603  goto retry;
1604  }
1605  if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
1606  rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvmsg(2) would block");
1607 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1608  if (!gc_done && (errno == EMFILE || errno == EMSGSIZE)) {
1609  /*
1610  * When SCM_RIGHTS hit the file descriptors limit:
1611  * - Linux 2.6.18 causes success with MSG_CTRUNC
1612  * - MacOS X 10.4 causes EMSGSIZE (and lost file descriptors?)
1613  * - Solaris 11 causes EMFILE
1614  */
1615  gc_and_retry:
1616  rb_gc();
1617  gc_done = 1;
1618  goto retry;
1619  }
1620 #endif
1621  rb_sys_fail("recvmsg(2)");
1622  }
1623 
1624  if (grow_buffer) {
1625  int grown = 0;
1626 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1627  if (NIL_P(vmaxdatlen) && (mh.msg_flags & MSG_TRUNC)) {
1628  if (SIZE_MAX/2 < maxdatlen)
1629  rb_raise(rb_eArgError, "max data length too big");
1630  maxdatlen *= 2;
1631  grown = 1;
1632  }
1633  if (NIL_P(vmaxctllen) && (mh.msg_flags & MSG_CTRUNC)) {
1634 #define BIG_ENOUGH_SPACE 65536
1635  if (BIG_ENOUGH_SPACE < maxctllen &&
1636  (socklen_t)mh.msg_controllen < (socklen_t)(maxctllen - BIG_ENOUGH_SPACE)) {
1637  /* there are big space bug truncated.
1638  * file descriptors limit? */
1639  if (!gc_done) {
1640  rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
1641  goto gc_and_retry;
1642  }
1643  }
1644  else {
1645  if (SIZE_MAX/2 < maxctllen)
1646  rb_raise(rb_eArgError, "max control message length too big");
1647  maxctllen *= 2;
1648  grown = 1;
1649  }
1650 #undef BIG_ENOUGH_SPACE
1651  }
1652 #else
1653  if (NIL_P(vmaxdatlen) && ss != -1 && ss == (ssize_t)iov.iov_len) {
1654  if (SIZE_MAX/2 < maxdatlen)
1655  rb_raise(rb_eArgError, "max data length too big");
1656  maxdatlen *= 2;
1657  grown = 1;
1658  }
1659 #endif
1660  if (grown) {
1661  rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
1662  goto retry;
1663  }
1664  else {
1665  grow_buffer = 0;
1666  if (flags != orig_flags) {
1667  rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
1668  flags = orig_flags;
1669  goto retry;
1670  }
1671  }
1672  }
1673 
1674  if (NIL_P(dat_str))
1675  dat_str = rb_tainted_str_new(datbuf, ss);
1676  else {
1677  rb_str_resize(dat_str, ss);
1678  OBJ_TAINT(dat_str);
1679  rb_obj_reveal(dat_str, rb_cString);
1680  }
1681 
1682  ret = rb_ary_new3(3, dat_str,
1684 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1685  INT2NUM(mh.msg_flags)
1686 #else
1687  Qnil
1688 #endif
1689  );
1690 
1691 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1692  family = rsock_getfamily(fptr->fd);
1693  if (mh.msg_controllen) {
1694  char *msg_end = (char *)mh.msg_control + mh.msg_controllen;
1695  for (cmh = CMSG_FIRSTHDR(&mh); cmh != NULL; cmh = CMSG_NXTHDR(&mh, cmh)) {
1696  VALUE ctl;
1697  char *ctl_end;
1698  size_t clen;
1699  if (cmh->cmsg_len == 0) {
1700  rb_raise(rb_eTypeError, "invalid control message (cmsg_len == 0)");
1701  }
1702  ctl_end = (char*)cmh + cmh->cmsg_len;
1703  clen = (ctl_end <= msg_end ? ctl_end : msg_end) - (char*)CMSG_DATA(cmh);
1704  ctl = ancdata_new(family, cmh->cmsg_level, cmh->cmsg_type, rb_tainted_str_new((char*)CMSG_DATA(cmh), clen));
1705  if (request_scm_rights)
1706  make_io_for_unix_rights(ctl, cmh, msg_end);
1707  else
1708  discard_cmsg(cmh, msg_end, (flags & MSG_PEEK) != 0);
1709  rb_ary_push(ret, ctl);
1710  }
1711  RB_GC_GUARD(ctl_str);
1712  }
1713 #endif
1714 
1715  return ret;
1716 }
1717 #endif
1718 
1719 #if defined(HAVE_RECVMSG)
1720 /*
1721  * call-seq:
1722  * basicsocket.recvmsg(maxmesglen=nil, flags=0, maxcontrollen=nil, opts={}) => [mesg, sender_addrinfo, rflags, *controls]
1723  *
1724  * recvmsg receives a message using recvmsg(2) system call in blocking manner.
1725  *
1726  * _maxmesglen_ is the maximum length of mesg to receive.
1727  *
1728  * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_PEEK.
1729  *
1730  * _maxcontrollen_ is the maximum length of controls (ancillary data) to receive.
1731  *
1732  * _opts_ is option hash.
1733  * Currently :scm_rights=>bool is the only option.
1734  *
1735  * :scm_rights option specifies that application expects SCM_RIGHTS control message.
1736  * If the value is nil or false, application don't expects SCM_RIGHTS control message.
1737  * In this case, recvmsg closes the passed file descriptors immediately.
1738  * This is the default behavior.
1739  *
1740  * If :scm_rights value is neither nil nor false, application expects SCM_RIGHTS control message.
1741  * In this case, recvmsg creates IO objects for each file descriptors for
1742  * Socket::AncillaryData#unix_rights method.
1743  *
1744  * The return value is 4-elements array.
1745  *
1746  * _mesg_ is a string of the received message.
1747  *
1748  * _sender_addrinfo_ is a sender socket address for connection-less socket.
1749  * It is an Addrinfo object.
1750  * For connection-oriented socket such as TCP, sender_addrinfo is platform dependent.
1751  *
1752  * _rflags_ is a flags on the received message which is bitwise OR of MSG_* constants such as Socket::MSG_TRUNC.
1753  * It will be nil if the system uses 4.3BSD style old recvmsg system call.
1754  *
1755  * _controls_ is ancillary data which is an array of Socket::AncillaryData objects such as:
1756  *
1757  * #<Socket::AncillaryData: AF_UNIX SOCKET RIGHTS 7>
1758  *
1759  * _maxmesglen_ and _maxcontrollen_ can be nil.
1760  * In that case, the buffer will be grown until the message is not truncated.
1761  * Internally, MSG_PEEK is used and MSG_TRUNC/MSG_CTRUNC are checked.
1762  *
1763  * recvmsg can be used to implement recv_io as follows:
1764  *
1765  * mesg, sender_sockaddr, rflags, *controls = sock.recvmsg(:scm_rights=>true)
1766  * controls.each {|ancdata|
1767  * if ancdata.cmsg_is?(:SOCKET, :RIGHTS)
1768  * return ancdata.unix_rights[0]
1769  * end
1770  * }
1771  *
1772  */
1773 VALUE
1775 {
1776  return bsock_recvmsg_internal(argc, argv, sock, 0);
1777 }
1778 #endif
1779 
1780 #if defined(HAVE_RECVMSG)
1781 /*
1782  * call-seq:
1783  * basicsocket.recvmsg_nonblock(maxdatalen=nil, flags=0, maxcontrollen=nil, opts={}) => [data, sender_addrinfo, rflags, *controls]
1784  *
1785  * recvmsg receives a message using recvmsg(2) system call in non-blocking manner.
1786  *
1787  * It is similar to BasicSocket#recvmsg
1788  * but non-blocking flag is set before the system call
1789  * and it doesn't retry the system call.
1790  *
1791  */
1792 VALUE
1794 {
1795  return bsock_recvmsg_internal(argc, argv, sock, 1);
1796 }
1797 #endif
1798 
1799 void
1801 {
1802 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
1803  /*
1804  * Document-class: Socket::AncillaryData
1805  *
1806  * Socket::AncillaryData represents the ancillary data (control information)
1807  * used by sendmsg and recvmsg system call. It contains socket #family,
1808  * control message (cmsg) #level, cmsg #type and cmsg #data.
1809  */
1810  rb_cAncillaryData = rb_define_class_under(rb_cSocket, "AncillaryData", rb_cObject);
1811  rb_define_method(rb_cAncillaryData, "initialize", ancillary_initialize, 4);
1812  rb_define_method(rb_cAncillaryData, "inspect", ancillary_inspect, 0);
1813  rb_define_method(rb_cAncillaryData, "family", ancillary_family_m, 0);
1814  rb_define_method(rb_cAncillaryData, "level", ancillary_level_m, 0);
1815  rb_define_method(rb_cAncillaryData, "type", ancillary_type_m, 0);
1816  rb_define_method(rb_cAncillaryData, "data", ancillary_data, 0);
1817 
1818  rb_define_method(rb_cAncillaryData, "cmsg_is?", ancillary_cmsg_is_p, 2);
1819 
1820  rb_define_singleton_method(rb_cAncillaryData, "int", ancillary_s_int, 4);
1821  rb_define_method(rb_cAncillaryData, "int", ancillary_int, 0);
1822 
1823  rb_define_singleton_method(rb_cAncillaryData, "unix_rights", ancillary_s_unix_rights, -1);
1824  rb_define_method(rb_cAncillaryData, "unix_rights", ancillary_unix_rights, 0);
1825 
1826  rb_define_method(rb_cAncillaryData, "timestamp", ancillary_timestamp, 0);
1827 
1828  rb_define_singleton_method(rb_cAncillaryData, "ip_pktinfo", ancillary_s_ip_pktinfo, -1);
1829  rb_define_method(rb_cAncillaryData, "ip_pktinfo", ancillary_ip_pktinfo, 0);
1830 
1831  rb_define_singleton_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_s_ipv6_pktinfo, 2);
1832  rb_define_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_ipv6_pktinfo, 0);
1833  rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_addr", ancillary_ipv6_pktinfo_addr, 0);
1834  rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_ifindex", ancillary_ipv6_pktinfo_ifindex, 0);
1835 #endif
1836 }
RUBY_EXTERN VALUE rb_cString
Definition: ruby.h:1591
void rb_gc(void)
Definition: gc.c:5193
#define T_OBJECT
Definition: ruby.h:477
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1179
#define RARRAY_LEN(a)
Definition: ruby.h:878
#define INT2NUM(x)
Definition: ruby.h:1296
int msg_iovlen
Definition: win32.h:239
void rb_io_set_nonblock(rb_io_t *fptr)
Definition: io.c:2378
void * msg_control
Definition: win32.h:240
VALUE rb_time_nano_new(time_t, long)
Definition: time.c:2305
#define PF_INET
Definition: sockport.h:109
#define SockAddrStringValue(v)
Definition: rubysocket.h:261
#define NUM2INT(x)
Definition: ruby.h:630
#define NUM2UINT(x)
Definition: ruby.h:631
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1646
int sendmsg(int, const struct msghdr *, int)
Definition: win32.c:3442
int msg_namelen
Definition: win32.h:237
#define Qtrue
Definition: ruby.h:426
Definition: io.h:61
Definition: win32.h:235
void * msg_name
Definition: win32.h:236
VALUE rb_eTypeError
Definition: error.c:548
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:900
VALUE rsock_init_sock(VALUE sock, int fd)
Definition: init.c:43
#define SYM2ID(x)
Definition: ruby.h:356
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:781
void rb_str_set_len(VALUE, long)
Definition: string.c:2007
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:657
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
#define rsock_bsock_sendmsg
Definition: rubysocket.h:351
#define RB_GC_GUARD(v)
Definition: ruby.h:523
struct iovec * msg_iov
Definition: win32.h:238
#define T_ARRAY
Definition: ruby.h:484
int rsock_getfamily(int sockfd)
Definition: init.c:608
#define SSIZET2NUM(v)
Definition: ruby.h:263
int recvmsg(int, struct msghdr *, int)
Definition: win32.c:3384
VALUE rb_str_tmp_new(long)
Definition: string.c:919
int msg_flags
Definition: win32.h:242
#define GetOpenFile(obj, fp)
Definition: io.h:118
VALUE rsock_io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len)
Definition: raddrinfo.c:2483
const char * rb_obj_classname(VALUE)
Definition: variable.c:406
VALUE rb_str_buf_cat(VALUE, const char *, long)
Definition: string.c:2123
#define NEWOBJ_OF(obj, type, klass, flags)
Definition: ruby.h:694
#define RB_TYPE_P(obj, type)
Definition: ruby.h:1672
VALUE rsock_addrinfo_new(struct sockaddr *addr, socklen_t len, int family, int socktype, int protocol, VALUE canonname, VALUE inspectname)
Definition: raddrinfo.c:747
unsigned long long uint64_t
Definition: sha2.h:102
#define RSTRING_SOCKLEN
Definition: rubysocket.h:122
int rsock_family_arg(VALUE domain)
Definition: constants.c:43
#define level
#define rsock_bsock_sendmsg_nonblock
Definition: rubysocket.h:352
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1561
#define RB_IO_WAIT_WRITABLE
Definition: ruby.h:1516
VALUE rb_str_cat2(VALUE, const char *)
Definition: string.c:2158
VALUE rb_ary_new(void)
Definition: array.c:499
#define UINT2NUM(x)
Definition: ruby.h:1306
#define NIL_P(v)
Definition: ruby.h:438
#define add(x, y)
Definition: date_strftime.c:23
static char msg[50]
Definition: strerror.c:8
int rsock_level_arg(int family, VALUE level)
Definition: constants.c:57
int fd
Definition: io.h:62
int rb_io_wait_writable(int)
Definition: io.c:1103
static const char * inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
Definition: getnameinfo.c:123
int argc
Definition: ruby.c:131
#define Qfalse
Definition: ruby.h:425
void rsock_init_ancdata(void)
Definition: ancdata.c:1800
#define ALLOCA_N(type, n)
Definition: ruby.h:1345
#define MEMCPY(p1, p2, type, n)
Definition: ruby.h:1360
#define rsock_bsock_recvmsg_nonblock
Definition: rubysocket.h:361
VALUE rb_obj_alloc(VALUE)
Definition: object.c:1804
#define OBJ_FREEZE(x)
Definition: ruby.h:1194
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Definition: object.c:62
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
VALUE rb_time_new(time_t, long)
Definition: time.c:2279
VALUE rb_cSocket
Definition: init.c:22
#define INIT_SOCKADDR(addr, family, len)
Definition: sockport.h:38
VALUE rb_str_resize(VALUE, long)
Definition: string.c:2024
static VALUE constant_to_sym(int constant, ID(*intern_const)(int))
Definition: option.c:6
#define IS_IP_FAMILY(af)
Definition: rubysocket.h:154
#define RSTRING_LEN(str)
Definition: ruby.h:841
VALUE rb_io_fdopen(int, int, const char *)
Definition: io.c:7247
int errno
int socklen_t
Definition: getaddrinfo.c:84
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1250
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1719
VALUE rb_ivar_set(VALUE, ID, VALUE)
Definition: variable.c:1133
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4308
unsigned long ID
Definition: ruby.h:89
#define Qnil
Definition: ruby.h:427
int type
Definition: tcltklib.c:112
#define OBJ_TAINT(x)
Definition: ruby.h:1184
unsigned long VALUE
Definition: ruby.h:88
static VALUE result
Definition: nkf.c:40
void rb_readwrite_sys_fail(int writable, const char *mesg)
Definition: io.c:11704
#define RB_IO_WAIT_READABLE
Definition: ruby.h:1515
Definition: win32.h:231
#define rb_ary_new3
Definition: intern.h:91
VALUE rb_str_dump(VALUE)
Definition: string.c:4902
void rb_sys_fail(const char *mesg)
Definition: error.c:1976
#define RSTRING_PTR(str)
Definition: ruby.h:845
VALUE rb_eSocket
Definition: init.c:25
int rb_io_read_pending(rb_io_t *)
Definition: io.c:830
#define quo(x, y)
Definition: date_strftime.c:26
VALUE rb_check_convert_type(VALUE, int, const char *, const char *)
Definition: object.c:2652
#define mul(x, y)
Definition: date_strftime.c:25
#define SIZE_MAX
Definition: ruby.h:274
void rb_fd_fix_cloexec(int fd)
Definition: io.c:221
#define NUM2SIZET(x)
Definition: ruby.h:680
VALUE rb_hash_aref(VALUE hash, VALUE key)
Definition: hash.c:706
#define RARRAY_PTR(a)
Definition: ruby.h:907
VALUE rb_str_catf(VALUE str, const char *format,...)
Definition: sprintf.c:1290
#define RTEST(v)
Definition: ruby.h:437
#define AF_UNSPEC
Definition: sockport.h:101
#define EMSGSIZE
Definition: win32.h:524
#define EWOULDBLOCK
Definition: rubysocket.h:126
#define T_FILE
Definition: ruby.h:488
VALUE rb_eNotImpError
Definition: error.c:558
const char * name
Definition: nkf.c:208
RUBY_EXTERN VALUE rb_eIOError
Definition: ruby.h:1611
#define ID2SYM(x)
Definition: ruby.h:355
const char * rb_id2name(ID id)
Definition: ripper.c:17271
Definition: ruby.h:762
#define IFNAMSIZ
int msg_controllen
Definition: win32.h:241
#define rsock_bsock_recvmsg
Definition: rubysocket.h:360
VALUE rb_tainted_str_new(const char *, long)
Definition: string.c:589
#define rb_intern(str)
VALUE rb_str_buf_new(long)
Definition: string.c:891
#define fstat(fd, st)
Definition: win32.h:214
#define SYMBOL_P(x)
Definition: ruby.h:354
#define stat(path, st)
Definition: win32.h:213
#define NULL
Definition: _sdbm.c:102
int rb_io_wait_readable(int)
Definition: io.c:1077
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1479
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:2297
void rb_io_check_closed(rb_io_t *)
Definition: io.c:617
VALUE rb_time_num_new(VALUE, VALUE)
Definition: time.c:2311
VALUE rb_eArgError
Definition: error.c:549
int rsock_cmsg_type_arg(int family, int level, VALUE type)
Definition: constants.c:100
VALUE rb_attr_get(VALUE, ID)
Definition: variable.c:1127
char ** argv
Definition: ruby.c:132
#define StringValue(v)
Definition: ruby.h:539
#define RUBY_UBF_IO
Definition: intern.h:872
VALUE rb_str_new(const char *, long)
Definition: string.c:534