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