⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sfxhash.c

📁 Linux snort-2.4.4源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*! * *  \f sfxhash.c * *  A Customized hash table library for storing and accessing key + data pairs. * *  This table incorporates a memory manager (memcap.c) to provide a memory cap,   *  and an automatic node recovery system for out of memory management. Keys and *  Data are copied into the hash table during the add operation. The data may *  be allocated and free'd by the user (by setting the datasize to zero ). A  *  user callback is provided to allow the user to do cleanup whenever a node *  is released, by either the ANR system or the relase() function. * *  Users can and should delete nodes when they know they are not needed anymore, *  but this custom table is designed for the case where nodes are allocated  *  permanently, we have to limit memory, and we wish to recycle old nodes.   *  Many problems have a natural node ageing paradigm working in our favor,  *  so automated node aging makes sense. i.e. thresholding, tcp state. * *  This hash table maps keys to data.  All keys must be unique. *  Uniqueness is enforcedby the code. * *  Features: * *    1) Keys must be fixed length (per table) binary byte sequences. *         keys are copied during the add function *    2) Data must be fixed length (per table) binary byte sequences. *         data is copied during the add function - if datasize > 0 *       Data may be managed by the user as well. *    3) Table row sizes can be automatically adjusted to *       the nearest prime number size during table initialization/creation. *    4) Memory management includes tracking the size of each allocation,  *       number of allocations, enforcing a memory cap, and automatic node  *       recovery - when  memory is low the oldest untouched node *       is unlinked and recycled for use as a new node. * *  Per Node Memory Usage: *  ---------------------- *     SFXHASH_NODE bytes *     KEYSIZE bytes *     [DATASIZE bytes] if datasize > 0 during call to sfxhash_new. * *  The hash node memory (sfxhash_node,key,and data) is allocated with  *  one call to s_malloc/memcap_alloc. * *  Copyright (C) 2001 Marc A Norton. *  Copyright (C) 2003 Sourcefire,Inc. * *  2003-06-03: cmg - added sfxhash_{l,m}ru to return {least,most} *              recently used node from the global list * *              - added _anrcount function *              - changed count function to return unsigned to match structure * *  2003-06-11: cmg added *              overhead_bytes + blocks to separate out the *              memcap constraints from the hash table itself *              find success v fail * *  2003-06-19: cmg added * *              ability to set own hash function *              ability to set own key cmp function * *  2003-06-30: rdempster *              fixed bug in that would anr from the freelist *               *  2005-11-15: modified sfxhash_add to check if 'data' is zero before memcpy'ing. *              this allows user to pass null for data, and set up the data area *              themselves after the call - this is much more flexible. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include "sfxhash.h"/* * Private Malloc - abstract the memory system */static void * s_malloc( SFXHASH * t, int n ){    return sfmemcap_alloc( &t->mc, n );}static void s_free( SFXHASH * t, void * p ){    sfmemcap_free( &t->mc, p );}/* *   User access to the memory management, do they need it ? WaitAndSee */void * sfxhash_alloc( SFXHASH * t, unsigned nbytes ){    return s_malloc( t, nbytes );}void   sfxhash_free( SFXHASH * t, void * p ){    s_free( t, p );}#ifdef XXXX/* *  A classic hash routine using prime numbers  * *  Constants for the Prime No. based hash routines   */#define PRIME_INIT   9791#define PRIME_SCALE  31static unsigned sfxhash_data( unsigned char *d, int n ){    int i;    register unsigned hash = PRIME_INIT;    for(i=0;i<n;i++)    {        hash = hash * PRIME_SCALE + d[i];    }      return hash;}#endif /* XXXX *//* *   Primiitive Prime number test, not very fast nor efficient, but should be ok for  *   hash table sizes of typical size.  NOT for real-time usage! */static int isPrime(int num ){    int i;    for(i=2;i<num;i++)    {        if( (num % i) == 0 ) break;//oops not prime, should have a remainder    }    if( i == num ) return 1;    return 0;}/* *  Iterate number till we find a prime. */static int calcNextPrime(int num ){    while( !isPrime( num ) ) num++;    return num;}/*! * * Create a new hash table * * By default, this will "splay" nodes to the top of a free list.  * * @param nrows    number of rows in hash table * @param keysize  key size in bytes, same for all keys * @param datasize datasize in bytes, zero indicates user manages data * @param maxmem   maximum memory to use in bytes * @param anr_flag Automatic Node Recovery boolean flag * @param anrfree  users Automatic Node Recovery memory release function * @param usrfree  users standard memory release function * * @return SFXHASH* * @retval  0 out of memory * @retval !0 Valid SFXHASH pointer   * *//*  Notes:  if nrows < 0 don't cal the nearest prime.  datasize must be the same for all entries, unless datasize is zero.  maxmem of 0 indicates no memory limits.*/SFXHASH * sfxhash_new( int nrows, int keysize, int datasize, int maxmem,                        int anr_flag,                        int (*anrfree)(void * key, void * data),                       int (*usrfree)(void * key, void * data),                       int recycle_flag ){    int       i;    SFXHASH * h;    if( nrows > 0 ) /* make sure we have a prime number */    {        nrows = calcNextPrime( nrows );    }    else   /* use the magnitude or nrows as is */    {         nrows = -nrows;    }    /* Allocate the table structure from general memory */    h = (SFXHASH*) calloc( 1, sizeof(SFXHASH) );    if( !h )     {        return 0;    }    /* this has a default hashing function */    h->sfhashfcn = sfhashfcn_new( nrows );        if( !h->sfhashfcn )     {        return 0;    }    sfmemcap_init( &h->mc, maxmem );    /* Allocate the array of node ptrs */    h->table = (SFXHASH_NODE**) s_malloc( h, sizeof(SFXHASH_NODE*) * nrows );    if( !h->table )     {        return 0;    }    for( i=0; i<nrows; i++ )    {        h->table[i] = 0;    }    h->anrfree  = anrfree;    h->usrfree  = usrfree;    h->keysize  = keysize;    h->datasize = datasize;    h->nrows    = nrows;    h->crow     = 0;     h->cnode    = 0;     h->count    = 0;    h->ghead    = 0;    h->gtail    = 0;    h->anr_count= 0;        h->anr_tries= 0;    h->anr_flag = anr_flag;     h->splay    = 1;     h->recycle_nodes = recycle_flag;    h->find_success = 0;    h->find_fail    = 0;        /* save off how much we've already allocated from our memcap */        h->overhead_bytes = h->mc.memused;    h->overhead_blocks = h->mc.nblocks;    return h;}/*! *  Set Splay mode : Splays nodes to front of list on each access *  * @param t SFXHASH table pointer * @param n boolean flag toggles splaying of hash nodes * */void sfxhash_splaymode( SFXHASH * t, int n ){    t->splay = n;}/*! *  Delete the hash Table  * *  free key's, free node's, and free the users data. * * @param h SFXHASH table pointer * */void sfxhash_delete( SFXHASH * h ){    unsigned    i;    SFXHASH_NODE * node, * onode;    if( !h ) return;     if( h->sfhashfcn ) sfhashfcn_free( h->sfhashfcn );     if( h->table )    {          for(i=0;i<h->nrows;i++)        {            for( node=h->table[i]; node;  )            {                onode = node;                node  = node->next;                                /* Notify user that we are about to free this node function */                if( h->usrfree )                    h->usrfree( onode->key, onode->data );                        s_free( h,onode );            }        }        s_free( h, h->table );        h->table = 0;    }    free( h ); /* free the table from general memory */}/*! *  Get the # of Nodes in HASH the table * * @param t SFXHASH table pointer * */unsigned sfxhash_count( SFXHASH * t ){    return t->count;}/*! *  Get the # auto recovery  * * @param t SFXHASH table pointer * */unsigned sfxhash_anr_count( SFXHASH * t ){    return t->anr_count;}/*! *  Get the # finds * * @param t SFXHASH table pointer * */unsigned sfxhash_find_total( SFXHASH * t ){    return t->find_success + t->find_fail;}/*! *  Get the # unsucessful finds * * @param t SFXHASH table pointer * */unsigned sfxhash_find_fail( SFXHASH * t ){    return t->find_fail;}/*! *  Get the # sucessful finds * * @param t SFXHASH table pointer * */unsigned sfxhash_find_success( SFXHASH * t ){    return t->find_success;}/*! *  Get the # of overhead bytes * * @param t SFXHASH table pointer * */unsigned sfxhash_overhead_bytes( SFXHASH * t ){    return t->overhead_bytes;}/*! *  Get the # of overhead blocks * * @param t SFXHASH table pointer * */unsigned sfxhash_overhead_blocks( SFXHASH * t ){    return t->overhead_blocks;}/* *  Free List - uses the NODE gnext/gprev fields */staticvoid sfxhash_save_free_node( SFXHASH *t, SFXHASH_NODE * hnode ){    /* Add A Node to the Free Node List */    if( t->fhead ) /* add the node to head of the the existing list */    {        hnode->gprev    = 0;          hnode->gnext    = t->fhead;        t->fhead->gprev = hnode;        t->fhead        = hnode;        /* tail is not affected */    }    else /* 1st node in this list */    {        hnode->gprev = 0;        hnode->gnext = 0;        t->fhead    = hnode;        t->ftail    = hnode;    }}staticSFXHASH_NODE * sfxhash_get_free_node( SFXHASH *t ){    SFXHASH_NODE * node = t->fhead;    /* Remove A Node from the Free Node List - remove the head node */    if( t->fhead  )     {        t->fhead = t->fhead->gnext;        if( t->fhead )             t->fhead->gprev = 0;        if( t->ftail  == node ) /* no more nodes - clear the tail */            t->ftail  =  0;    }    return node;}staticvoid sfxhash_glink_node( SFXHASH *t, SFXHASH_NODE * hnode ){    /* Add The Node */    if( t->ghead ) /* add the node to head of the the existing list */    {        hnode->gprev    = 0;          hnode->gnext    = t->ghead;        t->ghead->gprev = hnode;        t->ghead        = hnode;        /* tail is not affected */    }    else /* 1st node in this list */    {        hnode->gprev = 0;        hnode->gnext = 0;        t->ghead    = hnode;        t->gtail    = hnode;    }}staticvoid sfxhash_gunlink_node( SFXHASH *t, SFXHASH_NODE * hnode ){    /* Remove the Head Node */    if( t->ghead == hnode ) /* add the node to head of the the existing list */    {        t->ghead = t->ghead->gnext;        if( t->ghead )             t->ghead->gprev = 0;    }    if( hnode->gprev ) hnode->gprev->gnext = hnode->gnext;    if( hnode->gnext ) hnode->gnext->gprev = hnode->gprev;    if( t->gtail  == hnode )        t->gtail  =  hnode->gprev;             }void sfxhash_gmovetofront( SFXHASH *t, SFXHASH_NODE * hnode ){    if( hnode != t->ghead )    {        sfxhash_gunlink_node( t, hnode );        sfxhash_glink_node( t, hnode );    }}/* * */staticvoid sfxhash_link_node( SFXHASH * t, SFXHASH_NODE * hnode ){    /* Add The Node to the Hash Table Row List */    if( t->table[hnode->rindex] ) /* add the node to the existing list */    {        hnode->prev = 0;  // insert node as head node        hnode->next=t->table[hnode->rindex];        t->table[hnode->rindex]->prev = hnode;        t->table[hnode->rindex] = hnode;    }    else /* 1st node in this list */    {        hnode->prev=0;        hnode->next=0;        t->table[hnode->rindex] = hnode;    }}staticvoid sfxhash_unlink_node( SFXHASH * t, SFXHASH_NODE * hnode ){    if( hnode->prev )  // definitely not the 1st node in the list    {        hnode->prev->next = hnode->next;        if( hnode->next )             hnode->next->prev = hnode->prev;    }    else if( t->table[hnode->rindex] )  // must be the 1st node in the list    {        t->table[hnode->rindex] = t->table[hnode->rindex]->next;        if( t->table[hnode->rindex] )            t->table[hnode->rindex]->prev = 0;    }}/* *  move a node to the front of the row list at row = 'index' */static void movetofront( SFXHASH *t, SFXHASH_NODE * n ){    /* Modify Hash Node Row List */    if( t->table[n->rindex] != n ) // if not at front of list already...    {        /* Unlink the node */        sfxhash_unlink_node( t, n );             /* Link at front of list */        sfxhash_link_node( t, n );    }    /* Move node in the global hash node list to the front */    sfxhash_gmovetofront( t, n );}/* * Allocat a new hash node, uses Auto Node Recovery if needed and enabled. *  * The oldest node is the one with the longest time since it was last touched,  * and does not have any direct indication of how long the node has been around. * We don't monitor the actual time since last being touched, instead we use a * splayed global list of node pointers. As nodes are accessed they are splayed * to the front of the list. The oldest node is just the tail node. * */static SFXHASH_NODE * sfxhash_newnode( SFXHASH * t ){    SFXHASH_NODE * hnode;    /* Recycle Old Nodes - if any */    hnode = sfxhash_get_free_node( t );    /* Allocate memory for a node */    if( ! hnode )    {        hnode = (SFXHASH_NODE*)s_malloc( t, sizeof(SFXHASH_NODE) +                                         t->keysize + t->datasize );    }            /*  If we still haven't found hnode, we're at our memory limit.     *     *  Uses Automatic Node Recovery, to recycle the oldest node-based on access     *  (Unlink and reuse the tail node)     */     if( !hnode && t->anr_flag && t->gtail )    {        /* Find the oldes node the users willing to let go. */        for(hnode = t->gtail; hnode; hnode = hnode->gprev )        {            if( t->anrfree ) /* User has provided a permission+release callback function */            {                t->anr_tries++;/* Count # ANR requests */                                /* Ask the user for permission to release this node, but let them say no! */                if( t->anrfree( hnode->key, hnode->data ) )                {                    /* NO, don't recycle this node, user's not ready to let it go. */                                                continue;                }                                /* YES, user said we can recycle this node */            }            sfxhash_gunlink_node( t, hnode ); /* unlink from the global list */            sfxhash_unlink_node( t, hnode ); /* unlink from the row list */            t->count--;            t->anr_count++; /* count # of ANR operations */            break;        }    }    /* either we are returning a node or we're all full and the user     * won't let us allocate anymore and we return NULL */    return hnode;}/* * *  Find a Node based on the key, return the node and the index. *  The index is valid even if the return value is NULL, in which *  case the index is the corect row in which the node should be  *  created. * */static SFXHASH_NODE * sfxhash_find_node_row( SFXHASH * t, void * key, int * rindex ){    unsigned       hashkey;    int            index;    SFXHASH_NODE  *hnode;    hashkey = t->sfhashfcn->hash_fcn( t->sfhashfcn,                                      (unsigned char*)key,                                      t->keysize );    /*     printf("hashkey: %u t->keysize: %d\n", hashkey, t->keysize); *//*     flowkey_fprint(stdout, key);  *//*     printf("****\n"); */    index   = hashkey % t->nrows;    *rindex = index;       for( hnode=t->table[index]; hnode; hnode=hnode->next )    {        if( !t->sfhashfcn->keycmp_fcn(hnode->key,key,t->keysize) )        {            if( t->splay > 0 )                movetofront(t,hnode);            t->find_success++;                        return hnode;        }    }    t->find_fail++;                return NULL;}/*! * Add a key + data pair to the hash table * * 2003-06-06: *  - unique_tracker.c assumes that this splays *    nodes to the top when they are added. * *    This is done because of the successful find. * * @param t SFXHASH table pointer

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -