Extended maintenance of Ruby 1.9.3 ended on February 23, 2015. Read more
Socket::Option represents a socket option used by BasicSocket#getsockopt and BasicSocket#setsockopt. A socket option contains the socket family, protocol level, option name optname and option value data.
Creates a new Socket::Option object which contains boolean as data. Actually 0 or 1 as int is used.
p Socket::Option.bool(:INET, :SOCKET, :KEEPALIVE, true) #=> #<Socket::Option: INET SOCKET KEEPALIVE 1> p Socket::Option.bool(:INET, :SOCKET, :KEEPALIVE, false) #=> #<Socket::Option: AF_INET SOCKET KEEPALIVE 0>
static VALUE sockopt_s_bool(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE vbool) { int family = rsock_family_arg(vfamily); int level = rsock_level_arg(family, vlevel); int optname = rsock_optname_arg(family, level, voptname); int i = RTEST(vbool) ? 1 : 0; return rsock_sockopt_new(family, level, optname, rb_str_new((char*)&i, sizeof(i))); }
Creates a new Socket::Option object which contains an int as data.
The size and endian is dependent on the platform.
p Socket::Option.int(:INET, :SOCKET, :KEEPALIVE, 1) #=> #<Socket::Option: INET SOCKET KEEPALIVE 1>
static VALUE sockopt_s_int(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE vint) { int family = rsock_family_arg(vfamily); int level = rsock_level_arg(family, vlevel); int optname = rsock_optname_arg(family, level, voptname); int i = NUM2INT(vint); return rsock_sockopt_new(family, level, optname, rb_str_new((char*)&i, sizeof(i))); }
Creates a new Socket::Option object for SOL_SOCKET/SO_LINGER.
onoff should be an integer or a boolean.
secs should be the number of seconds.
p Socket::Option.linger(true, 10) #=> #<Socket::Option: UNSPEC SOCKET LINGER on 10sec>
static VALUE sockopt_s_linger(VALUE klass, VALUE vonoff, VALUE vsecs) { VALUE tmp; struct linger l; memset(&l, 0, sizeof(l)); if (!NIL_P(tmp = rb_check_to_integer(vonoff, "to_int"))) l.l_onoff = NUM2INT(tmp); else l.l_onoff = RTEST(vonoff) ? 1 : 0; l.l_linger = NUM2INT(vsecs); return rsock_sockopt_new(AF_UNSPEC, SOL_SOCKET, SO_LINGER, rb_str_new((char*)&l, sizeof(l))); }
Returns a new Socket::Option object.
sockopt = Socket::Option.new(:INET, :SOCKET, :KEEPALIVE, [1].pack("i")) p sockopt #=> #<Socket::Option: INET SOCKET KEEPALIVE 1>
static VALUE sockopt_initialize(VALUE self, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE data) { int family = rsock_family_arg(vfamily); int level = rsock_level_arg(family, vlevel); int optname = rsock_optname_arg(family, level, voptname); StringValue(data); rb_ivar_set(self, rb_intern("family"), INT2NUM(family)); rb_ivar_set(self, rb_intern("level"), INT2NUM(level)); rb_ivar_set(self, rb_intern("optname"), INT2NUM(optname)); rb_ivar_set(self, rb_intern("data"), data); return self; }
Returns the data in sockopt as an boolean value.
sockopt = Socket::Option.int(:INET, :SOCKET, :KEEPALIVE, 1) p sockopt.bool => true
static VALUE sockopt_bool(VALUE self) { int i; VALUE data = sockopt_data(self); StringValue(data); if (RSTRING_LEN(data) != sizeof(int)) rb_raise(rb_eTypeError, "size differ. expected as sizeof(int)=%d but %ld", (int)sizeof(int), (long)RSTRING_LEN(data)); memcpy((char*)&i, RSTRING_PTR(data), sizeof(int)); return i == 0 ? Qfalse : Qtrue; }
returns the socket option data as a string.
p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).data #=> "\x01\x00\x00\x00"
static VALUE sockopt_data(VALUE self) { VALUE v = rb_attr_get(self, rb_intern("data")); StringValue(v); return v; }
returns the socket family as an integer.
p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).family #=> 10
static VALUE sockopt_family_m(VALUE self) { return rb_attr_get(self, rb_intern("family")); }
Returns a string which shows sockopt in human-readable form.
p Socket::Option.new(:INET, :SOCKET, :KEEPALIVE, [1].pack("i")).inspect #=> "#<Socket::Option: INET SOCKET KEEPALIVE 1>"
static VALUE sockopt_inspect(VALUE self) { int family = NUM2INT(sockopt_family_m(self)); int level = NUM2INT(sockopt_level_m(self)); int optname = NUM2INT(sockopt_optname_m(self)); VALUE data = sockopt_data(self); VALUE v, ret; ID family_id, level_id, optname_id; int inspected; StringValue(data); ret = rb_sprintf("#<%s:", rb_obj_classname(self)); family_id = rsock_intern_family_noprefix(family); if (family_id) rb_str_catf(ret, " %s", rb_id2name(family_id)); else rb_str_catf(ret, " family:%d", family); if (level == SOL_SOCKET) { rb_str_cat2(ret, " SOCKET"); optname_id = rsock_intern_so_optname(optname); if (optname_id) rb_str_catf(ret, " %s", rb_id2name(optname_id)); else rb_str_catf(ret, " optname:%d", optname); } #ifdef HAVE_SYS_UN_H else if (family == AF_UNIX) { rb_str_catf(ret, " level:%d", level); optname_id = rsock_intern_local_optname(optname); if (optname_id) rb_str_catf(ret, " %s", rb_id2name(optname_id)); else rb_str_catf(ret, " optname:%d", optname); } #endif else if (IS_IP_FAMILY(family)) { level_id = rsock_intern_iplevel(level); if (level_id) rb_str_catf(ret, " %s", rb_id2name(level_id)); else rb_str_catf(ret, " level:%d", level); v = optname_to_sym(level, optname); if (SYMBOL_P(v)) rb_str_catf(ret, " %s", rb_id2name(SYM2ID(v))); else rb_str_catf(ret, " optname:%d", optname); } else { rb_str_catf(ret, " level:%d", level); rb_str_catf(ret, " optname:%d", optname); } inspected = 0; if (level == SOL_SOCKET) family = AF_UNSPEC; switch (family) { case AF_UNSPEC: switch (level) { case SOL_SOCKET: switch (optname) { # if defined(SO_DEBUG) /* POSIX */ case SO_DEBUG: inspected = inspect_int(level, optname, data, ret); break; # endif # if defined(SO_ERROR) /* POSIX */ case SO_ERROR: inspected = inspect_errno(level, optname, data, ret); break; # endif # if defined(SO_TYPE) /* POSIX */ case SO_TYPE: inspected = inspect_socktype(level, optname, data, ret); break; # endif # if defined(SO_ACCEPTCONN) /* POSIX */ case SO_ACCEPTCONN: inspected = inspect_int(level, optname, data, ret); break; # endif # if defined(SO_BROADCAST) /* POSIX */ case SO_BROADCAST: inspected = inspect_int(level, optname, data, ret); break; # endif # if defined(SO_REUSEADDR) /* POSIX */ case SO_REUSEADDR: inspected = inspect_int(level, optname, data, ret); break; # endif # if defined(SO_KEEPALIVE) /* POSIX */ case SO_KEEPALIVE: inspected = inspect_int(level, optname, data, ret); break; # endif # if defined(SO_OOBINLINE) /* POSIX */ case SO_OOBINLINE: inspected = inspect_int(level, optname, data, ret); break; # endif # if defined(SO_SNDBUF) /* POSIX */ case SO_SNDBUF: inspected = inspect_int(level, optname, data, ret); break; # endif # if defined(SO_RCVBUF) /* POSIX */ case SO_RCVBUF: inspected = inspect_int(level, optname, data, ret); break; # endif # if defined(SO_DONTROUTE) /* POSIX */ case SO_DONTROUTE: inspected = inspect_int(level, optname, data, ret); break; # endif # if defined(SO_RCVLOWAT) /* POSIX */ case SO_RCVLOWAT: inspected = inspect_int(level, optname, data, ret); break; # endif # if defined(SO_SNDLOWAT) /* POSIX */ case SO_SNDLOWAT: inspected = inspect_int(level, optname, data, ret); break; # endif # if defined(SO_LINGER) /* POSIX */ case SO_LINGER: inspected = inspect_linger(level, optname, data, ret); break; # endif # if defined(SO_RCVTIMEO) /* POSIX */ case SO_RCVTIMEO: inspected = inspect_timeval_as_interval(level, optname, data, ret); break; # endif # if defined(SO_SNDTIMEO) /* POSIX */ case SO_SNDTIMEO: inspected = inspect_timeval_as_interval(level, optname, data, ret); break; # endif # if defined(SO_PEERCRED) /* GNU/Linux, OpenBSD */ case SO_PEERCRED: inspected = inspect_peercred(level, optname, data, ret); break; # endif } break; } break; case AF_INET: #ifdef INET6 case AF_INET6: #endif switch (level) { # if defined(IPPROTO_IP) case IPPROTO_IP: switch (optname) { # if defined(IP_MULTICAST_IF) && defined(HAVE_TYPE_STRUCT_IP_MREQN) /* 4.4BSD, GNU/Linux */ case IP_MULTICAST_IF: inspected = inspect_ipv4_multicast_if(level, optname, data, ret); break; # endif # if defined(IP_ADD_MEMBERSHIP) /* 4.4BSD, GNU/Linux */ case IP_ADD_MEMBERSHIP: inspected = inspect_ipv4_add_drop_membership(level, optname, data, ret); break; # endif # if defined(IP_DROP_MEMBERSHIP) /* 4.4BSD, GNU/Linux */ case IP_DROP_MEMBERSHIP: inspected = inspect_ipv4_add_drop_membership(level, optname, data, ret); break; # endif } break; # endif # if defined(IPPROTO_IPV6) case IPPROTO_IPV6: switch (optname) { # if defined(IPV6_MULTICAST_HOPS) /* POSIX */ case IPV6_MULTICAST_HOPS: inspected = inspect_int(level, optname, data, ret); break; # endif # if defined(IPV6_MULTICAST_IF) /* POSIX */ case IPV6_MULTICAST_IF: inspected = inspect_ipv6_multicast_if(level, optname, data, ret); break; # endif # if defined(IPV6_MULTICAST_LOOP) /* POSIX */ case IPV6_MULTICAST_LOOP: inspected = inspect_uint(level, optname, data, ret); break; # endif # if defined(IPV6_JOIN_GROUP) /* POSIX */ case IPV6_JOIN_GROUP: inspected = inspect_ipv6_mreq(level, optname, data, ret); break; # endif # if defined(IPV6_LEAVE_GROUP) /* POSIX */ case IPV6_LEAVE_GROUP: inspected = inspect_ipv6_mreq(level, optname, data, ret); break; # endif # if defined(IPV6_UNICAST_HOPS) /* POSIX */ case IPV6_UNICAST_HOPS: inspected = inspect_int(level, optname, data, ret); break; # endif # if defined(IPV6_V6ONLY) /* POSIX */ case IPV6_V6ONLY: inspected = inspect_int(level, optname, data, ret); break; # endif } break; # endif # if defined(IPPROTO_TCP) case IPPROTO_TCP: switch (optname) { # if defined(TCP_NODELAY) /* POSIX */ case TCP_NODELAY: inspected = inspect_int(level, optname, data, ret); break; # endif } break; # endif } break; #ifdef HAVE_SYS_UN_H case AF_UNIX: switch (level) { case 0: switch (optname) { # if defined(LOCAL_PEERCRED) case LOCAL_PEERCRED: inspected = inspect_local_peercred(level, optname, data, ret); break; # endif } break; } break; #endif } if (!inspected) { rb_str_cat2(ret, " "); rb_str_append(ret, rb_str_dump(data)); } rb_str_cat2(ret, ">"); return ret; }
Returns the data in sockopt as an int.
The size and endian is dependent on the platform.
sockopt = Socket::Option.int(:INET, :SOCKET, :KEEPALIVE, 1) p sockopt.int => 1
static VALUE sockopt_int(VALUE self) { int i; VALUE data = sockopt_data(self); StringValue(data); if (RSTRING_LEN(data) != sizeof(int)) rb_raise(rb_eTypeError, "size differ. expected as sizeof(int)=%d but %ld", (int)sizeof(int), (long)RSTRING_LEN(data)); memcpy((char*)&i, RSTRING_PTR(data), sizeof(int)); return INT2NUM(i); }
returns the socket level as an integer.
p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).level #=> 41
static VALUE sockopt_level_m(VALUE self) { return INT2NUM(sockopt_level(self)); }
Returns the linger data in sockopt as a pair of boolean and integer.
sockopt = Socket::Option.linger(true, 10) p sockopt.linger => [true, 10]
static VALUE sockopt_linger(VALUE self) { int level = sockopt_level(self); int optname = sockopt_optname(self); VALUE data = sockopt_data(self); struct linger l; VALUE vonoff, vsecs; if (level != SOL_SOCKET || optname != SO_LINGER) rb_raise(rb_eTypeError, "linger socket option expected"); if (RSTRING_LEN(data) != sizeof(l)) rb_raise(rb_eTypeError, "size differ. expected as sizeof(struct linger)=%d but %ld", (int)sizeof(struct linger), (long)RSTRING_LEN(data)); memcpy((char*)&l, RSTRING_PTR(data), sizeof(struct linger)); switch (l.l_onoff) { case 0: vonoff = Qfalse; break; case 1: vonoff = Qtrue; break; default: vonoff = INT2NUM(l.l_onoff); break; } vsecs = INT2NUM(l.l_linger); return rb_assoc_new(vonoff, vsecs); }
returns the socket option name as an integer.
p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).optname #=> 2
static VALUE sockopt_optname_m(VALUE self) { return INT2NUM(sockopt_optname(self)); }
returns the socket option data as a string.
p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).data #=> "\x01\x00\x00\x00"
static VALUE sockopt_data(VALUE self) { VALUE v = rb_attr_get(self, rb_intern("data")); StringValue(v); return v; }
Calls String#unpack on sockopt.data.
sockopt = Socket::Option.new(:INET, :SOCKET, :KEEPALIVE, [1].pack("i")) p sockopt.unpack("i") #=> [1] p sockopt.data.unpack("i") #=> [1]
static VALUE sockopt_unpack(VALUE self, VALUE template) { return rb_funcall(sockopt_data(self), rb_intern("unpack"), 1, template); }
Commenting is here to help enhance the documentation. For example, code samples, or clarification of the documentation.
If you have questions about Ruby or the documentation, please post to one of the Ruby mailing lists. You will get better, faster, help that way.
If you wish to post a correction of the docs, please do so, but also file bug report so that it can be corrected for the next release. Thank you.
If you want to help improve the Ruby documentation, please visit Documenting-ruby.org.