diff --git a/src/session/CMakeLists.txt b/src/session/CMakeLists.txt new file mode 100644 index 0000000..b5f30b0 --- /dev/null +++ b/src/session/CMakeLists.txt @@ -0,0 +1,39 @@ +############################################################################### +# session manager +############################################################################### + +add_library(session_manager + session.cpp + session_address.cpp + session_pool.cpp + session_table.cpp) +target_include_directories(session_manager PUBLIC ${CMAKE_SOURCE_DIR}/deps/uthash) +target_include_directories(session_manager PUBLIC ${CMAKE_SOURCE_DIR}/src/packet) +target_include_directories(session_manager PUBLIC ${CMAKE_SOURCE_DIR}/src/session) +target_link_libraries(session_manager) + +############################################################################### +# gtest +############################################################################### + +add_executable(gtest_session gtest_session.cpp) +target_include_directories(gtest_session PUBLIC ${CMAKE_CURRENT_LIST_DIR}) +target_link_libraries(gtest_session session_manager gtest) + +add_executable(gtest_session_address gtest_session_address.cpp) +target_include_directories(gtest_session_address PUBLIC ${CMAKE_CURRENT_LIST_DIR}) +target_link_libraries(gtest_session_address session_manager gtest) + +add_executable(gtest_session_pool gtest_session_pool.cpp) +target_include_directories(gtest_session_pool PUBLIC ${CMAKE_CURRENT_LIST_DIR}) +target_link_libraries(gtest_session_pool session_manager gtest) + +add_executable(gtest_session_table gtest_session_table.cpp) +target_include_directories(gtest_session_table PUBLIC ${CMAKE_CURRENT_LIST_DIR}) +target_link_libraries(gtest_session_table session_manager gtest) + +include(GoogleTest) +gtest_discover_tests(gtest_session) +gtest_discover_tests(gtest_session_address) +gtest_discover_tests(gtest_session_pool) +gtest_discover_tests(gtest_session_table) \ No newline at end of file diff --git a/src/session/gtest_session.cpp b/src/session/gtest_session.cpp new file mode 100644 index 0000000..cf779ae --- /dev/null +++ b/src/session/gtest_session.cpp @@ -0,0 +1,85 @@ +#include + +#include "session_private.h" + +void free_ex_data(struct session *sess, uint8_t idx, void *ex_ptr, void *arg) +{ + if (ex_ptr) + { + printf("free_ex_data: %s\n", (char *)ex_ptr); + free(ex_ptr); + ex_ptr = NULL; + } +} + +TEST(SESSION, EX_NEW_INDEX) +{ + uint8_t idx1 = session_get_ex_new_index("key1", NULL, NULL); + uint8_t idx2 = session_get_ex_new_index("key2", NULL, NULL); + uint8_t idx3 = session_get_ex_new_index("key1", NULL, NULL); + EXPECT_TRUE(idx1 != idx2); + EXPECT_TRUE(idx1 == idx3); +} + +TEST(SESSION, EX_SET_GET) +{ + struct session sess; + memset(&sess, 0, sizeof(sess)); + uint8_t idx = session_get_ex_new_index("ex_set_get", NULL, NULL); + session_set_ex_data(&sess, idx, (void *)0x1234); + EXPECT_TRUE(session_get0_ex_data(&sess, idx) == (void *)0x1234); +} + +TEST(SESSION, EX_FREE_BY_RESET_NULL) +{ + struct session sess; + memset(&sess, 0, sizeof(sess)); + uint8_t idx = session_get_ex_new_index("ex_free_by_reset_null", free_ex_data, NULL); + char *ptr = strdup("hello"); + session_set_ex_data(&sess, idx, ptr); + session_set_ex_data(&sess, idx, NULL); +} + +TEST(SESSION, EX_FREE_BY_CALL_API) +{ + struct session sess; + memset(&sess, 0, sizeof(sess)); + uint8_t idx = session_get_ex_new_index("ex_free_by_call_api", free_ex_data, NULL); + char *ptr = strdup("hello"); + session_set_ex_data(&sess, idx, ptr); + session_free_ex_data(&sess, idx); +} + +TEST(SESSION, EV_QUEUE) +{ + uint32_t event = 0; + struct session sess; + session_init(&sess); + EXPECT_TRUE(session_pop_event(&sess, &event) == false); + EXPECT_TRUE(session_push_event(&sess, 0x1234) == true); + EXPECT_TRUE(session_pop_event(&sess, &event) == true); + EXPECT_TRUE(event == 0x1234); + EXPECT_TRUE(session_pop_event(&sess, &event) == false); + + for (int j = 0; j < 10; j++) + { + for (uint32_t i = 0; i < SESSION_EVENT_QUEUE_SIZE - 1; i++) + { + EXPECT_TRUE(session_push_event(&sess, i) == true); + } + EXPECT_TRUE(session_push_event(&sess, 0) == false); + + for (uint32_t i = 0; i < SESSION_EVENT_QUEUE_SIZE - 1; i++) + { + EXPECT_TRUE(session_pop_event(&sess, &event) == true); + EXPECT_TRUE(event == i); + } + EXPECT_TRUE(session_pop_event(&sess, &event) == false); + } +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/session/gtest_session_pool.cpp b/src/session/gtest_session_pool.cpp index 9e56cfa..2648280 100644 --- a/src/session/gtest_session_pool.cpp +++ b/src/session/gtest_session_pool.cpp @@ -12,32 +12,45 @@ TEST(SESSION_POOL, POP_PUSH) sess_pool = session_pool_create(3); EXPECT_TRUE(sess_pool != NULL); + EXPECT_TRUE(session_pool_get_count(sess_pool) == 3); - sess1 = session_pool_pop(sess_pool); + sess1 = session_pool_alloc(sess_pool); EXPECT_TRUE(sess1 != NULL); - sess2 = session_pool_pop(sess_pool); + EXPECT_TRUE(session_pool_get_count(sess_pool) == 2); + sess2 = session_pool_alloc(sess_pool); EXPECT_TRUE(sess2 != NULL); - sess3 = session_pool_pop(sess_pool); + EXPECT_TRUE(session_pool_get_count(sess_pool) == 1); + sess3 = session_pool_alloc(sess_pool); EXPECT_TRUE(sess3 != NULL); - sess4 = session_pool_pop(sess_pool); + EXPECT_TRUE(session_pool_get_count(sess_pool) == 0); + sess4 = session_pool_alloc(sess_pool); EXPECT_TRUE(sess4 == NULL); - session_pool_push(sess_pool, sess1); - session_pool_push(sess_pool, sess2); - session_pool_push(sess_pool, sess3); + session_pool_free(sess_pool, sess1); + EXPECT_TRUE(session_pool_get_count(sess_pool) == 1); + session_pool_free(sess_pool, sess2); + EXPECT_TRUE(session_pool_get_count(sess_pool) == 2); + session_pool_free(sess_pool, sess3); + EXPECT_TRUE(session_pool_get_count(sess_pool) == 3); - sess1 = session_pool_pop(sess_pool); + sess1 = session_pool_alloc(sess_pool); EXPECT_TRUE(sess1 != NULL); - sess2 = session_pool_pop(sess_pool); + EXPECT_TRUE(session_pool_get_count(sess_pool) == 2); + sess2 = session_pool_alloc(sess_pool); EXPECT_TRUE(sess2 != NULL); - sess3 = session_pool_pop(sess_pool); + EXPECT_TRUE(session_pool_get_count(sess_pool) == 1); + sess3 = session_pool_alloc(sess_pool); EXPECT_TRUE(sess3 != NULL); - sess4 = session_pool_pop(sess_pool); + EXPECT_TRUE(session_pool_get_count(sess_pool) == 0); + sess4 = session_pool_alloc(sess_pool); EXPECT_TRUE(sess4 == NULL); - session_pool_push(sess_pool, sess1); - session_pool_push(sess_pool, sess2); - session_pool_push(sess_pool, sess3); + session_pool_free(sess_pool, sess1); + EXPECT_TRUE(session_pool_get_count(sess_pool) == 1); + session_pool_free(sess_pool, sess2); + EXPECT_TRUE(session_pool_get_count(sess_pool) == 2); + session_pool_free(sess_pool, sess3); + EXPECT_TRUE(session_pool_get_count(sess_pool) == 3); session_pool_destroy(sess_pool); } diff --git a/src/session/gtest_session_table.cpp b/src/session/gtest_session_table.cpp new file mode 100644 index 0000000..9b8a820 --- /dev/null +++ b/src/session/gtest_session_table.cpp @@ -0,0 +1,132 @@ +#include + +#include "session_address.h" +#include "session_pool.h" +#include "session_table.h" + +#define SESSION_ADDRESS_IPV4_TCP(name) \ + struct session_address name = {0}; \ + (name).layers[0].type = LAYER_IPV4; \ + (name).layers[0].tuple.ipv4.src.s_addr = inet_addr("192.168.1.2"); \ + (name).layers[0].tuple.ipv4.dst.s_addr = inet_addr("192.168.1.3"); \ + (name).layers[1].type = LAYER_TCP; \ + (name).layers[1].tuple.tcp.src = htons(1234); \ + (name).layers[1].tuple.tcp.dst = htons(5678); \ + (name).used = 2; + +#define SESSION_ADDRESS_IPV6_UDP(name) \ + struct session_address name = {0}; \ + (name).layers[0].type = LAYER_IPV6; \ + inet_pton(AF_INET6, "2001:db8:0:0:0:ff00:42:8329", &(name).layers[0].tuple.ipv6.src); \ + inet_pton(AF_INET6, "2001:db8:0:0:0:ff00:42:832a", &(name).layers[0].tuple.ipv6.dst); \ + (name).layers[1].type = LAYER_UDP; \ + (name).layers[1].tuple.udp.src = htons(2345); \ + (name).layers[1].tuple.udp.dst = htons(443); \ + (name).used = 2; + +#define SESSION_ADDRESS_IPV4_UDP_IPV6_TCP(name) \ + struct session_address name = {0}; \ + (name).layers[0].type = LAYER_IPV4; \ + (name).layers[0].tuple.ipv4.src.s_addr = inet_addr("192.168.1.2"); \ + (name).layers[0].tuple.ipv4.dst.s_addr = inet_addr("192.168.1.3"); \ + (name).layers[1].type = LAYER_UDP; \ + (name).layers[1].tuple.udp.src = htons(1234); \ + (name).layers[1].tuple.udp.dst = htons(5678); \ + (name).layers[2].type = LAYER_IPV6; \ + inet_pton(AF_INET6, "2001:db8:0:0:0:ff00:42:8329", &(name).layers[2].tuple.ipv6.src); \ + inet_pton(AF_INET6, "2001:db8:0:0:0:ff00:42:832a", &(name).layers[2].tuple.ipv6.dst); \ + (name).layers[3].type = LAYER_TCP; \ + (name).layers[3].tuple.tcp.src = htons(2345); \ + (name).layers[3].tuple.tcp.dst = htons(443); \ + (name).used = 4; + +static void session_free_callback(struct session *sess, void *arg) +{ + if (sess) + { + struct session_pool *sess_pool = (struct session_pool *)arg; + session_pool_free(sess_pool, sess); + sess = NULL; + } +} + +TEST(SESSION_TABLE, OP_SESSION) +{ + struct session *sess1 = NULL; + struct session *sess2 = NULL; + struct session *sess3 = NULL; + struct session_pool *sess_pool = NULL; + struct session_table *sess_table = NULL; + + SESSION_ADDRESS_IPV4_TCP(sess1_addr); + SESSION_ADDRESS_IPV6_UDP(sess2_addr); + SESSION_ADDRESS_IPV4_UDP_IPV6_TCP(sess3_addr); + + // Create + sess_pool = session_pool_create(3); + EXPECT_TRUE(sess_pool != NULL); + sess_table = session_table_create(); + EXPECT_TRUE(sess_table != NULL); + session_table_set_freecb(sess_table, session_free_callback, sess_pool); + + // Add session + sess1 = session_pool_alloc(sess_pool); + EXPECT_TRUE(sess1 != NULL); + session_set_id(sess1, 1); + session_set_address(sess1, &sess1_addr); + + sess2 = session_pool_alloc(sess_pool); + EXPECT_TRUE(sess2 != NULL); + session_set_id(sess2, 2); + session_set_address(sess2, &sess2_addr); + + sess3 = session_pool_alloc(sess_pool); + EXPECT_TRUE(sess3 != NULL); + session_set_id(sess3, 3); + session_set_address(sess3, &sess3_addr); + + session_table_add_session(sess_table, sess1); + EXPECT_TRUE(session_table_get_count(sess_table) == 1); + session_table_add_session(sess_table, sess2); + EXPECT_TRUE(session_table_get_count(sess_table) == 2); + session_table_add_session(sess_table, sess3); + EXPECT_TRUE(session_table_get_count(sess_table) == 3); + + // Search session with id + EXPECT_TRUE(session_table_search_session_with_id(sess_table, 1) == sess1); + EXPECT_TRUE(session_table_search_session_with_id(sess_table, 2) == sess2); + EXPECT_TRUE(session_table_search_session_with_id(sess_table, 3) == sess3); + + // Search session with address + session_address_reverse(&sess3_addr); + EXPECT_TRUE(session_table_search_session_with_addr(sess_table, &sess1_addr) == sess1); + EXPECT_TRUE(session_table_search_session_with_addr(sess_table, &sess2_addr) == sess2); + EXPECT_TRUE(session_table_search_session_with_addr(sess_table, &sess3_addr) == sess3); + + // Delete session with id + session_table_delete_session_with_id(sess_table, 1); + EXPECT_TRUE(session_table_get_count(sess_table) == 2); + EXPECT_TRUE(session_table_search_session_with_id(sess_table, 1) == NULL); + EXPECT_TRUE(session_table_search_session_with_addr(sess_table, &sess1_addr) == NULL); + + session_table_delete_session_with_id(sess_table, 2); + EXPECT_TRUE(session_table_get_count(sess_table) == 1); + EXPECT_TRUE(session_table_search_session_with_id(sess_table, 2) == NULL); + EXPECT_TRUE(session_table_search_session_with_addr(sess_table, &sess2_addr) == NULL); + + // Delete session with address + session_table_delete_session_with_addr(sess_table, &sess3_addr); + EXPECT_TRUE(session_table_get_count(sess_table) == 0); + EXPECT_TRUE(session_table_search_session_with_id(sess_table, 3) == NULL); + EXPECT_TRUE(session_table_search_session_with_addr(sess_table, &sess3_addr) == NULL); + + // Destroy + session_table_destroy(sess_table); + session_pool_destroy(sess_pool); +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/session/session.cpp b/src/session/session.cpp new file mode 100644 index 0000000..cddc603 --- /dev/null +++ b/src/session/session.cpp @@ -0,0 +1,306 @@ +#include + +#include "session_private.h" + +#define EX_KEY_MAX_LEN 64 + +struct ex_schema +{ + char key[EX_KEY_MAX_LEN]; + session_ex_free_cb *free_cb; + void *args; +}; + +struct ex_manager +{ + struct ex_schema schemas[EX_DATA_MAX_COUNT]; + uint8_t count; +}; + +static struct ex_manager g_ex_manager = {0}; + +/****************************************************************************** + * ev queue + ******************************************************************************/ + +static void event_queue_init(struct event_queue *queue) +{ + queue->head_idx = 0; + queue->tail_idx = 0; +} + +static bool event_queue_is_empty(struct event_queue *queue) +{ + return queue->head_idx == queue->tail_idx; +} + +static bool event_queue_is_full(struct event_queue *queue) +{ + return (queue->tail_idx + 1) % SESSION_EVENT_QUEUE_SIZE == queue->head_idx; +} + +static bool event_queue_push(struct event_queue *queue, uint32_t event) +{ + if (event_queue_is_full(queue)) + { + return false; + } + + queue->events[queue->tail_idx] = event; + queue->tail_idx = (queue->tail_idx + 1) % SESSION_EVENT_QUEUE_SIZE; + + return true; +} + +static bool event_queue_pop(struct event_queue *queue, uint32_t *event) +{ + if (event_queue_is_empty(queue)) + { + return false; + } + + *event = queue->events[queue->head_idx]; + queue->head_idx = (queue->head_idx + 1) % SESSION_EVENT_QUEUE_SIZE; + + return true; +} + +/****************************************************************************** + * session + ******************************************************************************/ + +void session_init(struct session *sess) +{ + memset(sess, 0, sizeof(struct session)); + event_queue_init(&sess->events); +} + +// session id +void session_set_id(struct session *sess, uint64_t id) +{ + sess->id = id; +} + +uint64_t session_get_id(struct session *sess) +{ + return sess->id; +} + +// session address +void session_set_address(struct session *sess, struct session_address *addr) +{ + memcpy(&sess->addr, addr, sizeof(struct session_address)); +} + +struct session_address *session_get0_address(struct session *sess) +{ + return &sess->addr; +} + +// session state +void session_set_state(struct session *sess, enum session_state state) +{ + sess->state = state; +} + +enum session_state session_get_state(struct session *sess) +{ + return sess->state; +} + +// session type +void session_set_type(struct session *sess, enum session_type type) +{ + sess->type = type; +} + +enum session_type session_get_type(struct session *sess) +{ + return sess->type; +} + +// session metrics +void session_inc_c2s_metrics(struct session *sess, uint64_t packets, uint64_t bytes) +{ + sess->c2s_bytes += bytes; + sess->c2s_packets += packets; +} + +void session_inc_s2c_metrics(struct session *sess, uint64_t packets, uint64_t bytes) +{ + sess->s2c_bytes += bytes; + sess->s2c_packets += packets; +} + +uint64_t session_get_c2s_bytes(struct session *sess) +{ + return sess->c2s_bytes; +} + +uint64_t session_get_s2c_bytes(struct session *sess) +{ + return sess->s2c_bytes; +} + +uint64_t session_get_c2s_packets(struct session *sess) +{ + return sess->c2s_packets; +} + +uint64_t session_get_s2c_packets(struct session *sess) +{ + return sess->s2c_packets; +} + +// session metadata +void session_set_c2s_1st_md(struct session *sess, struct metadata *md) +{ + memcpy(&sess->c2s_1st_md, md, sizeof(struct metadata)); +} + +void session_set_s2c_1st_md(struct session *sess, struct metadata *md) +{ + memcpy(&sess->s2c_1st_md, md, sizeof(struct metadata)); +} + +struct metadata *session_get0_c2s_1st_md(struct session *sess) +{ + return &sess->c2s_1st_md; +} + +struct metadata *session_get0_s2c_1st_md(struct session *sess) +{ + return &sess->s2c_1st_md; +} + +// session timestamp +void session_set_create_time(struct session *sess, uint64_t timestamp) +{ + sess->create_time = timestamp; +} + +void session_set_last_time(struct session *sess, uint64_t timestamp) +{ + sess->last_time = timestamp; +} + +void session_set_expire_time(struct session *sess, uint64_t timestamp) +{ + sess->expire_time = timestamp; +} + +uint64_t session_get_create_time(struct session *sess) +{ + return sess->create_time; +} + +uint64_t session_get_last_time(struct session *sess) +{ + return sess->last_time; +} + +uint64_t session_get_expire_time(struct session *sess) +{ + return sess->expire_time; +} + +// session event +bool session_push_event(struct session *sess, uint32_t event) +{ + return event_queue_push(&sess->events, event); +} + +bool session_pop_event(struct session *sess, uint32_t *event) +{ + return event_queue_pop(&sess->events, event); +} + +/****************************************************************************** + * session ex data + ******************************************************************************/ + +/* + * the exdata prodoced by user, and comsumed by same user. + * so, the exdata is not shared by different user. + * otherwise, the exdata need dup by refer count, and free by refer count. + * + * if key exist, not allow update, return original index. + */ +uint8_t session_get_ex_new_index(const char *key, session_ex_free_cb *free_cb, void *args) +{ + if (g_ex_manager.count >= EX_DATA_MAX_COUNT) + { + abort(); + return EX_DATA_MAX_COUNT; + } + + for (uint8_t i = 0; i < g_ex_manager.count; i++) + { + if (strcmp(g_ex_manager.schemas[i].key, key) == 0) + { + return i; + } + } + + uint8_t idx = g_ex_manager.count; + g_ex_manager.count++; + + struct ex_schema *schema = &g_ex_manager.schemas[idx]; + strncpy(schema->key, key, EX_KEY_MAX_LEN); + schema->free_cb = free_cb; + schema->args = args; + + return idx; +} + +/* + * Support update ex_data. + * + * if key exist: run free_cb free old value, then set new value. + * if not run free_cb, old value will be memory leak. + * if not allow update, new value will be memory leak. + * if key not exist: set new value. + */ +void session_set_ex_data(struct session *sess, uint8_t idx, void *val) +{ + if (idx >= g_ex_manager.count) + { + assert(0); + return; + } + + session_free_ex_data(sess, idx); + sess->ex_data[idx] = val; +} + +void *session_get0_ex_data(struct session *sess, uint8_t idx) +{ + if (idx >= g_ex_manager.count) + { + assert(0); + return NULL; + } + + return sess->ex_data[idx]; +} + +/* + * after set ex_data, the owner of ex_data is session, so user should not free it directly. + * if user want to free ex_data, should use session_free_ex_data. + */ +void session_free_ex_data(struct session *sess, uint8_t idx) +{ + if (idx >= g_ex_manager.count) + { + assert(0); + return; + } + + struct ex_schema *schema = &g_ex_manager.schemas[idx]; + if (schema->free_cb != NULL && sess->ex_data[idx] != NULL) + { + schema->free_cb(sess, idx, sess->ex_data[idx], schema->args); + } + + sess->ex_data[idx] = NULL; +} diff --git a/src/session/session.h b/src/session/session.h new file mode 100644 index 0000000..0525fbd --- /dev/null +++ b/src/session/session.h @@ -0,0 +1,130 @@ +#ifndef _SESSION_H +#define _SESSION_H + +#ifdef __cpluscplus +extern "C" +{ +#endif + +#include + +enum session_state +{ + SESSION_STATE_OPENING, + SESSION_STATE_ACTIVE, + SESSION_STATE_DISCARD, + SESSION_STATE_CLOSING, + SESSION_STATE_CLOSED, + SESSION_STATE_FREE, +}; + +enum session_type +{ + SESSION_TYPE_TCP, + SESSION_TYPE_TCP_STREAM, // A TCP stream session is derived from the original TCP session + SESSION_TYPE_UDP, +}; + +enum session_event +{ + SESSION_EVENT_NONE = 0, + SESSION_EVENT_OPEN, + SESSION_EVENT_DATA, + SESSION_EVENT_CLOSE, + SESSION_EVENT_TIMEOUT, + + // Add new event before SESSION_EVENT_MAX + + SESSION_EVENT_MAX, +}; + +struct metadata +{ + char data[64]; // TODO +}; + +struct session; + +/****************************************************************************** + * session + ******************************************************************************/ + +void session_init(struct session *sess); + +// session id +void session_set_id(struct session *sess, uint64_t id); +uint64_t session_get_id(struct session *sess); + +// session address +void session_set_address(struct session *sess, struct session_address *addr); +struct session_address *session_get0_address(struct session *sess); + +// session state +void session_set_state(struct session *sess, enum session_state state); +enum session_state session_get_state(struct session *sess); + +// session type +void session_set_type(struct session *sess, enum session_type type); +enum session_type session_get_type(struct session *sess); + +// session metrics +void session_inc_c2s_metrics(struct session *sess, uint64_t packets, uint64_t bytes); +void session_inc_s2c_metrics(struct session *sess, uint64_t packets, uint64_t bytes); +uint64_t session_get_c2s_bytes(struct session *sess); +uint64_t session_get_s2c_bytes(struct session *sess); +uint64_t session_get_c2s_packets(struct session *sess); +uint64_t session_get_s2c_packets(struct session *sess); + +// session metadata +void session_set_c2s_1st_md(struct session *sess, struct metadata *md); +void session_set_s2c_1st_md(struct session *sess, struct metadata *md); +struct metadata *session_get0_c2s_1st_md(struct session *sess); +struct metadata *session_get0_s2c_1st_md(struct session *sess); + +// session timestamp +void session_set_create_time(struct session *sess, uint64_t timestamp); +void session_set_last_time(struct session *sess, uint64_t timestamp); +void session_set_expire_time(struct session *sess, uint64_t timestamp); +uint64_t session_get_create_time(struct session *sess); +uint64_t session_get_last_time(struct session *sess); +uint64_t session_get_expire_time(struct session *sess); + +// session event +bool session_push_event(struct session *sess, uint32_t event); +bool session_pop_event(struct session *sess, uint32_t *event); + +/****************************************************************************** + * session ex data + ******************************************************************************/ + +typedef void session_ex_free_cb(struct session *sess, uint8_t idx, void *ex_ptr, void *arg); + +/* + * the exdata prodoced by user, and comsumed by same user. + * so, the exdata is not shared by different user. + * otherwise, the exdata need dup by refer count, and free by refer count. + * + * if key exist, not allow update, return original index. + */ +uint8_t session_get_ex_new_index(const char *key, session_ex_free_cb *free_cb, void *args); +/* + * Support update ex_data. + * + * if key exist: run free_cb free old value, then set new value. + * if not run free_cb, old value will be memory leak. + * if not allow update, new value will be memory leak. + * if key not exist: set new value. + */ +void session_set_ex_data(struct session *sess, uint8_t idx, void *val); +void *session_get0_ex_data(struct session *sess, uint8_t idx); +/* + * after set ex_data, the owner of ex_data is session, so user should not free it directly. + * if user want to free ex_data, should use session_free_ex_data. + */ +void session_free_ex_data(struct session *sess, uint8_t idx); + +#ifdef __cpluscplus +} +#endif + +#endif diff --git a/src/session/session_address.cpp b/src/session/session_address.cpp index d151417..6fef91e 100644 --- a/src/session/session_address.cpp +++ b/src/session/session_address.cpp @@ -5,6 +5,7 @@ void session_address_init(struct session_address *addr, const struct packet *packet) { + memset(addr, 0, sizeof(struct session_address)); // TODO } diff --git a/src/session/session_pool.cpp b/src/session/session_pool.cpp index 195a989..b5847a6 100644 --- a/src/session/session_pool.cpp +++ b/src/session/session_pool.cpp @@ -1,4 +1,5 @@ #include "session_pool.h" +#include "session_private.h" struct session_pool { @@ -35,7 +36,7 @@ void session_pool_destroy(struct session_pool *pool) } } -struct session *session_pool_pop(struct session_pool *pool) +struct session *session_pool_alloc(struct session_pool *pool) { if (pool == NULL) { @@ -50,11 +51,12 @@ struct session *session_pool_pop(struct session_pool *pool) pool->sess = sess->next; sess->next = NULL; + pool->count--; return sess; } -void session_pool_push(struct session_pool *pool, struct session *sess) +void session_pool_free(struct session_pool *pool, struct session *sess) { if (pool == NULL || sess == NULL) { @@ -63,4 +65,15 @@ void session_pool_push(struct session_pool *pool, struct session *sess) sess->next = pool->sess; pool->sess = sess; + pool->count++; +} + +uint64_t session_pool_get_count(struct session_pool *pool) +{ + if (pool == NULL) + { + return 0; + } + + return pool->count; } \ No newline at end of file diff --git a/src/session/session_pool.h b/src/session/session_pool.h index a572e2d..d2e9b43 100644 --- a/src/session/session_pool.h +++ b/src/session/session_pool.h @@ -6,16 +6,15 @@ extern "C" { #endif -#include - #include "session.h" struct session_pool; struct session_pool *session_pool_create(uint64_t count); void session_pool_destroy(struct session_pool *pool); -struct session *session_pool_pop(struct session_pool *pool); -void session_pool_push(struct session_pool *pool, struct session *sess); +struct session *session_pool_alloc(struct session_pool *pool); +void session_pool_free(struct session_pool *pool, struct session *sess); +uint64_t session_pool_get_count(struct session_pool *pool); #ifdef __cpluscplus } diff --git a/src/session/session_private.h b/src/session/session_private.h new file mode 100644 index 0000000..8043913 --- /dev/null +++ b/src/session/session_private.h @@ -0,0 +1,92 @@ +/* + * The current file is private to the plugin, and pulgin can only use session.h + * The current file can only be used by session.cpp/session_pool.cpp/session_table.cpp + */ +#ifndef _SESSION_PRIVATE_H +#define _SESSION_PRIVATE_H + +#ifdef __cpluscplus +extern "C" +{ +#endif + +#include "uthash.h" +#include "session.h" +#include "session_address.h" + +#define EX_DATA_MAX_COUNT 128 +#define SESSION_EVENT_QUEUE_SIZE 256 + +struct event_queue +{ + uint32_t head_idx; + uint32_t tail_idx; + uint32_t events[SESSION_EVENT_QUEUE_SIZE]; +}; + +struct session +{ + // session state + enum session_state state; + + // session type + enum session_type type; + + // session metrics + uint64_t c2s_bytes; + uint64_t s2c_bytes; + uint64_t c2s_packets; + uint64_t s2c_packets; + + // session metadata + struct metadata c2s_1st_md; + struct metadata s2c_1st_md; + + // session timestamp + uint64_t create_time; + uint64_t last_time; + uint64_t expire_time; + + /****************************** + * Session Ev Queue Zone + ******************************/ + + struct event_queue events; + + /****************************** + * Session Ex Data Zone + ******************************/ + + void *ex_data[EX_DATA_MAX_COUNT]; + + /****************************** + * Session Timer Zone + ******************************/ + + // session timer + + /****************************** + * Session Pool Zone + ******************************/ + + // session pool recycle handle + struct session *next; + + /****************************** + * Session Table Zone + ******************************/ + + // session table key + uint64_t id; + struct session_address addr; + + // session table handle + UT_hash_handle hh1; /* handle for root_id hash table */ + UT_hash_handle hh2; /* handle for root_addr hash table */ +}; + +#ifdef __cpluscplus +} +#endif + +#endif diff --git a/src/session/session_table.cpp b/src/session/session_table.cpp new file mode 100644 index 0000000..58ed6ee --- /dev/null +++ b/src/session/session_table.cpp @@ -0,0 +1,161 @@ +#include + +#include "session_table.h" +#include "session_private.h" + +struct session_table +{ + struct session *root_id; + struct session *root_addr; + session_free_cb free_cb; + void *arg; + uint64_t count; +}; + +struct session_table *session_table_create() +{ + struct session_table *table = (struct session_table *)calloc(1, sizeof(struct session_table)); + table->count = 0; + + return table; +} + +void session_table_destroy(struct session_table *table) +{ + if (table) + { + struct session *node = NULL; + struct session *tmp = NULL; + HASH_ITER(hh1, table->root_id, node, tmp) + { + HASH_DELETE(hh1, table->root_id, node); + HASH_DELETE(hh2, table->root_addr, 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; + } +} + +void session_table_add_session(struct session_table *table, struct session *sess) +{ + if (table == NULL || sess == NULL) + { + return; + } + + if (session_address_selfcmp(&sess->addr) > 0) + { + session_address_reverse(&sess->addr); + } + + HASH_ADD(hh1, table->root_id, id, sizeof(sess->id), sess); + HASH_ADD(hh2, table->root_addr, addr, sizeof(sess->addr), sess); + + table->count++; +} + +void session_table_delete_session_with_id(struct session_table *table, uint64_t id) +{ + if (table == NULL) + { + return; + } + + struct session *sess = session_table_search_session_with_id(table, id); + if (sess == NULL) + { + return; + } + + HASH_DELETE(hh1, table->root_id, sess); + HASH_DELETE(hh2, table->root_addr, sess); + + if (table->free_cb && sess) + { + table->free_cb(sess, table->arg); + } + + table->count--; +} + +void session_table_delete_session_with_addr(struct session_table *table, struct session_address *addr) +{ + if (table == NULL) + { + return; + } + + struct session *sess = session_table_search_session_with_addr(table, addr); + if (sess == NULL) + { + return; + } + + HASH_DELETE(hh1, table->root_id, sess); + HASH_DELETE(hh2, table->root_addr, sess); + + if (table->free_cb && sess) + { + table->free_cb(sess, table->arg); + } + + table->count--; +} + +struct session *session_table_search_session_with_id(struct session_table *table, uint64_t id) +{ + if (table == NULL) + { + return NULL; + } + + struct session *sess = NULL; + HASH_FIND(hh1, table->root_id, &id, sizeof(id), sess); + + return sess; +} + +struct session *session_table_search_session_with_addr(struct session_table *table, struct session_address *addr) +{ + if (table == NULL) + { + return NULL; + } + + if (session_address_selfcmp(addr) > 0) + { + session_address_reverse(addr); + } + + struct session *sess = NULL; + HASH_FIND(hh2, table->root_addr, addr, sizeof(struct session_address), sess); + + return sess; +} diff --git a/src/session/session_table.h b/src/session/session_table.h new file mode 100644 index 0000000..45d3fb2 --- /dev/null +++ b/src/session/session_table.h @@ -0,0 +1,33 @@ +#ifndef _SESSION_TABLE_H +#define _SESSION_TABLE_H + +#ifdef __cpluscplus +extern "C" +{ +#endif + +#include "session.h" + +struct session_table; +struct session_table *session_table_create(); +void session_table_destroy(struct session_table *table); +uint64_t session_table_get_count(struct session_table *table); + +typedef void (*session_free_cb)(struct session *sess, void *arg); +void session_table_set_freecb(struct session_table *table, session_free_cb free_cb, void *arg); +/* + * Before add session: + * user must set session id and session address. + * must not add session with same id or same address. + */ +void session_table_add_session(struct session_table *table, struct session *sess); +void session_table_delete_session_with_id(struct session_table *table, uint64_t id); +void session_table_delete_session_with_addr(struct session_table *table, struct session_address *addr); +struct session *session_table_search_session_with_id(struct session_table *table, uint64_t id); +struct session *session_table_search_session_with_addr(struct session_table *table, struct session_address *addr); + +#ifdef __cpluscplus +} +#endif + +#endif