/* Abstract AVL Tree Generic Package Example 2. ** This code is in the public domain. ** Version: 1.5 Author: Walt Karas ** ** This example shows how to use the AVL generic package to create an ** IP address counting facility. Imagine we are writing software for ** an embedded CPU (with limited memory) that processes IP packets. ** We want to keep count of the number of times that we see each ** distinct destination address. We can assume that we will see at ** most 100 distinct destination addresses. */ #undef AVL_READ_ERRORS_HAPPEN /* Handle is index into array of nodes. */ #define AVL_HANDLE unsigned char /* Key is 32-bit IP address. */ #define AVL_KEY unsigned long typedef struct { /* IP address. */ unsigned long ip_addr; /* Number of times IP address seen. */ unsigned short cnt; /* Child node handles. The high bit of gt is robbed and used as ** the balance factor sign. The high bit of lt is robbed and used ** as the magnitude of the balance factor. */ unsigned char gt, lt; } node_T; /* The tree nodes are in an array which is inside the AVL tree structure ** (generated by cavl_if.h). The handles are indexes into this array. */ #define AVL_INSIDE_STRUCT node_T node[100]; #define AVL_GET_LESS(H, ACCESS) (L__tree->node[H].lt & 127) #define AVL_SET_LESS(H, LH) \ { register node_T *n = L__tree->node + (H); \ n->lt &= 128; n->lt |= (LH); } #define AVL_GET_GREATER(H, ACCESS) (L__tree->node[H].gt & 127) #define AVL_SET_GREATER(H, GH) \ { register node_T *n = L__tree->node + (H); \ n->gt &= 128; n->gt |= (GH); } #define AVL_GET_BALANCE_FACTOR(H) \ ((L__tree->node[H].gt & 128) ? -1 : ((L__tree->node[H].lt & 128) ? 1 : 0)) #define AVL_SET_BALANCE_FACTOR(H, BF) \ { \ register node_T *n = L__tree->node + (H); \ n->lt &= 127; n->lt |= ((BF) != 0) << 7; \ n->gt &= 127; n->gt |= ((BF) < 0) << 7; \ } #define COMPARE_KEY_KEY(K1, K2) ((K1) > (K2) ? 1 : ((K1) < (K2) ? -1 : 0)) #define AVL_COMPARE_KEY_NODE(K, H) \ COMPARE_KEY_KEY((K), L__tree->node[H].ip_addr) #define AVL_COMPARE_NODE_NODE(H1, H2) \ COMPARE_KEY_KEY(L__tree->node[H1].ip_addr, L__tree->node[H2].ip_addr) #define AVL_NULL 127 #define AVL_MAX_DEPTH 9 #define AVL_PRIVATE #include "cavl_if.h" static unsigned char num_nodes_used = 0; static avl tree; void init_ipac(void) { init(&tree); } /* The given IP address appeared as the destination address in a ** packet. */ void see_ipac(unsigned long ip_addr) { unsigned char n; node_T *p; if (num_nodes_used == 100) { n = search(&tree, ip_addr, AVL_EQUAL); if (n == 127) /* More than 100 distinct addresses seen, so ignore. */ return; p = tree.node + n; } else { /* Make p point to next free node. */ p = tree.node + num_nodes_used; p->ip_addr = ip_addr; p->cnt = 0; n = insert(&tree, num_nodes_used); if (n != num_nodes_used) /* Didn't insert the new node, because there is already a node ** in the tree with the seen address. So, we just want to ** increment the pointer in the node already in the tree. */ p = tree.node + n; else /* IP address was not seen before, so the new node was ** successfully inserted into the tree. */ num_nodes_used++; } /* Increment seen count, handling saturation properly. */ if ((~(p->cnt)) != 0) p->cnt++; } /* Dump contents of tree into array of addresses and corresponding ** array of counts. (Dump will be in ascending order by IP address.) */ unsigned char dump_ipac(unsigned long *ip_addr_list, unsigned short *cnt_list) { iter it; unsigned char n; node_T *p; unsigned char num_addr = 0; start_iter_least(&tree, &it); for (n = get_iter(&it); n != 127; incr_iter(&it), n = get_iter(&it)) { p = tree.node + n; *(ip_addr_list++) = p->ip_addr; *(cnt_list++) = p->cnt; num_addr++; } return(num_addr); } #define AVL_IMPL_MASK \ (AVL_IMPL_INSERT | AVL_IMPL_SEARCH | AVL_IMPL_START_ITER_LEAST | \ AVL_IMPL_GET_ITER | AVL_IMPL_INCR_ITER | AVL_IMPL_INIT) #include "cavl_impl.h" /* Demo main program. */ #define remove not_going_to_use #include #undef remove int main(void) { init_ipac(); see_ipac(40); see_ipac(35); see_ipac(30); see_ipac(25); see_ipac(20); see_ipac(15); see_ipac(10); see_ipac(5); see_ipac(35); see_ipac(30); see_ipac(25); see_ipac(20); see_ipac(15); see_ipac(10); see_ipac(5); see_ipac(30); see_ipac(25); see_ipac(20); see_ipac(15); see_ipac(10); see_ipac(5); see_ipac(25); see_ipac(20); see_ipac(15); see_ipac(10); see_ipac(5); see_ipac(20); see_ipac(15); see_ipac(10); see_ipac(5); see_ipac(15); see_ipac(10); see_ipac(5); see_ipac(10); see_ipac(5); see_ipac(5); { unsigned long ip_addr[100]; unsigned short count[100]; unsigned char i, num_addr = dump_ipac(ip_addr, count); for (i = 0; i < num_addr; i++) printf("%12lu %12u\n", ip_addr[i], count[i]); } return(0); }