/* * $Id$ * * Copyright (C) 2001-2003 Fhg Fokus * * This file is part of ser, a free SIP server. * * ser 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 * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * ser 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _CRC_H_ #define _CRC_H_ extern unsigned long int crc_32_tab[]; extern unsigned short int ccitt_tab[]; extern unsigned short int crc_16_tab[]; #endif #include <stdio.h> #include <string.h> #include <stdlib.h> #include "hash_func.h" #include "dprint.h" #include "crc.h" #include "ut.h" #ifdef _OBSOLETED int old_hash( str call_id, str cseq_nr ) { int hash_code = 0; int i; #if 0 /*def i386*/ int ci_len, cs_len; char *ci, *cs; trim_len( ci_len, ci, call_id ); trim_len( cs_len, cs, cseq_nr ); int dummy1; if (call_id.len>=4){ asm( "1: \n\r" "addl (%1), %0 \n\r" "add $4, %1 \n\r" "cmp %2, %1 \n\r" "jl 1b \n\r" : "=r"(hash_code), "=r"(dummy1) : "0" (hash_code), "1"(ci), "r"( (ci_len & (~3)) +ci) ); } #else if ( call_id.len>0 ) for( i=0 ; i<call_id.len ; hash_code+=call_id.s[i++] ); #endif #if 0 /*def i386*/ int dummy2; if (cseq_nr.len>=4){ asm( "1: \n\r" "addl (%1), %0 \n\r" "add $4, %1 \n\r" "cmp %2, %1 \n\r" "jl 1b \n\r" : "=r"(hash_code), "=r"(dummy2) : "0" (hash_code), "1"(cs), "r"((cs_len & (~3) )+ cs) ); } #else if ( cseq_nr.len>0 ) for( i=0 ; i<cseq_nr.len ; hash_code+=cseq_nr.s[i++] ); #endif /* this is a buggy line, see bellow hot to fix it -- as this code is obsoleted I dont care anymore */ return hash_code &= (TABLE_ENTRIES-1); /* TABLE_ENTRIES = 2^k */ } #endif int new_hash( str call_id, str cseq_nr ) { int hash_code = 0; int i,j, k, third; int ci_len, cs_len; char *ci, *cs; /* trim EoLs */ /* ci_len = call_id.len; while (ci_len && ((c=call_id.s[ci_len-1])==0 || c=='\r' || c=='\n')) ci_len--; cs_len = cseq_nr.len; while (cs_len && ((c=cseq_nr.s[cs_len-1])==0 || c=='\r' || c=='\n')) cs_len--; */ trim_len( ci_len, ci, call_id ); trim_len( cs_len, cs, cseq_nr ); /* run the cycle from the end ... we are interested in the most-right digits ... and just take the %10 value of it */ third=(ci_len-1)/3; for ( i=ci_len-1, j=2*third, k=third; k>0 ; i--, j--, k-- ) { hash_code+=crc_16_tab[(unsigned char)(*(ci+i)) /*+7*/ ]+ ccitt_tab[*(ci+k)+63]+ ccitt_tab[*(ci+j)+13]; } for( i=0 ; i<cs_len ; i++ ) //hash_code+=crc_32_tab[(cseq_nr.s[i]+hash_code)%243]; hash_code+=ccitt_tab[*(cs+i)+123]; /* hash_code conditioning */ #ifdef _BUG /* not flat ... % 111b has shorter period than & 111b by one and results in different distribution; ( 7 % 7 == 0, 7 %7 == 1 ) % is used as a part of the hash function too, not only for rounding; & is not flat; whoever comes up with a nicer flat hash function which does not take costly division is welcome; feel free to verify distribution using hashtest() */ hash_code &= (TABLE_ENTRIES-1); /* TABLE_ENTRIES = 2^k */ #endif hash_code=hash_code%(TABLE_ENTRIES-1)+1; return hash_code; } void hashtest_cycle( int hits[TABLE_ENTRIES+5], char *ip ) { long int i,j,k, l; int hashv; static char buf1[1024]; static char buf2[1024]; str call_id; str cseq; call_id.s=buf1; cseq.s=buf2; for (i=987654328;i<987654328+10;i++) for (j=85296341;j<85296341+10;j++) for (k=987654;k<=987654+10;k++) for (l=101;l<201;l++) { call_id.len=sprintf( buf1, "%d-%d-%d@%s",(int)i,(int)j, (int)k, ip ); cseq.len=sprintf( buf2, "%d", (int)l ); /* printf("%s\t%s\n", buf1, buf2 ); */ hashv=hash( call_id, cseq ); hits[ hashv ]++; } } int init_hash() { if (TABLE_ENTRIES != (1<<10)) { LOG(L_WARN, "WARNING: hash function optimized for %d entries\n", 1<<10); LOG(L_WARN, "WARNING: use of %d entries may lead " "to unflat distribution\n", TABLE_ENTRIES ); } else { DBG("DEBUG: hash function initialized with optimum table size\n"); } return 1; } void hashtest() { int hits[TABLE_ENTRIES+5]; int i; init_hash(); memset( hits, 0, sizeof hits ); hashtest_cycle( hits, "192.168.99.100" ); hashtest_cycle( hits, "172.168.99.100" ); hashtest_cycle( hits, "142.168.99.100" ); for (i=0; i<TABLE_ENTRIES+5; i++) printf("[%d. %d]\n", i, hits[i] ); exit(0); }