JCM-Net-Patricia

 view release on metacpan or  search on metacpan

Patricia.xs  view on Meta::CPAN

                inet_ntop(node->prefix->family, &node->prefix->add.sin6, buff, 40);
                XPUSHs(sv_2mortal(newSVpvf("%s/%d", buff, node->prefix->bitlen)));
#endif
            }
            PUTBACK;
            perl_call_sv(coderef, G_VOID|G_DISCARD);
            SPAGAIN;
        }
	n++;
    }
	
    if (node->r) {
         n += patricia_walk_inorder_perl(node->r, coderef);
    }

    return n;
}

typedef patricia_tree_t *JCM__Net__Patricia;
typedef patricia_node_t *JCM__Net__PatriciaNode;

MODULE = JCM::Net::Patricia		PACKAGE = JCM::Net::Patricia

PROTOTYPES: ENABLE

double
constant(name,arg)
	char *		name
	int		arg

int
have_ipv6()
	CODE:
#ifdef HAVE_IPV6
		RETVAL = 1;
#else
		RETVAL = 0;
#endif
	OUTPUT:	
		    RETVAL

JCM::Net::Patricia
_new(size)
	int				size
	CODE:
		RETVAL = New_Patricia(size);
	OUTPUT:	
		RETVAL

void
_add(tree, family, addr, bits, data)
	JCM::Net::Patricia			tree
	int				family
	char *				addr
	int				bits
	SV *				data
	PROTOTYPE: $$$$$
	PREINIT:
	   	prefix_t prefix;
	   	JCM__Net__PatriciaNode node;
	PPCODE:
		Fill_Prefix(prefix, family, addr, bits, tree->maxbits);
	   	node = patricia_lookup(tree, &prefix);
		if (NULL != node) {
		   /* { */
		   if (node->data) {
		      deref_data(node->data);
		   }
		   node->data = newSVsv(data);
		   /* } */
		   PUSHs(data);
		} else {
		   XSRETURN_UNDEF;
		}

void
_match(tree, family, addr, bits)
	JCM::Net::Patricia			tree
	int				family
	char *				addr
	int				bits
	PROTOTYPE: $$$$
	PREINIT:
	   	prefix_t prefix;
	   	JCM__Net__PatriciaNode node;
	PPCODE:
		Fill_Prefix(prefix, family, addr, bits, tree->maxbits);
		node = patricia_search_best(tree, &prefix);
		if (NULL != node) {
		   XPUSHs((SV *)node->data);
		} else {
		   XSRETURN_UNDEF;
		}

void
_matching_prefix(tree, family, addr, bits)
	JCM::Net::Patricia		tree
	int				family
	char *				addr
	int				bits
	PROTOTYPE: $$$$
	PREINIT:
	   	prefix_t prefix;
	   	JCM__Net__PatriciaNode node;
	PPCODE:
		Fill_Prefix(prefix, family, addr, bits, tree->maxbits);
		node = patricia_search_best(tree, &prefix);
		if (NULL != node) {
                   if (node->prefix->family == AF_INET) {
                       XPUSHs(sv_2mortal(
                            newSVpvf("%s/%d",
                            inet_ntoa(node->prefix->add.sin),
                            node->prefix->bitlen
                        )
                       ));
#ifdef HAVE_IPV6
                   } else {
                       char buff[40]; // Longest possible IPv6
                       inet_ntop(node->prefix->family, &node->prefix->add.sin6, buff, 40);
                       XPUSHs(sv_2mortal(newSVpvf("%s/%d", buff, node->prefix->bitlen)));
#endif
                   }
		} else {
		   XSRETURN_UNDEF;
		}


void
_exact(tree, family, addr, bits)
	JCM::Net::Patricia			tree
	int				family
	char *				addr
	int				bits
	PROTOTYPE: $$$$
	PREINIT:
	   	prefix_t prefix;
	   	JCM__Net__PatriciaNode node;
	PPCODE:
		Fill_Prefix(prefix, family, addr, bits, tree->maxbits);
		node = patricia_search_exact(tree, &prefix);
		if (NULL != node) {
		   XPUSHs((SV *)node->data);
		} else {
		   XSRETURN_UNDEF;
		}


