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