1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* ext/socket/option.c (sockopt_level): extracted from sockopt_level_m.

(sockopt_optname): extracted from sockopt_optname_m.
  (sockopt_data): apply StringValue.
  (sockopt_s_linger): new method.
  (sockopt_linger): new method.
  (inspect_linger): show onoff value if it is neither 0 nor 1.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@22634 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
akr 2009-02-25 15:26:25 +00:00
parent 1ff020df70
commit e6f0b1de89
3 changed files with 113 additions and 4 deletions

View file

@ -1,3 +1,12 @@
Thu Feb 26 00:21:21 2009 Tanaka Akira <akr@fsij.org>
* ext/socket/option.c (sockopt_level): extracted from sockopt_level_m.
(sockopt_optname): extracted from sockopt_optname_m.
(sockopt_data): apply StringValue.
(sockopt_s_linger): new method.
(sockopt_linger): new method.
(inspect_linger): show onoff value if it is neither 0 nor 1.
Wed Feb 25 23:23:03 2009 Tanaka Akira <akr@fsij.org>
* ext/socket/ancdata.c (ancillary_unix_rights): raise

View file

@ -83,6 +83,12 @@ sockopt_family_m(VALUE self)
return rb_attr_get(self, rb_intern("family"));
}
static int
sockopt_level(VALUE self)
{
return NUM2INT(rb_attr_get(self, rb_intern("level")));
}
/*
* call-seq:
* sockopt.level => integer
@ -95,7 +101,13 @@ sockopt_family_m(VALUE self)
static VALUE
sockopt_level_m(VALUE self)
{
return rb_attr_get(self, rb_intern("level"));
return INT2NUM(sockopt_level(self));
}
static int
sockopt_optname(VALUE self)
{
return NUM2INT(rb_attr_get(self, rb_intern("optname")));
}
/*
@ -110,7 +122,7 @@ sockopt_level_m(VALUE self)
static VALUE
sockopt_optname_m(VALUE self)
{
return rb_attr_get(self, rb_intern("optname"));
return INT2NUM(sockopt_optname(self));
}
/*
@ -125,7 +137,9 @@ sockopt_optname_m(VALUE self)
static VALUE
sockopt_data(VALUE self)
{
return rb_attr_get(self, rb_intern("data"));
VALUE v = rb_attr_get(self, rb_intern("data"));
StringValue(v);
return v;
}
/*
@ -219,6 +233,67 @@ sockopt_bool(VALUE self)
return i == 0 ? Qfalse : Qtrue;
}
/*
* call-seq:
* Socket::Option.linger(onoff, secs) => sockopt
*
* 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 sockopt_new(AF_UNSPEC, SOL_SOCKET, SO_LINGER, rb_str_new((char*)&l, sizeof(l)));
}
/*
* call-seq:
* sockopt.linger => [bool, seconds]
*
* 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);
}
static int
inspect_int(int level, int optname, VALUE data, VALUE ret)
{
@ -272,7 +347,12 @@ 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, " %s %dsec", s.l_onoff ? "on" : "off", s.l_linger);
switch (s.l_onoff) {
case 0: rb_str_cat2(ret, " off"); break;
case 1: rb_str_cat2(ret, " on"); break;
default: rb_str_catf(ret, " on(%d)", s.l_onoff); break;
}
rb_str_catf(ret, " %dsec", s.l_linger);
return 1;
}
else {
@ -598,6 +678,9 @@ Init_sockopt(void)
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_method(rb_cSockOpt, "unpack", sockopt_unpack, 1);
rb_define_method(rb_cSockOpt, "to_s", sockopt_data, 0); /* compatibility for ruby before 1.9.2 */

View file

@ -273,6 +273,23 @@ class TestSocket < Test::Unit::TestCase
}
end
def test_linger
opt = Socket::Option.linger(true, 0)
assert_equal([true, 0], opt.linger)
Addrinfo.tcp("127.0.0.1", 0).listen {|serv|
serv.local_address.connect {|s1|
s2, _ = serv.accept
begin
s1.setsockopt(opt)
s1.close
assert_raise(Errno::ECONNRESET) { s2.read }
ensure
s2.close
end
}
}
end
def test_timestamp
return if /linux|freebsd|netbsd|openbsd|solaris|darwin/ !~ RUBY_PLATFORM
t1 = Time.now.strftime("%Y-%m-%d")