Ruby 2.0.0p247(2013-06-27revision41674)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

ancdata.c
Go to the documentation of this file.
1 #include "rubysocket.h"
2
3 #include <time.h>
4
5 #if defined(HAVE_ST_MSG_CONTROL)
6 static VALUE rb_cAncillaryData;
7
8 static VALUE
9 constant_to_sym(int constant, ID (*intern_const)(int))
10 {
11 ID name = intern_const(constant);
12 if (name) {
13 return ID2SYM(name);
14 }
15
16 return INT2NUM(constant);
17 }
18
19 static VALUE
20 ip_cmsg_type_to_sym(int level, int cmsg_type)
21 {
22 switch (level) {
23 case SOL_SOCKET:
24 return constant_to_sym(cmsg_type, rsock_intern_scm_optname);
25 case IPPROTO_IP:
26 return constant_to_sym(cmsg_type, rsock_intern_ip_optname);
27 #ifdef IPPROTO_IPV6
28 case IPPROTO_IPV6:
29 return constant_to_sym(cmsg_type, rsock_intern_ipv6_optname);
30 #endif
31 case IPPROTO_TCP:
32 return constant_to_sym(cmsg_type, rsock_intern_tcp_optname);
33 case IPPROTO_UDP:
34 return constant_to_sym(cmsg_type, rsock_intern_udp_optname);
35 default:
36 return INT2NUM(cmsg_type);
37 }
38 }
39
40 /*
41 * call-seq:
42 * Socket::AncillaryData.new(family, cmsg_level, cmsg_type, cmsg_data) -> ancillarydata
43 *
44 * _family_ should be an integer, a string or a symbol.
45 * - Socket::AF_INET, "AF_INET", "INET", :AF_INET, :INET
46 * - Socket::AF_UNIX, "AF_UNIX", "UNIX", :AF_UNIX, :UNIX
47 * - etc.
48 *
49 * _cmsg_level_ should be an integer, a string or a symbol.
50 * - Socket::SOL_SOCKET, "SOL_SOCKET", "SOCKET", :SOL_SOCKET and :SOCKET
51 * - Socket::IPPROTO_IP, "IP" and :IP
52 * - Socket::IPPROTO_IPV6, "IPV6" and :IPV6
53 * - Socket::IPPROTO_TCP, "TCP" and :TCP
54 * - etc.
55 *
56 * _cmsg_type_ should be an integer, a string or a symbol.
57 * If a string/symbol is specified, it is interpreted depend on _cmsg_level_.
58 * - Socket::SCM_RIGHTS, "SCM_RIGHTS", "RIGHTS", :SCM_RIGHTS, :RIGHTS for SOL_SOCKET
59 * - Socket::IP_RECVTTL, "RECVTTL" and :RECVTTL for IPPROTO_IP
60 * - Socket::IPV6_PKTINFO, "PKTINFO" and :PKTINFO for IPPROTO_IPV6
61 * - etc.
62 *
63 * _cmsg_data_ should be a string.
64 *
65 * p Socket::AncillaryData.new(:INET, :TCP, :NODELAY, "")
66 * #=> #<Socket::AncillaryData: INET TCP NODELAY "">
67 *
68 * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "")
69 * #=> #<Socket::AncillaryData: INET6 IPV6 PKTINFO "">
70 *
71 */
72 static VALUE
73 ancillary_initialize(VALUE self, VALUE vfamily, VALUE vlevel, VALUE vtype, VALUE data)
74 {
75 int family = rsock_family_arg(vfamily);
76 int level = rsock_level_arg(family, vlevel);
77 int type = rsock_cmsg_type_arg(family, level, vtype);
78 StringValue(data);
79 rb_ivar_set(self, rb_intern("family"), INT2NUM(family));
80 rb_ivar_set(self, rb_intern("level"), INT2NUM(level));
81 rb_ivar_set(self, rb_intern("type"), INT2NUM(type));
82 rb_ivar_set(self, rb_intern("data"), data);
83 return self;
84 }
85
86 static VALUE
87 ancdata_new(int family, int level, int type, VALUE data)
88 {
89 NEWOBJ_OF(obj, struct RObject, rb_cAncillaryData, T_OBJECT);
90 StringValue(data);
91 ancillary_initialize((VALUE)obj, INT2NUM(family), INT2NUM(level), INT2NUM(type), data);
92 return (VALUE)obj;
93 }
94
95 static int
96 ancillary_family(VALUE self)
97 {
98 VALUE v = rb_attr_get(self, rb_intern("family"));
99 return NUM2INT(v);
100 }
101
102 /*
103 * call-seq:
104 * ancillarydata.family => integer
105 *
106 * returns the socket family as an integer.
107 *
108 * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").family
109 * #=> 10
110 */
111 static VALUE
112 ancillary_family_m(VALUE self)
113 {
114 return INT2NUM(ancillary_family(self));
115 }
116
117 static int
118 ancillary_level(VALUE self)
119 {
120 VALUE v = rb_attr_get(self, rb_intern("level"));
121 return NUM2INT(v);
122 }
123
124 /*
125 * call-seq:
126 * ancillarydata.level => integer
127 *
128 * returns the cmsg level as an integer.
129 *
130 * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").level
131 * #=> 41
132 */
133 static VALUE
134 ancillary_level_m(VALUE self)
135 {
136 return INT2NUM(ancillary_level(self));
137 }
138
139 static int
140 ancillary_type(VALUE self)
141 {
142 VALUE v = rb_attr_get(self, rb_intern("type"));
143 return NUM2INT(v);
144 }
145
146 /*
147 * call-seq:
148 * ancillarydata.type => integer
149 *
150 * returns the cmsg type as an integer.
151 *
152 * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").type
153 * #=> 2
154 */
155 static VALUE
156 ancillary_type_m(VALUE self)
157 {
158 return INT2NUM(ancillary_type(self));
159 }
160
161 /*
162 * call-seq:
163 * ancillarydata.data => string
164 *
165 * returns the cmsg data as a string.
166 *
167 * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").data
168 * #=> ""
169 */
170 static VALUE
171 ancillary_data(VALUE self)
172 {
173 VALUE v = rb_attr_get(self, rb_intern("data"));
174 StringValue(v);
175 return v;
176 }
177
178 #ifdef SCM_RIGHTS
179 /*
180 * call-seq:
181 * Socket::AncillaryData.unix_rights(io1, io2, ...) => ancillarydata
182 *
183 * Creates a new Socket::AncillaryData object which contains file descriptors as data.
184 *
185 * p Socket::AncillaryData.unix_rights(STDERR)
186 * #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 2>
187 */
188 static VALUE
189 ancillary_s_unix_rights(int argc, VALUE *argv, VALUE klass)
190 {
191 VALUE result, str, ary;
192 int i;
193
194 ary = rb_ary_new();
195
196 for (i = 0 ; i < argc; i++) {
197 VALUE obj = argv[i];
198 if (!RB_TYPE_P(obj, T_FILE)) {
199 rb_raise(rb_eTypeError, "IO expected");
200 }
201 rb_ary_push(ary, obj);
202 }
203
204 str = rb_str_buf_new(sizeof(int) * argc);
205
206 for (i = 0 ; i < argc; i++) {
207 VALUE obj = RARRAY_PTR(ary)[i];
208 rb_io_t *fptr;
209 int fd;
210 GetOpenFile(obj, fptr);
211 fd = fptr->fd;
212 rb_str_buf_cat(str, (char *)&fd, sizeof(int));
213 }
214
215 result = ancdata_new(AF_UNIX, SOL_SOCKET, SCM_RIGHTS, str);
216 rb_ivar_set(result, rb_intern("unix_rights"), ary);
217 return result;
218 }
219 #else
220 #define ancillary_s_unix_rights rb_f_notimplement
221 #endif
222
223 #ifdef SCM_RIGHTS
224 /*
225 * call-seq:
226 * ancillarydata.unix_rights => array-of-IOs or nil
227 *
228 * returns the array of IO objects for SCM_RIGHTS control message in UNIX domain socket.
229 *
230 * The class of the IO objects in the array is IO or Socket.
231 *
232 * The array is attached to _ancillarydata_ when it is instantiated.
233 * For example, BasicSocket#recvmsg attach the array when
234 * receives a SCM_RIGHTS control message and :scm_rights=>true option is given.
235 *
236 * # recvmsg needs :scm_rights=>true for unix_rights
237 * s1, s2 = UNIXSocket.pair
238 * p s1 #=> #<UNIXSocket:fd 3>
239 * s1.sendmsg "stdin and a socket", 0, nil, Socket::AncillaryData.unix_rights(STDIN, s1)
240 * _, _, _, ctl = s2.recvmsg(:scm_rights=>true)
241 * p ctl #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 6 7>
242 * p ctl.unix_rights #=> [#<IO:fd 6>, #<Socket:fd 7>]
243 * p File.identical?(STDIN, ctl.unix_rights[0]) #=> true
244 * p File.identical?(s1, ctl.unix_rights[1]) #=> true
245 *
246 * # If :scm_rights=>true is not given, unix_rights returns nil
247 * s1, s2 = UNIXSocket.pair
248 * s1.sendmsg "stdin and a socket", 0, nil, Socket::AncillaryData.unix_rights(STDIN, s1)
249 * _, _, _, ctl = s2.recvmsg
250 * p ctl #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 6 7>
251 * p ctl.unix_rights #=> nil
252 *
253 */
254 static VALUE
255 ancillary_unix_rights(VALUE self)
256 {
257 int level, type;
258
259 level = ancillary_level(self);
260 type = ancillary_type(self);
261
262 if (level != SOL_SOCKET || type != SCM_RIGHTS)
263 rb_raise(rb_eTypeError, "SCM_RIGHTS ancillary data expected");
264
265 return rb_attr_get(self, rb_intern("unix_rights"));
266 }
267 #else
268 #define ancillary_unix_rights rb_f_notimplement
269 #endif
270
271 #if defined(SCM_TIMESTAMP) || defined(SCM_TIMESTAMPNS) || defined(SCM_BINTIME)
272 /*
273 * call-seq:
274 * ancillarydata.timestamp => time
275 *
276 * returns the timestamp as a time object.
277 *
278 * _ancillarydata_ should be one of following type:
279 * - SOL_SOCKET/SCM_TIMESTAMP (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 */
297 static VALUE
298 ancillary_timestamp(VALUE self)
299 {
300 int level, type;
301 VALUE data;
302 VALUE result = Qnil;
303
304 level = ancillary_level(self);
305 type = ancillary_type(self);
306 data = ancillary_data(self);
307
308 # ifdef SCM_TIMESTAMP
309 if (level == SOL_SOCKET && type == SCM_TIMESTAMP &&
310 RSTRING_LEN(data) == sizeof(struct timeval)) {
311 struct timeval tv;
312 memcpy((char*)&tv, RSTRING_PTR(data), sizeof(tv));
313 result = rb_time_new(tv.tv_sec, tv.tv_usec);
314 }
315 # endif
316
317 # ifdef SCM_TIMESTAMPNS
318 if (level == SOL_SOCKET && type == SCM_TIMESTAMPNS &&
319 RSTRING_LEN(data) == sizeof(struct timespec)) {
320 struct timespec ts;
321 memcpy((char*)&ts, RSTRING_PTR(data), sizeof(ts));
322 result = rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
323 }
324 # endif
325
326 #define add(x,y) (rb_funcall((x), '+', 1, (y)))
327 #define mul(x,y) (rb_funcall((x), '*', 1, (y)))
328 #define quo(x,y) (rb_funcall((x), rb_intern("quo"), 1, (y)))
329
330 # ifdef SCM_BINTIME
331 if (level == SOL_SOCKET && type == SCM_BINTIME &&
332 RSTRING_LEN(data) == sizeof(struct bintime)) {
333 struct bintime bt;
334 VALUE d, timev;
335 memcpy((char*)&bt, RSTRING_PTR(data), sizeof(bt));
336 d = ULL2NUM(0x100000000ULL);
337 d = mul(d,d);
338 timev = add(TIMET2NUM(bt.sec), quo(ULL2NUM(bt.frac), d));
339 result = rb_time_num_new(timev, Qnil);
340 }
341 # endif
342
343 if (result == Qnil)
344 rb_raise(rb_eTypeError, "timestamp ancillary data expected");
345
346 return result;
347 }
348 #else
349 #define ancillary_timestamp rb_f_notimplement
350 #endif
351
352 /*
353 * call-seq:
354 * Socket::AncillaryData.int(family, cmsg_level, cmsg_type, integer) => ancillarydata
355 *
356 * Creates a new Socket::AncillaryData object which contains a int as data.
357 *
358 * The size and endian is dependent on the host.
359 *
360 * p Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, STDERR.fileno)
361 * #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 2>
362 */
363 static VALUE
364 ancillary_s_int(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE vtype, VALUE integer)
365 {
366 int family = rsock_family_arg(vfamily);
367 int level = rsock_level_arg(family, vlevel);
368 int type = rsock_cmsg_type_arg(family, level, vtype);
369 int i = NUM2INT(integer);
370 return ancdata_new(family, level, type, rb_str_new((char*)&i, sizeof(i)));
371 }
372
373 /*
374 * call-seq:
375 * ancillarydata.int => integer
376 *
377 * Returns the data in _ancillarydata_ as an int.
378 *
379 * The size and endian is dependent on the host.
380 *
381 * ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, STDERR.fileno)
382 * p ancdata.int #=> 2
383 */
384 static VALUE
385 ancillary_int(VALUE self)
386 {
387 VALUE data;
388 int i;
389 data = ancillary_data(self);
390 if (RSTRING_LEN(data) != sizeof(int))
391 rb_raise(rb_eTypeError, "size differ. expected as sizeof(int)=%d but %ld", (int)sizeof(int), (long)RSTRING_LEN(data));
392 memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
393 return INT2NUM(i);
394 }
395
396 #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST) /* GNU/Linux */
397 /*
398 * call-seq:
399 * Socket::AncillaryData.ip_pktinfo(addr, ifindex) => ancdata
400 * Socket::AncillaryData.ip_pktinfo(addr, ifindex, spec_dst) => ancdata
401 *
402 * Returns new ancillary data for IP_PKTINFO.
403 *
404 * If spec_dst is not given, addr is used.
405 *
406 * IP_PKTINFO is not standard.
407 *
408 * Supported platform: GNU/Linux
409 *
410 * addr = Addrinfo.ip("127.0.0.1")
411 * ifindex = 0
412 * spec_dst = Addrinfo.ip("127.0.0.1")
413 * p Socket::AncillaryData.ip_pktinfo(addr, ifindex, spec_dst)
414 * #=> #<Socket::AncillaryData: INET IP PKTINFO 127.0.0.1 ifindex:0 spec_dst:127.0.0.1>
415 *
416 */
417 static VALUE
418 ancillary_s_ip_pktinfo(int argc, VALUE *argv, VALUE self)
419 {
420 VALUE v_addr, v_ifindex, v_spec_dst;
421 unsigned int ifindex;
422 struct sockaddr_in sa;
423 struct in_pktinfo pktinfo;
424
425 rb_scan_args(argc, argv, "21", &v_addr, &v_ifindex, &v_spec_dst);
426
427 SockAddrStringValue(v_addr);
428 ifindex = NUM2UINT(v_ifindex);
429 if (NIL_P(v_spec_dst))
430 v_spec_dst = v_addr;
431 else
432 SockAddrStringValue(v_spec_dst);
433
434 memset(&pktinfo, 0, sizeof(pktinfo));
435
436 memset(&sa, 0, sizeof(sa));
437 if (RSTRING_LEN(v_addr) != sizeof(sa))
438 rb_raise(rb_eArgError, "addr size different to AF_INET sockaddr");
439 memcpy(&sa, RSTRING_PTR(v_addr), sizeof(sa));
440 if (sa.sin_family != AF_INET)
441 rb_raise(rb_eArgError, "addr is not AF_INET sockaddr");
442 memcpy(&pktinfo.ipi_addr, &sa.sin_addr, sizeof(pktinfo.ipi_addr));
443
444 pktinfo.ipi_ifindex = ifindex;
445
446 memset(&sa, 0, sizeof(sa));
447 if (RSTRING_LEN(v_spec_dst) != sizeof(sa))
448 rb_raise(rb_eArgError, "spec_dat size different to AF_INET sockaddr");
449 memcpy(&sa, RSTRING_PTR(v_spec_dst), sizeof(sa));
450 if (sa.sin_family != AF_INET)
451 rb_raise(rb_eArgError, "spec_dst is not AF_INET sockaddr");
452 memcpy(&pktinfo.ipi_spec_dst, &sa.sin_addr, sizeof(pktinfo.ipi_spec_dst));
453
454 return ancdata_new(AF_INET, IPPROTO_IP, IP_PKTINFO, rb_str_new((char *)&pktinfo, sizeof(pktinfo)));
455 }
456 #else
457 #define ancillary_s_ip_pktinfo rb_f_notimplement
458 #endif
459
460 #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST) /* GNU/Linux */
461 /*
462 * call-seq:
463 * ancdata.ip_pktinfo => [addr, ifindex, spec_dst]
464 *
465 * Extracts addr, ifindex and spec_dst from IP_PKTINFO ancillary data.
466 *
467 * IP_PKTINFO is not standard.
468 *
469 * Supported platform: GNU/Linux
470 *
471 * addr = Addrinfo.ip("127.0.0.1")
472 * ifindex = 0
473 * spec_dest = Addrinfo.ip("127.0.0.1")
474 * ancdata = Socket::AncillaryData.ip_pktinfo(addr, ifindex, spec_dest)
475 * p ancdata.ip_pktinfo
476 * #=> [#<Addrinfo: 127.0.0.1>, 0, #<Addrinfo: 127.0.0.1>]
477 *
478 *
479 */
480 static VALUE
481 ancillary_ip_pktinfo(VALUE self)
482 {
483 int level, type;
484 VALUE data;
485 struct in_pktinfo pktinfo;
486 struct sockaddr_in sa;
487 VALUE v_spec_dst, v_addr;
488
489 level = ancillary_level(self);
490 type = ancillary_type(self);
491 data = ancillary_data(self);
492
493 if (level != IPPROTO_IP || type != IP_PKTINFO ||
494 RSTRING_LEN(data) != sizeof(struct in_pktinfo)) {
495 rb_raise(rb_eTypeError, "IP_PKTINFO ancillary data expected");
496 }
497
498 memcpy(&pktinfo, RSTRING_PTR(data), sizeof(struct in_pktinfo));
499 memset(&sa, 0, sizeof(sa));
500
501 sa.sin_family = AF_INET;
502 memcpy(&sa.sin_addr, &pktinfo.ipi_addr, sizeof(sa.sin_addr));
503 v_addr = rsock_addrinfo_new((struct sockaddr *)&sa, sizeof(sa), PF_INET, 0, 0, Qnil, Qnil);
504
505 sa.sin_family = AF_INET;
506 memcpy(&sa.sin_addr, &pktinfo.ipi_spec_dst, sizeof(sa.sin_addr));
507 v_spec_dst = rsock_addrinfo_new((struct sockaddr *)&sa, sizeof(sa), PF_INET, 0, 0, Qnil, Qnil);
508
509 return rb_ary_new3(3, v_addr, UINT2NUM(pktinfo.ipi_ifindex), v_spec_dst);
510 }
511 #else
512 #define ancillary_ip_pktinfo rb_f_notimplement
513 #endif
514
515 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */
516 /*
517 * call-seq:
518 * Socket::AncillaryData.ipv6_pktinfo(addr, ifindex) => ancdata
519 *
520 * Returns new ancillary data for IPV6_PKTINFO.
521 *
522 * IPV6_PKTINFO is defined by RFC 3542.
523 *
524 * addr = Addrinfo.ip("::1")
525 * ifindex = 0
526 * p Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
527 * #=> #<Socket::AncillaryData: INET6 IPV6 PKTINFO ::1 ifindex:0>
528 *
529 */
530 static VALUE
531 ancillary_s_ipv6_pktinfo(VALUE self, VALUE v_addr, VALUE v_ifindex)
532 {
533 unsigned int ifindex;
534 struct sockaddr_in6 sa;
535 struct in6_pktinfo pktinfo;
536
537 SockAddrStringValue(v_addr);
538 ifindex = NUM2UINT(v_ifindex);
539
540 memset(&pktinfo, 0, sizeof(pktinfo));
541
542 memset(&sa, 0, sizeof(sa));
543 if (RSTRING_LEN(v_addr) != sizeof(sa))
544 rb_raise(rb_eArgError, "addr size different to AF_INET6 sockaddr");
545 memcpy(&sa, RSTRING_PTR(v_addr), sizeof(sa));
546 if (sa.sin6_family != AF_INET6)
547 rb_raise(rb_eArgError, "addr is not AF_INET6 sockaddr");
548 memcpy(&pktinfo.ipi6_addr, &sa.sin6_addr, sizeof(pktinfo.ipi6_addr));
549
550 pktinfo.ipi6_ifindex = ifindex;
551
552 return ancdata_new(AF_INET6, IPPROTO_IPV6, IPV6_PKTINFO, rb_str_new((char *)&pktinfo, sizeof(pktinfo)));
553 }
554 #else
555 #define ancillary_s_ipv6_pktinfo rb_f_notimplement
556 #endif
557
558 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */
559 static void
560 extract_ipv6_pktinfo(VALUE self, struct in6_pktinfo *pktinfo_ptr, struct sockaddr_in6 *sa_ptr)
561 {
562 int level, type;
563 VALUE data;
564
565 level = ancillary_level(self);
566 type = ancillary_type(self);
567 data = ancillary_data(self);
568
569 if (level != IPPROTO_IPV6 || type != IPV6_PKTINFO ||
570 RSTRING_LEN(data) != sizeof(struct in6_pktinfo)) {
571 rb_raise(rb_eTypeError, "IPV6_PKTINFO ancillary data expected");
572 }
573
574 memcpy(pktinfo_ptr, RSTRING_PTR(data), sizeof(*pktinfo_ptr));
575
576 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 */
600 static VALUE
601 ancillary_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 */
630 static VALUE
631 ancillary_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 */
657 static VALUE
658 ancillary_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 */
670 static int
671 anc_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 */
690 static int
691 anc_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
709 static int
710 anc_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 */
775 static int
776 anc_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 */
796 static int
797 anc_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 */
825 static int
826 anc_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 */
853 static int
854 inspect_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 */
875 static int
876 inspect_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 */
895 static int
896 inspect_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 */
951 static VALUE
952 ancillary_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 */
1089 static VALUE
1090 ancillary_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)
1106 struct sendmsg_args_struct {
1107 int fd;
1108 const struct msghdr *msg;
1109 int flags;
1110 };
1111
1112 static void *
1113 nogvl_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
1119 static ssize_t
1120 rb_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
1129 static VALUE
1130 bsock_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 (!nonblock && rb_io_wait_writable(fptr->fd)) {
1284 rb_io_check_closed(fptr);
1285 goto retry;
1286 }
1287
1288 if (ss == -1) {
1289 if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
1290 rb_mod_sys_fail(rb_mWaitWritable, "sendmsg(2) would block");
1291 rb_sys_fail("sendmsg(2)");
1292 }
1293
1294 return SSIZET2NUM(ss);
1295 }
1296 #endif
1297
1298 #if defined(HAVE_SENDMSG)
1299 /*
1300 * call-seq:
1301 * basicsocket.sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
1302 *
1303 * sendmsg sends a message using sendmsg(2) system call in blocking manner.
1304 *
1305 * _mesg_ is a string to send.
1306 *
1307 * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_OOB.
1308 *
1309 * _dest_sockaddr_ is a destination socket address for connection-less socket.
1310 * It should be a sockaddr such as a result of Socket.sockaddr_in.
1311 * An Addrinfo object can be used too.
1312 *
1313 * _controls_ is a list of ancillary data.
1314 * The element of _controls_ should be Socket::AncillaryData or
1315 * 3-elements array.
1316 * The 3-element array should contains cmsg_level, cmsg_type and data.
1317 *
1318 * The return value, _numbytes_sent_ is an integer which is the number of bytes sent.
1319 *
1320 * sendmsg can be used to implement send_io as follows:
1321 *
1322 * # use Socket::AncillaryData.
1323 * ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, io.fileno)
1324 * sock.sendmsg("a", 0, nil, ancdata)
1325 *
1326 * # use 3-element array.
1327 * ancdata = [:SOCKET, :RIGHTS, [io.fileno].pack("i!")]
1328 * sock.sendmsg("\0", 0, nil, ancdata)
1329 *
1330 */
1331 VALUE
1332 rsock_bsock_sendmsg(int argc, VALUE *argv, VALUE sock)
1333 {
1334 return bsock_sendmsg_internal(argc, argv, sock, 0);
1335 }
1336 #endif
1337
1338 #if defined(HAVE_SENDMSG)
1339 /*
1340 * call-seq:
1341 * basicsocket.sendmsg_nonblock(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
1342 *
1343 * sendmsg_nonblock sends a message using sendmsg(2) system call in non-blocking manner.
1344 *
1345 * It is similar to BasicSocket#sendmsg
1346 * but the non-blocking flag is set before the system call
1347 * and it doesn't retry the system call.
1348 *
1349 */
1350 VALUE
1351 rsock_bsock_sendmsg_nonblock(int argc, VALUE *argv, VALUE sock)
1352 {
1353 return bsock_sendmsg_internal(argc, argv, sock, 1);
1354 }
1355 #endif
1356
1357 #if defined(HAVE_RECVMSG)
1358 struct recvmsg_args_struct {
1359 int fd;
1360 struct msghdr *msg;
1361 int flags;
1362 };
1363
1364 ssize_t
1365 rsock_recvmsg(int socket, struct msghdr *message, int flags)
1366 {
1367 #ifdef MSG_CMSG_CLOEXEC
1368 /* MSG_CMSG_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
1369 flags |= MSG_CMSG_CLOEXEC;
1370 #endif
1371 return recvmsg(socket, message, flags);
1372 }
1373
1374 static void *
1375 nogvl_recvmsg_func(void *ptr)
1376 {
1377 struct recvmsg_args_struct *args = ptr;
1378 int flags = args->flags;
1379 return (void *)rsock_recvmsg(args->fd, args->msg, flags);
1380 }
1381
1382 static ssize_t
1383 rb_recvmsg(int fd, struct msghdr *msg, int flags)
1384 {
1385 struct recvmsg_args_struct args;
1386 args.fd = fd;
1387 args.msg = msg;
1388 args.flags = flags;
1389 return (ssize_t)rb_thread_call_without_gvl(nogvl_recvmsg_func, &args, RUBY_UBF_IO, 0);
1390 }
1391
1392 #if defined(HAVE_ST_MSG_CONTROL)
1393 static void
1394 discard_cmsg(struct cmsghdr *cmh, char *msg_end, int msg_peek_p)
1395 {
1396 # if !defined(FD_PASSING_WORK_WITH_RECVMSG_MSG_PEEK)
1397 /*
1398 * FreeBSD 8.2.0, NetBSD 5 and MacOS X Snow Leopard doesn't
1399 * allocate fds by recvmsg with MSG_PEEK.
1400 * [ruby-dev:44189]
1401 * http://bugs.ruby-lang.org/issues/5075
1402 *
1403 * Linux 2.6.38 allocate fds by recvmsg with MSG_PEEK.
1404 */
1405 if (msg_peek_p)
1406 return;
1407 # endif
1408 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
1409 int *fdp = (int *)CMSG_DATA(cmh);
1410 int *end = (int *)((char *)cmh + cmh->cmsg_len);
1411 while ((char *)fdp + sizeof(int) <= (char *)end &&
1412 (char *)fdp + sizeof(int) <= msg_end) {
1413 rb_fd_fix_cloexec(*fdp);
1414 close(*fdp);
1415 fdp++;
1416 }
1417 }
1418 }
1419 #endif
1420
1421 void
1422 rsock_discard_cmsg_resource(struct msghdr *mh, int msg_peek_p)
1423 {
1424 #if defined(HAVE_ST_MSG_CONTROL)
1425 struct cmsghdr *cmh;
1426 char *msg_end;
1427
1428 if (mh->msg_controllen == 0)
1429 return;
1430
1431 msg_end = (char *)mh->msg_control + mh->msg_controllen;
1432
1433 for (cmh = CMSG_FIRSTHDR(mh); cmh != NULL; cmh = CMSG_NXTHDR(mh, cmh)) {
1434 discard_cmsg(cmh, msg_end, msg_peek_p);
1435 }
1436 #endif
1437 }
1438
1439 #if defined(HAVE_ST_MSG_CONTROL)
1440 static void
1441 make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end)
1442 {
1443 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
1444 int *fdp, *end;
1445 VALUE ary = rb_ary_new();
1446 rb_ivar_set(ctl, rb_intern("unix_rights"), ary);
1447 fdp = (int *)CMSG_DATA(cmh);
1448 end = (int *)((char *)cmh + cmh->cmsg_len);
1449 while ((char *)fdp + sizeof(int) <= (char *)end &&
1450 (char *)fdp + sizeof(int) <= msg_end) {
1451 int fd = *fdp;
1452 struct stat stbuf;
1453 VALUE io;
1454 if (fstat(fd, &stbuf) == -1)
1455 rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");
1456 rb_fd_fix_cloexec(fd);
1457 if (S_ISSOCK(stbuf.st_mode))
1458 io = rsock_init_sock(rb_obj_alloc(rb_cSocket), fd);
1459 else
1460 io = rb_io_fdopen(fd, O_RDWR, NULL);
1461 ary = rb_attr_get(ctl, rb_intern("unix_rights"));
1462 rb_ary_push(ary, io);
1463 fdp++;
1464 }
1465 OBJ_FREEZE(ary);
1466 }
1467 }
1468 #endif
1469
1470 static VALUE
1471 bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
1472 {
1473 rb_io_t *fptr;
1474 VALUE vmaxdatlen, vmaxctllen, vflags, vopts;
1475 int grow_buffer;
1476 size_t maxdatlen;
1477 int flags, orig_flags;
1478 int request_scm_rights;
1479 struct msghdr mh;
1480 struct iovec iov;
1481 struct sockaddr_storage namebuf;
1482 char datbuf0[4096], *datbuf;
1483 VALUE dat_str = Qnil;
1484 VALUE ret;
1485 ssize_t ss;
1486 #if defined(HAVE_ST_MSG_CONTROL)
1487 struct cmsghdr *cmh;
1488 size_t maxctllen;
1489 union {
1490 char bytes[4096];
1491 struct cmsghdr align;
1492 } ctlbuf0;
1493 char *ctlbuf;
1494 VALUE ctl_str = Qnil;
1495 int family;
1496 int gc_done = 0;
1497 #endif
1498
1499 rb_secure(4);
1500
1501 vopts = Qnil;
1502 if (0 < argc && RB_TYPE_P(argv[argc-1], T_HASH))
1503 vopts = argv[--argc];
1504
1505 rb_scan_args(argc, argv, "03", &vmaxdatlen, &vflags, &vmaxctllen);
1506
1507 maxdatlen = NIL_P(vmaxdatlen) ? sizeof(datbuf0) : NUM2SIZET(vmaxdatlen);
1508 #if defined(HAVE_ST_MSG_CONTROL)
1509 maxctllen = NIL_P(vmaxctllen) ? sizeof(ctlbuf0) : NUM2SIZET(vmaxctllen);
1510 #else
1511 if (!NIL_P(vmaxctllen))
1512 rb_raise(rb_eArgError, "control message not supported");
1513 #endif
1514 flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
1515 #ifdef MSG_DONTWAIT
1516 if (nonblock)
1517 flags |= MSG_DONTWAIT;
1518 #endif
1519 orig_flags = flags;
1520
1521 grow_buffer = NIL_P(vmaxdatlen) || NIL_P(vmaxctllen);
1522
1523 request_scm_rights = 0;
1524 if (!NIL_P(vopts) && RTEST(rb_hash_aref(vopts, ID2SYM(rb_intern("scm_rights")))))
1525 request_scm_rights = 1;
1526
1527 GetOpenFile(sock, fptr);
1528 if (rb_io_read_pending(fptr)) {
1529 rb_raise(rb_eIOError, "recvmsg for buffered IO");
1530 }
1531
1532 #if !defined(HAVE_ST_MSG_CONTROL)
1533 if (grow_buffer) {
1534 int socktype;
1535 socklen_t optlen = (socklen_t)sizeof(socktype);
1536 if (getsockopt(fptr->fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen) == -1) {
1537 rb_sys_fail("getsockopt(SO_TYPE)");
1538 }
1539 if (socktype == SOCK_STREAM)
1540 grow_buffer = 0;
1541 }
1542 #endif
1543
1544 retry:
1545 if (maxdatlen <= sizeof(datbuf0))
1546 datbuf = datbuf0;
1547 else {
1548 if (NIL_P(dat_str))
1549 dat_str = rb_str_tmp_new(maxdatlen);
1550 else
1551 rb_str_resize(dat_str, maxdatlen);
1552 datbuf = RSTRING_PTR(dat_str);
1553 }
1554
1555 #if defined(HAVE_ST_MSG_CONTROL)
1556 if (maxctllen <= sizeof(ctlbuf0))
1557 ctlbuf = ctlbuf0.bytes;
1558 else {
1559 if (NIL_P(ctl_str))
1560 ctl_str = rb_str_tmp_new(maxctllen);
1561 else
1562 rb_str_resize(ctl_str, maxctllen);
1563 ctlbuf = RSTRING_PTR(ctl_str);
1564 }
1565 #endif
1566
1567 memset(&mh, 0, sizeof(mh));
1568
1569 memset(&namebuf, 0, sizeof(namebuf));
1570 mh.msg_name = (struct sockaddr *)&namebuf;
1571 mh.msg_namelen = (socklen_t)sizeof(namebuf);
1572
1573 mh.msg_iov = &iov;
1574 mh.msg_iovlen = 1;
1575 iov.iov_base = datbuf;
1576 iov.iov_len = maxdatlen;
1577
1578 #if defined(HAVE_ST_MSG_CONTROL)
1579 mh.msg_control = ctlbuf;
1580 mh.msg_controllen = (socklen_t)maxctllen;
1581 #endif
1582
1583 if (grow_buffer)
1584 flags |= MSG_PEEK;
1585
1586 rb_io_check_closed(fptr);
1587 if (nonblock)
1588 rb_io_set_nonblock(fptr);
1589
1590 ss = rb_recvmsg(fptr->fd, &mh, flags);
1591
1592 if (!nonblock && rb_io_wait_readable(fptr->fd)) {
1593 rb_io_check_closed(fptr);
1594 goto retry;
1595 }
1596
1597 if (ss == -1) {
1598 if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
1599 rb_mod_sys_fail(rb_mWaitReadable, "recvmsg(2) would block");
1600 #if defined(HAVE_ST_MSG_CONTROL)
1601 if (!gc_done && (errno == EMFILE || errno == EMSGSIZE)) {
1602 /*
1603 * When SCM_RIGHTS hit the file descriptors limit:
1604 * - Linux 2.6.18 causes success with MSG_CTRUNC
1605 * - MacOS X 10.4 causes EMSGSIZE (and lost file descriptors?)
1606 * - Solaris 11 causes EMFILE
1607 */
1608 gc_and_retry:
1609 rb_gc();
1610 gc_done = 1;
1611 goto retry;
1612 }
1613 #endif
1614 rb_sys_fail("recvmsg(2)");
1615 }
1616
1617 if (grow_buffer) {
1618 int grown = 0;
1619 #if defined(HAVE_ST_MSG_CONTROL)
1620 if (NIL_P(vmaxdatlen) && (mh.msg_flags & MSG_TRUNC)) {
1621 if (SIZE_MAX/2 < maxdatlen)
1622 rb_raise(rb_eArgError, "max data length too big");
1623 maxdatlen *= 2;
1624 grown = 1;
1625 }
1626 if (NIL_P(vmaxctllen) && (mh.msg_flags & MSG_CTRUNC)) {
1627 #define BIG_ENOUGH_SPACE 65536
1628 if (BIG_ENOUGH_SPACE < maxctllen &&
1629 mh.msg_controllen < (socklen_t)(maxctllen - BIG_ENOUGH_SPACE)) {
1630 /* there are big space bug truncated.
1631 * file descriptors limit? */
1632 if (!gc_done) {
1633 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
1634 goto gc_and_retry;
1635 }
1636 }
1637 else {
1638 if (SIZE_MAX/2 < maxctllen)
1639 rb_raise(rb_eArgError, "max control message length too big");
1640 maxctllen *= 2;
1641 grown = 1;
1642 }
1643 #undef BIG_ENOUGH_SPACE
1644 }
1645 #else
1646 if (NIL_P(vmaxdatlen) && ss != -1 && ss == (ssize_t)iov.iov_len) {
1647 if (SIZE_MAX/2 < maxdatlen)
1648 rb_raise(rb_eArgError, "max data length too big");
1649 maxdatlen *= 2;
1650 grown = 1;
1651 }
1652 #endif
1653 if (grown) {
1654 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
1655 goto retry;
1656 }
1657 else {
1658 grow_buffer = 0;
1659 if (flags != orig_flags) {
1660 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
1661 flags = orig_flags;
1662 goto retry;
1663 }
1664 }
1665 }
1666
1667 if (NIL_P(dat_str))
1668 dat_str = rb_tainted_str_new(datbuf, ss);
1669 else {
1670 rb_str_resize(dat_str, ss);
1671 OBJ_TAINT(dat_str);
1672 RBASIC(dat_str)->klass = rb_cString;
1673 }
1674
1675 ret = rb_ary_new3(3, dat_str,
1676 rsock_io_socket_addrinfo(sock, mh.msg_name, mh.msg_namelen),
1677 #if defined(HAVE_ST_MSG_CONTROL)
1678 INT2NUM(mh.msg_flags)
1679 #else
1680 Qnil
1681 #endif
1682 );
1683
1684 #if defined(HAVE_ST_MSG_CONTROL)
1685 family = rsock_getfamily(fptr->fd);
1686 if (mh.msg_controllen) {
1687 char *msg_end = (char *)mh.msg_control + mh.msg_controllen;
1688 for (cmh = CMSG_FIRSTHDR(&mh); cmh != NULL; cmh = CMSG_NXTHDR(&mh, cmh)) {
1689 VALUE ctl;
1690 char *ctl_end;
1691 size_t clen;
1692 if (cmh->cmsg_len == 0) {
1693 rb_raise(rb_eTypeError, "invalid control message (cmsg_len == 0)");
1694 }
1695 ctl_end = (char*)cmh + cmh->cmsg_len;
1696 clen = (ctl_end <= msg_end ? ctl_end : msg_end) - (char*)CMSG_DATA(cmh);
1697 ctl = ancdata_new(family, cmh->cmsg_level, cmh->cmsg_type, rb_tainted_str_new((char*)CMSG_DATA(cmh), clen));
1698 if (request_scm_rights)
1699 make_io_for_unix_rights(ctl, cmh, msg_end);
1700 else
1701 discard_cmsg(cmh, msg_end, (flags & MSG_PEEK) != 0);
1702 rb_ary_push(ret, ctl);
1703 }
1704 }
1705 #endif
1706
1707 return ret;
1708 }
1709 #endif
1710
1711 #if defined(HAVE_RECVMSG)
1712 /*
1713 * call-seq:
1714 * basicsocket.recvmsg(maxmesglen=nil, flags=0, maxcontrollen=nil, opts={}) => [mesg, sender_addrinfo, rflags, *controls]
1715 *
1716 * recvmsg receives a message using recvmsg(2) system call in blocking manner.
1717 *
1718 * _maxmesglen_ is the maximum length of mesg to receive.
1719 *
1720 * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_PEEK.
1721 *
1722 * _maxcontrollen_ is the maximum length of controls (ancillary data) to receive.
1723 *
1724 * _opts_ is option hash.
1725 * Currently :scm_rights=>bool is the only option.
1726 *
1727 * :scm_rights option specifies that application expects SCM_RIGHTS control message.
1728 * If the value is nil or false, application don't expects SCM_RIGHTS control message.
1729 * In this case, recvmsg closes the passed file descriptors immediately.
1730 * This is the default behavior.
1731 *
1732 * If :scm_rights value is neither nil nor false, application expects SCM_RIGHTS control message.
1733 * In this case, recvmsg creates IO objects for each file descriptors for
1734 * Socket::AncillaryData#unix_rights method.
1735 *
1736 * The return value is 4-elements array.
1737 *
1738 * _mesg_ is a string of the received message.
1739 *
1740 * _sender_addrinfo_ is a sender socket address for connection-less socket.
1741 * It is an Addrinfo object.
1742 * For connection-oriented socket such as TCP, sender_addrinfo is platform dependent.
1743 *
1744 * _rflags_ is a flags on the received message which is bitwise OR of MSG_* constants such as Socket::MSG_TRUNC.
1745 * It will be nil if the system uses 4.3BSD style old recvmsg system call.
1746 *
1747 * _controls_ is ancillary data which is an array of Socket::AncillaryData objects such as:
1748 *
1749 * #<Socket::AncillaryData: AF_UNIX SOCKET RIGHTS 7>
1750 *
1751 * _maxmesglen_ and _maxcontrollen_ can be nil.
1752 * In that case, the buffer will be grown until the message is not truncated.
1753 * Internally, MSG_PEEK is used and MSG_TRUNC/MSG_CTRUNC are checked.
1754 *
1755 * recvmsg can be used to implement recv_io as follows:
1756 *
1757 * mesg, sender_sockaddr, rflags, *controls = sock.recvmsg(:scm_rights=>true)
1758 * controls.each {|ancdata|
1759 * if ancdata.cmsg_is?(:SOCKET, :RIGHTS)
1760 * return ancdata.unix_rights[0]
1761 * end
1762 * }
1763 *
1764 */
1765 VALUE
1766 rsock_bsock_recvmsg(int argc, VALUE *argv, VALUE sock)
1767 {
1768 return bsock_recvmsg_internal(argc, argv, sock, 0);
1769 }
1770 #endif
1771
1772 #if defined(HAVE_RECVMSG)
1773 /*
1774 * call-seq:
1775 * basicsocket.recvmsg_nonblock(maxdatalen=nil, flags=0, maxcontrollen=nil, opts={}) => [data, sender_addrinfo, rflags, *controls]
1776 *
1777 * recvmsg receives a message using recvmsg(2) system call in non-blocking manner.
1778 *
1779 * It is similar to BasicSocket#recvmsg
1780 * but non-blocking flag is set before the system call
1781 * and it doesn't retry the system call.
1782 *
1783 */
1784 VALUE
1785 rsock_bsock_recvmsg_nonblock(int argc, VALUE *argv, VALUE sock)
1786 {
1787 return bsock_recvmsg_internal(argc, argv, sock, 1);
1788 }
1789 #endif
1790
1791 void
1792 rsock_init_ancdata(void)
1793 {
1794 #if defined(HAVE_ST_MSG_CONTROL)
1795 /*
1796 * Document-class: Socket::AncillaryData
1797 *
1798 * Socket::AncillaryData represents the ancillary data (control information)
1799 * used by sendmsg and recvmsg system call. It contains socket #family,
1800 * control message (cmsg) #level, cmsg #type and cmsg #data.
1801 */
1802 rb_cAncillaryData = rb_define_class_under(rb_cSocket, "AncillaryData", rb_cObject);
1803 rb_define_method(rb_cAncillaryData, "initialize", ancillary_initialize, 4);
1804 rb_define_method(rb_cAncillaryData, "inspect", ancillary_inspect, 0);
1805 rb_define_method(rb_cAncillaryData, "family", ancillary_family_m, 0);
1806 rb_define_method(rb_cAncillaryData, "level", ancillary_level_m, 0);
1807 rb_define_method(rb_cAncillaryData, "type", ancillary_type_m, 0);
1808 rb_define_method(rb_cAncillaryData, "data", ancillary_data, 0);
1809
1810 rb_define_method(rb_cAncillaryData, "cmsg_is?", ancillary_cmsg_is_p, 2);
1811
1812 rb_define_singleton_method(rb_cAncillaryData, "int", ancillary_s_int, 4);
1813 rb_define_method(rb_cAncillaryData, "int", ancillary_int, 0);
1814
1815 rb_define_singleton_method(rb_cAncillaryData, "unix_rights", ancillary_s_unix_rights, -1);
1816 rb_define_method(rb_cAncillaryData, "unix_rights", ancillary_unix_rights, 0);
1817
1818 rb_define_method(rb_cAncillaryData, "timestamp", ancillary_timestamp, 0);
1819
1820 rb_define_singleton_method(rb_cAncillaryData, "ip_pktinfo", ancillary_s_ip_pktinfo, -1);
1821 rb_define_method(rb_cAncillaryData, "ip_pktinfo", ancillary_ip_pktinfo, 0);
1822
1823 rb_define_singleton_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_s_ipv6_pktinfo, 2);
1824 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_ipv6_pktinfo, 0);
1825 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_addr", ancillary_ipv6_pktinfo_addr, 0);
1826 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_ifindex", ancillary_ipv6_pktinfo_ifindex, 0);
1827 #endif
1828 }
1829