forked from Mirrors/sngrep
htable: Custom hashtable implementation
This commit is contained in:
parent
03a0ebc7d0
commit
d6d5665394
|
@ -12,7 +12,7 @@ sngrep_SOURCES+=capture_openssl.c
|
|||
endif
|
||||
sngrep_SOURCES+=address.c packet.c sip.c sip_call.c sip_msg.c sip_attr.c main.c
|
||||
sngrep_SOURCES+=option.c group.c filter.c keybinding.c media.c setting.c rtp.c
|
||||
sngrep_SOURCES+=util.c vector.c ui_panel.c scrollbar.c
|
||||
sngrep_SOURCES+=util.c hash.c vector.c ui_panel.c scrollbar.c
|
||||
sngrep_SOURCES+=ui_manager.c ui_call_list.c ui_call_flow.c ui_call_raw.c
|
||||
sngrep_SOURCES+=ui_stats.c ui_filter.c ui_save.c ui_msg_diff.c
|
||||
sngrep_SOURCES+=ui_column_select.c ui_settings.c
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** sngrep - SIP Messages flow viewer
|
||||
**
|
||||
** Copyright (C) 2013-2016 Ivan Alonso (Kaian)
|
||||
** Copyright (C) 2013-2016 Irontec SL. All rights reserved.
|
||||
**
|
||||
** This program 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 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program 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, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
****************************************************************************/
|
||||
/**
|
||||
* @file hash.c
|
||||
* @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
|
||||
*
|
||||
* @brief Source code of functions defined in hash.h
|
||||
*
|
||||
*/
|
||||
#include "hash.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
htable_t *
|
||||
htable_create(size_t size)
|
||||
{
|
||||
htable_t *h;
|
||||
|
||||
// Allocate memory for this table data
|
||||
if (!(h = malloc(sizeof(htable_t))))
|
||||
return NULL;
|
||||
|
||||
h->size = size;
|
||||
|
||||
// Allocate memory for this table buckets
|
||||
if (!(h->buckets = malloc(sizeof(hentry_t) * size))) {
|
||||
free(h);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Initialize allocated memory
|
||||
memset(h->buckets, 0, sizeof(hentry_t) * size);
|
||||
|
||||
// Return allocated table
|
||||
return h;
|
||||
}
|
||||
|
||||
void
|
||||
htable_destroy(htable_t *table)
|
||||
{
|
||||
free(table->buckets);
|
||||
free(table);
|
||||
}
|
||||
|
||||
int
|
||||
htable_insert(htable_t *table, const char *key, void *data)
|
||||
{
|
||||
// Get hash position for given entry
|
||||
size_t pos = htable_hash(table, key);
|
||||
|
||||
// Create a new entry for given key
|
||||
hentry_t *entry;
|
||||
if (!(entry = malloc(sizeof(hentry_t))))
|
||||
return -1;
|
||||
|
||||
entry->key = key;
|
||||
entry->data = data;
|
||||
entry->next = 0;
|
||||
|
||||
// Check if the hash position is in use
|
||||
hentry_t *exists = table->buckets[pos];
|
||||
|
||||
if (!exists) {
|
||||
table->buckets[pos] = entry;
|
||||
} else {
|
||||
while (exists->next) {
|
||||
exists = exists->next;
|
||||
}
|
||||
exists->next = entry;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
htable_remove(htable_t *table, const char *key)
|
||||
{
|
||||
// Get hash position for given entry
|
||||
size_t pos = htable_hash(table, key);
|
||||
|
||||
// Check if the hash position is in use
|
||||
hentry_t *entry, *prev = NULL;
|
||||
for (entry = table->buckets[pos]; entry; prev = entry, entry = entry->next) {
|
||||
if (!strcmp(entry->key, key)) {
|
||||
if (prev) {
|
||||
prev->next = entry->next;
|
||||
} else {
|
||||
table->buckets[pos] = entry->next;
|
||||
}
|
||||
// Remove item memory
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
htable_find(htable_t *table, const char *key)
|
||||
{
|
||||
// Get hash position for given entry
|
||||
size_t pos = htable_hash(table, key);
|
||||
|
||||
// Check if the hash position is in use
|
||||
hentry_t *entry;
|
||||
for (entry = table->buckets[pos]; entry; entry = entry->next) {
|
||||
if (!strcmp(entry->key, key)) {
|
||||
//! Found
|
||||
return entry->data;
|
||||
}
|
||||
}
|
||||
|
||||
// Not found
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t
|
||||
htable_hash(htable_t *table, const char *key)
|
||||
{
|
||||
// dbj2 - http://www.cse.yorku.ca/~oz/hash.html
|
||||
size_t hash = 5381;
|
||||
while (*key++) {
|
||||
hash = ((hash << 5) + hash) ^ *key;
|
||||
}
|
||||
return hash & (table->size - 1);
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** sngrep - SIP Messages flow viewer
|
||||
**
|
||||
** Copyright (C) 2013-2016 Ivan Alonso (Kaian)
|
||||
** Copyright (C) 2013-2016 Irontec SL. All rights reserved.
|
||||
**
|
||||
** This program 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 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program 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, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
****************************************************************************/
|
||||
/**
|
||||
* @file hash.h
|
||||
* @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
|
||||
*
|
||||
* @brief Functions to manage hash tables
|
||||
*/
|
||||
|
||||
#ifndef __SNGREP_HASH_H_
|
||||
#define __SNGREP_HASH_H_
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
|
||||
//! Shorter declaration of hash structures
|
||||
typedef struct htable htable_t;
|
||||
typedef struct hentry hentry_t;
|
||||
|
||||
/**
|
||||
* Structure to hold a Hash table entry
|
||||
*/
|
||||
struct hentry {
|
||||
//! Key of the hash entry
|
||||
const char *key;
|
||||
//! Pointer to has entry data
|
||||
void *data;
|
||||
//! Next entry sharing the same hash value
|
||||
hentry_t *next;
|
||||
};
|
||||
|
||||
struct htable {
|
||||
//! Fixed hash table limit
|
||||
size_t size;
|
||||
// Hash table entries
|
||||
hentry_t **buckets;
|
||||
};
|
||||
|
||||
htable_t *
|
||||
htable_create(size_t size);
|
||||
|
||||
void
|
||||
htable_destroy(htable_t *table);
|
||||
|
||||
int
|
||||
htable_insert(htable_t *table, const char *key, void *data);
|
||||
|
||||
void
|
||||
htable_remove(htable_t *table, const char *key);
|
||||
|
||||
void *
|
||||
htable_find(htable_t *table, const char *key);
|
||||
|
||||
size_t
|
||||
htable_hash(htable_t *table, const char *key);
|
||||
|
||||
#endif /* __SNGREP_HASH_H_ */
|
33
src/sip.c
33
src/sip.c
|
@ -31,7 +31,6 @@
|
|||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <search.h>
|
||||
#include <stdarg.h>
|
||||
#include "sip.h"
|
||||
#include "option.h"
|
||||
|
@ -155,7 +154,7 @@ sip_init(int limit, int only_calls, int no_incomplete)
|
|||
calls.active = vector_create(10, 10);
|
||||
|
||||
// Create hash table for callid search
|
||||
hcreate(calls.limit);
|
||||
calls.callids = htable_create(calls.limit);
|
||||
|
||||
// By default sort by call index ascending
|
||||
calls.sort.by = SIP_ATTR_CALLINDEX;
|
||||
|
@ -182,7 +181,7 @@ sip_deinit()
|
|||
// Remove all calls
|
||||
sip_calls_clear();
|
||||
// Remove Call-id hash table
|
||||
hdestroy();
|
||||
htable_destroy(calls.callids);
|
||||
// Remove calls vector
|
||||
vector_destroy(calls.list);
|
||||
vector_destroy(calls.active);
|
||||
|
@ -278,7 +277,6 @@ sip_validate_packet(packet_t *packet)
|
|||
sip_msg_t *
|
||||
sip_check_packet(packet_t *packet)
|
||||
{
|
||||
ENTRY entry;
|
||||
sip_msg_t *msg;
|
||||
sip_call_t *call;
|
||||
char callid[1024], xcallid[1024];
|
||||
|
@ -346,10 +344,8 @@ sip_check_packet(packet_t *packet)
|
|||
if (!(call = call_create(callid, xcallid)))
|
||||
goto skip_message;
|
||||
|
||||
// Store this call in hash table
|
||||
entry.key = (char *) call->callid;
|
||||
entry.data = (void *) call;
|
||||
hsearch(entry, ENTER);
|
||||
// Add this Call-Id to hash table
|
||||
htable_insert(calls.callids, call->callid, call);
|
||||
|
||||
// Set call index
|
||||
call->index = ++calls.last_index;
|
||||
|
@ -470,13 +466,7 @@ sip_find_by_index(int index)
|
|||
sip_call_t *
|
||||
sip_find_by_callid(const char *callid)
|
||||
{
|
||||
ENTRY entry, *eptr;
|
||||
|
||||
entry.key = (char *) callid;
|
||||
if ((eptr = hsearch(entry, FIND)))
|
||||
return eptr->data;
|
||||
|
||||
return NULL;
|
||||
return htable_find(calls.callids, callid);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -655,8 +645,8 @@ void
|
|||
sip_calls_clear()
|
||||
{
|
||||
// Create again the callid hash table
|
||||
hdestroy();
|
||||
hcreate(calls.limit);
|
||||
htable_destroy(calls.callids);
|
||||
calls.callids = htable_create(calls.limit);
|
||||
// Remove all items from vector
|
||||
vector_clear(calls.list);
|
||||
vector_clear(calls.active);
|
||||
|
@ -665,11 +655,14 @@ sip_calls_clear()
|
|||
void
|
||||
sip_calls_rotate()
|
||||
{
|
||||
// Remove first call from active and call lists
|
||||
sip_call_t *call = vector_first(calls.list);
|
||||
if (sip_call_is_active(call))
|
||||
vector_remove(calls.active, call);
|
||||
|
||||
// Remove from callids hash
|
||||
htable_remove(calls.callids, call->callid);
|
||||
// Remove first call from active and call lists
|
||||
vector_remove(calls.active, call);
|
||||
vector_remove(calls.list, call);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#endif
|
||||
#include "sip_call.h"
|
||||
#include "vector.h"
|
||||
#include "hash.h"
|
||||
|
||||
#define MAX_SIP_PAYLOAD 10240
|
||||
|
||||
|
@ -124,6 +125,8 @@ struct sip_call_list {
|
|||
sip_sort_t sort;
|
||||
//! Last created id
|
||||
int last_index;
|
||||
//! Call-Ids hash table
|
||||
htable_t *callids;
|
||||
|
||||
// Max call limit
|
||||
int limit;
|
||||
|
|
|
@ -201,6 +201,10 @@ vector_remove(vector_t *vector, void *item)
|
|||
{
|
||||
// Get item position
|
||||
int idx = vector_index(vector, item);
|
||||
// Not found in the vector
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
// Decrease item counter
|
||||
vector->count--;
|
||||
// Move the rest of the elements one position up
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
check_PROGRAMS=test-001 test-002 test-003 test-004 test-005
|
||||
check_PROGRAMS+=test-006 test-007 test-008 test-009
|
||||
check_PROGRAMS+=test-006 test-007 test-008 test-009 test-010
|
||||
|
||||
test_001_SOURCES=test_001.c
|
||||
test_002_SOURCES=test_002.c
|
||||
|
@ -10,5 +10,6 @@ test_006_SOURCES=test_006.c
|
|||
test_007_SOURCES=test_007.c ../src/vector.c ../src/util.c
|
||||
test_008_SOURCES=test_008.c
|
||||
test_009_SOURCES=test_009.c
|
||||
test_010_SOURCES=test_010.c ../src/hash.c
|
||||
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** sngrep - SIP Messages flow viewer
|
||||
**
|
||||
** Copyright (C) 2013-2016 Ivan Alonso (Kaian)
|
||||
** Copyright (C) 2013-2016 Irontec SL. All rights reserved.
|
||||
**
|
||||
** This program 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 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program 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, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
****************************************************************************/
|
||||
/**
|
||||
* @file test_vector.c
|
||||
* @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
|
||||
*
|
||||
* Basic testing of vector structures
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "hash.h"
|
||||
|
||||
int main ()
|
||||
{
|
||||
htable_t *table;
|
||||
table = htable_create(10);
|
||||
assert(table);
|
||||
|
||||
// Check a key is not found
|
||||
assert(htable_find(table, "notfoud") == NULL);
|
||||
|
||||
// Check a key can be added
|
||||
htable_insert(table, "key", "data");
|
||||
const char *data = htable_find(table, "key");
|
||||
// And found
|
||||
assert(strcmp(data, "data") == 0);
|
||||
|
||||
// Try filling all the buckets
|
||||
htable_insert(table, "key1", "data1");
|
||||
htable_insert(table, "key2", "data2");
|
||||
htable_insert(table, "key3", "data3");
|
||||
htable_insert(table, "key4", "data4");
|
||||
htable_insert(table, "key5", "data5");
|
||||
htable_insert(table, "key6", "data6");
|
||||
htable_insert(table, "key7", "data7");
|
||||
htable_insert(table, "key8", "data8");
|
||||
htable_insert(table, "key9", "data9");
|
||||
htable_insert(table, "key10", "data10");
|
||||
htable_insert(table, "key11", "data11");
|
||||
htable_insert(table, "key12", "data12");
|
||||
htable_insert(table, "key13", "data13");
|
||||
htable_insert(table, "key14", "data14");
|
||||
htable_insert(table, "key15", "data15");
|
||||
|
||||
// Find one entry
|
||||
const char *data7 = htable_find(table, "key7");
|
||||
assert(strcmp(data7, "data7") == 0);
|
||||
|
||||
// Remove one entry
|
||||
htable_remove(table, "key7");
|
||||
assert(htable_find(table, "key7") == NULL);
|
||||
|
||||
// Find another entries
|
||||
const char *data5 = htable_find(table, "key5");
|
||||
assert(strcmp(data5, "data5") == 0);
|
||||
const char *data10 = htable_find(table, "key10");
|
||||
assert(strcmp(data10, "data10") == 0);
|
||||
|
||||
// Remove all entries
|
||||
htable_remove(table, "key1");
|
||||
htable_remove(table, "key2");
|
||||
htable_remove(table, "key3");
|
||||
htable_remove(table, "key4");
|
||||
htable_remove(table, "key5");
|
||||
htable_remove(table, "key6");
|
||||
htable_remove(table, "key7");
|
||||
htable_remove(table, "key8");
|
||||
htable_remove(table, "key9");
|
||||
htable_remove(table, "key10");
|
||||
htable_remove(table, "key11");
|
||||
htable_remove(table, "key12");
|
||||
htable_remove(table, "key13");
|
||||
htable_remove(table, "key14");
|
||||
htable_remove(table, "key15");
|
||||
|
||||
// Search a not found entry
|
||||
assert(htable_find(table, "key7") == NULL);
|
||||
|
||||
// Destroy the table
|
||||
htable_destroy(table);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue