From f952501c14316f8639949e3537aead6351224bcd Mon Sep 17 00:00:00 2001 From: Hleb Valoshka <375gnu@gmail.com> Date: Thu, 12 Sep 2013 16:31:13 +0300 Subject: Remove Scope IDs from IPv6 addresses. Scoped ipv6 addresses are defined in rfc4007. Ruby doesn't support them yet and it's unknown whether it will (see http://bugs.ruby-lang.org/issues/8464). So we just remove scope ids. Tested with MRI and Rubinius. --- ext/raindrops/linux_inet_diag.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/ext/raindrops/linux_inet_diag.c b/ext/raindrops/linux_inet_diag.c index cd4a876..7b5bae1 100644 --- a/ext/raindrops/linux_inet_diag.c +++ b/ext/raindrops/linux_inet_diag.c @@ -134,12 +134,49 @@ static int st_free_data(st_data_t key, st_data_t value, st_data_t ignored) return ST_DELETE; } +/* + * call-seq: + * remove_scope_id(ip_address) + * + * Returns copy of IP address with Scope ID removed, + * if address has it (only IPv6 actually may have it). + */ +static VALUE remove_scope_id(const char *addr) +{ + VALUE rv = rb_str_new2(addr); + long len = RSTRING_LEN(rv); + char *ptr = RSTRING_PTR(rv); + char *pct = memchr(ptr, '%', len); + + /* + * remove scoped portion + * Ruby equivalent: rv.sub!(/%([^\]]*)\]/, "]") + */ + if (pct) { + size_t newlen = pct - ptr; + char *rbracket = memchr(pct, ']', len - newlen); + + if (rbracket) { + size_t move = len - (rbracket - ptr); + + memmove(pct, rbracket, move); + newlen += move; + + rb_str_set_len(rv, newlen); + } else { + rb_raise(rb_eArgError, + "']' not found in IPv6 addr=%s", ptr); + } + } + return rv; +} + static int st_to_hash(st_data_t key, st_data_t value, VALUE hash) { struct listen_stats *stats = (struct listen_stats *)value; if (stats->listener_p) { - VALUE k = rb_str_new2((const char *)key); + VALUE k = remove_scope_id((const char *)key); VALUE v = rb_listen_stats(stats); OBJ_FREEZE(k); @@ -153,7 +190,7 @@ static int st_AND_hash(st_data_t key, st_data_t value, VALUE hash) struct listen_stats *stats = (struct listen_stats *)value; if (stats->listener_p) { - VALUE k = rb_str_new2((const char *)key); + VALUE k = remove_scope_id((const char *)key); if (rb_hash_lookup(hash, k) == Qtrue) { VALUE v = rb_listen_stats(stats); -- cgit v1.2.3-24-ge0c7