123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- /*
- * $Id: dtrie.c 5237 2008-11-21 10:17:10Z henningw $
- *
- * Copyright (C) 2008 1&1 Internet AG
- *
- * This file is part of sip-router, a free SIP server.
- *
- * sip-router is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * sip-router is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
- /**
- * \file
- * \brief Trie datastructure with utility functions
- *
- * Provides a generic trie datastructure and utility functions to
- * initialize and manage individual nodes. Its optimized towards
- * the usecase of a matching tree that contains only digits, e.g.
- * for LCR or blacklist modules. Nevertheless it also supports the
- * matching of characters when configured correctly. For normal
- * digit only matching you need to use a branches parameter of
- * 10, when you use 128, the complete standard ascii charset is
- * available for matching. The trie is setup in shared memory.
- * - Module: \ref carrierroute
- * - Module: \ref userblacklist
- */
- #include "dtrie.h"
- #include "../../dprint.h"
- #include "../../mem/shm_mem.h"
- #include "../../mem/mem.h"
- struct dtrie_node_t *dtrie_init(const unsigned int branches)
- {
- struct dtrie_node_t *root;
- root = shm_malloc(sizeof(struct dtrie_node_t));
- if (root == NULL) {
- SHM_MEM_ERROR;
- return NULL;
- }
- LM_DBG("allocate %lu bytes for root at %p\n",
- (long unsigned)sizeof(struct dtrie_node_t), root);
- memset(root, 0, sizeof(struct dtrie_node_t));
- root->child = shm_malloc(sizeof(struct dtrie_node_t *) * branches);
- if (root->child == NULL) {
- shm_free(root);
- SHM_MEM_ERROR;
- return NULL;
- }
- LM_DBG("allocate %lu bytes for %d root children pointer at %p\n",
- (long unsigned)sizeof(struct dtrie_node_t *) * branches,
- branches, root->child);
- memset(root->child, 0, sizeof(struct dtrie_node_t *) * branches);
- return root;
- }
- void dtrie_delete(struct dtrie_node_t *root, struct dtrie_node_t *node,
- dt_delete_func_t delete_payload, const unsigned int branches)
- {
- unsigned int i;
- if (node==NULL) return;
- for (i=0; i<branches; i++) {
- dtrie_delete(root, node->child[i], delete_payload, branches);
- node->child[i] = NULL;
- }
- if (delete_payload) {
- delete_payload(node->data);
- }
- node->data = NULL;
- if (node != root) {
- LM_DBG("free node at %p\n", node);
- shm_free(node->child);
- node->child = NULL;
- shm_free(node);
- }
- }
- void dtrie_destroy(struct dtrie_node_t **root, dt_delete_func_t delete_payload, const unsigned int branches)
- {
- if ((root!=NULL) && (*root!=NULL)) {
- dtrie_delete(*root, *root, delete_payload, branches);
- LM_DBG("free root at %p\n", root);
- shm_free((*root)->child);
- shm_free(*root);
- *root = NULL;
- }
- }
- void dtrie_clear(struct dtrie_node_t *root, dt_delete_func_t delete_payload,
- const unsigned int branches)
- {
- dtrie_delete(root, root, delete_payload, branches);
- }
- int dtrie_insert(struct dtrie_node_t *root, const char *number, const unsigned int numberlen,
- void *data, const unsigned int branches)
- {
- struct dtrie_node_t *node = root;
- unsigned char digit, i=0;
- while (i<numberlen) {
- if (branches==10) {
- digit = number[i] - '0';
- if (digit>9) {
- LM_ERR("cannot insert non-numerical character\n");
- return -1;
- }
- } else {
- digit = number[i];
- if (digit>127) {
- LM_ERR("cannot insert extended ascii character\n");
- return -1;
- }
- }
- if (node->child[digit] == NULL) {
- node->child[digit] = shm_malloc(sizeof(struct dtrie_node_t));
- if(node->child[digit] == NULL ){
- SHM_MEM_ERROR;
- return -1;
- }
- LM_DBG("allocate %lu bytes for node at %p\n", (long unsigned)sizeof(struct dtrie_node_t), node->child[digit]);
- memset(node->child[digit], 0, sizeof(struct dtrie_node_t));
- node->child[digit]->child = shm_malloc(sizeof(struct dtrie_node_t *) * branches);
- if(node->child[digit]->child == NULL){
- SHM_MEM_ERROR;
- shm_free(node->child[digit]);
- return -1;
- }
- LM_DBG("allocate %lu bytes for %d root children pointer at %p\n",
- (long unsigned)sizeof(struct dtrie_node_t *) * branches,
- branches, node->child[digit]->child);
- memset(node->child[digit]->child, 0, sizeof(struct dtrie_node_t *) * branches);
- }
- node = node->child[digit];
- i++;
- }
- node->data = data;
- return 0;
- }
- unsigned int dtrie_size(const struct dtrie_node_t *root, const unsigned int branches)
- {
- unsigned int i, sum = 0;
- if (root == NULL) return 0;
- for (i=0; i<branches; i++) {
- sum += dtrie_size(root->child[i], branches);
- }
- return sum+1;
- }
- unsigned int dtrie_loaded_nodes(const struct dtrie_node_t *root, const unsigned int branches)
- {
- unsigned int i, sum = 0;
- if (root == NULL) return 0;
- for (i=0; i<branches; i++) {
- sum += dtrie_loaded_nodes(root->child[i], branches);
- }
- if (root->data != NULL) sum++;
- return sum;
- }
- unsigned int dtrie_leaves(const struct dtrie_node_t *root, const unsigned int branches)
- {
- unsigned int i, sum = 0, leaf = 1;
- for (i=0; i<branches; i++) {
- if (root->child[i]) {
- sum += dtrie_leaves(root->child[i], branches);
- leaf = 0;
- }
- }
- return sum+leaf;
- }
- void **dtrie_longest_match(struct dtrie_node_t *root, const char *number,
- const unsigned int numberlen, int *nmatchptr, const unsigned int branches)
- {
- struct dtrie_node_t *node = root;
- unsigned char digit, i = 0;
- void **ret = NULL;
- if (nmatchptr) *nmatchptr=-1;
- if (node->data != NULL) {
- if (nmatchptr) *nmatchptr=0;
- ret = &node->data;
- }
- while (i<numberlen) {
- if (branches==10) {
- digit = number[i] - '0';
- if (digit>9) return ret;
- } else {
- digit = number[i];
- if (digit>127) return ret;
- }
-
- if (node->child[digit] == NULL) return ret;
- node = node->child[digit];
- i++;
- if (node->data != NULL) {
- if (nmatchptr) *nmatchptr=i;
- ret = &node->data;
- }
- }
- return ret;
- }
- void **dtrie_contains(struct dtrie_node_t *root, const char *number,
- const unsigned int numberlen, const unsigned int branches)
- {
- int nmatch;
- void **ret;
- ret = dtrie_longest_match(root, number, numberlen, &nmatch, branches);
- if (nmatch == numberlen) return ret;
- return NULL;
- }
|