Ruby  1.9.3p448(2013-06-27revision41675)
option.c
Go to the documentation of this file.
1 #include "rubysocket.h"
2 
4 
5 static VALUE
6 constant_to_sym(int constant, ID (*intern_const)(int))
7 {
8  ID name = intern_const(constant);
9  if (name) {
10  return ID2SYM(name);
11  }
12 
13  return INT2NUM(constant);
14 }
15 
16 static VALUE
17 optname_to_sym(int level, int optname)
18 {
19  switch (level) {
20  case SOL_SOCKET:
21  return constant_to_sym(optname, rsock_intern_so_optname);
22  case IPPROTO_IP:
23  return constant_to_sym(optname, rsock_intern_ip_optname);
24 #ifdef INET6
25  case IPPROTO_IPV6:
26  return constant_to_sym(optname, rsock_intern_ipv6_optname);
27 #endif
28  case IPPROTO_TCP:
29  return constant_to_sym(optname, rsock_intern_tcp_optname);
30  case IPPROTO_UDP:
31  return constant_to_sym(optname, rsock_intern_udp_optname);
32  default:
33  return INT2NUM(optname);
34  }
35 }
36 
37 /*
38  * call-seq:
39  * Socket::Option.new(family, level, optname, data) => sockopt
40  *
41  * Returns a new Socket::Option object.
42  *
43  * sockopt = Socket::Option.new(:INET, :SOCKET, :KEEPALIVE, [1].pack("i"))
44  * p sockopt #=> #<Socket::Option: INET SOCKET KEEPALIVE 1>
45  *
46  */
47 static VALUE
48 sockopt_initialize(VALUE self, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE data)
49 {
50  int family = rsock_family_arg(vfamily);
51  int level = rsock_level_arg(family, vlevel);
52  int optname = rsock_optname_arg(family, level, voptname);
53  StringValue(data);
54  rb_ivar_set(self, rb_intern("family"), INT2NUM(family));
55  rb_ivar_set(self, rb_intern("level"), INT2NUM(level));
56  rb_ivar_set(self, rb_intern("optname"), INT2NUM(optname));
57  rb_ivar_set(self, rb_intern("data"), data);
58  return self;
59 }
60 
61 VALUE
62 rsock_sockopt_new(int family, int level, int optname, VALUE data)
63 {
64  NEWOBJ(obj, struct RObject);
66  StringValue(data);
67  sockopt_initialize((VALUE)obj, INT2NUM(family), INT2NUM(level), INT2NUM(optname), data);
68  return (VALUE)obj;
69 }
70 
71 /*
72  * call-seq:
73  * sockopt.family => integer
74  *
75  * returns the socket family as an integer.
76  *
77  * p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).family
78  * #=> 10
79  */
80 static VALUE
82 {
83  return rb_attr_get(self, rb_intern("family"));
84 }
85 
86 static int
88 {
89  return NUM2INT(rb_attr_get(self, rb_intern("level")));
90 }
91 
92 /*
93  * call-seq:
94  * sockopt.level => integer
95  *
96  * returns the socket level as an integer.
97  *
98  * p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).level
99  * #=> 41
100  */
101 static VALUE
103 {
104  return INT2NUM(sockopt_level(self));
105 }
106 
107 static int
109 {
110  return NUM2INT(rb_attr_get(self, rb_intern("optname")));
111 }
112 
113 /*
114  * call-seq:
115  * sockopt.optname => integer
116  *
117  * returns the socket option name as an integer.
118  *
119  * p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).optname
120  * #=> 2
121  */
122 static VALUE
124 {
125  return INT2NUM(sockopt_optname(self));
126 }
127 
128 /*
129  * call-seq:
130  * sockopt.data => string
131  *
132  * returns the socket option data as a string.
133  *
134  * p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).data
135  * #=> "\x01\x00\x00\x00"
136  */
137 static VALUE
139 {
140  VALUE v = rb_attr_get(self, rb_intern("data"));
141  StringValue(v);
142  return v;
143 }
144 
145 /*
146  * call-seq:
147  * Socket::Option.int(family, level, optname, integer) => sockopt
148  *
149  * Creates a new Socket::Option object which contains an int as data.
150  *
151  * The size and endian is dependent on the platform.
152  *
153  * p Socket::Option.int(:INET, :SOCKET, :KEEPALIVE, 1)
154  * #=> #<Socket::Option: INET SOCKET KEEPALIVE 1>
155  */
156 static VALUE
157 sockopt_s_int(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE vint)
158 {
159  int family = rsock_family_arg(vfamily);
160  int level = rsock_level_arg(family, vlevel);
161  int optname = rsock_optname_arg(family, level, voptname);
162  int i = NUM2INT(vint);
163  return rsock_sockopt_new(family, level, optname, rb_str_new((char*)&i, sizeof(i)));
164 }
165 
166 /*
167  * call-seq:
168  * sockopt.int => integer
169  *
170  * Returns the data in _sockopt_ as an int.
171  *
172  * The size and endian is dependent on the platform.
173  *
174  * sockopt = Socket::Option.int(:INET, :SOCKET, :KEEPALIVE, 1)
175  * p sockopt.int => 1
176  */
177 static VALUE
179 {
180  int i;
181  VALUE data = sockopt_data(self);
182  StringValue(data);
183  if (RSTRING_LEN(data) != sizeof(int))
184  rb_raise(rb_eTypeError, "size differ. expected as sizeof(int)=%d but %ld",
185  (int)sizeof(int), (long)RSTRING_LEN(data));
186  memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
187  return INT2NUM(i);
188 }
189 
190 /*
191  * call-seq:
192  * Socket::Option.bool(family, level, optname, bool) => sockopt
193  *
194  * Creates a new Socket::Option object which contains boolean as data.
195  * Actually 0 or 1 as int is used.
196  *
197  * p Socket::Option.bool(:INET, :SOCKET, :KEEPALIVE, true)
198  * #=> #<Socket::Option: INET SOCKET KEEPALIVE 1>
199  *
200  * p Socket::Option.bool(:INET, :SOCKET, :KEEPALIVE, false)
201  * #=> #<Socket::Option: AF_INET SOCKET KEEPALIVE 0>
202  *
203  */
204 static VALUE
205 sockopt_s_bool(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE vbool)
206 {
207  int family = rsock_family_arg(vfamily);
208  int level = rsock_level_arg(family, vlevel);
209  int optname = rsock_optname_arg(family, level, voptname);
210  int i = RTEST(vbool) ? 1 : 0;
211  return rsock_sockopt_new(family, level, optname, rb_str_new((char*)&i, sizeof(i)));
212 }
213 
214 /*
215  * call-seq:
216  * sockopt.bool => true or false
217  *
218  * Returns the data in _sockopt_ as an boolean value.
219  *
220  * sockopt = Socket::Option.int(:INET, :SOCKET, :KEEPALIVE, 1)
221  * p sockopt.bool => true
222  */
223 static VALUE
225 {
226  int i;
227  VALUE data = sockopt_data(self);
228  StringValue(data);
229  if (RSTRING_LEN(data) != sizeof(int))
230  rb_raise(rb_eTypeError, "size differ. expected as sizeof(int)=%d but %ld",
231  (int)sizeof(int), (long)RSTRING_LEN(data));
232  memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
233  return i == 0 ? Qfalse : Qtrue;
234 }
235 
236 /*
237  * call-seq:
238  * Socket::Option.linger(onoff, secs) => sockopt
239  *
240  * Creates a new Socket::Option object for SOL_SOCKET/SO_LINGER.
241  *
242  * _onoff_ should be an integer or a boolean.
243  *
244  * _secs_ should be the number of seconds.
245  *
246  * p Socket::Option.linger(true, 10)
247  * #=> #<Socket::Option: UNSPEC SOCKET LINGER on 10sec>
248  *
249  */
250 static VALUE
251 sockopt_s_linger(VALUE klass, VALUE vonoff, VALUE vsecs)
252 {
253  VALUE tmp;
254  struct linger l;
255  memset(&l, 0, sizeof(l));
256  if (!NIL_P(tmp = rb_check_to_integer(vonoff, "to_int")))
257  l.l_onoff = NUM2INT(tmp);
258  else
259  l.l_onoff = RTEST(vonoff) ? 1 : 0;
260  l.l_linger = NUM2INT(vsecs);
261  return rsock_sockopt_new(AF_UNSPEC, SOL_SOCKET, SO_LINGER, rb_str_new((char*)&l, sizeof(l)));
262 }
263 
264 /*
265  * call-seq:
266  * sockopt.linger => [bool, seconds]
267  *
268  * Returns the linger data in _sockopt_ as a pair of boolean and integer.
269  *
270  * sockopt = Socket::Option.linger(true, 10)
271  * p sockopt.linger => [true, 10]
272  */
273 static VALUE
275 {
276  int level = sockopt_level(self);
277  int optname = sockopt_optname(self);
278  VALUE data = sockopt_data(self);
279  struct linger l;
280  VALUE vonoff, vsecs;
281 
282  if (level != SOL_SOCKET || optname != SO_LINGER)
283  rb_raise(rb_eTypeError, "linger socket option expected");
284  if (RSTRING_LEN(data) != sizeof(l))
285  rb_raise(rb_eTypeError, "size differ. expected as sizeof(struct linger)=%d but %ld",
286  (int)sizeof(struct linger), (long)RSTRING_LEN(data));
287  memcpy((char*)&l, RSTRING_PTR(data), sizeof(struct linger));
288  switch (l.l_onoff) {
289  case 0: vonoff = Qfalse; break;
290  case 1: vonoff = Qtrue; break;
291  default: vonoff = INT2NUM(l.l_onoff); break;
292  }
293  vsecs = INT2NUM(l.l_linger);
294  return rb_assoc_new(vonoff, vsecs);
295 }
296 
297 static int
298 inspect_int(int level, int optname, VALUE data, VALUE ret)
299 {
300  if (RSTRING_LEN(data) == sizeof(int)) {
301  int i;
302  memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
303  rb_str_catf(ret, " %d", i);
304  return 1;
305  }
306  else {
307  return 0;
308  }
309 }
310 
311 static int
312 inspect_errno(int level, int optname, VALUE data, VALUE ret)
313 {
314  if (RSTRING_LEN(data) == sizeof(int)) {
315  int i;
316  char *err;
317  memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
318  err = strerror(i);
319  rb_str_catf(ret, " %s (%d)", err, i);
320  return 1;
321  }
322  else {
323  return 0;
324  }
325 }
326 
327 #if defined(IPV6_MULTICAST_LOOP)
328 static int
329 inspect_uint(int level, int optname, VALUE data, VALUE ret)
330 {
331  if (RSTRING_LEN(data) == sizeof(int)) {
332  unsigned int i;
333  memcpy((char*)&i, RSTRING_PTR(data), sizeof(unsigned int));
334  rb_str_catf(ret, " %u", i);
335  return 1;
336  }
337  else {
338  return 0;
339  }
340 }
341 #endif
342 
343 #if defined(SOL_SOCKET) && defined(SO_LINGER) /* POSIX */
344 static int
345 inspect_linger(int level, int optname, VALUE data, VALUE ret)
346 {
347  if (RSTRING_LEN(data) == sizeof(struct linger)) {
348  struct linger s;
349  memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
350  switch (s.l_onoff) {
351  case 0: rb_str_cat2(ret, " off"); break;
352  case 1: rb_str_cat2(ret, " on"); break;
353  default: rb_str_catf(ret, " on(%d)", s.l_onoff); break;
354  }
355  rb_str_catf(ret, " %dsec", s.l_linger);
356  return 1;
357  }
358  else {
359  return 0;
360  }
361 }
362 #endif
363 
364 #if defined(SOL_SOCKET) && defined(SO_TYPE) /* POSIX */
365 static int
366 inspect_socktype(int level, int optname, VALUE data, VALUE ret)
367 {
368  if (RSTRING_LEN(data) == sizeof(int)) {
369  int i;
370  ID id;
371  memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
372  id = rsock_intern_socktype(i);
373  if (id)
374  rb_str_catf(ret, " %s", rb_id2name(id));
375  else
376  rb_str_catf(ret, " %d", i);
377  return 1;
378  }
379  else {
380  return 0;
381  }
382 }
383 #endif
384 
385 static int
386 inspect_timeval_as_interval(int level, int optname, VALUE data, VALUE ret)
387 {
388  if (RSTRING_LEN(data) == sizeof(struct timeval)) {
389  struct timeval s;
390  memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
391  rb_str_catf(ret, " %ld.%06ldsec", (long)s.tv_sec, (long)s.tv_usec);
392  return 1;
393  }
394  else {
395  return 0;
396  }
397 }
398 
399 /*
400  * socket option for IPv4 multicast is bit confusing.
401  *
402  * IP Multicast is implemented by Steve Deering at first:
403  * IP Multicast Extensions for 4.3BSD UNIX and related systems
404  * (MULTICAST 1.2 Release)
405  * http://www.kohala.com/start/mcast.api.txt
406  *
407  * There are 3 socket options which takes a struct.
408  *
409  * IP_MULTICAST_IF: struct in_addr
410  * IP_ADD_MEMBERSHIP: struct ip_mreq
411  * IP_DROP_MEMBERSHIP: struct ip_mreq
412  *
413  * But they uses an IP address to specify an interface.
414  * This means the API cannot specify an unnumbered interface.
415  *
416  * Linux 2.4 introduces struct ip_mreqn to fix this problem.
417  * struct ip_mreqn has imr_ifindex field to specify interface index.
418  *
419  * IP_MULTICAST_IF: struct ip_mreqn
420  * IP_ADD_MEMBERSHIP: struct ip_mreqn
421  * IP_DROP_MEMBERSHIP: struct ip_mreqn
422  *
423  * FreeBSD 7 obtained struct ip_mreqn for IP_MULTICAST_IF.
424  * http://www.FreeBSD.org/cgi/cvsweb.cgi/src/sys/netinet/in.h.diff?r1=1.99;r2=1.100
425  *
426  * Another hackish workaround is "RFC 1724 hack".
427  * RFC 1724 section 3.3 suggests unnumbered interfaces
428  * specified by pseudo address 0.0.0.0/8.
429  * NetBSD 4 and FreeBSD 5 documented it.
430  * http://cvsweb.netbsd.org/cgi-bin/cvsweb.cgi/src/share/man/man4/ip.4.diff?r1=1.16&r2=1.17
431  * http://www.FreeBSD.org/cgi/cvsweb.cgi/src/share/man/man4/ip.4.diff?r1=1.37;r2=1.38
432  * FreeBSD 7.0 removed it.
433  * http://www.FreeBSD.org/cgi/cvsweb.cgi/src/share/man/man4/ip.4.diff?r1=1.49;r2=1.50
434  *
435  * RFC 1724 hack is not supported by Socket::Option#inspect because
436  * it is not distinguishable by the size.
437  */
438 
439 #ifndef HAVE_INET_NTOP
440 static char *
441 inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
442 {
443 #ifdef HAVE_INET_NTOA
444  struct in_addr in;
445  memcpy(&in.s_addr, addr, sizeof(in.s_addr));
446  snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in));
447 #else
448  unsigned long x = ntohl(*(unsigned long*)addr);
449  snprintf(numaddr, numaddr_len, "%d.%d.%d.%d",
450  (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
451  (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff);
452 #endif
453  return numaddr;
454 }
455 #endif
456 
457 /* Although the buffer size needed depends on the prefixes, "%u" may generate "4294967295". */
458 static int
459 rb_if_indextoname(const char *succ_prefix, const char *fail_prefix, unsigned int ifindex, char *buf, size_t len)
460 {
461 #if defined(HAVE_IF_INDEXTONAME)
462  char ifbuf[IFNAMSIZ];
463  if (if_indextoname(ifindex, ifbuf) == NULL)
464  return snprintf(buf, len, "%s%u", fail_prefix, ifindex);
465  else
466  return snprintf(buf, len, "%s%s", succ_prefix, ifbuf);
467 #else
468 # ifndef IFNAMSIZ
469 # define IFNAMSIZ (sizeof(unsigned int)*3+1)
470 # endif
471  return snprintf(buf, len, "%s%u", fail_prefix, ifindex);
472 #endif
473 }
474 
475 #if defined(IPPROTO_IP) && defined(HAVE_TYPE_STRUCT_IP_MREQ) /* 4.4BSD, GNU/Linux */
476 static int
477 inspect_ipv4_mreq(int level, int optname, VALUE data, VALUE ret)
478 {
479  if (RSTRING_LEN(data) == sizeof(struct ip_mreq)) {
480  struct ip_mreq s;
481  char addrbuf[INET_ADDRSTRLEN];
482  memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
483  if (inet_ntop(AF_INET, &s.imr_multiaddr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
484  rb_str_cat2(ret, " invalid-address");
485  else
486  rb_str_catf(ret, " %s", addrbuf);
487  if (inet_ntop(AF_INET, &s.imr_interface, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
488  rb_str_catf(ret, " invalid-address");
489  else
490  rb_str_catf(ret, " %s", addrbuf);
491  return 1;
492  }
493  else {
494  return 0;
495  }
496 }
497 #endif
498 
499 #if defined(IPPROTO_IP) && defined(HAVE_TYPE_STRUCT_IP_MREQN) /* GNU/Linux, FreeBSD 7 */
500 static int
501 inspect_ipv4_mreqn(int level, int optname, VALUE data, VALUE ret)
502 {
503  if (RSTRING_LEN(data) == sizeof(struct ip_mreqn)) {
504  struct ip_mreqn s;
505  char addrbuf[INET_ADDRSTRLEN], ifbuf[32+IFNAMSIZ];
506  memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
507  if (inet_ntop(AF_INET, &s.imr_multiaddr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
508  rb_str_cat2(ret, " invalid-address");
509  else
510  rb_str_catf(ret, " %s", addrbuf);
511  if (inet_ntop(AF_INET, &s.imr_address, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
512  rb_str_catf(ret, " invalid-address");
513  else
514  rb_str_catf(ret, " %s", addrbuf);
515  rb_if_indextoname(" ", " ifindex:", s.imr_ifindex, ifbuf, sizeof(ifbuf));
516  rb_str_cat2(ret, ifbuf);
517  return 1;
518  }
519  else {
520  return 0;
521  }
522 }
523 #endif
524 
525 #if defined(IPPROTO_IP) && defined(HAVE_TYPE_STRUCT_IP_MREQ) /* 4.4BSD, GNU/Linux */
526 static int
527 inspect_ipv4_add_drop_membership(int level, int optname, VALUE data, VALUE ret)
528 {
529  if (RSTRING_LEN(data) == sizeof(struct ip_mreq))
530  return inspect_ipv4_mreq(level, optname, data, ret);
531 # if defined(HAVE_TYPE_STRUCT_IP_MREQN)
532  else if (RSTRING_LEN(data) == sizeof(struct ip_mreqn))
533  return inspect_ipv4_mreqn(level, optname, data, ret);
534 # endif
535  else
536  return 0;
537 }
538 #endif
539 
540 #if defined(IPPROTO_IP) && defined(IP_MULTICAST_IF) && defined(HAVE_TYPE_STRUCT_IP_MREQN) /* 4.4BSD, GNU/Linux */
541 static int
542 inspect_ipv4_multicast_if(int level, int optname, VALUE data, VALUE ret)
543 {
544  if (RSTRING_LEN(data) == sizeof(struct in_addr)) {
545  struct in_addr s;
546  char addrbuf[INET_ADDRSTRLEN];
547  memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
548  if (inet_ntop(AF_INET, &s, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
549  rb_str_cat2(ret, " invalid-address");
550  else
551  rb_str_catf(ret, " %s", addrbuf);
552  return 1;
553  }
554  else if (RSTRING_LEN(data) == sizeof(struct ip_mreqn)) {
555  return inspect_ipv4_mreqn(level, optname, data, ret);
556  }
557  else {
558  return 0;
559  }
560 }
561 #endif
562 
563 #if defined(IPV6_MULTICAST_IF) /* POSIX, RFC 3493 */
564 static int
565 inspect_ipv6_multicast_if(int level, int optname, VALUE data, VALUE ret)
566 {
567  if (RSTRING_LEN(data) == sizeof(int)) {
568  char ifbuf[32+IFNAMSIZ];
569  unsigned int ifindex;
570  memcpy((char*)&ifindex, RSTRING_PTR(data), sizeof(unsigned int));
571  rb_if_indextoname(" ", " ", ifindex, ifbuf, sizeof(ifbuf));
572  rb_str_cat2(ret, ifbuf);
573  return 1;
574  }
575  else {
576  return 0;
577  }
578 }
579 #endif
580 
581 #if defined(IPPROTO_IPV6) && defined(HAVE_TYPE_STRUCT_IPV6_MREQ) /* POSIX, RFC 3493 */
582 static int
583 inspect_ipv6_mreq(int level, int optname, VALUE data, VALUE ret)
584 {
585  if (RSTRING_LEN(data) == sizeof(struct ipv6_mreq)) {
586  struct ipv6_mreq s;
587  char addrbuf[INET6_ADDRSTRLEN], ifbuf[32+IFNAMSIZ];
588  memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
589  if (inet_ntop(AF_INET6, &s.ipv6mr_multiaddr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
590  rb_str_cat2(ret, " invalid-address");
591  else
592  rb_str_catf(ret, " %s", addrbuf);
593  rb_if_indextoname(" ", " interface:", s.ipv6mr_interface, ifbuf, sizeof(ifbuf));
594  rb_str_cat2(ret, ifbuf);
595  return 1;
596  }
597  else {
598  return 0;
599  }
600 }
601 #endif
602 
603 #if defined(SOL_SOCKET) && defined(SO_PEERCRED) /* GNU/Linux, OpenBSD */
604 #if defined(__OpenBSD__)
605 #define RUBY_SOCK_PEERCRED struct sockpeercred
606 #else
607 #define RUBY_SOCK_PEERCRED struct ucred
608 #endif
609 static int
610 inspect_peercred(int level, int optname, VALUE data, VALUE ret)
611 {
612  if (RSTRING_LEN(data) == sizeof(RUBY_SOCK_PEERCRED)) {
613  RUBY_SOCK_PEERCRED cred;
614  memcpy(&cred, RSTRING_PTR(data), sizeof(RUBY_SOCK_PEERCRED));
615  rb_str_catf(ret, " pid=%u euid=%u egid=%u",
616  (unsigned)cred.pid, (unsigned)cred.uid, (unsigned)cred.gid);
617  rb_str_cat2(ret, " (ucred)");
618  return 1;
619  }
620  else {
621  return 0;
622  }
623 }
624 #endif
625 
626 #if defined(LOCAL_PEERCRED) /* FreeBSD, MacOS X */
627 static int
628 inspect_local_peercred(int level, int optname, VALUE data, VALUE ret)
629 {
630  if (RSTRING_LEN(data) == sizeof(struct xucred)) {
631  struct xucred cred;
632  memcpy(&cred, RSTRING_PTR(data), sizeof(struct xucred));
633  if (cred.cr_version != XUCRED_VERSION)
634  return 0;
635  rb_str_catf(ret, " version=%u", cred.cr_version);
636  rb_str_catf(ret, " euid=%u", cred.cr_uid);
637  if (cred.cr_ngroups) {
638  int i;
639  const char *sep = " groups=";
640  for (i = 0; i < cred.cr_ngroups; i++) {
641  rb_str_catf(ret, "%s%u", sep, cred.cr_groups[i]);
642  sep = ",";
643  }
644  }
645  rb_str_cat2(ret, " (xucred)");
646  return 1;
647  }
648  else {
649  return 0;
650  }
651 }
652 #endif
653 
654 
655 /*
656  * call-seq:
657  * sockopt.inspect => string
658  *
659  * Returns a string which shows sockopt in human-readable form.
660  *
661  * p Socket::Option.new(:INET, :SOCKET, :KEEPALIVE, [1].pack("i")).inspect
662  * #=> "#<Socket::Option: INET SOCKET KEEPALIVE 1>"
663  *
664  */
665 static VALUE
667 {
668  int family = NUM2INT(sockopt_family_m(self));
669  int level = NUM2INT(sockopt_level_m(self));
670  int optname = NUM2INT(sockopt_optname_m(self));
671  VALUE data = sockopt_data(self);
672  VALUE v, ret;
673  ID family_id, level_id, optname_id;
674  int inspected;
675 
676  StringValue(data);
677 
678  ret = rb_sprintf("#<%s:", rb_obj_classname(self));
679 
680  family_id = rsock_intern_family_noprefix(family);
681  if (family_id)
682  rb_str_catf(ret, " %s", rb_id2name(family_id));
683  else
684  rb_str_catf(ret, " family:%d", family);
685 
686  if (level == SOL_SOCKET) {
687  rb_str_cat2(ret, " SOCKET");
688 
689  optname_id = rsock_intern_so_optname(optname);
690  if (optname_id)
691  rb_str_catf(ret, " %s", rb_id2name(optname_id));
692  else
693  rb_str_catf(ret, " optname:%d", optname);
694  }
695 #ifdef HAVE_SYS_UN_H
696  else if (family == AF_UNIX) {
697  rb_str_catf(ret, " level:%d", level);
698 
699  optname_id = rsock_intern_local_optname(optname);
700  if (optname_id)
701  rb_str_catf(ret, " %s", rb_id2name(optname_id));
702  else
703  rb_str_catf(ret, " optname:%d", optname);
704  }
705 #endif
706  else if (IS_IP_FAMILY(family)) {
707  level_id = rsock_intern_iplevel(level);
708  if (level_id)
709  rb_str_catf(ret, " %s", rb_id2name(level_id));
710  else
711  rb_str_catf(ret, " level:%d", level);
712 
713  v = optname_to_sym(level, optname);
714  if (SYMBOL_P(v))
715  rb_str_catf(ret, " %s", rb_id2name(SYM2ID(v)));
716  else
717  rb_str_catf(ret, " optname:%d", optname);
718  }
719  else {
720  rb_str_catf(ret, " level:%d", level);
721  rb_str_catf(ret, " optname:%d", optname);
722  }
723 
724  inspected = 0;
725 
726  if (level == SOL_SOCKET)
727  family = AF_UNSPEC;
728  switch (family) {
729  case AF_UNSPEC:
730  switch (level) {
731  case SOL_SOCKET:
732  switch (optname) {
733 # if defined(SO_DEBUG) /* POSIX */
734  case SO_DEBUG: inspected = inspect_int(level, optname, data, ret); break;
735 # endif
736 # if defined(SO_ERROR) /* POSIX */
737  case SO_ERROR: inspected = inspect_errno(level, optname, data, ret); break;
738 # endif
739 # if defined(SO_TYPE) /* POSIX */
740  case SO_TYPE: inspected = inspect_socktype(level, optname, data, ret); break;
741 # endif
742 # if defined(SO_ACCEPTCONN) /* POSIX */
743  case SO_ACCEPTCONN: inspected = inspect_int(level, optname, data, ret); break;
744 # endif
745 # if defined(SO_BROADCAST) /* POSIX */
746  case SO_BROADCAST: inspected = inspect_int(level, optname, data, ret); break;
747 # endif
748 # if defined(SO_REUSEADDR) /* POSIX */
749  case SO_REUSEADDR: inspected = inspect_int(level, optname, data, ret); break;
750 # endif
751 # if defined(SO_KEEPALIVE) /* POSIX */
752  case SO_KEEPALIVE: inspected = inspect_int(level, optname, data, ret); break;
753 # endif
754 # if defined(SO_OOBINLINE) /* POSIX */
755  case SO_OOBINLINE: inspected = inspect_int(level, optname, data, ret); break;
756 # endif
757 # if defined(SO_SNDBUF) /* POSIX */
758  case SO_SNDBUF: inspected = inspect_int(level, optname, data, ret); break;
759 # endif
760 # if defined(SO_RCVBUF) /* POSIX */
761  case SO_RCVBUF: inspected = inspect_int(level, optname, data, ret); break;
762 # endif
763 # if defined(SO_DONTROUTE) /* POSIX */
764  case SO_DONTROUTE: inspected = inspect_int(level, optname, data, ret); break;
765 # endif
766 # if defined(SO_RCVLOWAT) /* POSIX */
767  case SO_RCVLOWAT: inspected = inspect_int(level, optname, data, ret); break;
768 # endif
769 # if defined(SO_SNDLOWAT) /* POSIX */
770  case SO_SNDLOWAT: inspected = inspect_int(level, optname, data, ret); break;
771 # endif
772 # if defined(SO_LINGER) /* POSIX */
773  case SO_LINGER: inspected = inspect_linger(level, optname, data, ret); break;
774 # endif
775 # if defined(SO_RCVTIMEO) /* POSIX */
776  case SO_RCVTIMEO: inspected = inspect_timeval_as_interval(level, optname, data, ret); break;
777 # endif
778 # if defined(SO_SNDTIMEO) /* POSIX */
779  case SO_SNDTIMEO: inspected = inspect_timeval_as_interval(level, optname, data, ret); break;
780 # endif
781 # if defined(SO_PEERCRED) /* GNU/Linux, OpenBSD */
782  case SO_PEERCRED: inspected = inspect_peercred(level, optname, data, ret); break;
783 # endif
784  }
785  break;
786  }
787  break;
788 
789  case AF_INET:
790 #ifdef INET6
791  case AF_INET6:
792 #endif
793  switch (level) {
794 # if defined(IPPROTO_IP)
795  case IPPROTO_IP:
796  switch (optname) {
797 # if defined(IP_MULTICAST_IF) && defined(HAVE_TYPE_STRUCT_IP_MREQN) /* 4.4BSD, GNU/Linux */
798  case IP_MULTICAST_IF: inspected = inspect_ipv4_multicast_if(level, optname, data, ret); break;
799 # endif
800 # if defined(IP_ADD_MEMBERSHIP) /* 4.4BSD, GNU/Linux */
801  case IP_ADD_MEMBERSHIP: inspected = inspect_ipv4_add_drop_membership(level, optname, data, ret); break;
802 # endif
803 # if defined(IP_DROP_MEMBERSHIP) /* 4.4BSD, GNU/Linux */
804  case IP_DROP_MEMBERSHIP: inspected = inspect_ipv4_add_drop_membership(level, optname, data, ret); break;
805 # endif
806  }
807  break;
808 # endif
809 
810 # if defined(IPPROTO_IPV6)
811  case IPPROTO_IPV6:
812  switch (optname) {
813 # if defined(IPV6_MULTICAST_HOPS) /* POSIX */
814  case IPV6_MULTICAST_HOPS: inspected = inspect_int(level, optname, data, ret); break;
815 # endif
816 # if defined(IPV6_MULTICAST_IF) /* POSIX */
817  case IPV6_MULTICAST_IF: inspected = inspect_ipv6_multicast_if(level, optname, data, ret); break;
818 # endif
819 # if defined(IPV6_MULTICAST_LOOP) /* POSIX */
820  case IPV6_MULTICAST_LOOP: inspected = inspect_uint(level, optname, data, ret); break;
821 # endif
822 # if defined(IPV6_JOIN_GROUP) /* POSIX */
823  case IPV6_JOIN_GROUP: inspected = inspect_ipv6_mreq(level, optname, data, ret); break;
824 # endif
825 # if defined(IPV6_LEAVE_GROUP) /* POSIX */
826  case IPV6_LEAVE_GROUP: inspected = inspect_ipv6_mreq(level, optname, data, ret); break;
827 # endif
828 # if defined(IPV6_UNICAST_HOPS) /* POSIX */
829  case IPV6_UNICAST_HOPS: inspected = inspect_int(level, optname, data, ret); break;
830 # endif
831 # if defined(IPV6_V6ONLY) /* POSIX */
832  case IPV6_V6ONLY: inspected = inspect_int(level, optname, data, ret); break;
833 # endif
834  }
835  break;
836 # endif
837 
838 # if defined(IPPROTO_TCP)
839  case IPPROTO_TCP:
840  switch (optname) {
841 # if defined(TCP_NODELAY) /* POSIX */
842  case TCP_NODELAY: inspected = inspect_int(level, optname, data, ret); break;
843 # endif
844  }
845  break;
846 # endif
847  }
848  break;
849 
850 #ifdef HAVE_SYS_UN_H
851  case AF_UNIX:
852  switch (level) {
853  case 0:
854  switch (optname) {
855 # if defined(LOCAL_PEERCRED)
856  case LOCAL_PEERCRED: inspected = inspect_local_peercred(level, optname, data, ret); break;
857 # endif
858  }
859  break;
860  }
861  break;
862 #endif
863  }
864 
865  if (!inspected) {
866  rb_str_cat2(ret, " ");
867  rb_str_append(ret, rb_str_dump(data));
868  }
869 
870  rb_str_cat2(ret, ">");
871 
872  return ret;
873 }
874 
875 /*
876  * call-seq:
877  * sockopt.unpack(template) => array
878  *
879  * Calls String#unpack on sockopt.data.
880  *
881  * sockopt = Socket::Option.new(:INET, :SOCKET, :KEEPALIVE, [1].pack("i"))
882  * p sockopt.unpack("i") #=> [1]
883  * p sockopt.data.unpack("i") #=> [1]
884  */
885 static VALUE
886 sockopt_unpack(VALUE self, VALUE template)
887 {
888  return rb_funcall(sockopt_data(self), rb_intern("unpack"), 1, template);
889 }
890 
891 void
893 {
894  /*
895  * Document-class: Socket::Option
896  *
897  * Socket::Option represents a socket option used by
898  * BasicSocket#getsockopt and BasicSocket#setsockopt. A socket option
899  * contains the socket #family, protocol #level, option name #optname and
900  * option value #data.
901  */
909 
912 
915 
918 
920 
921  rb_define_method(rb_cSockOpt, "to_s", sockopt_data, 0); /* compatibility for ruby before 1.9.2 */
922 }
923 
#define RSTRING_LEN(string)
Definition: generator.h:45
#define T_OBJECT
Definition: ruby.h:413
static VALUE sockopt_unpack(VALUE self, VALUE template)
Definition: option.c:886
int i
Definition: win32ole.c:776
static VALUE sockopt_family_m(VALUE self)
Definition: option.c:81
#define NUM2INT(x)
Definition: ruby.h:536
static VALUE sockopt_bool(VALUE self)
Definition: option.c:224
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1342
#define Qtrue
Definition: ruby.h:366
static int rb_if_indextoname(const char *succ_prefix, const char *fail_prefix, unsigned int ifindex, char *buf, size_t len)
Definition: option.c:459
const int id
Definition: nkf.c:209
static VALUE sockopt_inspect(VALUE self)
Definition: option.c:666
long tv_sec
Definition: ossl_asn1.c:17
VALUE rb_eTypeError
Definition: error.c:467
static VALUE optname_to_sym(int level, int optname)
Definition: option.c:17
static int inspect_timeval_as_interval(int level, int optname, VALUE data, VALUE ret)
Definition: option.c:386
static VALUE INT2NUM(int v)
Definition: ruby.h:981
static VALUE sockopt_linger(VALUE self)
Definition: option.c:274
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:638
#define RSTRING_PTR(string)
Definition: generator.h:42
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:514
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1574
VALUE rb_check_to_integer(VALUE, const char *)
Definition: object.c:2127
#define ID2SYM(i)
Definition: cparse.c:63
const char * rb_obj_classname(VALUE)
Definition: variable.c:318
static VALUE sockopt_level_m(VALUE self)
Definition: option.c:102
static VALUE sockopt_data(VALUE self)
Definition: option.c:138
int rsock_family_arg(VALUE domain)
Definition: constants.c:43
VALUE rsock_sockopt_new(int family, int level, int optname, VALUE data)
Definition: option.c:62
long tv_usec
Definition: ossl_asn1.c:18
static VALUE sockopt_initialize(VALUE self, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE data)
Definition: option.c:48
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1246
#define SYM2ID(v)
Definition: cparse.c:66
static int inspect_errno(int level, int optname, VALUE data, VALUE ret)
Definition: option.c:312
static VALUE sockopt_s_bool(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE vbool)
Definition: option.c:205
VALUE rb_str_cat2(VALUE, const char *)
Definition: string.c:1900
#define snprintf
Definition: subst.h:6
#define NIL_P(v)
Definition: ruby.h:374
int rsock_level_arg(int family, VALUE level)
Definition: constants.c:57
#define NEWOBJ(obj, type)
Definition: ruby.h:580
#define Qfalse
Definition: ruby.h:365
static char * inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
Definition: option.c:441
int err
Definition: win32.c:78
VALUE rb_cSocket
Definition: init.c:22
static VALUE constant_to_sym(int constant, ID(*intern_const)(int))
Definition: option.c:6
#define IS_IP_FAMILY(af)
Definition: rubysocket.h:116
static int sockopt_optname(VALUE self)
Definition: option.c:108
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1203
VALUE rb_ivar_set(VALUE, ID, VALUE)
Definition: variable.c:1038
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:3913
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:460
unsigned long ID
Definition: ruby.h:89
#define NULL
unsigned long VALUE
Definition: ruby.h:88
register unsigned int len
Definition: name2ctype.h:22210
VALUE rb_str_dump(VALUE)
Definition: string.c:4522
static VALUE sockopt_optname_m(VALUE self)
Definition: option.c:123
#define SYMBOL_P(v)
Definition: cparse.c:69
static int inspect_int(int level, int optname, VALUE data, VALUE ret)
Definition: option.c:298
static VALUE sockopt_int(VALUE self)
Definition: option.c:178
static VALUE sockopt_s_int(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE vint)
Definition: option.c:157
VALUE rb_str_catf(VALUE str, const char *format,...)
Definition: sprintf.c:1239
RUBY_EXTERN char * strerror(int)
Definition: strerror.c:11
#define RTEST(v)
Definition: ruby.h:373
#define AF_UNSPEC
Definition: sockport.h:69
static VALUE sockopt_s_linger(VALUE klass, VALUE vonoff, VALUE vsecs)
Definition: option.c:251
v
Definition: win32ole.c:790
int rsock_optname_arg(int family, int level, VALUE optname)
Definition: constants.c:69
VALUE rb_cSockOpt
Definition: option.c:3
const char * name
Definition: nkf.c:208
const char * rb_id2name(ID id)
Definition: ripper.c:15493
static int sockopt_level(VALUE self)
Definition: option.c:87
Definition: ruby.h:602
#define IFNAMSIZ
void rsock_init_sockopt(void)
Definition: option.c:892
#define rb_intern(str)
#define OBJSETUP(obj, c, t)
Definition: ruby.h:581
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1209
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:2039
VALUE rb_attr_get(VALUE, ID)
Definition: variable.c:1032
#define StringValue(v)
Definition: ruby.h:466
VALUE rb_str_new(const char *, long)
Definition: string.c:410