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