void
_remove(tree, family, addr, bits)
	JCM::Net::Patricia			tree
	int				family
	char *				addr
	int				bits
	PROTOTYPE: $$$$
	PREINIT:
	   	prefix_t prefix;
	   	JCM__Net__PatriciaNode node;
	PPCODE:
		Fill_Prefix(prefix, family, addr, bits, tree->maxbits);
	   	node = patricia_search_exact(tree, &prefix);
		if (NULL != node) {
		   XPUSHs(sv_mortalcopy((SV *)node->data));
		   deref_data(node->data);
		   patricia_remove(tree, node);
		} else {
		   XSRETURN_UNDEF;
		}

size_t
climb(tree, ...)
	JCM::Net::Patricia			tree
	PREINIT:
		patricia_node_t *node = NULL;
		size_t n = 0;
		SV *func = NULL;
	CODE:
		if (2 == items) {
		   func = ST(1);
		} else if (2 < items) {
	           croak("Usage: JCM::Net::Patricia::climb(tree[,CODEREF])");
		}
		PATRICIA_WALK (tree->head, node) {
		   if (NULL != func) {
		      PUSHMARK(SP);
		      XPUSHs(sv_mortalcopy((SV *)node->data));
		      if (node->prefix->family == AF_INET) {
		         XPUSHs(sv_2mortal(
		            newSVpvf("%s/%d",
		               inet_ntoa(node->prefix->add.sin),
		               node->prefix->bitlen
		            )
		         ));
#ifdef HAVE_IPV6
		      } else {
		         char buff[40]; // Longest possible IPv6
		         inet_ntop(node->prefix->family, &node->prefix->add.sin6, buff, 40);
		         XPUSHs(sv_2mortal(newSVpvf("%s/%d", buff, node->prefix->bitlen)));
#endif
		      }
		      PUTBACK;
		      perl_call_sv(func, G_VOID|G_DISCARD);
		      SPAGAIN;
		   }
		   n++;
		} PATRICIA_WALK_END;
		RETVAL = n;
	OUTPUT:	
		RETVAL

size_t
climb_inorder(tree, ...)
	JCM::Net::Patricia			tree
	PREINIT:
		size_t n = 0;
		SV *func = NULL;
	CODE:
		func = NULL;
		if (2 == items) {
		   func = ST(1);
		} else if (2 < items) {
	           croak("Usage: JCM::Net::Patricia::climb_inorder(tree[,CODEREF])");
		}
                n = patricia_walk_inorder_perl(tree->head, func);
		RETVAL = n;
	OUTPUT:	
		RETVAL

void
STORABLE_freeze(tree, cloning)
	JCM::Net::Patricia			tree
	SV *				cloning
	PREINIT:
		patricia_node_t *node = NULL;
		struct frozen_header frozen_header;
		struct frozen_node *frozen_nodes, *frozen_node;
		size_t n = 0, i = 0, nd = 0;
		SV *frozen_patricia;
	PPCODE:
		if (SvTRUE(cloning))
		  XSRETURN_UNDEF;

		/* I do not know enough of patricia.c to
		 * decide whether inactive nodes can
		 * be present in a tree, and whether such
		 * nodes can be skipped while copying,
		 * so we copy everything and do not use
		 * num_active_node here. */
		PATRICIA_WALK_ALL (tree->head, node) {
			n++;
		} PATRICIA_WALK_END;

		if (n > 2147483646)
			croak("JCM::Net::Patricia::STORABLE_freeze: too many nodes");

		frozen_header.magic           = htonl(FROZEN_MAGIC);
		frozen_header.major           = FROZEN_MAJOR;
		frozen_header.minor           = FROZEN_MINOR;
		frozen_header.maxbits         = htons((uint16_t)tree->maxbits);
		frozen_header.num_total_node  = htonl(n);
		frozen_header.num_active_node = htonl(tree->num_active_node);

		frozen_patricia = newSVpv((char *)&frozen_header, sizeof(frozen_header));
		XPUSHs(frozen_patricia);

		frozen_nodes = calloc(n, sizeof(struct frozen_node));

		/* We use user1 field to store the index of each node
		 * in the frozen_node array;  it is okay since JCM::Net::Patricia
		 * is not using it for anything anywhere else */
		PATRICIA_WALK_ALL (tree->head, node) {
		    node->user1 = (void *)(IV)i;

		    frozen_node = &frozen_nodes[i];
		    frozen_node->l_index = htonl(-1);
		    frozen_node->r_index = htonl(-1);
		    frozen_node->bitlen = node->bit;
		    if (node->prefix) {
			frozen_node->bitlen |= 0x8000;
			frozen_node->family = htons(node->prefix->family);
			if (tree->maxbits == 32)
			    memcpy(&frozen_node->address, &node->prefix->add, 4);
			else
			    memcpy(&frozen_node->address, &node->prefix->add, 16);
		    }
		    frozen_node->bitlen = htons(frozen_node->bitlen);

		    if (node->data) {
			frozen_node->d_index = htonl(nd);
			nd++;
			XPUSHs(sv_2mortal(newRV_inc((SV *)node->data)));
		    } else {
			frozen_node->d_index = htonl(-1);
		    }
		    if (node->parent && node->parent->l == node) {
			frozen_nodes[(IV)node->parent->user1].l_index = htonl(i);
		    } else if (node->parent && node->parent->r == node) {
			frozen_nodes[(IV)node->parent->user1].r_index = htonl(i);
		    }
		    i++;
		} PATRICIA_WALK_END;

		sv_catpvn(frozen_patricia, (char*)frozen_nodes, n*sizeof(struct frozen_node));
		free(frozen_nodes);

