about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2016-02-25 09:34:08 +0000
committerEric Wong <e@80x24.org>2016-02-25 09:41:27 +0000
commit83b7b3ef9582b05462b851571cf9dce44276b88c (patch)
tree83849e75ad82183550cbc04860106dae9458fca5
parent1ac312ae86fb047613ff8558dd8f6ad43ae2ac59 (diff)
downloadraindrops-83b7b3ef9582b05462b851571cf9dce44276b88c.tar.gz
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.
-rw-r--r--ext/raindrops/linux_inet_diag.c15
-rw-r--r--test/test_linux.rb7
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