Ruby 2.7.0p0(2019-12-25revision647ee6f091eafcce70ffb75ddf7e121e192ab217)

option.c
Go to the documentation of this file.
1 #include "rubysocket.h"
2
3 VALUE rb_cSockOpt;
4
5 #define pack_var(v) rb_str_new((const char *)&(v), sizeof(v))
6
7 #define CAT(x,y) x##y
8 #define XCAT(x,y) CAT(x,y)
9
10 #if defined(__linux__) || \
11 defined(__GNU__) /* GNU/Hurd */ || \
12 defined(__FreeBSD__) || \
13 defined(__DragonFly__) || \
14 defined(__APPLE__) || \
15 defined(_WIN32) || \
16 defined(__CYGWIN__)
17 # define TYPE_IP_MULTICAST_LOOP int
18 # define TYPE_IP_MULTICAST_TTL int
19 #else
20 /* The original IP multicast implementation by Steve Deering
21 * NetBSD
22 * OpenBSD
23 * SunOS
24 */
25 # define TYPE_IP_MULTICAST_LOOP byte
26 # define TYPE_IP_MULTICAST_TTL byte
27 # define USE_INSPECT_BYTE 1
28 #endif
29
30 #define check_size(len, size) \
31 ((len) == (size) ? \
32 (void)0 : \
33 rb_raise(rb_eTypeError, "size differ. expected as "#size"=%d but %ld", \
34 (int)size, (long)(len)))
35
36 static VALUE
37 sockopt_pack_byte(VALUE value)
38 {
39 char i = NUM2CHR(rb_to_int(value));
40 return pack_var(i);
41 }
42
43 static VALUE
44 sockopt_pack_int(VALUE value)
45 {
46 int i = NUM2INT(rb_to_int(value));
47 return pack_var(i);
48 }
49
50 static VALUE
51 constant_to_sym(int constant, ID (*intern_const)(int))
52 {
53 ID name = intern_const(constant);
54 if (name) {
55 return ID2SYM(name);
56 }
57
58 return INT2NUM(constant);
59 }
60
61 static VALUE
62 optname_to_sym(int level, int optname)
63 {
64 switch (level) {
65 case SOL_SOCKET:
66 return constant_to_sym(optname, rsock_intern_so_optname);
67 case IPPROTO_IP:
68 return constant_to_sym(optname, rsock_intern_ip_optname);
69 #ifdef IPPROTO_IPV6
70 case IPPROTO_IPV6:
71 return constant_to_sym(optname, rsock_intern_ipv6_optname);
72 #endif
73 case IPPROTO_TCP:
74 return constant_to_sym(optname, rsock_intern_tcp_optname);
75 case IPPROTO_UDP:
76 return constant_to_sym(optname, rsock_intern_udp_optname);
77 default:
78 return INT2NUM(optname);
79 }
80 }
81
82 /*
83 * call-seq:
84 * Socket::Option.new(family, level, optname, data) => sockopt
85 *
86 * Returns a new Socket::Option object.
87 *
88 * sockopt = Socket::Option.new(:INET, :SOCKET, :KEEPALIVE, [1].pack("i"))
89 * p sockopt #=> #<Socket::Option: INET SOCKET KEEPALIVE 1>
90 *
91 */
92 static VALUE
93 sockopt_initialize(VALUE self, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE data)
94 {
95 int family = rsock_family_arg(vfamily);
96 int level = rsock_level_arg(family, vlevel);
97 int optname = rsock_optname_arg(family, level, voptname);
98 StringValue(data);
99 rb_ivar_set(self, rb_intern("family"), INT2NUM(family));
100 rb_ivar_set(self, rb_intern("level"), INT2NUM(level));
101 rb_ivar_set(self, rb_intern("optname"), INT2NUM(optname));
102 rb_ivar_set(self, rb_intern("data"), data);
103 return self;
104 }
105
106 VALUE
107 rsock_sockopt_new(int family, int level, int optname, VALUE data)
108 {
109 NEWOBJ_OF(obj, struct RObject, rb_cSockOpt, T_OBJECT);
110 StringValue(data);
111 sockopt_initialize((VALUE)obj, INT2NUM(family), INT2NUM(level), INT2NUM(optname), data);
112 return (VALUE)obj;
113 }
114
115 /*
116 * call-seq:
117 * sockopt.family => integer
118 *
119 * returns the socket family as an integer.
120 *
121 * p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).family
122 * #=> 10
123 */
124 static VALUE
125 sockopt_family_m(VALUE self)
126 {
127 return rb_attr_get(self, rb_intern("family"));
128 }
129
130 static int
131 sockopt_level(VALUE self)
132 {
133 return NUM2INT(rb_attr_get(self, rb_intern("level")));
134 }
135
136 /*
137 * call-seq:
138 * sockopt.level => integer
139 *
140 * returns the socket level as an integer.
141 *
142 * p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).level
143 * #=> 41
144 */
145 static VALUE
146 sockopt_level_m(VALUE self)
147 {
148 return INT2NUM(sockopt_level(self));
149 }
150
151 static int
152 sockopt_optname(VALUE self)
153 {
154 return NUM2INT(rb_attr_get(self, rb_intern("optname")));
155 }
156
157 /*
158 * call-seq:
159 * sockopt.optname => integer
160 *
161 * returns the socket option name as an integer.
162 *
163 * p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).optname
164 * #=> 2
165 */
166 static VALUE
167 sockopt_optname_m(VALUE self)
168 {
169 return INT2NUM(sockopt_optname(self));
170 }
171
172 /*
173 * call-seq:
174 * sockopt.data => string
175 * sockopt.to_s => string
176 *
177 * returns the socket option data as a string.
178 *
179 * p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).data
180 * #=> "\x01\x00\x00\x00"
181 */
182 static VALUE
183 sockopt_data(VALUE self)
184 {
185 VALUE v = rb_attr_get(self, rb_intern("data"));
186 StringValue(v);
187 return v;
188 }
189
190 /*
191 * call-seq:
192 * Socket::Option.byte(family, level, optname, integer) => sockopt
193 *
194 * Creates a new Socket::Option object which contains a byte as data.
195 *
196 * p Socket::Option.byte(:INET, :SOCKET, :KEEPALIVE, 1)
197 * #=> #<Socket::Option: INET SOCKET KEEPALIVE 1>
198 */
199 static VALUE
200 sockopt_s_byte(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE vint)
201 {
202 int family = rsock_family_arg(vfamily);
203 int level = rsock_level_arg(family, vlevel);
204 int optname = rsock_optname_arg(family, level, voptname);
205 return rsock_sockopt_new(family, level, optname, sockopt_pack_byte(vint));
206 }
207
208 /*
209 * call-seq:
210 * sockopt.byte => integer
211 *
212 * Returns the data in _sockopt_ as an byte.
213 *
214 * sockopt = Socket::Option.byte(:INET, :SOCKET, :KEEPALIVE, 1)
215 * p sockopt.byte => 1
216 */
217 static VALUE
218 sockopt_byte(VALUE self)
219 {
220 VALUE data = sockopt_data(self);
221 StringValue(data);
222 check_size(RSTRING_LEN(data), sizeof(char));
223 return CHR2FIX(*RSTRING_PTR(data));
224 }
225
226 /*
227 * call-seq:
228 * Socket::Option.int(family, level, optname, integer) => sockopt
229 *
230 * Creates a new Socket::Option object which contains an int as data.
231 *
232 * The size and endian is dependent on the platform.
233 *
234 * p Socket::Option.int(:INET, :SOCKET, :KEEPALIVE, 1)
235 * #=> #<Socket::Option: INET SOCKET KEEPALIVE 1>
236 */
237 static VALUE
238 sockopt_s_int(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE vint)
239 {
240 int family = rsock_family_arg(vfamily);
241 int level = rsock_level_arg(family, vlevel);
242 int optname = rsock_optname_arg(family, level, voptname);
243 return rsock_sockopt_new(family, level, optname, sockopt_pack_int(vint));
244 }
245
246 /*
247 * call-seq:
248 * sockopt.int => integer
249 *
250 * Returns the data in _sockopt_ as an int.
251 *
252 * The size and endian is dependent on the platform.
253 *
254 * sockopt = Socket::Option.int(:INET, :SOCKET, :KEEPALIVE, 1)
255 * p sockopt.int => 1
256 */
257 static VALUE
258 sockopt_int(VALUE self)
259 {
260 int i;
261 VALUE data = sockopt_data(self);
262 StringValue(data);
263 check_size(RSTRING_LEN(data), sizeof(int));
264 memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
265 return INT2NUM(i);
266 }
267
268 /*
269 * call-seq:
270 * Socket::Option.bool(family, level, optname, bool) => sockopt
271 *
272 * Creates a new Socket::Option object which contains boolean as data.
273 * Actually 0 or 1 as int is used.
274 *
275 * require 'socket'
276 *
277 * p Socket::Option.bool(:INET, :SOCKET, :KEEPALIVE, true)
278 * #=> #<Socket::Option: INET SOCKET KEEPALIVE 1>
279 *
280 * p Socket::Option.bool(:INET, :SOCKET, :KEEPALIVE, false)
281 * #=> #<Socket::Option: AF_INET SOCKET KEEPALIVE 0>
282 *
283 */
284 static VALUE
285 sockopt_s_bool(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE vbool)
286 {
287 int family = rsock_family_arg(vfamily);
288 int level = rsock_level_arg(family, vlevel);
289 int optname = rsock_optname_arg(family, level, voptname);
290 int i = RTEST(vbool) ? 1 : 0;
291 return rsock_sockopt_new(family, level, optname, pack_var(i));
292 }
293
294 /*
295 * call-seq:
296 * sockopt.bool => true or false
297 *
298 * Returns the data in _sockopt_ as an boolean value.
299 *
300 * sockopt = Socket::Option.int(:INET, :SOCKET, :KEEPALIVE, 1)
301 * p sockopt.bool => true
302 */
303 static VALUE
304 sockopt_bool(VALUE self)
305 {
306 int i;
307 long len;
308 VALUE data = sockopt_data(self);
309 StringValue(data);
310 len = RSTRING_LEN(data);
311 if (len == 1) {
312 return *RSTRING_PTR(data) == 0 ? Qfalse : Qtrue;
313 }
314 check_size(len, sizeof(int));
315 memcpy((char*)&i, RSTRING_PTR(data), len);
316 return i == 0 ? Qfalse : Qtrue;
317 }
318
319 /*
320 * call-seq:
321 * Socket::Option.linger(onoff, secs) => sockopt
322 *
323 * Creates a new Socket::Option object for SOL_SOCKET/SO_LINGER.
324 *
325 * _onoff_ should be an integer or a boolean.
326 *
327 * _secs_ should be the number of seconds.
328 *
329 * p Socket::Option.linger(true, 10)
330 * #=> #<Socket::Option: UNSPEC SOCKET LINGER on 10sec>
331 *
332 */
333 static VALUE
334 sockopt_s_linger(VALUE klass, VALUE vonoff, VALUE vsecs)
335 {
336 VALUE tmp;
337 struct linger l;
338 memset(&l, 0, sizeof(l));
339 if (!NIL_P(tmp = rb_check_to_integer(vonoff, "to_int")))
340 l.l_onoff = NUM2INT(tmp);
341 else
342 l.l_onoff = RTEST(vonoff) ? 1 : 0;
343 l.l_linger = NUM2INT(vsecs);
344 return rsock_sockopt_new(AF_UNSPEC, SOL_SOCKET, SO_LINGER, pack_var(l));
345 }
346
347 /*
348 * call-seq:
349 * sockopt.linger => [bool, seconds]
350 *
351 * Returns the linger data in _sockopt_ as a pair of boolean and integer.
352 *
353 * sockopt = Socket::Option.linger(true, 10)
354 * p sockopt.linger => [true, 10]
355 */
356 static VALUE
357 sockopt_linger(VALUE self)
358 {
359 int level = sockopt_level(self);
360 int optname = sockopt_optname(self);
361 VALUE data = sockopt_data(self);
362 struct linger l;
363 VALUE vonoff, vsecs;
364
365 if (level != SOL_SOCKET || optname != SO_LINGER)
366 rb_raise(rb_eTypeError, "linger socket option expected");
367 check_size(RSTRING_LEN(data), sizeof(struct linger));
368 memcpy((char*)&l, RSTRING_PTR(data), sizeof(struct linger));
369 switch (l.l_onoff) {
370 case 0: vonoff = Qfalse; break;
371 case 1: vonoff = Qtrue; break;
372 default: vonoff = INT2NUM(l.l_onoff); break;
373 }
374 vsecs = INT2NUM(l.l_linger);
375 return rb_assoc_new(vonoff, vsecs);
376 }
377
378 /*
379 * call-seq:
380 * Socket::Option.ipv4_multicast_loop(integer) => sockopt
381 *
382 * Creates a new Socket::Option object for IP_MULTICAST_LOOP.
383 *
384 * The size is dependent on the platform.
385 *
386 * sockopt = Socket::Option.int(:INET, :IPPROTO_IP, :IP_MULTICAST_LOOP, 1)
387 * p sockopt.int => 1
388 *
389 * p Socket::Option.ipv4_multicast_loop(10)
390 * #=> #<Socket::Option: INET IP MULTICAST_LOOP 10>
391 *
392 */
393 static VALUE
394 sockopt_s_ipv4_multicast_loop(VALUE klass, VALUE value)
395 {
396
397 #if defined(IPPROTO_IP) && defined(IP_MULTICAST_LOOP)
398 VALUE o = XCAT(sockopt_pack_,TYPE_IP_MULTICAST_LOOP)(value);
399 return rsock_sockopt_new(AF_INET, IPPROTO_IP, IP_MULTICAST_LOOP, o);
400 #else
401 # error IPPROTO_IP or IP_MULTICAST_LOOP is not implemented
402 #endif
403 }
404
405 /*
406 * call-seq:
407 * sockopt.ipv4_multicast_loop => integer
408 *
409 * Returns the ipv4_multicast_loop data in _sockopt_ as an integer.
410 *
411 * sockopt = Socket::Option.ipv4_multicast_loop(10)
412 * p sockopt.ipv4_multicast_loop => 10
413 */
414 static VALUE
415 sockopt_ipv4_multicast_loop(VALUE self)
416 {
417 int family = NUM2INT(sockopt_family_m(self));
418 int level = sockopt_level(self);
419 int optname = sockopt_optname(self);
420
421 #if defined(IPPROTO_IP) && defined(IP_MULTICAST_LOOP)
422 if (family == AF_INET && level == IPPROTO_IP && optname == IP_MULTICAST_LOOP) {
423 return XCAT(sockopt_,TYPE_IP_MULTICAST_LOOP)(self);
424 }
425 #endif
426 rb_raise(rb_eTypeError, "ipv4_multicast_loop socket option expected");
427 UNREACHABLE_RETURN(Qnil);
428 }
429
430 #define inspect_ipv4_multicast_loop(a,b,c,d) \
431 XCAT(inspect_,TYPE_IP_MULTICAST_LOOP)(a,b,c,d)
432
433 /*
434 * call-seq:
435 * Socket::Option.ipv4_multicast_ttl(integer) => sockopt
436 *
437 * Creates a new Socket::Option object for IP_MULTICAST_TTL.
438 *
439 * The size is dependent on the platform.
440 *
441 * p Socket::Option.ipv4_multicast_ttl(10)
442 * #=> #<Socket::Option: INET IP MULTICAST_TTL 10>
443 *
444 */
445 static VALUE
446 sockopt_s_ipv4_multicast_ttl(VALUE klass, VALUE value)
447 {
448 #if defined(IPPROTO_IP) && defined(IP_MULTICAST_TTL)
449 VALUE o = XCAT(sockopt_pack_,TYPE_IP_MULTICAST_TTL)(value);
450 return rsock_sockopt_new(AF_INET, IPPROTO_IP, IP_MULTICAST_TTL, o);
451 #else
452 # error IPPROTO_IP or IP_MULTICAST_TTL is not implemented
453 #endif
454 }
455
456 /*
457 * call-seq:
458 * sockopt.ipv4_multicast_ttl => integer
459 *
460 * Returns the ipv4_multicast_ttl data in _sockopt_ as an integer.
461 *
462 * sockopt = Socket::Option.ipv4_multicast_ttl(10)
463 * p sockopt.ipv4_multicast_ttl => 10
464 */
465 static VALUE
466 sockopt_ipv4_multicast_ttl(VALUE self)
467 {
468 int family = NUM2INT(sockopt_family_m(self));
469 int level = sockopt_level(self);
470 int optname = sockopt_optname(self);
471
472 #if defined(IPPROTO_IP) && defined(IP_MULTICAST_TTL)
473 if (family == AF_INET && level == IPPROTO_IP && optname == IP_MULTICAST_TTL) {
474 return XCAT(sockopt_,TYPE_IP_MULTICAST_TTL)(self);
475 }
476 #endif
477 rb_raise(rb_eTypeError, "ipv4_multicast_ttl socket option expected");
478 UNREACHABLE_RETURN(Qnil);
479 }
480
481 #define inspect_ipv4_multicast_ttl(a,b,c,d) \
482 XCAT(inspect_,TYPE_IP_MULTICAST_TTL)(a,b,c,d)
483
484 static int
485 inspect_int(int level, int optname, VALUE data, VALUE ret)
486 {
487 if (RSTRING_LEN(data) == sizeof(int)) {
488 int i;
489 memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
490 rb_str_catf(ret, " %d", i);
491 return 1;
492 }
493 else {
494 return 0;
495 }
496 }
497
498 #ifdef USE_INSPECT_BYTE
499 static int
500 inspect_byte(int level, int optname, VALUE data, VALUE ret)
501 {
502 if (RSTRING_LEN(data) == sizeof(unsigned char)) {
503 rb_str_catf(ret, " %d", (unsigned char)*RSTRING_PTR(data));
504 return 1;
505 }
506 else {
507 return 0;
508 }
509 }
510 #endif
511
512 static int
513 inspect_errno(int level, int optname, VALUE data, VALUE ret)
514 {
515 if (RSTRING_LEN(data) == sizeof(int)) {
516 int i;
517 char *err;
518 memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
519 err = strerror(i);
520 rb_str_catf(ret, " %s (%d)", err, i);
521 return 1;
522 }
523 else {
524 return 0;
525 }
526 }
527
528 #if defined(IPV6_MULTICAST_LOOP)
529 static int
530 inspect_uint(int level, int optname, VALUE data, VALUE ret)
531 {
532 if (RSTRING_LEN(data) == sizeof(int)) {
533 unsigned int i;
534 memcpy((char*)&i, RSTRING_PTR(data), sizeof(unsigned int));
535 rb_str_catf(ret, " %u", i);
536 return 1;
537 }
538 else {
539 return 0;
540 }
541 }
542 #endif
543
544 #if defined(SOL_SOCKET) && defined(SO_LINGER) /* POSIX */
545 static int
546 inspect_linger(int level, int optname, VALUE data, VALUE ret)
547 {
548 if (RSTRING_LEN(data) == sizeof(struct linger)) {
549 struct linger s;
550 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
551 switch (s.l_onoff) {
552 case 0: rb_str_cat2(ret, " off"); break;
553 case 1: rb_str_cat2(ret, " on"); break;
554 default: rb_str_catf(ret, " on(%d)", s.l_onoff); break;
555 }
556 rb_str_catf(ret, " %dsec", s.l_linger);
557 return 1;
558 }
559 else {
560 return 0;
561 }
562 }
563 #endif
564
565 #if defined(SOL_SOCKET) && defined(SO_TYPE) /* POSIX */
566 static int
567 inspect_socktype(int level, int optname, VALUE data, VALUE ret)
568 {
569 if (RSTRING_LEN(data) == sizeof(int)) {
570 int i;
571 ID id;
572 memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
573 id = rsock_intern_socktype(i);
574 if (id)
575 rb_str_catf(ret, " %s", rb_id2name(id));
576 else
577 rb_str_catf(ret, " %d", i);
578 return 1;
579 }
580 else {
581 return 0;
582 }
583 }
584 #endif
585
586 static int
587 inspect_timeval_as_interval(int level, int optname, VALUE data, VALUE ret)
588 {
589 if (RSTRING_LEN(data) == sizeof(struct timeval)) {
590 struct timeval s;
591 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
592 rb_str_catf(ret, " %ld.%06ldsec", (long)s.tv_sec, (long)s.tv_usec);
593 return 1;
594 }
595 else {
596 return 0;
597 }
598 }
599
600 /*
601 * socket option for IPv4 multicast is bit confusing.
602 *
603 * IP Multicast is implemented by Steve Deering at first:
604 * IP Multicast Extensions for 4.3BSD UNIX and related systems
605 * (MULTICAST 1.2 Release)
606 * http://www.kohala.com/start/mcast.api.txt
607 *
608 * There are 2 socket options which takes a u_char (unsigned char).
609 *
610 * IP_MULTICAST_TTL
611 * IP_MULTICAST_LOOP
612 *
613 * However Linux and FreeBSD setsockname accepts int argument
614 * as well as u_char.
615 * Their getsockname returns int.
616 *
617 * There are 3 socket options which takes a struct.
618 *
619 * IP_MULTICAST_IF: struct in_addr
620 * IP_ADD_MEMBERSHIP: struct ip_mreq
621 * IP_DROP_MEMBERSHIP: struct ip_mreq
622 *
623 * But they uses an IP address to specify an interface.
624 * This means the API cannot specify an unnumbered interface.
625 *
626 * Linux 2.4 introduces struct ip_mreqn to fix this problem.
627 * struct ip_mreqn has imr_ifindex field to specify interface index.
628 *
629 * IP_MULTICAST_IF: struct ip_mreqn
630 * IP_ADD_MEMBERSHIP: struct ip_mreqn
631 * IP_DROP_MEMBERSHIP: struct ip_mreqn
632 *
633 * FreeBSD 7 obtained struct ip_mreqn for IP_MULTICAST_IF.
634 * http://www.FreeBSD.org/cgi/cvsweb.cgi/src/sys/netinet/in.h.diff?r1=1.99;r2=1.100
635 *
636 * Another hackish workaround is "RFC 1724 hack".
637 * RFC 1724 section 3.3 suggests unnumbered interfaces
638 * specified by pseudo address 0.0.0.0/8.
639 * NetBSD 4 and FreeBSD 5 documented it.
640 * http://cvsweb.netbsd.org/cgi-bin/cvsweb.cgi/src/share/man/man4/ip.4.diff?r1=1.16&r2=1.17
641 * http://www.FreeBSD.org/cgi/cvsweb.cgi/src/share/man/man4/ip.4.diff?r1=1.37;r2=1.38
642 * FreeBSD 7.0 removed it.
643 * http://www.FreeBSD.org/cgi/cvsweb.cgi/src/share/man/man4/ip.4.diff?r1=1.49;r2=1.50
644 *
645 * RFC 1724 hack is not supported by Socket::Option#inspect because
646 * it is not distinguishable by the size.
647 */
648
649 #if !defined HAVE_INET_NTOP && ! defined _WIN32
650 const char *
651 inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
652 {
653 #ifdef HAVE_INET_NTOA
654 struct in_addr in;
655 memcpy(&in.s_addr, addr, sizeof(in.s_addr));
656 snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in));
657 #else
658 unsigned long x = ntohl(*(unsigned long*)addr);
659 snprintf(numaddr, numaddr_len, "%d.%d.%d.%d",
660 (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
661 (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff);
662 #endif
663 return numaddr;
664 }
665 #endif
666
667 /* Although the buffer size needed depends on the prefixes, "%u" may generate "4294967295". */
668 static int
669 rb_if_indextoname(const char *succ_prefix, const char *fail_prefix, unsigned int ifindex, char *buf, size_t len)
670 {
671 #if defined(HAVE_IF_INDEXTONAME)
672 char ifbuf[IFNAMSIZ];
673 if (if_indextoname(ifindex, ifbuf) == NULL)
674 return snprintf(buf, len, "%s%u", fail_prefix, ifindex);
675 else
676 return snprintf(buf, len, "%s%s", succ_prefix, ifbuf);
677 #else
678 # ifndef IFNAMSIZ
679 # define IFNAMSIZ (sizeof(unsigned int)*3+1)
680 # endif
681 return snprintf(buf, len, "%s%u", fail_prefix, ifindex);
682 #endif
683 }
684
685 #if defined(IPPROTO_IP) && defined(HAVE_TYPE_STRUCT_IP_MREQ) /* 4.4BSD, GNU/Linux */
686 static int
687 inspect_ipv4_mreq(int level, int optname, VALUE data, VALUE ret)
688 {
689 if (RSTRING_LEN(data) == sizeof(struct ip_mreq)) {
690 struct ip_mreq s;
691 char addrbuf[INET_ADDRSTRLEN];
692 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
693 if (inet_ntop(AF_INET, &s.imr_multiaddr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
694 rb_str_cat2(ret, " invalid-address");
695 else
696 rb_str_catf(ret, " %s", addrbuf);
697 if (inet_ntop(AF_INET, &s.imr_interface, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
698 rb_str_catf(ret, " invalid-address");
699 else
700 rb_str_catf(ret, " %s", addrbuf);
701 return 1;
702 }
703 else {
704 return 0;
705 }
706 }
707 #endif
708
709 #if defined(IPPROTO_IP) && defined(HAVE_TYPE_STRUCT_IP_MREQN) /* GNU/Linux, FreeBSD 7 */
710 static int
711 inspect_ipv4_mreqn(int level, int optname, VALUE data, VALUE ret)
712 {
713 if (RSTRING_LEN(data) == sizeof(struct ip_mreqn)) {
714 struct ip_mreqn s;
715 char addrbuf[INET_ADDRSTRLEN], ifbuf[32+IFNAMSIZ];
716 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
717 if (inet_ntop(AF_INET, &s.imr_multiaddr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
718 rb_str_cat2(ret, " invalid-address");
719 else
720 rb_str_catf(ret, " %s", addrbuf);
721 if (inet_ntop(AF_INET, &s.imr_address, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
722 rb_str_catf(ret, " invalid-address");
723 else
724 rb_str_catf(ret, " %s", addrbuf);
725 rb_if_indextoname(" ", " ifindex:", s.imr_ifindex, ifbuf, sizeof(ifbuf));
726 rb_str_cat2(ret, ifbuf);
727 return 1;
728 }
729 else {
730 return 0;
731 }
732 }
733 #endif
734
735 #if defined(IPPROTO_IP) && defined(HAVE_TYPE_STRUCT_IP_MREQ) /* 4.4BSD, GNU/Linux */
736 static int
737 inspect_ipv4_add_drop_membership(int level, int optname, VALUE data, VALUE ret)
738 {
739 if (RSTRING_LEN(data) == sizeof(struct ip_mreq))
740 return inspect_ipv4_mreq(level, optname, data, ret);
741 # if defined(HAVE_TYPE_STRUCT_IP_MREQN)
742 else if (RSTRING_LEN(data) == sizeof(struct ip_mreqn))
743 return inspect_ipv4_mreqn(level, optname, data, ret);
744 # endif
745 else
746 return 0;
747 }
748 #endif
749
750 #if defined(IPPROTO_IP) && defined(IP_MULTICAST_IF) && defined(HAVE_TYPE_STRUCT_IP_MREQN) /* 4.4BSD, GNU/Linux */
751 static int
752 inspect_ipv4_multicast_if(int level, int optname, VALUE data, VALUE ret)
753 {
754 if (RSTRING_LEN(data) == sizeof(struct in_addr)) {
755 struct in_addr s;
756 char addrbuf[INET_ADDRSTRLEN];
757 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
758 if (inet_ntop(AF_INET, &s, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
759 rb_str_cat2(ret, " invalid-address");
760 else
761 rb_str_catf(ret, " %s", addrbuf);
762 return 1;
763 }
764 else if (RSTRING_LEN(data) == sizeof(struct ip_mreqn)) {
765 return inspect_ipv4_mreqn(level, optname, data, ret);
766 }
767 else {
768 return 0;
769 }
770 }
771 #endif
772
773 #if defined(IPV6_MULTICAST_IF) /* POSIX, RFC 3493 */
774 static int
775 inspect_ipv6_multicast_if(int level, int optname, VALUE data, VALUE ret)
776 {
777 if (RSTRING_LEN(data) == sizeof(int)) {
778 char ifbuf[32+IFNAMSIZ];
779 unsigned int ifindex;
780 memcpy((char*)&ifindex, RSTRING_PTR(data), sizeof(unsigned int));
781 rb_if_indextoname(" ", " ", ifindex, ifbuf, sizeof(ifbuf));
782 rb_str_cat2(ret, ifbuf);
783 return 1;
784 }
785 else {
786 return 0;
787 }
788 }
789 #endif
790
791 #if defined(IPPROTO_IPV6) && defined(HAVE_TYPE_STRUCT_IPV6_MREQ) /* POSIX, RFC 3493 */
792 static int
793 inspect_ipv6_mreq(int level, int optname, VALUE data, VALUE ret)
794 {
795 if (RSTRING_LEN(data) == sizeof(struct ipv6_mreq)) {
796 struct ipv6_mreq s;
797 char addrbuf[INET6_ADDRSTRLEN], ifbuf[32+IFNAMSIZ];
798 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
799 if (inet_ntop(AF_INET6, &s.ipv6mr_multiaddr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
800 rb_str_cat2(ret, " invalid-address");
801 else
802 rb_str_catf(ret, " %s", addrbuf);
803 rb_if_indextoname(" ", " interface:", s.ipv6mr_interface, ifbuf, sizeof(ifbuf));
804 rb_str_cat2(ret, ifbuf);
805 return 1;
806 }
807 else {
808 return 0;
809 }
810 }
811 #endif
812
813 #if defined(IPPROTO_TCP) && defined(TCP_INFO) && defined(HAVE_TYPE_STRUCT_TCP_INFO)
814
815 #ifdef __FreeBSD__
816 # ifndef HAVE_CONST_TCP_ESTABLISHED
817 # define TCP_ESTABLISHED TCPS_ESTABLISHED
818 # endif
819 # ifndef HAVE_CONST_TCP_SYN_SENT
820 # define TCP_SYN_SENT TCPS_SYN_SENT
821 # endif
822 # ifndef HAVE_CONST_TCP_SYN_RECV
823 # define TCP_SYN_RECV TCPS_SYN_RECEIVED
824 # endif
825 # ifndef HAVE_CONST_TCP_FIN_WAIT1
826 # define TCP_FIN_WAIT1 TCPS_FIN_WAIT_1
827 # endif
828 # ifndef HAVE_CONST_TCP_FIN_WAIT2
829 # define TCP_FIN_WAIT2 TCPS_FIN_WAIT_2
830 # endif
831 # ifndef HAVE_CONST_TCP_TIME_WAIT
832 # define TCP_TIME_WAIT TCPS_TIME_WAIT
833 # endif
834 # ifndef HAVE_CONST_TCP_CLOSE
835 # define TCP_CLOSE TCPS_CLOSED
836 # endif
837 # ifndef HAVE_CONST_TCP_CLOSE_WAIT
838 # define TCP_CLOSE_WAIT TCPS_CLOSE_WAIT
839 # endif
840 # ifndef HAVE_CONST_TCP_LAST_ACK
841 # define TCP_LAST_ACK TCPS_LAST_ACK
842 # endif
843 # ifndef HAVE_CONST_TCP_LISTEN
844 # define TCP_LISTEN TCPS_LISTEN
845 # endif
846 # ifndef HAVE_CONST_TCP_CLOSING
847 # define TCP_CLOSING TCPS_CLOSING
848 # endif
849 #endif
850
851 #if defined(HAVE_CONST_TCP_ESTABLISHED) && !defined(TCP_ESTABLISHED)
852 # define TCP_ESTABLISHED TCP_ESTABLISHED
853 #endif
854 #if defined(HAVE_CONST_TCP_SYN_SENT) && !defined(TCP_SYN_SENT)
855 # define TCP_SYN_SENT TCP_SYN_SENT
856 #endif
857 #if defined(HAVE_CONST_TCP_SYN_RECV) && !defined(TCP_SYN_RECV)
858 # define TCP_SYN_RECV TCP_SYN_RECV
859 #endif
860 #if defined(HAVE_CONST_TCP_FIN_WAIT1) && !defined(TCP_FIN_WAIT1)
861 # define TCP_FIN_WAIT1 TCP_FIN_WAIT1
862 #endif
863 #if defined(HAVE_CONST_TCP_FIN_WAIT2) && !defined(TCP_FIN_WAIT2)
864 # define TCP_FIN_WAIT2 TCP_FIN_WAIT2
865 #endif
866 #if defined(HAVE_CONST_TCP_TIME_WAIT) && !defined(TCP_TIME_WAIT)
867 # define TCP_TIME_WAIT TCP_TIME_WAIT
868 #endif
869 #if defined(HAVE_CONST_TCP_CLOSE) && !defined(TCP_CLOSE)
870 # define TCP_CLOSE TCP_CLOSE
871 #endif
872 #if defined(HAVE_CONST_TCP_CLOSE_WAIT) && !defined(TCP_CLOSE_WAIT)
873 # define TCP_CLOSE_WAIT TCP_CLOSE_WAIT
874 #endif
875 #if defined(HAVE_CONST_TCP_LAST_ACK) && !defined(TCP_LAST_ACK)
876 # define TCP_LAST_ACK TCP_LAST_ACK
877 #endif
878 #if defined(HAVE_CONST_TCP_LISTEN) && !defined(TCP_LISTEN)
879 # define TCP_LISTEN TCP_LISTEN
880 #endif
881 #if defined(HAVE_CONST_TCP_CLOSING) && !defined(TCP_CLOSING)
882 # define TCP_CLOSING TCP_CLOSING
883 #endif
884
885 static void
886 inspect_tcpi_options(VALUE ret, uint8_t options)
887 {
888 int sep = '=';
889
890 rb_str_cat2(ret, " options");
891 #define INSPECT_TCPI_OPTION(optval, name) \
892 if (options & (optval)) { \
893 options &= ~(uint8_t)(optval); \
894 rb_str_catf(ret, "%c%s", sep, name); \
895 sep = ','; \
896 }
897 #ifdef TCPI_OPT_TIMESTAMPS /* GNU/Linux, FreeBSD */
898 INSPECT_TCPI_OPTION(TCPI_OPT_TIMESTAMPS, "TIMESTAMPS");
899 #endif
900 #ifdef TCPI_OPT_SACK /* GNU/Linux, FreeBSD */
901 INSPECT_TCPI_OPTION(TCPI_OPT_SACK, "SACK");
902 #endif
903 #ifdef TCPI_OPT_WSCALE /* GNU/Linux, FreeBSD */
904 INSPECT_TCPI_OPTION(TCPI_OPT_WSCALE, "WSCALE");
905 #endif
906 #ifdef TCPI_OPT_ECN /* GNU/Linux, FreeBSD */
907 INSPECT_TCPI_OPTION(TCPI_OPT_ECN, "ECN");
908 #endif
909 #ifdef TCPI_OPT_ECN_SEEN /* GNU/Linux */
910 INSPECT_TCPI_OPTION(TCPI_OPT_ECN_SEEN, "ECN_SEEN");
911 #endif
912 #ifdef TCPI_OPT_SYN_DATA /* GNU/Linux */
913 INSPECT_TCPI_OPTION(TCPI_OPT_SYN_DATA, "SYN_DATA");
914 #endif
915 #ifdef TCPI_OPT_TOE /* FreeBSD */
916 INSPECT_TCPI_OPTION(TCPI_OPT_TOE, "TOE");
917 #endif
918 #undef INSPECT_TCPI_OPTION
919
920 if (options || sep == '=') {
921 rb_str_catf(ret, "%c%u", sep, options);
922 }
923 }
924
925 static void
926 inspect_tcpi_usec(VALUE ret, const char *prefix, uint32_t t)
927 {
928 rb_str_catf(ret, "%s%u.%06us", prefix, t / 1000000, t % 1000000);
929 }
930
931 #if !defined __FreeBSD__ && ( \
932 defined HAVE_STRUCT_TCP_INFO_TCPI_LAST_DATA_SENT || \
933 defined HAVE_STRUCT_TCP_INFO_TCPI_LAST_DATA_RECV || \
934 defined HAVE_STRUCT_TCP_INFO_TCPI_LAST_ACK_SENT || \
935 defined HAVE_STRUCT_TCP_INFO_TCPI_LAST_ACK_RECV || \
936 0)
937 static void
938 inspect_tcpi_msec(VALUE ret, const char *prefix, uint32_t t)
939 {
940 rb_str_catf(ret, "%s%u.%03us", prefix, t / 1000, t % 1000);
941 }
942 #endif
943
944 #ifdef __FreeBSD__
945 # define inspect_tcpi_rto(ret, t) inspect_tcpi_usec(ret, " rto=", t)
946 # define inspect_tcpi_last_data_recv(ret, t) inspect_tcpi_usec(ret, " last_data_recv=", t)
947 # define inspect_tcpi_rtt(ret, t) inspect_tcpi_usec(ret, " rtt=", t)
948 # define inspect_tcpi_rttvar(ret, t) inspect_tcpi_usec(ret, " rttvar=", t)
949 #else
950 # define inspect_tcpi_rto(ret, t) inspect_tcpi_usec(ret, " rto=", t)
951 # define inspect_tcpi_ato(ret, t) inspect_tcpi_usec(ret, " ato=", t)
952 # define inspect_tcpi_last_data_sent(ret, t) inspect_tcpi_msec(ret, " last_data_sent=", t)
953 # define inspect_tcpi_last_data_recv(ret, t) inspect_tcpi_msec(ret, " last_data_recv=", t)
954 # define inspect_tcpi_last_ack_sent(ret, t) inspect_tcpi_msec(ret, " last_ack_sent=", t)
955 # define inspect_tcpi_last_ack_recv(ret, t) inspect_tcpi_msec(ret, " last_ack_recv=", t)
956 # define inspect_tcpi_rtt(ret, t) inspect_tcpi_usec(ret, " rtt=", t)
957 # define inspect_tcpi_rttvar(ret, t) inspect_tcpi_usec(ret, " rttvar=", t)
958 # define inspect_tcpi_rcv_rtt(ret, t) inspect_tcpi_usec(ret, " rcv_rtt=", t)
959 #endif
960
961 static int
962 inspect_tcp_info(int level, int optname, VALUE data, VALUE ret)
963 {
964 size_t actual_size = RSTRING_LEN(data);
965 if (sizeof(struct tcp_info) <= actual_size) {
966 struct tcp_info s;
967 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
968 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_STATE
969 switch (s.tcpi_state) {
970 # ifdef TCP_ESTABLISHED
971 case TCP_ESTABLISHED: rb_str_cat_cstr(ret, " state=ESTABLISHED"); break;
972 # endif
973 # ifdef TCP_SYN_SENT
974 case TCP_SYN_SENT: rb_str_cat_cstr(ret, " state=SYN_SENT"); break;
975 # endif
976 # ifdef TCP_SYN_RECV
977 case TCP_SYN_RECV: rb_str_cat_cstr(ret, " state=SYN_RECV"); break;
978 # endif
979 # ifdef TCP_FIN_WAIT1
980 case TCP_FIN_WAIT1: rb_str_cat_cstr(ret, " state=FIN_WAIT1"); break;
981 # endif
982 # ifdef TCP_FIN_WAIT2
983 case TCP_FIN_WAIT2: rb_str_cat_cstr(ret, " state=FIN_WAIT2"); break;
984 # endif
985 # ifdef TCP_TIME_WAIT
986 case TCP_TIME_WAIT: rb_str_cat_cstr(ret, " state=TIME_WAIT"); break;
987 # endif
988 # ifdef TCP_CLOSE
989 case TCP_CLOSE: rb_str_cat_cstr(ret, " state=CLOSED"); break; /* RFC 793 uses "CLOSED", not "CLOSE" */
990 # endif
991 # ifdef TCP_CLOSE_WAIT
992 case TCP_CLOSE_WAIT: rb_str_cat_cstr(ret, " state=CLOSE_WAIT"); break;
993 # endif
994 # ifdef TCP_LAST_ACK
995 case TCP_LAST_ACK: rb_str_cat_cstr(ret, " state=LAST_ACK"); break;
996 # endif
997 # ifdef TCP_LISTEN
998 case TCP_LISTEN: rb_str_cat_cstr(ret, " state=LISTEN"); break;
999 # endif
1000 # ifdef TCP_CLOSING
1001 case TCP_CLOSING: rb_str_cat_cstr(ret, " state=CLOSING"); break;
1002 # endif
1003 default: rb_str_catf(ret, " state=%u", s.tcpi_state); break;
1004 }
1005 #endif
1006 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_CA_STATE
1007 switch (s.tcpi_ca_state) {
1008 case TCP_CA_Open: rb_str_cat_cstr(ret, " ca_state=Open"); break;
1009 case TCP_CA_Disorder: rb_str_cat_cstr(ret, " ca_state=Disorder"); break;
1010 case TCP_CA_CWR: rb_str_cat_cstr(ret, " ca_state=CWR"); break;
1011 case TCP_CA_Recovery: rb_str_cat_cstr(ret, " ca_state=Recovery"); break;
1012 case TCP_CA_Loss: rb_str_cat_cstr(ret, " ca_state=Loss"); break;
1013 default: rb_str_catf(ret, " ca_state=%u", s.tcpi_ca_state); break;
1014 }
1015 #endif
1016 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_RETRANSMITS
1017 rb_str_catf(ret, " retransmits=%u", s.tcpi_retransmits);
1018 #endif
1019 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_PROBES
1020 rb_str_catf(ret, " probes=%u", s.tcpi_probes);
1021 #endif
1022 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_BACKOFF
1023 rb_str_catf(ret, " backoff=%u", s.tcpi_backoff);
1024 #endif
1025 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_OPTIONS
1026 inspect_tcpi_options(ret, s.tcpi_options);
1027 #endif
1028 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_SND_WSCALE
1029 rb_str_catf(ret, " snd_wscale=%u", s.tcpi_snd_wscale);
1030 #endif
1031 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_RCV_WSCALE
1032 rb_str_catf(ret, " rcv_wscale=%u", s.tcpi_rcv_wscale);
1033 #endif
1034 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_RTO
1035 inspect_tcpi_rto(ret, s.tcpi_rto);
1036 #endif
1037 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_ATO
1038 inspect_tcpi_ato(ret, s.tcpi_ato);
1039 #endif
1040 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_SND_MSS
1041 rb_str_catf(ret, " snd_mss=%u", s.tcpi_snd_mss);
1042 #endif
1043 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_RCV_MSS
1044 rb_str_catf(ret, " rcv_mss=%u", s.tcpi_rcv_mss);
1045 #endif
1046 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_UNACKED
1047 rb_str_catf(ret, " unacked=%u", s.tcpi_unacked);
1048 #endif
1049 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_SACKED
1050 rb_str_catf(ret, " sacked=%u", s.tcpi_sacked);
1051 #endif
1052 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_LOST
1053 rb_str_catf(ret, " lost=%u", s.tcpi_lost);
1054 #endif
1055 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_RETRANS
1056 rb_str_catf(ret, " retrans=%u", s.tcpi_retrans);
1057 #endif
1058 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_FACKETS
1059 rb_str_catf(ret, " fackets=%u", s.tcpi_fackets);
1060 #endif
1061 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_LAST_DATA_SENT
1062 inspect_tcpi_last_data_sent(ret, s.tcpi_last_data_sent);
1063 #endif
1064 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_LAST_ACK_SENT
1065 inspect_tcpi_last_ack_sent(ret, s.tcpi_last_ack_sent);
1066 #endif
1067 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_LAST_DATA_RECV
1068 inspect_tcpi_last_data_recv(ret, s.tcpi_last_data_recv);
1069 #endif
1070 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_LAST_ACK_RECV
1071 inspect_tcpi_last_ack_recv(ret, s.tcpi_last_ack_recv);
1072 #endif
1073 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_PMTU
1074 rb_str_catf(ret, " pmtu=%u", s.tcpi_pmtu);
1075 #endif
1076 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_RCV_SSTHRESH
1077 rb_str_catf(ret, " rcv_ssthresh=%u", s.tcpi_rcv_ssthresh);
1078 #endif
1079 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_RTT
1080 inspect_tcpi_rtt(ret, s.tcpi_rtt);
1081 #endif
1082 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_RTTVAR
1083 inspect_tcpi_rttvar(ret, s.tcpi_rttvar);
1084 #endif
1085 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_SND_SSTHRESH
1086 rb_str_catf(ret, " snd_ssthresh=%u", s.tcpi_snd_ssthresh);
1087 #endif
1088 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_SND_CWND
1089 rb_str_catf(ret, " snd_cwnd=%u", s.tcpi_snd_cwnd);
1090 #endif
1091 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_ADVMSS
1092 rb_str_catf(ret, " advmss=%u", s.tcpi_advmss);
1093 #endif
1094 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_REORDERING
1095 rb_str_catf(ret, " reordering=%u", s.tcpi_reordering);
1096 #endif
1097 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_RCV_RTT
1098 inspect_tcpi_rcv_rtt(ret, s.tcpi_rcv_rtt);
1099 #endif
1100 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_RCV_SPACE
1101 rb_str_catf(ret, " rcv_space=%u", s.tcpi_rcv_space);
1102 #endif
1103 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_TOTAL_RETRANS
1104 rb_str_catf(ret, " total_retrans=%u", s.tcpi_total_retrans);
1105 #endif
1106 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_SND_WND
1107 rb_str_catf(ret, " snd_wnd=%u", s.tcpi_snd_wnd); /* FreeBSD */
1108 #endif
1109 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_SND_BWND
1110 rb_str_catf(ret, " snd_bwnd=%u", s.tcpi_snd_bwnd); /* FreeBSD */
1111 #endif
1112 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_SND_NXT
1113 rb_str_catf(ret, " snd_nxt=%u", s.tcpi_snd_nxt); /* FreeBSD */
1114 #endif
1115 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_RCV_NXT
1116 rb_str_catf(ret, " rcv_nxt=%u", s.tcpi_rcv_nxt); /* FreeBSD */
1117 #endif
1118 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_TOE_TID
1119 rb_str_catf(ret, " toe_tid=%u", s.tcpi_toe_tid); /* FreeBSD */
1120 #endif
1121 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_SND_REXMITPACK
1122 rb_str_catf(ret, " snd_rexmitpack=%u", s.tcpi_snd_rexmitpack); /* FreeBSD */
1123 #endif
1124 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_RCV_OOOPACK
1125 rb_str_catf(ret, " rcv_ooopack=%u", s.tcpi_rcv_ooopack); /* FreeBSD */
1126 #endif
1127 #ifdef HAVE_STRUCT_TCP_INFO_TCPI_SND_ZEROWIN
1128 rb_str_catf(ret, " snd_zerowin=%u", s.tcpi_snd_zerowin); /* FreeBSD */
1129 #endif
1130 if (sizeof(struct tcp_info) < actual_size)
1131 rb_str_catf(ret, " (%u bytes too long)", (unsigned)(actual_size - sizeof(struct tcp_info)));
1132 return 1;
1133 }
1134 else {
1135 return 0;
1136 }
1137 }
1138 #endif
1139
1140 #if defined(SOL_SOCKET) && defined(SO_PEERCRED) /* GNU/Linux, OpenBSD */
1141 #if defined(__OpenBSD__)
1142 #define RUBY_SOCK_PEERCRED struct sockpeercred
1143 #else
1144 #define RUBY_SOCK_PEERCRED struct ucred
1145 #endif
1146 static int
1147 inspect_peercred(int level, int optname, VALUE data, VALUE ret)
1148 {
1149 if (RSTRING_LEN(data) == sizeof(RUBY_SOCK_PEERCRED)) {
1150 RUBY_SOCK_PEERCRED cred;
1151 memcpy(&cred, RSTRING_PTR(data), sizeof(RUBY_SOCK_PEERCRED));
1152 rb_str_catf(ret, " pid=%u euid=%u egid=%u",
1153 (unsigned)cred.pid, (unsigned)cred.uid, (unsigned)cred.gid);
1154 rb_str_cat2(ret, " (ucred)");
1155 return 1;
1156 }
1157 else {
1158 return 0;
1159 }
1160 }
1161 #endif
1162
1163 #if defined(LOCAL_PEERCRED) /* FreeBSD, MacOS X */
1164 static int
1165 inspect_local_peercred(int level, int optname, VALUE data, VALUE ret)
1166 {
1167 if (RSTRING_LEN(data) == sizeof(struct xucred)) {
1168 struct xucred cred;
1169 memcpy(&cred, RSTRING_PTR(data), sizeof(struct xucred));
1170 if (cred.cr_version != XUCRED_VERSION)
1171 return 0;
1172 rb_str_catf(ret, " version=%u", cred.cr_version);
1173 rb_str_catf(ret, " euid=%u", cred.cr_uid);
1174 if (cred.cr_ngroups) {
1175 int i;
1176 const char *sep = " groups=";
1177 for (i = 0; i < cred.cr_ngroups; i++) {
1178 rb_str_catf(ret, "%s%u", sep, cred.cr_groups[i]);
1179 sep = ",";
1180 }
1181 }
1182 rb_str_cat2(ret, " (xucred)");
1183 return 1;
1184 }
1185 else {
1186 return 0;
1187 }
1188 }
1189 #endif
1190
1191
1192 /*
1193 * call-seq:
1194 * sockopt.inspect => string
1195 *
1196 * Returns a string which shows sockopt in human-readable form.
1197 *
1198 * p Socket::Option.new(:INET, :SOCKET, :KEEPALIVE, [1].pack("i")).inspect
1199 * #=> "#<Socket::Option: INET SOCKET KEEPALIVE 1>"
1200 *
1201 */
1202 static VALUE
1203 sockopt_inspect(VALUE self)
1204 {
1205 int family = NUM2INT(sockopt_family_m(self));
1206 int level = NUM2INT(sockopt_level_m(self));
1207 int optname = NUM2INT(sockopt_optname_m(self));
1208 VALUE data = sockopt_data(self);
1209 VALUE v, ret;
1210 ID family_id, level_id, optname_id;
1211 int inspected;
1212
1213 StringValue(data);
1214
1215 ret = rb_sprintf("#<%s:", rb_obj_classname(self));
1216
1217 family_id = rsock_intern_family_noprefix(family);
1218 if (family_id)
1219 rb_str_catf(ret, " %s", rb_id2name(family_id));
1220 else
1221 rb_str_catf(ret, " family:%d", family);
1222
1223 if (level == SOL_SOCKET) {
1224 rb_str_cat2(ret, " SOCKET");
1225
1226 optname_id = rsock_intern_so_optname(optname);
1227 if (optname_id)
1228 rb_str_catf(ret, " %s", rb_id2name(optname_id));
1229 else
1230 rb_str_catf(ret, " optname:%d", optname);
1231 }
1232 #ifdef HAVE_SYS_UN_H
1233 else if (family == AF_UNIX) {
1234 rb_str_catf(ret, " level:%d", level);
1235
1236 optname_id = rsock_intern_local_optname(optname);
1237 if (optname_id)
1238 rb_str_catf(ret, " %s", rb_id2name(optname_id));
1239 else
1240 rb_str_catf(ret, " optname:%d", optname);
1241 }
1242 #endif
1243 else if (IS_IP_FAMILY(family)) {
1244 level_id = rsock_intern_iplevel(level);
1245 if (level_id)
1246 rb_str_catf(ret, " %s", rb_id2name(level_id));
1247 else
1248 rb_str_catf(ret, " level:%d", level);
1249
1250 v = optname_to_sym(level, optname);
1251 if (SYMBOL_P(v))
1252 rb_str_catf(ret, " %"PRIsVALUE, rb_sym2str(v));
1253 else
1254 rb_str_catf(ret, " optname:%d", optname);
1255 }
1256 else {
1257 rb_str_catf(ret, " level:%d", level);
1258 rb_str_catf(ret, " optname:%d", optname);
1259 }
1260
1261 inspected = 0;
1262
1263 if (level == SOL_SOCKET)
1264 family = AF_UNSPEC;
1265 switch (family) {
1266 case AF_UNSPEC:
1267 switch (level) {
1268 case SOL_SOCKET:
1269 switch (optname) {
1270 # if defined(SO_DEBUG) /* POSIX */
1271 case SO_DEBUG: inspected = inspect_int(level, optname, data, ret); break;
1272 # endif
1273 # if defined(SO_ERROR) /* POSIX */
1274 case SO_ERROR: inspected = inspect_errno(level, optname, data, ret); break;
1275 # endif
1276 # if defined(SO_TYPE) /* POSIX */
1277 case SO_TYPE: inspected = inspect_socktype(level, optname, data, ret); break;
1278 # endif
1279 # if defined(SO_ACCEPTCONN) /* POSIX */
1280 case SO_ACCEPTCONN: inspected = inspect_int(level, optname, data, ret); break;
1281 # endif
1282 # if defined(SO_BROADCAST) /* POSIX */
1283 case SO_BROADCAST: inspected = inspect_int(level, optname, data, ret); break;
1284 # endif
1285 # if defined(SO_REUSEADDR) /* POSIX */
1286 case SO_REUSEADDR: inspected = inspect_int(level, optname, data, ret); break;
1287 # endif
1288 # if defined(SO_KEEPALIVE) /* POSIX */
1289 case SO_KEEPALIVE: inspected = inspect_int(level, optname, data, ret); break;
1290 # endif
1291 # if defined(SO_OOBINLINE) /* POSIX */
1292 case SO_OOBINLINE: inspected = inspect_int(level, optname, data, ret); break;
1293 # endif
1294 # if defined(SO_SNDBUF) /* POSIX */
1295 case SO_SNDBUF: inspected = inspect_int(level, optname, data, ret); break;
1296 # endif
1297 # if defined(SO_RCVBUF) /* POSIX */
1298 case SO_RCVBUF: inspected = inspect_int(level, optname, data, ret); break;
1299 # endif
1300 # if defined(SO_DONTROUTE) /* POSIX */
1301 case SO_DONTROUTE: inspected = inspect_int(level, optname, data, ret); break;
1302 # endif
1303 # if defined(SO_RCVLOWAT) /* POSIX */
1304 case SO_RCVLOWAT: inspected = inspect_int(level, optname, data, ret); break;
1305 # endif
1306 # if defined(SO_SNDLOWAT) /* POSIX */
1307 case SO_SNDLOWAT: inspected = inspect_int(level, optname, data, ret); break;
1308 # endif
1309 # if defined(SO_LINGER) /* POSIX */
1310 case SO_LINGER: inspected = inspect_linger(level, optname, data, ret); break;
1311 # endif
1312 # if defined(SO_RCVTIMEO) /* POSIX */
1313 case SO_RCVTIMEO: inspected = inspect_timeval_as_interval(level, optname, data, ret); break;
1314 # endif
1315 # if defined(SO_SNDTIMEO) /* POSIX */
1316 case SO_SNDTIMEO: inspected = inspect_timeval_as_interval(level, optname, data, ret); break;
1317 # endif
1318 # if defined(SO_PEERCRED) /* GNU/Linux, OpenBSD */
1319 case SO_PEERCRED: inspected = inspect_peercred(level, optname, data, ret); break;
1320 # endif
1321 }
1322 break;
1323 }
1324 break;
1325
1326 case AF_INET:
1327 #ifdef INET6
1328 case AF_INET6:
1329 #endif
1330 switch (level) {
1331 # if defined(IPPROTO_IP)
1332 case IPPROTO_IP:
1333 switch (optname) {
1334 # if defined(IP_MULTICAST_IF) && defined(HAVE_TYPE_STRUCT_IP_MREQN) /* 4.4BSD, GNU/Linux */
1335 case IP_MULTICAST_IF: inspected = inspect_ipv4_multicast_if(level, optname, data, ret); break;
1336 # endif
1337 # if defined(IP_ADD_MEMBERSHIP) /* 4.4BSD, GNU/Linux */
1338 case IP_ADD_MEMBERSHIP: inspected = inspect_ipv4_add_drop_membership(level, optname, data, ret); break;
1339 # endif
1340 # if defined(IP_DROP_MEMBERSHIP) /* 4.4BSD, GNU/Linux */
1341 case IP_DROP_MEMBERSHIP: inspected = inspect_ipv4_add_drop_membership(level, optname, data, ret); break;
1342 # endif
1343 # if defined(IP_MULTICAST_LOOP) /* 4.4BSD, GNU/Linux */
1344 case IP_MULTICAST_LOOP: inspected = inspect_ipv4_multicast_loop(level, optname, data, ret); break;
1345 # endif
1346 # if defined(IP_MULTICAST_TTL) /* 4.4BSD, GNU/Linux */
1347 case IP_MULTICAST_TTL: inspected = inspect_ipv4_multicast_ttl(level, optname, data, ret); break;
1348 # endif
1349 }
1350 break;
1351 # endif
1352
1353 # if defined(IPPROTO_IPV6)
1354 case IPPROTO_IPV6:
1355 switch (optname) {
1356 # if defined(IPV6_MULTICAST_HOPS) /* POSIX */
1357 case IPV6_MULTICAST_HOPS: inspected = inspect_int(level, optname, data, ret); break;
1358 # endif
1359 # if defined(IPV6_MULTICAST_IF) /* POSIX */
1360 case IPV6_MULTICAST_IF: inspected = inspect_ipv6_multicast_if(level, optname, data, ret); break;
1361 # endif
1362 # if defined(IPV6_MULTICAST_LOOP) /* POSIX */
1363 case IPV6_MULTICAST_LOOP: inspected = inspect_uint(level, optname, data, ret); break;
1364 # endif
1365 # if defined(IPV6_JOIN_GROUP) /* POSIX */
1366 case IPV6_JOIN_GROUP: inspected = inspect_ipv6_mreq(level, optname, data, ret); break;
1367 # endif
1368 # if defined(IPV6_LEAVE_GROUP) /* POSIX */
1369 case IPV6_LEAVE_GROUP: inspected = inspect_ipv6_mreq(level, optname, data, ret); break;
1370 # endif
1371 # if defined(IPV6_UNICAST_HOPS) /* POSIX */
1372 case IPV6_UNICAST_HOPS: inspected = inspect_int(level, optname, data, ret); break;
1373 # endif
1374 # if defined(IPV6_V6ONLY) /* POSIX */
1375 case IPV6_V6ONLY: inspected = inspect_int(level, optname, data, ret); break;
1376 # endif
1377 }
1378 break;
1379 # endif
1380
1381 # if defined(IPPROTO_TCP)
1382 case IPPROTO_TCP:
1383 switch (optname) {
1384 # if defined(TCP_NODELAY) /* POSIX */
1385 case TCP_NODELAY: inspected = inspect_int(level, optname, data, ret); break;
1386 # endif
1387 # if defined(TCP_INFO) && defined(HAVE_TYPE_STRUCT_TCP_INFO) /* Linux, FreeBSD */
1388 case TCP_INFO: inspected = inspect_tcp_info(level, optname, data, ret); break;
1389 # endif
1390 }
1391 break;
1392 # endif
1393 }
1394 break;
1395
1396 #ifdef HAVE_SYS_UN_H
1397 case AF_UNIX:
1398 switch (level) {
1399 case 0:
1400 switch (optname) {
1401 # if defined(LOCAL_PEERCRED)
1402 case LOCAL_PEERCRED: inspected = inspect_local_peercred(level, optname, data, ret); break;
1403 # endif
1404 }
1405 break;
1406 }
1407 break;
1408 #endif
1409 }
1410
1411 if (!inspected) {
1412 rb_str_cat2(ret, " ");
1413 rb_str_append(ret, rb_str_dump(data));
1414 }
1415
1416 rb_str_cat2(ret, ">");
1417
1418 return ret;
1419 }
1420
1421 /*
1422 * call-seq:
1423 * sockopt.unpack(template) => array
1424 *
1425 * Calls String#unpack on sockopt.data.
1426 *
1427 * sockopt = Socket::Option.new(:INET, :SOCKET, :KEEPALIVE, [1].pack("i"))
1428 * p sockopt.unpack("i") #=> [1]
1429 * p sockopt.data.unpack("i") #=> [1]
1430 */
1431 static VALUE
1432 sockopt_unpack(VALUE self, VALUE template)
1433 {
1434 return rb_funcall(sockopt_data(self), rb_intern("unpack"), 1, template);
1435 }
1436
1437 void
1438 rsock_init_sockopt(void)
1439 {
1440 /*
1441 * Document-class: Socket::Option
1442 *
1443 * Socket::Option represents a socket option used by
1444 * BasicSocket#getsockopt and BasicSocket#setsockopt. A socket option
1445 * contains the socket #family, protocol #level, option name #optname and
1446 * option value #data.
1447 */
1448 rb_cSockOpt = rb_define_class_under(rb_cSocket, "Option", rb_cObject);
1449 rb_define_method(rb_cSockOpt, "initialize", sockopt_initialize, 4);
1450 rb_define_method(rb_cSockOpt, "family", sockopt_family_m, 0);
1451 rb_define_method(rb_cSockOpt, "level", sockopt_level_m, 0);
1452 rb_define_method(rb_cSockOpt, "optname", sockopt_optname_m, 0);
1453 rb_define_method(rb_cSockOpt, "data", sockopt_data, 0);
1454 rb_define_method(rb_cSockOpt, "inspect", sockopt_inspect, 0);
1455
1456 rb_define_singleton_method(rb_cSockOpt, "int", sockopt_s_int, 4);
1457 rb_define_method(rb_cSockOpt, "int", sockopt_int, 0);
1458
1459 rb_define_singleton_method(rb_cSockOpt, "byte", sockopt_s_byte, 4);
1460 rb_define_method(rb_cSockOpt, "byte", sockopt_byte, 0);
1461
1462 rb_define_singleton_method(rb_cSockOpt, "bool", sockopt_s_bool, 4);
1463 rb_define_method(rb_cSockOpt, "bool", sockopt_bool, 0);
1464
1465 rb_define_singleton_method(rb_cSockOpt, "linger", sockopt_s_linger, 2);
1466 rb_define_method(rb_cSockOpt, "linger", sockopt_linger, 0);
1467
1468 rb_define_singleton_method(rb_cSockOpt, "ipv4_multicast_ttl", sockopt_s_ipv4_multicast_ttl, 1);
1469 rb_define_method(rb_cSockOpt, "ipv4_multicast_ttl", sockopt_ipv4_multicast_ttl, 0);
1470
1471 rb_define_singleton_method(rb_cSockOpt, "ipv4_multicast_loop", sockopt_s_ipv4_multicast_loop, 1);
1472 rb_define_method(rb_cSockOpt, "ipv4_multicast_loop", sockopt_ipv4_multicast_loop, 0);
1473
1474 rb_define_method(rb_cSockOpt, "unpack", sockopt_unpack, 1);
1475
1476 rb_define_method(rb_cSockOpt, "to_s", sockopt_data, 0); /* compatibility for ruby before 1.9.2 */
1477 }
AF_UNSPEC
#define AF_UNSPEC
Definition: sockport.h:101
ID
unsigned long ID
Definition: ruby.h:103
rb_id2name
const char * rb_id2name(ID)
Definition: symbol.c:801
rb_assoc_new
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:896
id
const int id
Definition: nkf.c:209
inet_ntop
const char * inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
Definition: option.c:651
memset
void * memset(void *, int, size_t)
rb_cSockOpt
VALUE rb_cSockOpt
Definition: option.c:3
IPPROTO_UDP
#define IPPROTO_UDP
Definition: constdefs.h:627
INET_ADDRSTRLEN
#define INET_ADDRSTRLEN
Definition: constdefs.h:1825
IPPROTO_TCP
#define IPPROTO_TCP
Definition: constdefs.h:610
rsock_intern_tcp_optname
ID rsock_intern_tcp_optname(int val)
Definition: constdefs.c:6829
rsock_intern_udp_optname
ID rsock_intern_udp_optname(int val)
Definition: constdefs.c:6838
snprintf
int snprintf(char *__restrict, size_t, const char *__restrict,...) __attribute__((__format__(__printf__
RObject
Definition: ruby.h:922
RSTRING_PTR
#define RSTRING_PTR(str)
Definition: ruby.h:1009
rb_attr_get
VALUE rb_attr_get(VALUE, ID)
Definition: variable.c:1084
VALUE
unsigned long VALUE
Definition: ruby.h:102
rb_intern
#define rb_intern(str)
INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN
Definition: constdefs.h:1832
rsock_intern_ipv6_optname
ID rsock_intern_ipv6_optname(int val)
Definition: constdefs.c:6820
StringValue
use StringValue() instead")))
IPPROTO_IP
#define IPPROTO_IP
Definition: constdefs.h:586
rb_str_cat2
#define rb_str_cat2
Definition: intern.h:912
rb_define_singleton_method
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1755
XCAT
#define XCAT(x, y)
Definition: option.c:8
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1551
INT2NUM
#define INT2NUM(x)
Definition: ruby.h:1609
Qfalse
#define Qfalse
Definition: ruby.h:467
NULL
#define NULL
Definition: _sdbm.c:101
IS_IP_FAMILY
#define IS_IP_FAMILY(af)
Definition: rubysocket.h:162
uint32_t
unsigned int uint32_t
Definition: sha2.h:101
socklen_t
int socklen_t
Definition: getaddrinfo.c:83
PRIsVALUE
#define PRIsVALUE
Definition: ruby.h:166
rsock_intern_local_optname
ID rsock_intern_local_optname(int val)
Definition: constdefs.c:6856
ID2SYM
#define ID2SYM(x)
Definition: ruby.h:414
T_OBJECT
#define T_OBJECT
Definition: ruby.h:523
CHR2FIX
#define CHR2FIX(x)
Definition: ruby.h:1648
v
int VALUE v
Definition: rb_mjit_min_header-2.7.0.h:12332
rsock_intern_family_noprefix
ID rsock_intern_family_noprefix(int val)
Definition: constdefs.c:6757
rb_cSocket
VALUE rb_cSocket
Definition: init.c:26
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2669
obj
const VALUE VALUE obj
Definition: rb_mjit_min_header-2.7.0.h:5742
NUM2CHR
#define NUM2CHR(x)
Definition: ruby.h:1647
memcpy
void * memcpy(void *__restrict, const void *__restrict, size_t)
rb_str_dump
VALUE rb_str_dump(VALUE)
Definition: string.c:6042
strerror
RUBY_EXTERN char * strerror(int)
Definition: strerror.c:11
i
uint32_t i
Definition: rb_mjit_min_header-2.7.0.h:5464
rb_check_to_integer
VALUE rb_check_to_integer(VALUE, const char *)
Tries to convert val into Integer.
Definition: object.c:2999
rsock_optname_arg
int rsock_optname_arg(int family, int level, VALUE optname)
Definition: constants.c:68
TYPE_IP_MULTICAST_TTL
#define TYPE_IP_MULTICAST_TTL
Definition: option.c:26
IFNAMSIZ
#define IFNAMSIZ
TYPE_IP_MULTICAST_LOOP
#define TYPE_IP_MULTICAST_LOOP
Definition: option.c:25
rsock_intern_socktype
ID rsock_intern_socktype(int val)
Definition: constdefs.c:6775
rsock_init_sockopt
void rsock_init_sockopt(void)
Definition: option.c:1438
rb_eTypeError
VALUE rb_eTypeError
Definition: error.c:922
uint8_t
unsigned char uint8_t
Definition: sha2.h:100
rb_to_int
VALUE rb_to_int(VALUE)
Converts val into Integer.
Definition: object.c:3021
inspect_ipv4_multicast_ttl
#define inspect_ipv4_multicast_ttl(a, b, c, d)
Definition: option.c:481
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:2010
buf
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4322
rb_str_cat_cstr
#define rb_str_cat_cstr(str, ptr)
Definition: rb_mjit_min_header-2.7.0.h:6126
rb_funcall
#define rb_funcall(recv, mid, argc,...)
Definition: rb_mjit_min_header-2.7.0.h:6585
rb_str_append
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:2965
rb_sprintf
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1197
klass
VALUE klass
Definition: rb_mjit_min_header-2.7.0.h:13254
timeval
Definition: missing.h:53
inspect_ipv4_multicast_loop
#define inspect_ipv4_multicast_loop(a, b, c, d)
Definition: option.c:430
NIL_P
#define NIL_P(v)
Definition: ruby.h:482
rsock_sockopt_new
VALUE rsock_sockopt_new(int family, int level, int optname, VALUE data)
Definition: option.c:107
rsock_level_arg
int rsock_level_arg(int family, VALUE level)
Definition: constants.c:56
rb_obj_classname
const char * rb_obj_classname(VALUE)
Definition: variable.c:289
err
int err
Definition: win32.c:135
Qtrue
#define Qtrue
Definition: ruby.h:468
rb_str_catf
VALUE rb_str_catf(VALUE str, const char *format,...)
Definition: sprintf.c:1237
check_size
#define check_size(len, size)
Definition: option.c:30
len
uint8_t len
Definition: escape.c:17
SYMBOL_P
#define SYMBOL_P(x)
Definition: ruby.h:413
rsock_intern_ip_optname
ID rsock_intern_ip_optname(int val)
Definition: constdefs.c:6811
rubysocket.h
rb_ivar_set
VALUE rb_ivar_set(VALUE, ID, VALUE)
Definition: variable.c:1300
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:698
rb_sym2str
VALUE rb_sym2str(VALUE)
Definition: symbol.c:784
rsock_intern_iplevel
ID rsock_intern_iplevel(int val)
Definition: constdefs.c:6793
rsock_intern_so_optname
ID rsock_intern_so_optname(int val)
Definition: constdefs.c:6802
NEWOBJ_OF
#define NEWOBJ_OF(obj, type, klass, flags)
Definition: ruby.h:785
NUM2INT
#define NUM2INT(x)
Definition: ruby.h:715
Qnil
#define Qnil
Definition: ruby.h:469
rsock_family_arg
int rsock_family_arg(VALUE domain)
Definition: constants.c:42
UNREACHABLE_RETURN
#define UNREACHABLE_RETURN(val)
Definition: ruby.h:59
RSTRING_LEN
#define RSTRING_LEN(str)
Definition: ruby.h:1005
pack_var
#define pack_var(v)
Definition: option.c:5
RTEST
#define RTEST(v)
Definition: ruby.h:481
name
const char * name
Definition: nkf.c:208