void
STORABLE_thaw(tobj, cloning, serialized, ...)
	SV *				tobj
	SV *				cloning
	SV *				serialized;
	PREINIT:
		struct frozen_patricia *frozen_patricia;
		struct frozen_node *frozen_node;
		struct _patricia_tree_t *tree;
		patricia_node_t *node = NULL, *child, **fixup;
		int n, n_calculated, i, d_index, l_index, r_index;
		STRLEN len;
	PPCODE:
		if (SvTRUE(cloning))
		    XSRETURN_UNDEF;

		tree = calloc(1, sizeof(*tree));
		frozen_patricia = (struct frozen_patricia*)SvPV(serialized, len);

		if (ntohl(frozen_patricia->header.magic) != FROZEN_MAGIC)
		    croak("JCM::Net::Patricia::STORABLE_thaw: magic mismatch");
		if (frozen_patricia->header.major != FROZEN_MAJOR)
		    croak("JCM::Net::Patricia::STORABLE_thaw: major mismatch");
		if (frozen_patricia->header.minor != FROZEN_MINOR)
		    croak("JCM::Net::Patricia::STORABLE_thaw: minor mismatch");

		tree->maxbits          = ntohs(frozen_patricia->header.maxbits);
		tree->num_active_node  = ntohl(frozen_patricia->header.num_active_node);
		tree->head             = NULL;

		n            = ntohl(frozen_patricia->header.num_total_node);
		n_calculated = (len - sizeof(frozen_patricia->header)) / sizeof(struct frozen_node);
		if (n_calculated < n)
		    croak("JCM::Net::Patricia::STORABLE_thaw: size mismatch");
		fixup = calloc(n, sizeof(patricia_node_t *));

		for (i = 0; i < n; i++) {
		    node = calloc(1, sizeof(*node));
		    memset(node, 0, sizeof(*node));
		    frozen_node = &frozen_patricia->node[i];

		    node->bit = ntohs(frozen_node->bitlen) & ~0x8000;
		    d_index = ntohl(frozen_node->d_index);
		    if (d_index >= 0)
			node->data = newSVsv(SvRV(ST(3+d_index)));

		    if (ntohs(frozen_node->bitlen) & 0x8000) {
			node->prefix = calloc(1, sizeof(*node->prefix));
			node->prefix->bitlen = node->bit;
			node->prefix->family = ntohs(frozen_node->family);
#ifndef HAVE_IPV6
			if (tree->maxbits > 32)
			    croak("JCM::Net::Patricia::STORABLE_thaw: IPv6 is not supported by Net::Patricia on this machine");
#endif
			if (tree->maxbits == 32) {
			    memcpy(&node->prefix->add, &frozen_node->address, 4);
			} else
			    memcpy(&node->prefix->add, &frozen_node->address, 16);
			node->prefix->ref_count = 1;
		    }
		    fixup[i] = node;
		}

		/* Fix pointers up. */
		if (n)
		    tree->head = fixup[0];
		for (i = 0; i < n; i++) {
		    frozen_node = &frozen_patricia->node[i];
		    node = fixup[i];

		    l_index = ntohl(frozen_node->l_index);
		    if (l_index >= 0) {
			child = fixup[l_index];



( run in 0.816 second using v1.01-cache-2.11-cpan-5511b514fd6 )