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
constant_to_sym(int constant,ID (* intern_const)(int))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
ip_cmsg_type_to_sym(int level,int cmsg_type)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
ancillary_initialize(VALUE self,VALUE vfamily,VALUE vlevel,VALUE vtype,VALUE data)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
ancdata_new(int family,int level,int type,VALUE data)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
ancillary_family(VALUE self)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
ancillary_family_m(VALUE self)115 ancillary_family_m(VALUE self)
116 {
117     return INT2NUM(ancillary_family(self));
118 }
119 
120 static int
ancillary_level(VALUE self)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
ancillary_level_m(VALUE self)137 ancillary_level_m(VALUE self)
138 {
139     return INT2NUM(ancillary_level(self));
140 }
141 
142 static int
ancillary_type(VALUE self)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
ancillary_type_m(VALUE self)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
ancillary_data(VALUE self)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
ancillary_s_unix_rights(int argc,VALUE * argv,VALUE klass)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
ancillary_unix_rights(VALUE self)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
ancillary_timestamp(VALUE self)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
ancillary_s_int(VALUE klass,VALUE vfamily,VALUE vlevel,VALUE vtype,VALUE integer)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
ancillary_int(VALUE self)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
ancillary_s_ip_pktinfo(int argc,VALUE * argv,VALUE self)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
ancillary_ip_pktinfo(VALUE self)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
ancillary_s_ipv6_pktinfo(VALUE self,VALUE v_addr,VALUE v_ifindex)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
extract_ipv6_pktinfo(VALUE self,struct in6_pktinfo * pktinfo_ptr,struct sockaddr_in6 * sa_ptr)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
ancillary_ipv6_pktinfo(VALUE self)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
ancillary_ipv6_pktinfo_addr(VALUE self)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
ancillary_ipv6_pktinfo_ifindex(VALUE self)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
anc_inspect_socket_rights(int level,int type,VALUE data,VALUE ret)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
anc_inspect_passcred_credentials(int level,int type,VALUE data,VALUE ret)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
anc_inspect_socket_creds(int level,int type,VALUE data,VALUE ret)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
anc_inspect_ip_recvdstaddr(int level,int type,VALUE data,VALUE ret)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
anc_inspect_ip_pktinfo(int level,int type,VALUE data,VALUE ret)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;
805         char buf[INET_ADDRSTRLEN > IFNAMSIZ ? INET_ADDRSTRLEN : IFNAMSIZ];
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
anc_inspect_ipv6_pktinfo(int level,int type,VALUE data,VALUE ret)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
inspect_timeval_as_abstime(int level,int optname,VALUE data,VALUE ret)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
inspect_timespec_as_abstime(int level,int optname,VALUE data,VALUE ret)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
inspect_bintime_as_abstime(int level,int optname,VALUE data,VALUE ret)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
ancillary_inspect(VALUE self)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
ancillary_cmsg_is_p(VALUE self,VALUE vlevel,VALUE vtype)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 *
nogvl_sendmsg_func(void * ptr)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
rb_sendmsg(int fd,const struct msghdr * msg,int flags)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
bsock_sendmsg_internal(VALUE sock,VALUE data,VALUE vflags,VALUE dest_sockaddr,VALUE controls,VALUE ex,int nonblock)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 	    }
1290 	    rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e,
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
rsock_bsock_sendmsg(VALUE sock,VALUE data,VALUE flags,VALUE dest_sockaddr,VALUE controls)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
rsock_bsock_sendmsg_nonblock(VALUE sock,VALUE data,VALUE flags,VALUE dest_sockaddr,VALUE controls,VALUE ex)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
rsock_recvmsg(int socket,struct msghdr * message,int flags)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 *
nogvl_recvmsg_func(void * ptr)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
rb_recvmsg(int fd,struct msghdr * msg,int flags)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
discard_cmsg(struct cmsghdr * cmh,char * msg_end,int msg_peek_p)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
rsock_discard_cmsg_resource(struct msghdr * mh,int msg_peek_p)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
make_io_for_unix_rights(VALUE ctl,struct cmsghdr * cmh,char * msg_end)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)
1430                 rsock_cmsg_cloexec_state = rsock_detect_cloexec(fd);
1431             if (rsock_cmsg_cloexec_state == 0 || fd <= 2)
1432                 rb_maygvl_fd_fix_cloexec(fd);
1433             if (S_ISSOCK(stbuf.st_mode))
1434                 io = rsock_init_sock(rb_obj_alloc(rb_cSocket), fd);
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
bsock_recvmsg_internal(VALUE sock,VALUE vmaxdatlen,VALUE vflags,VALUE vmaxctllen,VALUE scm_rights,VALUE ex,int nonblock)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,
1639                          rsock_io_socket_addrinfo(sock, mh.msg_name, mh.msg_namelen),
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
rsock_bsock_recvmsg(VALUE sock,VALUE dlen,VALUE flags,VALUE clen,VALUE scm_rights)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
rsock_bsock_recvmsg_nonblock(VALUE sock,VALUE dlen,VALUE flags,VALUE clen,VALUE scm_rights,VALUE ex)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
rsock_init_ancdata(void)1695 rsock_init_ancdata(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 }
1735