# Socket::Option

e\$BDs0F\$J\$s\$G\$9\$,!"e(BSocket::Option e\$B%/%i%9\$r:n\$C\$F!"e(B
BasicSocket#getsockopt e\$B\$,e(B Socket::Option
e\$B%\$%s%9%?%s%9\$rJV\$7!"e(B
BasicSocket#setsockopt e\$B\$,e(B Socket::Option e\$B%\$%s%9%?%s%9\$r<u\$1e(B
e\$BIU\$1\$k\$h\$&\$K\$9\$k\$N\$O\$I\$&\$G\$7\$g\$&\$+!#e(B

e\$B8=:_!“e(Bgetsockopt e\$B\$O%P%\$%J%j\$Ne(B string
e\$B\$rJV\$7\$^\$9\$,!”\$3\$l\$O\$oe(B
e\$B\$+\$j\$d\$9\$\$\$b\$N\$H\$O\$\$\$(\$^\$;\$s!#e(B

e\$B\$?\$H\$(\$P!"0J2<\$NNc\$O!“e(BSOL_SOCKET e\$B\$Ne(B SO_TYPE
e\$B\$H\$\$\$&\$N\$rLd\$\$9ge(B
e\$B\$o\$;\$?\$b\$N\$G\$9\$,!“e(B”\x02\x00\x00\x00” e\$B\$H\$\$\$&7k2L\$,2?\$r0UL#\$7e(B
e\$B\$F\$\$\$k\$+\$O\$h\$/\$o\$+\$j\$^\$;\$s!#e(B

% ruby -rsocket -e ’
s = Socket.new(Socket::PF_INET, Socket::SOCK_DGRAM, 0)
p s.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE)’
“\x02\x00\x00\x00”

e\$B\$3\$3\$G!"e(Bgetsockopt e\$B\$,e(B string
e\$B\$G\$J\$/!“FH<+\$N%/%i%9\$N%%V%8%'e(B
e\$B%/%H\$rJV\$9\$3\$H\$K\$9\$l\$P!“e(B(e\$B\$”\$He(B SOL_SOCKET e\$B\$He(B SO_TYPE
e\$B\$H\$\$\$&\$Ne(B
e\$B\$r%
%V%8%’%/%H\$K5-O?\$7\$F\$*\$1\$Pe(B) inspect e\$B\$rE,@Z\$K<BAu\$9\$k\$3\$He(B
e\$B\$K\$h\$j!”\$o\$+\$j\$d\$9\$/I=<(\$9\$k\$3\$H\$,\$G\$-\$^\$9!#\$3\$N>l9g\$O!"e(B
SOCK_DGRAM e\$B\$H\$\$\$&L>A0\$rI=<(\$G\$-\$^\$9!#e(B

% ./ruby -rsocket -e ’
s = Socket.new(Socket::PF_INET, Socket::SOCK_DGRAM, 0)
p s.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE)’
#<Socket::Option: SOCKET TYPE SOCK_DGRAM>

e\$B\$^\$?!“e(Binspect e\$B\$@\$1\$G\$J\$/!”%G!<%?\$NCf?H\$r<h\$j=P\$9%a%=%C%I\$b\$De(B
e\$B\$1\$i\$l\$^\$9!#e(B

e\$B>e5-\$Ne(B “\x02\x00\x00\x00” e\$B\$Oe(B SOCK_DGRAM
e\$B\$G\$9\$,!"\$=\$NCM\$r<h\$je(B
e\$B=P\$9\$K\$O!"e(Bsockopt.unpack(“i”)[0] e\$B\$H\$7\$J\$\$\$H\$\$\$1\$^\$;\$s!#e(B
Socket::Option#int e\$B\$K\$h\$j!"e(Bsockopt.int e\$B\$G:Q\$^\$;\$i\$l\$^\$9!#e(B

e\$B\$^\$?!"@8@.\$9\$k\$[\$&\$b4JC1\$K\$J\$j\$^\$9!#e(B
e\$B>e5-\$N\$h\$&\$Je(B int e\$B\$N\$b\$N\$G\$"\$l\$P!“e(B[opt].pack(“i”)
e\$B\$G:Q\$`\$N\$Ge(B
e\$B\$=\$s\$J\$KBgJQ\$G\$O\$”\$j\$^\$;\$s\$,!"%=%1%C%H%*%W%7%g%s\$OI,\$:\$7\$be(B
int e\$B\$P\$+\$j\$G\$O\$"\$j\$^\$;\$s!#e(B

SO_LINGER e\$B\$@\$H9=B\$BN\$G!“Cf\$Ke(B int e\$B\$,\$U\$?\$DJB\$s\$G\$\$\$^\$9!#5,3Je(B
e\$B\$O=gHV\$^\$G\$O7h\$a\$F\$/\$l\$F\$\$\$J\$\$\$N\$G!”=gHV\$r\$I\$&\$9\$k\$+\$O%W%i%Ce(B
e\$B%H%U%)!<%`0MB8\$K\$J\$j\$^\$9!#e(B

SO_SNDTIMEO e\$B\$de(B SO_RCVTIMEO e\$B\$Oe(B struct timeval e\$B\$G!"Cf\$Ke(B
time_t
e\$B\$,F~\$C\$F\$\$\$^\$9\$,!"e(Btime_t e\$B\$N%5%\$%:\$O%W%i%C%H%U%)!<%`\$K0MB8\$7e(B
e\$B\$^\$9!#e(B

e\$B%^%k%A%-%c%9%H4X78\$H\$+\$G\$Oe(B IP e\$B%"%I%l%9\$rF~\$l\$J\$\$\$H\$\$\$1\$J\$\$\$3e(B
e\$B\$H\$b\$"\$j\$^\$9!#e(B

e\$B\$3\$&\$\$\$&9=B\$BN\$N07\$\$\$O!"\$d\$O\$je(B C e\$B\$G=q\$\$\$?\$[\$&\$,3N<B\$G!“e(B
Socket::Option.linger e\$B\$H\$+!”%/%i%9%a%=%C%I\$H\$7\$F@8@.%a%=%C%Ie(B
e\$B\$r:n\$j!“e(Bsetsockopt e\$B\$KEO\$;\$l\$P4JC1\$G\$9!#e(B
(e\$B\$H\$j\$”\$(\$:8=;~E@\$G\$Oe(B Socket::Option.int e\$B\$7\$+:n\$C\$F\$^\$;\$s\$,e(B)

BasicSocket#getsockopt e\$B\$OJV\$9CM\$,JQ\$o\$k\$N\$GHs8_49\$K\$J\$j\$^\$9e(B
e\$B\$,!“BP:v\$H\$7\$Fe(B SocketOption#unpack e\$B\$r<BAu\$7\$F\$”\$j\$^\$9!#\$D\$^e(B
e\$B\$j!“e(Bunpack e\$B\$r8F\$S=P\$98B\$j\$O8_49\$G!”\$1\$C\$3\$&5_\$(\$k\$s\$8\$c\$J\$\$e(B
e\$B\$+\$H;W\$C\$F\$^\$9!#\$^\$?!"\$=\$l\$G\$O:Q\$^\$J\$\$\$H\$-\$K\$O!"e(B
Socket::Option#data e\$B%a%=%C%I\$Ge(B string e\$B\$J0JA0\$NCM\$,<h\$j=P\$;\$^e(B
e\$B\$9!#e(B

e\$B\$H\$\$\$&\$o\$1\$G\$I\$&\$G\$7\$g\$&\$+!#e(B

# — ext/.document (revision 21646) +++ ext/.document (working copy) @@ -20,6 +20,7 @@ socket/udpsocket.c socket/unixsocket.c socket/unixserver.c socket/socket.c +socket/option.c socket/constants.c socket/lib/socket.rb stringio/stringio.c Index: ext/socket/rubysocket.h

— ext/socket/rubysocket.h (revision 21646)
+++ ext/socket/rubysocket.h (working copy)
@@ -135,6 +135,7 @@ extern VALUE rb_cUNIXServer;
#endif
extern VALUE rb_cSocket;
+extern VALUE rb_cSockOpt;

extern VALUE rb_eSocket;

@@ -214,6 +215,8 @@ VALUE sock_listen(VALUE sock, VALUE log)
socklen_t *len);
VALUE s_accept_nonblock(VALUE klass, rb_io_t *fptr, struct sockaddr

+VALUE sockopt_new(int level, int optname, VALUE data);
+
void Init_basicsocket(void);
void Init_ipsocket(void);
void Init_tcpsocket(void);
@@ -224,6 +227,7 @@ void Init_unixsocket(void);
void Init_unixserver(void);
void Init_socket_constants(void);
+void Init_sockopt(void);
void Init_socket_init(void);

# #endif Index: ext/socket/init.c

— ext/socket/init.c (revision 21646)
+++ ext/socket/init.c (working copy)
@@ -510,6 +510,7 @@ Init_socket_init()
Init_udpsocket();
Init_unixsocket();
Init_unixserver();

• Init_sockopt();
Init_socket_constants();
}
Index: ext/socket/option.c
===================================================================
— ext/socket/option.c (revision 0)
+++ ext/socket/option.c (revision 0)
@@ -0,0 +1,373 @@
+#include “rubysocket.h”

+VALUE rb_cSockOpt;
+
+static VALUE
+constant_to_sym(int constant, ID (*intern_const)(int))
+{

• ID name = intern_const(constant);
• if (name) {
• ``````   return ID2SYM(name);
``````
• }
• return INT2NUM(constant);
+}

+static VALUE
+optname_to_sym(int level, int optname)
+{

• switch (level) {
• `````` case SOL_SOCKET:
``````
• ``````   return constant_to_sym(optname, intern_so_optname);
``````
• `````` case IPPROTO_IP:
``````
• ``````   return constant_to_sym(optname, intern_ip_optname);
``````
• `````` case IPPROTO_IPV6:
``````
• ``````   return constant_to_sym(optname, intern_ipv6_optname);
``````
• `````` case IPPROTO_TCP:
``````
• ``````   return constant_to_sym(optname, intern_tcp_optname);
``````
• `````` case IPPROTO_UDP:
``````
• ``````   return constant_to_sym(optname, intern_udp_optname);
``````
• `````` default:
``````
• ``````   return INT2NUM(optname);
``````
• }
+}

+static VALUE
+sockopt_initialize(VALUE self, VALUE vlevel, VALUE voptname, VALUE
data)
+{

• int level;
• StringValue(data);
• level = level_arg(vlevel);
• rb_ivar_set(self, rb_intern(“level”), INT2NUM(level));
• rb_ivar_set(self, rb_intern(“optname”), INT2NUM(optname_arg(level,
voptname)));
• rb_ivar_set(self, rb_intern(“data”), data);
• return self;
+}

+VALUE
+sockopt_new(int level, int optname, VALUE data)
+{

• NEWOBJ(obj, struct RObject);
• OBJSETUP(obj, rb_cSockOpt, T_OBJECT);
• StringValue(data);
• sockopt_initialize((VALUE)obj, INT2NUM(level), INT2NUM(optname),
data);
• return (VALUE)obj;
+}

+/*

• call-seq:
• sockopt.level => integer
• returns the socket level as an integer.
• p Socket::Option.new(:IPV6, :RECVPKTINFO, [1].pack(“i!”)).level
• */
+static VALUE
+sockopt_level(VALUE self)
+{
• return rb_attr_get(self, rb_intern(“level”));
+}

+/*

• call-seq:
• sockopt.optname => integer
• returns the socket option name as an integer.
• p Socket::Option.new(:IPV6, :RECVPKTINFO, [1].pack(“i!”)).optname
• */
+static VALUE
+sockopt_optname(VALUE self)
+{
• return rb_attr_get(self, rb_intern(“optname”));
+}

+/*

• call-seq:
• sockopt.data => string
• returns the socket option data as a string.
• p Socket::Option.new(:IPV6, :PKTINFO, [1].pack(“i!”)).data
• */
+static VALUE
+sockopt_data(VALUE self)
+{
• return rb_attr_get(self, rb_intern(“data”));
+}

+/*

• call-seq:
• Socket::Option.int(level, optname, integer) => sockopt
• Creates a new Socket::Option object which contains an int as data.
• The size and endian is dependent on the host.
• p Socket::Option.int(:SOCKET, :KEEPALIVE, 1)
• #=> #<Socket::Option: SOCKET KEEPALIVE 1>
• */
+static VALUE
+sockopt_s_int(VALUE klass, VALUE vlevel, VALUE voptname, VALUE vint)
+{
• int level = level_arg(vlevel);
• int optname = optname_arg(level, voptname);
• int i = NUM2INT(vint);
• return sockopt_new(level, optname, rb_str_new((char*)&i,
sizeof(i)));
+}

+/*

• call-seq:
• sockopt.int => integer
• Returns the data in sockopt as an int.
• The size and endian is dependent on the host.
• sockopt = Socket::Option.int(: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);
+}

+static int
+inspect_int(int level, int optname, VALUE data, VALUE ret)
+{

• if (RSTRING_LEN(data) == sizeof(int)) {
• ``````   int i;
``````
• ``````   memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
``````
• ``````   rb_str_catf(ret, " %d", i);
``````
• ``````   return 0;
``````
• }
• else {
• ``````   return -1;
``````
• }
+}

+static int
+inspect_uint(int level, int optname, VALUE data, VALUE ret)
+{

• if (RSTRING_LEN(data) == sizeof(int)) {
• ``````   unsigned int i;
``````
• ``````   memcpy((char*)&i, RSTRING_PTR(data), sizeof(unsigned int));
``````
• ``````   rb_str_catf(ret, " %u", i);
``````
• ``````   return 0;
``````
• }
• else {
• ``````   return -1;
``````
• }
+}

+#if defined(SOL_SOCKET) && defined(SO_LINGER) /* POSIX */
+static int
+inspect_linger(int level, int optname, VALUE data, VALUE ret)
+{

• if (RSTRING_LEN(data) == sizeof(struct linger)) {
• ``````   struct linger s;
``````
• ``````   memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
``````
• ``````   rb_str_catf(ret, " onoff:%d linger:%d", s.l_onoff, s.l_linger);
``````
• ``````   return 0;
``````
• }
• else {
• ``````   return -1;
``````
• }
+}
+#endif

+#if defined(SOL_SOCKET) && defined(SO_TYPE) /* POSIX */
+static int
+inspect_socktype(int level, int optname, VALUE data, VALUE ret)
+{

• if (RSTRING_LEN(data) == sizeof(int)) {
• ``````   int i;
``````
• ``````   ID id;
``````
• ``````   memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
``````
• ``````   id = intern_socktype(i);
``````
• ``````   if (id)
``````
• ``````       rb_str_catf(ret, " %s", rb_id2name(id));
``````
• ``````   else
``````
• ``````       rb_str_catf(ret, " %d", i);
``````
• ``````   return 0;
``````
• }
• else {
• ``````   return -1;
``````
• }
+}
+#endif

+static int
+inspect_timeval(int level, int optname, VALUE data, VALUE ret)
+{

• if (RSTRING_LEN(data) == sizeof(struct linger)) {
• ``````   struct timeval s;
``````
• ``````   memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
``````
• ``````   rb_str_catf(ret, " %ld.%06ldsec", (long)s.tv_sec,
``````

(long)s.tv_usec);

• ``````   return 0;
``````
• }
• else {
• ``````   return -1;
``````
• }
+}

+static VALUE
+sockopt_inspect(VALUE self)
+{

• int level = NUM2INT(sockopt_level(self));
• int optname = NUM2INT(sockopt_optname(self));
• VALUE data = sockopt_data(self);
• VALUE v, ret;
• ID level_id;
• StringValue(data);
• ret = rb_sprintf("#<%s: ", rb_obj_classname(self));
• level_id = intern_level(level);
• if (level_id)
• ``````   rb_str_cat2(ret, 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);
``````
• switch (level) {
+# if defined(SOL_SOCKET)
• `````` case SOL_SOCKET:
``````
• ``````   switch (optname) {
``````

+# if defined(SO_DEBUG) /* POSIX */

• ``````     case SO_DEBUG: if (inspect_int(level, optname, data, ret) ==
``````

-1) goto dump; break;
+# endif
+# if defined(SO_ERROR) /* POSIX */

• ``````     case SO_ERROR: if (inspect_int(level, optname, data, ret) ==
``````

-1) goto dump; break;
+# endif
+# if defined(SO_TYPE) /* POSIX */

• ``````     case SO_TYPE: if (inspect_socktype(level, optname, data, ret)
``````

== -1) goto dump; break;
+# endif
+# if defined(SO_ACCEPTCONN) /* POSIX */

• ``````     case SO_ACCEPTCONN: if (inspect_int(level, optname, data,
``````

ret) == -1) goto dump; break;
+# endif
+# if defined(SO_BROADCAST) /* POSIX */

• ``````     case SO_BROADCAST: if (inspect_int(level, optname, data, ret)
``````

== -1) goto dump; break;
+# endif
+# if defined(SO_REUSEADDR) /* POSIX */

• ``````     case SO_REUSEADDR: if (inspect_int(level, optname, data, ret)
``````

== -1) goto dump; break;
+# endif
+# if defined(SO_KEEPALIVE) /* POSIX */

• ``````     case SO_KEEPALIVE: if (inspect_int(level, optname, data, ret)
``````

== -1) goto dump; break;
+# endif
+# if defined(SO_OOBINLINE) /* POSIX */

• ``````     case SO_OOBINLINE: if (inspect_int(level, optname, data, ret)
``````

== -1) goto dump; break;
+# endif
+# if defined(SO_SNDBUF) /* POSIX */

• ``````     case SO_SNDBUF: if (inspect_int(level, optname, data, ret) ==
``````

-1) goto dump; break;
+# endif
+# if defined(SO_RCVBUF) /* POSIX */

• ``````     case SO_RCVBUF: if (inspect_int(level, optname, data, ret) ==
``````

-1) goto dump; break;
+# endif
+# if defined(SO_DONTROUTE) /* POSIX */

• ``````     case SO_DONTROUTE: if (inspect_int(level, optname, data, ret)
``````

== -1) goto dump; break;
+# endif
+# if defined(SO_RCVLOWAT) /* POSIX */

• ``````     case SO_RCVLOWAT: if (inspect_int(level, optname, data, ret)
``````

== -1) goto dump; break;
+# endif
+# if defined(SO_SNDLOWAT) /* POSIX */

• ``````     case SO_SNDLOWAT: if (inspect_int(level, optname, data, ret)
``````

== -1) goto dump; break;
+# endif
+
+# if defined(SO_LINGER) /* POSIX */

• ``````     case SO_LINGER: if (inspect_linger(level, optname, data, ret)
``````

== -1) goto dump; break;
+# endif
+# if defined(SO_RCVTIMEO) /* POSIX */

• ``````     case SO_RCVTIMEO: if (inspect_timeval(level, optname, data,
``````

ret) == -1) goto dump; break;
+# endif
+# if defined(SO_SNDTIMEO) /* POSIX */

• ``````     case SO_SNDTIMEO: if (inspect_timeval(level, optname, data,
``````

ret) == -1) goto dump; break;
+# endif
+

• ``````     default: goto dump;
``````
• ``````   }
``````
• ``````   break;
``````

+# endif
+
+# if defined(IPPROTO_IPV6)

• `````` case IPPROTO_IPV6:
``````
• ``````   switch (optname) {
``````
• ``````     /* IPV6_JOIN_GROUP ipv6_mreq, IPV6_LEAVE_GROUP ipv6_mreq */
``````

+# if defined(IPV6_MULTICAST_HOPS) /* POSIX */

• ``````     case IPV6_MULTICAST_HOPS: if (inspect_int(level, optname,
``````

data, ret) == -1) goto dump; break;
+# endif
+# if defined(IPV6_MULTICAST_IF) /* POSIX */

• ``````     case IPV6_MULTICAST_IF: if (inspect_uint(level, optname,
``````

data, ret) == -1) goto dump; break;
+# endif
+# if defined(IPV6_MULTICAST_LOOP) /* POSIX */

• ``````     case IPV6_MULTICAST_LOOP: if (inspect_uint(level, optname,
``````

data, ret) == -1) goto dump; break;
+# endif
+# if defined(IPV6_UNICAST_HOPS) /* POSIX */

• ``````     case IPV6_UNICAST_HOPS: if (inspect_int(level, optname, data,
``````

ret) == -1) goto dump; break;
+# endif
+# if defined(IPV6_V6ONLY) /* POSIX */

• ``````     case IPV6_V6ONLY: if (inspect_int(level, optname, data, ret)
``````

== -1) goto dump; break;
+# endif

• ``````     default: goto dump;
``````
• ``````   }
``````
• ``````   break;
``````

+# endif
+
+# if defined(IPPROTO_TCP)

• `````` case IPPROTO_TCP:
``````
• ``````   switch (optname) {
``````

+# if defined(TCP_NODELAY) /* POSIX */

• ``````     case TCP_NODELAY: if (inspect_int(level, optname, data, ret)
``````

== -1) goto dump; break;
+# endif

• ``````     default: goto dump;
``````
• ``````   }
``````
• ``````   break;
``````

+# endif
+

• `````` default:
``````
• `````` dump:
``````
• ``````   data = rb_str_dump(data);
``````
• ``````   rb_str_catf(ret, " %s", StringValueCStr(data));
``````
• }
• rb_str_cat2(ret, “>”);
• return ret;
+}

+static VALUE
+sockopt_unpack(VALUE self, VALUE template)
+{

• return rb_funcall(sockopt_data(self), rb_intern(“unpack”), 1,
template);
+}

+void
+Init_sockopt(void)
+{

• rb_cSockOpt = rb_define_class_under(rb_cSocket, “Option”,
rb_cObject);
• rb_define_method(rb_cSockOpt, “initialize”, sockopt_initialize, 3);
• rb_define_method(rb_cSockOpt, “level”, sockopt_level, 0);
• rb_define_method(rb_cSockOpt, “optname”, sockopt_optname, 0);
• rb_define_method(rb_cSockOpt, “data”, sockopt_data, 0);
• rb_define_method(rb_cSockOpt, “inspect”, sockopt_inspect, 0);
• rb_define_singleton_method(rb_cSockOpt, “int”, sockopt_s_int, 3);
• rb_define_method(rb_cSockOpt, “int”, sockopt_int, 0);
• rb_define_method(rb_cSockOpt, “unpack”, sockopt_unpack, 1);
+}

# Index: ext/socket/depend

— ext/socket/depend (revision 21646)
+++ ext/socket/depend (working copy)
@@ -13,6 +13,7 @@ sockssocket.o: sockssocket.c \$(SOCK_HEAD

# getnameinfo.o: getnameinfo.c \$(arch_hdrdir)/ruby/config.h addrinfo.h sockport.h Index: ext/socket/mkconstants.rb

— ext/socket/mkconstants.rb (revision 21646)
+++ ext/socket/mkconstants.rb (working copy)
@@ -254,6 +254,13 @@ def_intern(‘intern_family’, /\AAF_/)
def_intern(‘intern_protocol_family’, /\APF_/)
def_intern(‘intern_socktype’, /\ASOCK_/)
def_intern(‘intern_ipproto’, /\AIPPROTO_/)
+def_intern(‘intern_level’, /\A(SOL_SOCKET\z|IPPROTO_)/,
/\A(SOL_|IPPROTO_)/)
+def_intern(‘intern_so_optname’, /\ASO_/, “SO_”)
+def_intern(‘intern_ip_optname’, /\AIP_/, “IP_”)
+def_intern(‘intern_ipv6_optname’, /\AIPV6_/, “IPV6_”)
+def_intern(‘intern_tcp_optname’, /\ATCP_/, “TCP_”)
+def_intern(‘intern_udp_optname’, /\AUDP_/, “UDP_”)
+def_intern(‘intern_scm_optname’, /\ASCM_/, “SCM_”)

result << ERB.new(<<‘EOS’, nil, ‘%’).result(binding)

# Index: ext/socket/extconf.rb

— ext/socket/extconf.rb (revision 21646)
+++ ext/socket/extconf.rb (working copy)
@@ -254,6 +254,7 @@ \$objs = [
“udpsocket.#{\$OBJEXT}”,
“unixsocket.#{\$OBJEXT}”,
“unixserver.#{\$OBJEXT}”,

• “option.#{\$OBJEXT}”,
]

# Index: ext/socket/basicsocket.c

— ext/socket/basicsocket.c (revision 21646)
+++ ext/socket/basicsocket.c (working copy)
@@ -192,14 +192,24 @@ bsock_close_write(VALUE sock)
*
*/
static VALUE
-bsock_setsockopt(VALUE sock, VALUE lev, VALUE optname, VALUE val)
+bsock_setsockopt(int argc, VALUE *argv, VALUE sock)
{

• VALUE lev, optname, val;
int level, option;
rb_io_t *fptr;
int i;
char *v;
int vlen;

• if (argc == 1) {

• ``````   lev = rb_funcall(argv[0], rb_intern("level"), 0);
``````
• ``````   optname = rb_funcall(argv[0], rb_intern("optname"), 0);
``````
• ``````   val = rb_funcall(argv[0], rb_intern("data"), 0);
``````
• }

• else {

• ``````   rb_scan_args(argc, argv, "30", &lev, &optname, &val);
``````
• }

• rb_secure(2);
level = level_arg(lev);
option = optname_arg(level, optname);
@@ -290,7 +300,7 @@ bsock_getsockopt(VALUE sock, VALUE lev,
if (getsockopt(fptr->fd, level, option, buf, &len) < 0)
rb_sys_fail_path(fptr->pathv);

• return rb_str_new(buf, len);
• return sockopt_new(level, option, rb_str_new(buf, len));
#else
rb_notimplement();
#endif
@@ -626,7 +636,7 @@ Init_basicsocket(void)
0);
rb_define_method(rb_cBasicSocket, “close_write”, bsock_close_write,
0);
rb_define_method(rb_cBasicSocket, “shutdown”, bsock_shutdown, -1);
• rb_define_method(rb_cBasicSocket, “setsockopt”, bsock_setsockopt,
3);
• rb_define_method(rb_cBasicSocket, “setsockopt”, bsock_setsockopt,
-1);
rb_define_method(rb_cBasicSocket, “getsockopt”, bsock_getsockopt,
2);
rb_define_method(rb_cBasicSocket, “getsockname”, bsock_getsockname,
0);
rb_define_method(rb_cBasicSocket, “getpeername”, bsock_getpeername,
0);
Index: test/socket/test_basicsocket.rb
===================================================================
— test/socket/test_basicsocket.rb (revision 21646)
+++ test/socket/test_basicsocket.rb (working copy)
@@ -15,19 +15,19 @@ class TestBasicSocket < Test::Unit::Test
def test_getsockopt
inet_stream do |s|
n = s.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE)
• `````` assert_equal([Socket::SOCK_STREAM].pack("i"), n)
``````
• `````` assert_equal([Socket::SOCK_STREAM].pack("i"), n.data)

n = s.getsockopt("SOL_SOCKET", "SO_TYPE")
``````
• `````` assert_equal([Socket::SOCK_STREAM].pack("i"), n)
``````
• `````` assert_equal([Socket::SOCK_STREAM].pack("i"), n.data)

n = s.getsockopt(:SOL_SOCKET, :SO_TYPE)
``````
• `````` assert_equal([Socket::SOCK_STREAM].pack("i"), n)
``````
• `````` assert_equal([Socket::SOCK_STREAM].pack("i"), n.data)

n = s.getsockopt(:SOCKET, :TYPE)
``````
• `````` assert_equal([Socket::SOCK_STREAM].pack("i"), n)
``````
• `````` assert_equal([Socket::SOCK_STREAM].pack("i"), n.data)

n = s.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR)
``````
• `````` assert_equal([0].pack("i"), n)
``````
• `````` assert_equal([0].pack("i"), n.data)

val = Object.new
class << val; self end.send(:define_method, :to_int) {``````