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