hashTable.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * SNMPStats Module 
00005  * Copyright (C) 2006 SOMA Networks, INC.
00006  * Written by: Jeffrey Magder (jmagder@somanetworks.com)
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify it
00011  * under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023  * USA
00024  *
00025  * History:
00026  * --------
00027  * 2006-11-23 initial version (jmagder)
00028  *
00029  * Hash Stuff;
00030  */
00031 
00044 #include <stdlib.h>
00045 #include <string.h>
00046 
00047 #include "hashTable.h"
00048 #include "../../dprint.h"
00049 #include "../../mem/mem.h"
00050 
00051 #include <net-snmp/net-snmp-config.h>
00052 #include <net-snmp/net-snmp-includes.h>
00053 #include <net-snmp/agent/net-snmp-agent-includes.h>
00054 #include "snmpSIPRegUserTable.h"
00055 
00056 
00060 int calculateHashSlot(char *theString, int hashTableSize) 
00061 {
00062         char *currentCharacter = theString;
00063         int   runningTotal     = 0;
00064 
00065         while (*currentCharacter != '\0') {
00066                 runningTotal += *currentCharacter;
00067                 currentCharacter++;
00068         }
00069 
00070         return runningTotal % hashTableSize;
00071 }
00072 
00084 aorToIndexStruct_t *findHashRecord(hashSlot_t *theTable, char *aor, int size)
00085 {
00086         int hashIndex = calculateHashSlot(aor, size);
00087         int aorStringLength = strlen(aor);
00088 
00089         aorToIndexStruct_t *currentRecord = theTable[hashIndex].first;
00090 
00091         while (currentRecord != NULL) {
00092                 
00093                 /* If the strings are the same length and the same in every
00094                  * other way, then return the given record. */
00095                 if (currentRecord->aorLength == aorStringLength &&
00096                     memcmp(currentRecord->aor, aor, aorStringLength)==0) {
00097                         return currentRecord;
00098                 }
00099 
00100                 currentRecord = currentRecord->next;
00101         }
00102 
00103         return NULL;
00104 }
00105 
00106 
00110 hashSlot_t  *createHashTable(int size) 
00111 {
00112         hashSlot_t *hashTable     = NULL;
00113         int         numberOfBytes = sizeof(hashSlot_t)*size;
00114 
00115         hashTable = pkg_malloc(numberOfBytes);
00116 
00117         if (!hashTable)
00118         {
00119                 LM_ERR("no more pkg memory");
00120                 return NULL;
00121         }
00122 
00123         memset(hashTable, 0, numberOfBytes);
00124 
00125         return hashTable;
00126 }
00127 
00128 
00130 void insertHashRecord(hashSlot_t *theTable, aorToIndexStruct_t *theRecord, 
00131                 int size) 
00132 {
00133         int hashIndex = calculateHashSlot(theRecord->aor, size);
00134 
00135         /* Link up this record backward so that it points to whatever the last
00136          * 'last element' was.  */
00137         theRecord->prev = theTable[hashIndex].last;
00138 
00139         /* This is the first record in the hash table, so assign the first and
00140          * last pointers to this record. */
00141         if (theTable[hashIndex].last == NULL) {
00142                 
00143                 theTable[hashIndex].last  = theRecord;
00144                 theTable[hashIndex].first = theRecord;
00145 
00146         } else {
00147                 
00148                 /* Make the element that was previously the last element point
00149                  * to this new record, as its next element. */
00150                 theTable[hashIndex].last->next = theRecord;
00151 
00152                 /* Reassign the 'final element' pointer to this new record. */
00153                 theTable[hashIndex].last = theRecord;
00154 
00155         }
00156         
00157 }
00158 
00168 void deleteUser(hashSlot_t *theTable, char *aor, int hashTableSize)
00169 {
00170         int hashIndex = calculateHashSlot(aor, hashTableSize);
00171         int searchStringLength = strlen(aor);
00172 
00173         aorToIndexStruct_t *previousRecord = theTable[hashIndex].first;
00174         aorToIndexStruct_t *currentRecord  = theTable[hashIndex].first;
00175 
00176         while (currentRecord != NULL) {
00177 
00178                 /* First make sure both strings are the same length.  If so,
00179                  * then compare all bytes.  If this succeeds, then we need to
00180                  * link up the previous and next element together. */
00181                 if (currentRecord->aorLength == searchStringLength &&
00182                     memcmp(currentRecord->aor, aor, searchStringLength) == 0) {
00183 
00184                         currentRecord->numContacts--;
00185 
00186                         /* There are still contacts relying on this user, so
00187                          * don't delete anything. */
00188                         if (currentRecord->numContacts > 0) 
00189                         {
00190                                 return;
00191                         }
00192 
00193                         /* There are no more contacts relying on this user, so
00194                          * delete the row from the table. */
00195                         deleteRegUserRow(currentRecord->userIndex);
00196 
00197 
00198                         /* Maintenance of the hash table */
00199 
00200                         if (currentRecord->prev == NULL) 
00201                         {
00202                                         /* Edge Case: First element in list was just deleted, so set
00203                                          * up the first element to point to the one after the one
00204                                          * just deleted */
00205                                         theTable[hashIndex].first = currentRecord->next;
00206                         }
00207                         else
00208                         {
00209                                         /* Not the first element, so hook up the previous node to
00210                                          * the node after the one just deleted. */
00211                                         currentRecord->prev->next = currentRecord->next;
00212                         }
00213 
00214                         if (currentRecord->next == NULL)
00215                         {
00216                                         /* Edge Case: The last element has been targetted for
00217                                          * deletion.  So move the pointer to the node just before
00218                                          * this one.  */
00219                                         theTable[hashIndex].last = currentRecord->prev;
00220                         }
00221                         else
00222                         {
00223                                         /* Not the last element, so hook up next nodes previous
00224                                          * element to this nodes previous.  */
00225                                         currentRecord->next->prev = currentRecord->prev;
00226                         }
00227 
00228                         pkg_free(currentRecord);
00229 
00230                         /* We are done, so just return. */
00231                         return;
00232                 }
00233 
00234                 /* Advance to the next records. */
00235                 previousRecord = currentRecord;
00236                 currentRecord = currentRecord->next;
00237         }
00238 
00239 }
00240 
00241 
00250 aorToIndexStruct_t *createHashRecord(int userIndex, char *aor) 
00251 {
00252         int aorLength =strlen(aor);
00253 
00254     aorToIndexStruct_t *theRecord = pkg_malloc(sizeof(aorToIndexStruct_t)+
00255             (aorLength+1)* sizeof(char));
00256         if (theRecord == NULL)
00257         {
00258                 LM_ERR("failed to create a mapping record for %s", aor);
00259                 return NULL;
00260         }
00261 
00262         memset(theRecord, 0, sizeof(aorToIndexStruct_t));
00263 
00264         theRecord->aor = (char*)theRecord + sizeof(aorToIndexStruct_t);
00265     memcpy(theRecord->aor, aor, aorLength );
00266         theRecord->aor[aorLength] = '\0';
00267     theRecord->aorLength = aorLength;
00268         theRecord->userIndex = userIndex;
00269         theRecord->numContacts = 1;
00270 
00271         return theRecord;
00272 }
00273 
00274 
00275 
00276 
00278 void printHashSlot(hashSlot_t *theTable, int index) 
00279 {
00280         aorToIndexStruct_t *currentRecord = theTable[index].first;
00281 
00282         LM_ERR("dumping Hash Slot #%d\n", index);
00283 
00284         while (currentRecord != NULL) {
00285                 LM_ERR( "\tString: %s - Index: %d\n", 
00286                                 currentRecord->aor, currentRecord->userIndex);
00287                 currentRecord = currentRecord->next;
00288         }
00289 }