Skip Menu |

This queue is for tickets about the Net-Patricia CPAN distribution.

Report information
The Basics
Id: 66755
Status: new
Priority: 0/
Queue: Net-Patricia

People
Owner: Nobody in particular
Requestors: RJH [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: (no value)
Fixed in: (no value)



Subject: Function to return all matching records
I've attached a patch to add match_all and match_all_string functions to Net::Patricia. These work identically to match and match_string, only they return all matching records. If there's any interest in applying this upstream, I'm willing to finish it off (it needs POD and IPv4 tests).
Subject: match_all.patch
diff -Naur Net-Patricia-1.19-orig/libpatricia/patricia.c Net-Patricia-1.19/libpatricia/patricia.c --- Net-Patricia-1.19-orig/libpatricia/patricia.c 2011-03-05 15:03:56.000000000 +0000 +++ Net-Patricia-1.19/libpatricia/patricia.c 2011-03-07 14:25:11.000000000 +0000 @@ -523,14 +523,17 @@ /* if inclusive != 0, "best" may be the given prefix itself */ +/* optional out argument 'parents' will be an array of parent node objects */ patricia_node_t * -patricia_search_best2 (patricia_tree_t *patricia, prefix_t *prefix, int inclusive) +patricia_search_best2 (patricia_tree_t *patricia, prefix_t *prefix, patricia_node_t ***parents, int *num_parents, + int inclusive) { patricia_node_t *node; patricia_node_t *stack[PATRICIA_MAXBITS + 1]; u_char *addr; u_int bitlen; int cnt = 0; + int i; assert (patricia); assert (prefix); @@ -609,6 +612,16 @@ fprintf (stderr, "patricia_search_best: found %s/%d\n", prefix_toa (node->prefix), node->prefix->bitlen); #endif /* PATRICIA_DEBUG */ + if (num_parents != NULL) + *num_parents = cnt; + if (parents != NULL && cnt > 0) { + *parents = malloc(sizeof(patricia_node_t *) * (cnt)); + if (*parents != NULL) { + for (i = 0; i < cnt; i++) { + (*parents)[i] = stack[i]; + } + } + } return (node); } } @@ -619,9 +632,14 @@ patricia_node_t * patricia_search_best (patricia_tree_t *patricia, prefix_t *prefix) { - return (patricia_search_best2 (patricia, prefix, 1)); + return (patricia_search_best2 (patricia, prefix, NULL, NULL, 1)); } +patricia_node_t * +patricia_search_parents (patricia_tree_t *patricia, prefix_t *prefix, patricia_node_t ***parents, int *num_parents) +{ + return patricia_search_best2 (patricia, prefix, parents, num_parents, 1); +} patricia_node_t * patricia_lookup (patricia_tree_t *patricia, prefix_t *prefix) diff -Naur Net-Patricia-1.19-orig/libpatricia/patricia.h Net-Patricia-1.19/libpatricia/patricia.h --- Net-Patricia-1.19-orig/libpatricia/patricia.h 2011-03-05 15:03:56.000000000 +0000 +++ Net-Patricia-1.19/libpatricia/patricia.h 2011-03-07 14:26:23.000000000 +0000 @@ -80,8 +80,10 @@ patricia_node_t *patricia_search_exact (patricia_tree_t *patricia, prefix_t *prefix); patricia_node_t *patricia_search_best (patricia_tree_t *patricia, prefix_t *prefix); -patricia_node_t * patricia_search_best2 (patricia_tree_t *patricia, prefix_t *prefix, - int inclusive); +patricia_node_t * patricia_search_parents (patricia_tree_t *patricia, prefix_t *prefix, + patricia_node_t ***parents, int *num_parents); +patricia_node_t * patricia_search_best2 (patricia_tree_t *patricia, prefix_t *prefix, + patricia_node_t ***parents, int *num_parents, int inclusive); patricia_node_t *patricia_lookup (patricia_tree_t *patricia, prefix_t *prefix); void patricia_remove (patricia_tree_t *patricia, patricia_node_t *node); patricia_tree_t *New_Patricia (int maxbits); diff -Naur Net-Patricia-1.19-orig/Patricia.pm Net-Patricia-1.19/Patricia.pm --- Net-Patricia-1.19-orig/Patricia.pm 2011-03-05 15:03:56.000000000 +0000 +++ Net-Patricia-1.19/Patricia.pm 2011-03-05 15:50:07.000000000 +0000 @@ -87,6 +87,12 @@ $self->match($self->_ip_bits($str)) } +sub match_all_string { + croak "match_string: wrong number of args" if (@_ != 2); + my ($self,$str) = @_; + $self->match_all($self->_ip_bits($str)) +} + sub match_exact_string { croak "match_exact_string: wrong number of args" if (@_ != 2); my ($self,$str) = @_; @@ -198,6 +204,15 @@ $self->SUPER::_match(AF_INET, $packed, $bits); } +sub match_all { + croak "match: wrong number of args" if (@_ < 2 || @_ > 3); + my ($self, $ip, $bits) = @_; + my $packed = inet_aton($ip); + croak("invalid key") unless (defined $packed); + $bits = 32 if (@_ < 3); + $self->SUPER::_match_all(AF_INET, $packed, $bits); +} + sub exact { croak "exact: wrong number of args" if (@_ < 2 || @_ > 3); my ($self, $ip, $bits) = @_; @@ -285,6 +300,15 @@ $self->SUPER::_match(AF_INET6, $packed, $bits); } +sub match_all { + croak "match: wrong number of args" if (@_ < 2 || @_ > 3); + my ($self, $ip, $bits) = @_; + my $packed = inet_pton(AF_INET6, $ip); + croak("invalid key") unless (defined $packed); + $bits = 128 if (@_ < 3); + $self->SUPER::_match_all(AF_INET6, $packed, $bits); +} + sub exact { croak "exact: wrong number of args" if (@_ < 2 || @_ > 3); my ($self, $ip, $bits) = @_; diff -Naur Net-Patricia-1.19-orig/Patricia.xs Net-Patricia-1.19/Patricia.xs --- Net-Patricia-1.19-orig/Patricia.xs 2011-03-05 15:03:56.000000000 +0000 +++ Net-Patricia-1.19/Patricia.xs 2011-03-07 14:38:25.000000000 +0000 @@ -246,6 +246,34 @@ } void +_match_all(tree, family, addr, bits) + Net::Patricia tree + int family + char * addr + int bits + PROTOTYPE: $$$$ + PREINIT: + prefix_t prefix; + Net__PatriciaNode node; + Net__PatriciaNode *parents; + int num_parents; + int i; + PPCODE: + Fill_Prefix(prefix, family, addr, bits, tree->maxbits); + node = patricia_search_parents(tree, &prefix, &parents, &num_parents); + if (NULL != node) { + if (parents == NULL) + croak("out of memory, could not allocate storage for parents"); + + if (num_parents > 0) { + for (i = 0; i < num_parents; i++) + XPUSHs((SV *)parents[i]->data); + free(parents); + } + XPUSHs((SV *)node->data); + } + +void _exact(tree, family, addr, bits) Net::Patricia tree int family diff -Naur Net-Patricia-1.19-orig/t/02match_all.t Net-Patricia-1.19/t/02match_all.t --- Net-Patricia-1.19-orig/t/02match_all.t 1970-01-01 01:00:00.000000000 +0100 +++ Net-Patricia-1.19/t/02match_all.t 2011-03-07 13:08:50.000000000 +0000 @@ -0,0 +1,45 @@ +use strict; +use warnings; +use Test::More tests => 8; +use Net::Patricia; +use Socket; + +my $tree = Net::Patricia->new(AF_INET6); +can_ok($tree, 'match_all_string') + or BAIL_OUT('No method match_all_string'); + +sub test { + my ($query, $expected_result, $message) = @_; + my @result = $tree->match_all_string($query); + is_deeply(\@result, $expected_result, $message); +} + +test('::', [], 'lookup against no data'); + +$tree->add_string('::/0', 'root'); +test('::', ['root'], 'lookup against root zone'); + +$tree->add_string('2001::/16', '/16'); +$tree->add_string('2001:51a:ff::/48', '/48'); + +test('::', ['root'], 'root lookup'); +test('2001:51a:ff::1', ['root', '/16', '/48'], 'general lookup'); +test('2001:b::', ['root', '/16'], 'less general lookup'); + +$tree->add_string('2001:51a:ff::1'); +test('2001:51a:ff::1', ['root', '/16', '/48', '2001:51a:ff::1'], 'exact IP match'); + +# Reset and try a more complex example +$tree = Net::Patricia->new(AF_INET6); + +$tree->add_string('::/0'); +$tree->add_string('2800::/12'); +$tree->add_string('2a00::/12'); +$tree->add_string('2a00::/22'); +$tree->add_string('2a00:1000::/32'); +$tree->add_string('2a00:1400::/48'); +$tree->add_string('2a00:1440::/32'); +$tree->add_string('2a00:1450::/32'); + +test('2a00:1450:8002::6a', ['::/0', '2a00::/12', '2a00:1450::/32']); +