diff options
author | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-02-08 15:12:27 +0000 |
---|---|---|
committer | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-02-08 15:12:27 +0000 |
commit | c02ce88762eeda44002b82f4176e9fdbc0dd7e3c (patch) | |
tree | 84ee65ed2aaf50af5b1f9ad4adb59c3f561aa95b /ext | |
parent | 3e11901f1c03f7d3a88349644223f6c920f5f9e2 (diff) | |
download | ruby-c02ce88762eeda44002b82f4176e9fdbc0dd7e3c.tar.gz |
* ext/socket/rubysocket.h (sockopt_new): add family argument.
* ext/socket/option.c (sockopt_initialize): add vfamily argument.
(sockopt_new): add family argument and record it in the object.
(sockopt_family): new method.
(sockopt_s_int): add vfamily argument.
(sockopt_inspect): show family.
* ext/socket/basicsocket.c (bsock_getsockopt): check address family
using getsockname.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@22135 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext')
-rw-r--r-- | ext/socket/basicsocket.c | 10 | ||||
-rw-r--r-- | ext/socket/option.c | 54 | ||||
-rw-r--r-- | ext/socket/rubysocket.h | 2 |
3 files changed, 50 insertions, 16 deletions
diff --git a/ext/socket/basicsocket.c b/ext/socket/basicsocket.c index da8ab106a3..65c19d00ee 100644 --- a/ext/socket/basicsocket.c +++ b/ext/socket/basicsocket.c @@ -290,6 +290,8 @@ bsock_getsockopt(VALUE sock, VALUE lev, VALUE optname) socklen_t len; char *buf; rb_io_t *fptr; + struct sockaddr_storage ss; + socklen_t sslen = sizeof(ss); level = level_arg(lev); option = optname_arg(level, optname); @@ -297,10 +299,16 @@ bsock_getsockopt(VALUE sock, VALUE lev, VALUE optname) buf = ALLOCA_N(char,len); GetOpenFile(sock, fptr); + + if (getsockname(fptr->fd, (struct sockaddr*)&ss, &sslen) < 0) + rb_sys_fail("getsockname(2)"); + if (getsockopt(fptr->fd, level, option, buf, &len) < 0) rb_sys_fail_path(fptr->pathv); - return sockopt_new(level, option, rb_str_new(buf, len)); + if (sslen < (char*)&ss.ss_family + sizeof(ss.ss_family) - (char*)&ss) + ss.ss_family = AF_UNSPEC; + return sockopt_new(ss.ss_family, level, option, rb_str_new(buf, len)); #else rb_notimplement(); #endif diff --git a/ext/socket/option.c b/ext/socket/option.c index 283dd7b279..c07779e796 100644 --- a/ext/socket/option.c +++ b/ext/socket/option.c @@ -35,11 +35,14 @@ optname_to_sym(int level, int optname) } static VALUE -sockopt_initialize(VALUE self, VALUE vlevel, VALUE voptname, VALUE data) +sockopt_initialize(VALUE self, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE data) { + int family; int level; StringValue(data); level = level_arg(vlevel); + family = family_arg(vfamily); + 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_arg(level, voptname))); rb_ivar_set(self, rb_intern("data"), data); @@ -47,22 +50,36 @@ sockopt_initialize(VALUE self, VALUE vlevel, VALUE voptname, VALUE data) } VALUE -sockopt_new(int level, int optname, VALUE data) +sockopt_new(int family, 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); + sockopt_initialize((VALUE)obj, INT2NUM(family), INT2NUM(level), INT2NUM(optname), data); return (VALUE)obj; } /* * call-seq: + * sockopt.family => integer + * + * returns the socket family as an integer. + * + * p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).family + */ +static VALUE +sockopt_family(VALUE self) +{ + return rb_attr_get(self, rb_intern("family")); +} + +/* + * call-seq: * sockopt.level => integer * * returns the socket level as an integer. * - * p Socket::Option.new(:IPV6, :RECVPKTINFO, [1].pack("i!")).level + * p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).level */ static VALUE sockopt_level(VALUE self) @@ -76,7 +93,7 @@ sockopt_level(VALUE self) * * returns the socket option name as an integer. * - * p Socket::Option.new(:IPV6, :RECVPKTINFO, [1].pack("i!")).optname + * p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).optname */ static VALUE sockopt_optname(VALUE self) @@ -90,7 +107,7 @@ sockopt_optname(VALUE self) * * returns the socket option data as a string. * - * p Socket::Option.new(:IPV6, :PKTINFO, [1].pack("i!")).data + * p Socket::Option.new(:INET6, :IPV6, :PKTINFO, [1].pack("i!")).data */ static VALUE sockopt_data(VALUE self) @@ -100,7 +117,7 @@ sockopt_data(VALUE self) /* * call-seq: - * Socket::Option.int(level, optname, integer) => sockopt + * Socket::Option.int(family, level, optname, integer) => sockopt * * Creates a new Socket::Option object which contains an int as data. * @@ -110,12 +127,13 @@ sockopt_data(VALUE self) * #=> #<Socket::Option: SOCKET KEEPALIVE 1> */ static VALUE -sockopt_s_int(VALUE klass, VALUE vlevel, VALUE voptname, VALUE vint) +sockopt_s_int(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE vint) { + int family = family_arg(vfamily); 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))); + return sockopt_new(family, level, optname, rb_str_new((char*)&i, sizeof(i))); } /* @@ -241,21 +259,28 @@ inspect_peercred(int level, int optname, VALUE data, VALUE ret) static VALUE sockopt_inspect(VALUE self) { + int family = NUM2INT(sockopt_family(self)); int level = NUM2INT(sockopt_level(self)); int optname = NUM2INT(sockopt_optname(self)); VALUE data = sockopt_data(self); VALUE v, ret; - ID level_id; + ID family_id, level_id; StringValue(data); ret = rb_sprintf("#<%s: ", rb_obj_classname(self)); + family_id = intern_family(family); + if (family_id) + rb_str_cat2(ret, rb_id2name(family_id)); + else + rb_str_catf(ret, "family:%d", family); + level_id = intern_level(level); if (level_id) - rb_str_cat2(ret, rb_id2name(level_id)); + rb_str_catf(ret, " %s", rb_id2name(level_id)); else - rb_str_catf(ret, "level:%d", level); + rb_str_catf(ret, " level:%d", level); v = optname_to_sym(level, optname); if (SYMBOL_P(v)) @@ -381,13 +406,14 @@ 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, "initialize", sockopt_initialize, 4); + rb_define_method(rb_cSockOpt, "family", sockopt_family, 0); 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_singleton_method(rb_cSockOpt, "int", sockopt_s_int, 4); rb_define_method(rb_cSockOpt, "int", sockopt_int, 0); rb_define_method(rb_cSockOpt, "unpack", sockopt_unpack, 1); diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h index 2effdb3559..99028443e9 100644 --- a/ext/socket/rubysocket.h +++ b/ext/socket/rubysocket.h @@ -244,7 +244,7 @@ VALUE sock_listen(VALUE sock, VALUE log); VALUE s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len); VALUE s_accept_nonblock(VALUE klass, rb_io_t *fptr, struct sockaddr *sockaddr, socklen_t *len); -VALUE sockopt_new(int level, int optname, VALUE data); +VALUE sockopt_new(int family, int level, int optname, VALUE data); void Init_basicsocket(void); void Init_ipsocket(void); |