From 83b7b3ef9582b05462b851571cf9dce44276b88c Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 25 Feb 2016 09:34:08 +0000 Subject: linux: tcp_listener_stats drops "true" placeholders With invalid addresses specified which give no currently-bound address, we must avoid leaving placeholders ('true' objects) in our results. Clean up some shadowing "cur" while we're at it. --- ext/raindrops/linux_inet_diag.c | 15 ++++++++++++--- test/test_linux.rb | 7 +++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/ext/raindrops/linux_inet_diag.c b/ext/raindrops/linux_inet_diag.c index 35bb127..58415c6 100644 --- a/ext/raindrops/linux_inet_diag.c +++ b/ext/raindrops/linux_inet_diag.c @@ -618,6 +618,13 @@ static VALUE tcp_stats(struct nogvl_args *args, VALUE addr) return rb_listen_stats(&args->stats); } +static int drop_placeholders(st_data_t k, st_data_t v, st_data_t ign) +{ + if ((VALUE)v == Qtrue) + return ST_DELETE; + return ST_CONTINUE; +} + /* * call-seq: * Raindrops::Linux.tcp_listener_stats([addrs[, sock]]) => hash @@ -658,10 +665,9 @@ static VALUE tcp_listener_stats(int argc, VALUE *argv, VALUE self) case T_ARRAY: { long i; long len = RARRAY_LEN(addrs); - VALUE cur; if (len == 1) { - cur = rb_ary_entry(addrs, 0); + VALUE cur = rb_ary_entry(addrs, 0); rb_hash_aset(rv, cur, tcp_stats(&args, cur)); return rv; @@ -671,7 +677,7 @@ static VALUE tcp_listener_stats(int argc, VALUE *argv, VALUE self) VALUE cur = rb_ary_entry(addrs, i); parse_addr(&check, cur); - rb_hash_aset(rv, cur, Qtrue); + rb_hash_aset(rv, cur, Qtrue /* placeholder */); } /* fall through */ } @@ -689,6 +695,9 @@ static VALUE tcp_listener_stats(int argc, VALUE *argv, VALUE self) st_foreach(args.table, NIL_P(addrs) ? st_to_hash : st_AND_hash, rv); st_free_table(args.table); + if (RHASH_SIZE(rv) > 1) + rb_hash_foreach(rv, drop_placeholders, Qfalse); + /* let GC deal with corner cases */ if (argc < 2) rb_io_close(sock); return rv; diff --git a/test/test_linux.rb b/test/test_linux.rb index 0e79a86..bfefcc4 100644 --- a/test/test_linux.rb +++ b/test/test_linux.rb @@ -214,6 +214,13 @@ class TestLinux < Test::Unit::TestCase assert_equal 0, stats[addr1].active assert_equal 1, stats[addr2].queued assert_equal 1, stats[addr2].active + + # make sure we don't leave "true" placeholders in results if a + # listener becomes invalid (even momentarily). + s2.close + stats = tcp_listener_stats(addrs) + assert stats.values.all? { |x| x.instance_of?(Raindrops::ListenStats) }, + "placeholders left: #{stats.inspect}" end # tries to overflow buffers -- cgit v1.2.3-24-ge0c7