From a78e45b5fe018f98e03e4bbf8e036822349980cb Mon Sep 17 00:00:00 2001 From: naruse Date: Fri, 31 May 2013 17:37:55 +0000 Subject: * ext/socket/option.c (sockopt_s_byte): constructor of the sockopt whose value's is byte. * ext/socket/option.c (sockopt_byte): getter for above. * ext/socket/option.c (inspect_byte): inspect for above. * ext/socket/option.c (sockopt_s_ip_multicast_loop): constructor of the sockopt whose optname is IP_MULTICAST_LOOP. * ext/socket/option.c (sockopt_ip_multicast_loop): getter for above. * ext/socket/option.c (sockopt_s_ip_multicast_ttl): constructor of the sockopt whose optname is IP_MULTICAST_TTL. * ext/socket/option.c (sockopt_ip_multicast_ttl): getter for above. * ext/socket/option.c (sockopt_inspect): use above. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@41009 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/socket/option.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) (limited to 'ext/socket/option.c') diff --git a/ext/socket/option.c b/ext/socket/option.c index 0259613972..f2f052e8e6 100644 --- a/ext/socket/option.c +++ b/ext/socket/option.c @@ -142,6 +142,50 @@ sockopt_data(VALUE self) return v; } +/* + * call-seq: + * Socket::Option.byte(family, level, optname, integer) => sockopt + * + * Creates a new Socket::Option object which contains a byte as data. + * + * The size and endian is dependent on the platform. + * + * p Socket::Option.byte(:INET, :SOCKET, :KEEPALIVE, 1) + * #=> # + */ +static VALUE +sockopt_s_byte(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); + unsigned char i = (unsigned char)NUM2CHR(vint); + return rsock_sockopt_new(family, level, optname, rb_str_new((char*)&i, sizeof(i))); +} + +/* + * call-seq: + * sockopt.byte => integer + * + * Returns the data in _sockopt_ as an byte. + * + * The size and endian is dependent on the platform. + * + * sockopt = Socket::Option.byte(:INET, :SOCKET, :KEEPALIVE, 1) + * p sockopt.byte => 1 + */ +static VALUE +sockopt_byte(VALUE self) +{ + unsigned char i; + VALUE data = sockopt_data(self); + StringValue(data); + if (RSTRING_LEN(data) != sizeof(i)) + rb_raise(rb_eTypeError, "size differ. expected as sizeof(int)=%d but %ld", + (int)sizeof(i), (long)RSTRING_LEN(data)); + return CHR2FIX(*RSTRING_PTR(data)); +} + /* * call-seq: * Socket::Option.int(family, level, optname, integer) => sockopt @@ -294,6 +338,138 @@ sockopt_linger(VALUE self) return rb_assoc_new(vonoff, vsecs); } +/* + * call-seq: + * Socket::Option.ip_multicast_loop(integer) => sockopt + * + * Creates a new Socket::Option object for IP_MULTICAST_LOOP. + * + * The size is dependent on the platform. + * + * sockopt = Socket::Option.int(:INET, :IPPROTO_IP, :IP_MULTICAST_LOOP, 1) + * p sockopt.int => 1 + * + * p Socket::Option.ip_multicast_loop(10) + * #=> # + * + */ +static VALUE +sockopt_s_ip_multicast_loop(VALUE klass, VALUE value) +{ +#if defined(IPPROTO_IP) && defined(IP_MULTICAST_LOOP) +# ifdef __NetBSD__ + unsigned char i = NUM2CHR(rb_to_int(value)); +# else + int i = NUM2INT(rb_to_int(value)); +# endif + return rsock_sockopt_new(AF_INET, IPPROTO_IP, IP_MULTICAST_LOOP, + rb_str_new((char*)&i, sizeof(i))); +#else +# error IPPROTO_IP or IP_MULTICAST_LOOP is not implemented +#endif +} + +/* + * call-seq: + * sockopt.ip_multicast_loop => integer + * + * Returns the ip_multicast_loop data in _sockopt_ as a integer. + * + * sockopt = Socket::Option.ip_multicast_loop(10) + * p sockopt.ip_multicast_loop => 10 + */ +static VALUE +sockopt_ip_multicast_loop(VALUE self) +{ + int family = NUM2INT(sockopt_family_m(self)); + int level = sockopt_level(self); + int optname = sockopt_optname(self); + +#if defined(IPPROTO_IP) && defined(IP_MULTICAST_LOOP) + if (family == AF_INET && level == IPPROTO_IP && optname == IP_MULTICAST_LOOP) { +# ifdef __NetBSD__ + return sockopt_byte(self); +# else + return sockopt_int(self); +# endif + } +#endif + rb_raise(rb_eTypeError, "ip_multicast_loop socket option expected"); + UNREACHABLE; +} + +#ifdef __NetBSD__ +# define inspect_ip_multicast_loop(a,b,c,d) inspect_byte(a,b,c,d) +#else +# define inspect_ip_multicast_loop(a,b,c,d) inspect_int(a,b,c,d) +#endif + +/* + * call-seq: + * Socket::Option.ip_multicast_ttl(integer) => sockopt + * + * Creates a new Socket::Option object for IP_MULTICAST_TTL. + * + * The size is dependent on the platform. + * + * p Socket::Option.ip_multicast_ttl(10) + * #=> # + * + */ +static VALUE +sockopt_s_ip_multicast_ttl(VALUE klass, VALUE value) +{ +#if defined(IPPROTO_IP) && defined(IP_MULTICAST_TTL) +# ifdef __NetBSD__ + unsigned char i = NUM2CHR(rb_to_int(value)); +# else + int i = NUM2INT(rb_to_int(value)); +# endif + return rsock_sockopt_new(AF_INET, IPPROTO_IP, IP_MULTICAST_TTL, + rb_str_new((char*)&i, sizeof(i))); +#else +# error IPPROTO_IP or IP_MULTICAST_TTL is not implemented +#endif +} + +/* + * call-seq: + * sockopt.ip_multicast_ttl => integer + * + * Returns the ip_multicast_ttl data in _sockopt_ as a integer. + * + * sockopt = Socket::Option.ip_multicast_ttl(10) + * p sockopt.ip_multicast_ttl => 10 + */ +static VALUE +sockopt_ip_multicast_ttl(VALUE self) +{ + int family = NUM2INT(sockopt_family_m(self)); + int level = sockopt_level(self); + int optname = sockopt_optname(self); + +#if defined(IPPROTO_IP) && defined(IP_MULTICAST_TTL) + if (family == AF_INET && level == IPPROTO_IP && optname == IP_MULTICAST_TTL) { +# ifdef __NetBSD__ + return sockopt_byte(self); +# else + return sockopt_int(self); +# endif + } +/* + defined(IP_MULTICAST_LOOP) + */ +#endif + rb_raise(rb_eTypeError, "ip_multicast_ttl socket option expected"); + UNREACHABLE; +} + +#ifdef __NetBSD__ +# define inspect_ip_multicast_ttl(a,b,c,d) inspect_byte(a,b,c,d) +#else +# define inspect_ip_multicast_ttl(a,b,c,d) inspect_int(a,b,c,d) +#endif + static int inspect_int(int level, int optname, VALUE data, VALUE ret) { @@ -308,6 +484,18 @@ inspect_int(int level, int optname, VALUE data, VALUE ret) } } +static int +inspect_byte(int level, int optname, VALUE data, VALUE ret) +{ + if (RSTRING_LEN(data) == sizeof(unsigned char)) { + rb_str_catf(ret, " %d", (unsigned char)*RSTRING_PTR(data)); + return 1; + } + else { + return 0; + } +} + static int inspect_errno(int level, int optname, VALUE data, VALUE ret) { @@ -804,6 +992,12 @@ sockopt_inspect(VALUE self) # 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 +# if defined(IP_MULTICAST_LOOP) /* 4.4BSD, GNU/Linux */ + case IP_MULTICAST_LOOP: inspected = inspect_ip_multicast_loop(level, optname, data, ret); break; +# endif +# if defined(IP_MULTICAST_TTL) /* 4.4BSD, GNU/Linux */ + case IP_MULTICAST_TTL: inspected = inspect_ip_multicast_ttl(level, optname, data, ret); break; # endif } break; @@ -912,12 +1106,21 @@ rsock_init_sockopt(void) rb_define_singleton_method(rb_cSockOpt, "int", sockopt_s_int, 4); rb_define_method(rb_cSockOpt, "int", sockopt_int, 0); + rb_define_singleton_method(rb_cSockOpt, "byte", sockopt_s_byte, 4); + rb_define_method(rb_cSockOpt, "byte", sockopt_byte, 0); + rb_define_singleton_method(rb_cSockOpt, "bool", sockopt_s_bool, 4); rb_define_method(rb_cSockOpt, "bool", sockopt_bool, 0); rb_define_singleton_method(rb_cSockOpt, "linger", sockopt_s_linger, 2); rb_define_method(rb_cSockOpt, "linger", sockopt_linger, 0); + rb_define_singleton_method(rb_cSockOpt, "ip_multicast_ttl", sockopt_s_ip_multicast_ttl, 1); + rb_define_method(rb_cSockOpt, "ip_multicast_ttl", sockopt_ip_multicast_ttl, 0); + + rb_define_singleton_method(rb_cSockOpt, "ip_multicast_loop", sockopt_s_ip_multicast_loop, 1); + rb_define_method(rb_cSockOpt, "ip_multicast_loop", sockopt_ip_multicast_loop, 0); + rb_define_method(rb_cSockOpt, "unpack", sockopt_unpack, 1); rb_define_method(rb_cSockOpt, "to_s", sockopt_data, 0); /* compatibility for ruby before 1.9.2 */ -- cgit v1.2.3