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