#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 *head; // Least recently used struct session *tail; // Most recently used }; /****************************************************************************** * Private API ******************************************************************************/ static void HASH_FUNCTION_OVERWRITE(const struct tuple6 *tuple, unsigned int keylen, uint32_t *hashv) { *hashv = tuple6_hash(tuple); } static int HASH_KEYCMP_OVERWRITE(const void *key_a, const void *key_b, size_t len) { struct tuple6 *tuple_a = (struct tuple6 *)key_a; struct tuple6 *tuple_b = (struct tuple6 *)key_b; if (tuple6_cmp(tuple_a, tuple_b) == 0) { return 0; } struct tuple6 reversed; tuple6_reverse(tuple_b, &reversed); if (tuple6_cmp(tuple_a, &reversed) == 0) { return 0; } return -1; } // add session to the tail of the list static void add_session_to_list(struct session_table *table, struct session *sess) { if (table == NULL || sess == NULL) { return; } sess->next_ptr = NULL; sess->prev_ptr = NULL; if (table->head == NULL && table->tail == NULL) { table->head = sess; table->tail = sess; } else { table->tail->next_ptr = sess; sess->prev_ptr = table->tail; table->tail = sess; } } static void del_session_from_list(struct session_table *table, struct session *sess) { if (table == NULL || sess == NULL) { return; } if (sess->prev_ptr) { sess->prev_ptr->next_ptr = sess->next_ptr; } else { table->head = sess->next_ptr; } if (sess->next_ptr) { sess->next_ptr->prev_ptr = sess->prev_ptr; } else { table->tail = sess->prev_ptr; } } /****************************************************************************** * Public API ******************************************************************************/ struct session_table *session_table_new() { struct session_table *table = (struct session_table *)calloc(1, sizeof(struct session_table)); table->count = 0; table->head = NULL; table->tail = NULL; return table; } void session_table_free(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(struct session_table *table, const struct tuple6 *tuple, struct session *sess) { if (table == NULL || sess == NULL) { return -1; } if (session_table_find_tuple(table, tuple)) { return -1; } HASH_ADD(hh, table->root, tuple, sizeof(sess->tuple), sess); add_session_to_list(table, sess); table->count++; return 0; } void session_table_del(struct session_table *table, const struct tuple6 *tuple) { if (table == NULL) { return; } struct session *sess = session_table_find_tuple(table, tuple); if (sess == NULL) { return; } HASH_DELETE(hh, table->root, sess); if (table->free_cb && sess) { table->free_cb(sess, table->arg); } del_session_from_list(table, sess); table->count--; } struct session *session_table_find_tuple(struct session_table *table, const struct tuple6 *tuple) { if (table == NULL) { return NULL; } struct session *sess = NULL; HASH_FIND(hh, table->root, tuple, sizeof(struct tuple6), sess); if (sess == NULL) { struct tuple6 out; memset(&out, 0, sizeof(struct tuple6)); tuple6_reverse(tuple, &out); HASH_FIND(hh, table->root, &out, sizeof(struct tuple6), sess); } if (sess) { del_session_from_list(table, sess); add_session_to_list(table, sess); } return sess; } struct session *session_table_find_lru(struct session_table *table) { if (table == NULL) { return NULL; } return table->head; } struct session *session_table_find_mru(struct session_table *table) { if (table == NULL) { return NULL; } return table->tail; }