#include #define HASH_FUNCTION(keyptr, keylen, hashv) HASH_FUNCTION_OVERWRITE(keyptr, keylen, &hashv) #define HASH_KEYCMP(a, b, len) HASH_KEYCMP_OVERWRITE(a, b, len) #include "session_table.h" #include "session_private.h" struct session_table { struct session *root; session_free_cb free_cb; void *arg; uint64_t count; struct session *oldest_ptr; struct session *newest_ptr; }; /****************************************************************************** * Private API ******************************************************************************/ static void HASH_FUNCTION_OVERWRITE(const struct session_key *key, unsigned int keylen, uint32_t *hashv) { *hashv = session_key_hash(key); } static int HASH_KEYCMP_OVERWRITE(const void *key1, const void *key2, size_t len) { struct session_key *sess_key1 = (struct session_key *)key1; struct session_key *sess_key2 = (struct session_key *)key2; if (session_key_cmp(sess_key1, sess_key2) == 0) { return 0; } struct session_key reverse_key; session_key_reverse(sess_key2, &reverse_key); if (session_key_cmp(sess_key1, &reverse_key) == 0) { return 0; } return -1; } static void session_table_add_session_to_linklist(struct session_table *table, struct session *sess) { if (table == NULL || sess == NULL) { return; } if (table->newest_ptr == NULL) { table->oldest_ptr = sess; table->newest_ptr = sess; sess->prev_ptr = NULL; sess->next_ptr = NULL; } else { sess->next_ptr = table->newest_ptr; table->newest_ptr->prev_ptr = sess; sess->prev_ptr = NULL; table->newest_ptr = sess; } } static void session_table_del_session_from_linklist(struct session_table *table, struct session *sess) { if (table == NULL || sess == NULL) { return; } if (sess->prev_ptr == NULL && sess->next_ptr == NULL) { table->oldest_ptr = NULL; table->newest_ptr = NULL; } else if (sess->prev_ptr == NULL && sess->next_ptr != NULL) { table->newest_ptr = sess->next_ptr; sess->next_ptr->prev_ptr = NULL; } else if (sess->prev_ptr != NULL && sess->next_ptr == NULL) { table->oldest_ptr = sess->prev_ptr; sess->prev_ptr->next_ptr = NULL; } else { sess->prev_ptr->next_ptr = sess->next_ptr; sess->next_ptr->prev_ptr = sess->prev_ptr; } sess->prev_ptr = NULL; sess->next_ptr = NULL; } /****************************************************************************** * Public API ******************************************************************************/ struct session_table *session_table_create() { struct session_table *table = (struct session_table *)calloc(1, sizeof(struct session_table)); table->count = 0; table->oldest_ptr = NULL; table->newest_ptr = NULL; return table; } void session_table_destroy(struct session_table *table) { if (table) { struct session *node = NULL; struct session *tmp = NULL; HASH_ITER(hh, table->root, node, tmp) { HASH_DELETE(hh, table->root, node); if (table->free_cb && node) { table->free_cb(node, table->arg); } } table->count--; free(table); table = NULL; } } uint64_t session_table_get_count(struct session_table *table) { if (table == NULL) { return 0; } return table->count; } void session_table_set_freecb(struct session_table *table, session_free_cb free_cb, void *arg) { if (table) { table->free_cb = free_cb; table->arg = arg; } } int session_table_add_session(struct session_table *table, const struct session_key *key, struct session *sess) { if (table == NULL || sess == NULL) { return -1; } if (session_table_find_session(table, key)) { return -1; } HASH_ADD(hh, table->root, key, sizeof(sess->key), sess); session_table_add_session_to_linklist(table, sess); table->count++; return 0; } void session_table_delete_session(struct session_table *table, const struct session_key *key) { if (table == NULL) { return; } struct session *sess = session_table_find_session(table, key); if (sess == NULL) { return; } HASH_DELETE(hh, table->root, sess); if (table->free_cb && sess) { table->free_cb(sess, table->arg); } session_table_del_session_from_linklist(table, sess); table->count--; } struct session *session_table_find_session(struct session_table *table, const struct session_key *key) { if (table == NULL) { return NULL; } struct session *sess = NULL; HASH_FIND(hh, table->root, key, sizeof(struct session_key), sess); return sess; } struct session *session_table_find_oldest_session(struct session_table *table) { if (table == NULL) { return NULL; } return table->oldest_ptr; } struct session *session_table_find_newest_session(struct session_table *table) { if (table == NULL) { return NULL; } return table->newest_ptr; }