diff --git a/CMakeLists.txt b/CMakeLists.txt index ebbd5f2..8336773 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,7 +56,7 @@ add_custom_target("install-program" COMMAND ${CMAKE_COMMAND} ARGS -DCOMPONENT=Pr add_custom_target("install-profile" COMMAND ${CMAKE_COMMAND} ARGS -DCOMPONENT=Profile -P cmake_install.cmake) enable_testing() -#add_subdirectory(vendor) +add_subdirectory(vendor) add_subdirectory(common) add_subdirectory(platform) #add_subdirectory(script) \ No newline at end of file diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index e28808d..a42ed48 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -1,3 +1,5 @@ -add_library(common src/conntable.cpp src/bfd.cpp) +add_library(common src/stream_addr.cpp src/stream_table.cpp src/bfd.cpp) -target_include_directories(common PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) \ No newline at end of file +target_include_directories(common PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) + +add_subdirectory(test) \ No newline at end of file diff --git a/common/include/conntable.h b/common/include/conntable.h deleted file mode 100644 index 89701a0..0000000 --- a/common/include/conntable.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _CONNTABLE_H -#define _CONNTABLE_H - -#ifdef __cpluscplus -extern "C" -{ -#endif - -#include - -struct tuple4 -{ - /* data */ -}; - -struct conntable; - -struct conntable *conntable_create(); -void conntable_destory(struct conntable *table); - -void conntable_add(struct conntable *table, uint64_t streamid, void *val); -void conntable_del(struct conntable *table, uint64_t streamid); -void *conntable_search_by_streamid(struct conntable *table, uint64_t streamid); -void *conntable_search_by_tuple4(struct conntable *table, struct tuple4 *tuplekey); - -#ifdef __cpluscplus -} -#endif - -#endif diff --git a/common/include/stream_addr.h b/common/include/stream_addr.h new file mode 100644 index 0000000..2cb13a5 --- /dev/null +++ b/common/include/stream_addr.h @@ -0,0 +1,49 @@ +#ifndef _STREAM_ADDR_H +#define _STREAM_ADDR_H + +#ifdef __cpluscplus +extern "C" +{ +#endif + +#include + +enum stream_addr_type +{ + STREAM_ADDR_TYPE_V4, + STREAM_ADDR_TYPE_V6, +}; + +struct stream_addr_v4 +{ + struct in_addr src_addr; /* network order */ + struct in_addr dst_addr; /* network order */ + in_port_t src_port; /* network order */ + in_port_t dst_port; /* network order */ +}; + +struct stream_addr_v6 +{ + struct in6_addr src_addr; /* network order */ + struct in6_addr dst_addr; /* network order */ + in_port_t src_port; /* network order */ + in_port_t dst_port; /* network order */ +}; + +struct stream_addr +{ + enum stream_addr_type addr_type; + union + { + struct stream_addr_v4 addr_v4; + struct stream_addr_v6 addr_v6; + }; +}; + +char *stream_addr_to_str(const struct stream_addr *addr); + +#ifdef __cpluscplus +} +#endif + +#endif diff --git a/common/include/stream_table.h b/common/include/stream_table.h new file mode 100644 index 0000000..ee477c4 --- /dev/null +++ b/common/include/stream_table.h @@ -0,0 +1,50 @@ +#ifndef _STREAM_TABLE_H +#define _STREAM_TABLE_H + +#ifdef __cpluscplus +extern "C" +{ +#endif + +#include +#include + +#include "uthash.h" +#include "stream_addr.h" + +// Note: key_streamaddr must be initialized by memset(0) before use !!! + +typedef void fn_free_cb(void *args); + +struct stream_node +{ + uint64_t key_streamid; /* first key */ + struct stream_addr key_streamaddr; /* second key */ + + void *val_data; + fn_free_cb *val_freecb; + + UT_hash_handle hh1; /* handle for first hash table */ + UT_hash_handle hh2; /* handle for second hash table */ +}; + +struct stream_table; + +struct stream_table *stream_table_create(); +void stream_table_destory(struct stream_table *table); + +// key_streamaddr : deep copy +// val_data : shallow copy (malloc by user, free by val_freecb) +int stream_table_insert(struct stream_table *table, uint64_t key_streamid, const struct stream_addr *key_streamaddr, void *val_data, const fn_free_cb *val_freecb); + +int stream_table_delete_by_streamid(struct stream_table *table, uint64_t key_streamid); +int stream_table_delete_by_streamaddr(struct stream_table *table, const struct stream_addr *key_streamaddr); + +struct stream_node *stream_table_search_by_streamid(struct stream_table *table, uint64_t key_streamid); +struct stream_node *stream_table_search_by_streamaddr(struct stream_table *table, const struct stream_addr *key_streamaddr); + +#ifdef __cpluscplus +} +#endif + +#endif diff --git a/common/src/conntable.cpp b/common/src/conntable.cpp deleted file mode 100644 index fdf3e00..0000000 --- a/common/src/conntable.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "conntable.h" -#include "uthash.h" -#include "log.h" - -struct conntable *conntable_create() -{ - return NULL; -} - -void conntable_destory(struct conntable *table) -{ -} - -void conntable_add(struct conntable *table, uint64_t streamid, void *val) -{ -} - -void conntable_del(struct conntable *table, uint64_t streamid) -{ -} - -void *conntable_search_by_streamid(struct conntable *table, uint64_t streamid) -{ - return NULL; -} - -void *conntable_search_by_tuple4(struct conntable *table, struct tuple4 *tuplekey) -{ - return NULL; -} diff --git a/common/src/stream_addr.cpp b/common/src/stream_addr.cpp new file mode 100644 index 0000000..e8872d8 --- /dev/null +++ b/common/src/stream_addr.cpp @@ -0,0 +1,33 @@ +#include +#include + +#include "stream_addr.h" + +char *stream_addr_to_str(const struct stream_addr *addr) +{ + char *str_ret = NULL; + + if (addr->addr_type == STREAM_ADDR_TYPE_V4) + { + char src_addr[INET_ADDRSTRLEN] = {0}; + char dst_addr[INET_ADDRSTRLEN] = {0}; + uint16_t src_port = ntohs((uint16_t)addr->addr_v4.src_port); + uint16_t dst_port = ntohs((uint16_t)addr->addr_v4.dst_port); + inet_ntop(AF_INET, &addr->addr_v4.src_addr, src_addr, sizeof(src_addr)); + inet_ntop(AF_INET, &addr->addr_v4.dst_addr, dst_addr, sizeof(dst_addr)); + asprintf(&str_ret, "%s %u %s %u", src_addr, src_port, dst_addr, dst_port); + } + + if (addr->addr_type == STREAM_ADDR_TYPE_V6) + { + char src_addr[INET6_ADDRSTRLEN] = {0}; + char dst_addr[INET6_ADDRSTRLEN] = {0}; + uint16_t src_port = ntohs((uint16_t)addr->addr_v6.src_port); + uint16_t dst_port = ntohs((uint16_t)addr->addr_v6.dst_port); + inet_ntop(AF_INET6, &addr->addr_v6.src_addr, src_addr, sizeof(src_addr)); + inet_ntop(AF_INET6, &addr->addr_v6.dst_addr, dst_addr, sizeof(dst_addr)); + asprintf(&str_ret, "%s %u %s %u", src_addr, src_port, dst_addr, dst_port); + } + + return str_ret; +} \ No newline at end of file diff --git a/common/src/stream_table.cpp b/common/src/stream_table.cpp new file mode 100644 index 0000000..1714dd9 --- /dev/null +++ b/common/src/stream_table.cpp @@ -0,0 +1,161 @@ +#include + +#include "stream_table.h" +#include "log.h" + +struct stream_table +{ + struct stream_node *streamid_root; + struct stream_node *streamaddr_root; +}; + +// Note: key_streamaddr must be initialized by memset(0) before use !!! + +struct stream_table *stream_table_create() +{ + struct stream_table *table = (struct stream_table *)calloc(1, sizeof(struct stream_table)); + assert(table); + + return table; +} + +void stream_table_destory(struct stream_table *table) +{ + if (table) + { + struct stream_node *temp = NULL; + struct stream_node *node = NULL; + HASH_ITER(hh1, table->streamid_root, node, temp) + { + HASH_DELETE(hh1, table->streamid_root, node); + HASH_DELETE(hh2, table->streamaddr_root, node); + + if (node->val_freecb && node->val_data) + { + node->val_freecb(node->val_data); + } + + free(node); + node = NULL; + } + + free(table); + table = NULL; + } +} + +// key_streamaddr : deep copy +// val_data : shallow copy (malloc by user, free by val_freecb) +int stream_table_insert(struct stream_table *table, uint64_t key_streamid, const struct stream_addr *key_streamaddr, void *val_data, const fn_free_cb *val_freecb) +{ + struct stream_node *temp = NULL; + HASH_FIND(hh1, table->streamid_root, &key_streamid, sizeof(key_streamid), temp); + if (temp) + { + LOG_DEBUG("stream table insert: key %lu exists", key_streamid); + return -1; + } + + temp = (struct stream_node *)calloc(1, sizeof(struct stream_node)); + assert(temp); + + temp->key_streamid = key_streamid; + memcpy(&temp->key_streamaddr, key_streamaddr, sizeof(struct stream_addr)); + temp->val_data = val_data; + temp->val_freecb = val_freecb; + + HASH_ADD(hh1, table->streamid_root, key_streamid, sizeof(temp->key_streamid), temp); + HASH_ADD(hh2, table->streamaddr_root, key_streamaddr, sizeof(temp->key_streamaddr), temp); + + LOG_DEBUG("stream table insert: key %lu success", key_streamid); + + return 0; +} + +int stream_table_delete_by_streamid(struct stream_table *table, uint64_t key_streamid) +{ + struct stream_node *temp = NULL; + HASH_FIND(hh1, table->streamid_root, &key_streamid, sizeof(key_streamid), temp); + if (!temp) + { + LOG_DEBUG("stream table delete: key %lu not exists", key_streamid); + return -1; + } + + HASH_DELETE(hh1, table->streamid_root, temp); + HASH_DELETE(hh2, table->streamaddr_root, temp); + + if (temp->val_freecb && temp->val_data) + { + temp->val_freecb(temp->val_data); + } + + free(temp); + temp = NULL; + + LOG_DEBUG("stream table delete: key %lu success", key_streamid); + return 0; +} + +int stream_table_delete_by_streamaddr(struct stream_table *table, const struct stream_addr *key_streamaddr) +{ + struct stream_node *temp = NULL; + char *addr_str = stream_addr_to_str(key_streamaddr); + HASH_FIND(hh2, table->streamaddr_root, key_streamaddr, sizeof(*key_streamaddr), temp); + if (!temp) + { + LOG_DEBUG("stream table delete: key %s not exists", addr_str); + free(addr_str); + return -1; + } + + HASH_DELETE(hh1, table->streamid_root, temp); + HASH_DELETE(hh2, table->streamaddr_root, temp); + + if (temp->val_freecb && temp->val_data) + { + temp->val_freecb(temp->val_data); + } + + free(temp); + temp = NULL; + + LOG_DEBUG("stream table delete: key %s success", addr_str); + free(addr_str); + addr_str = NULL; + + return 0; +} + +struct stream_node *stream_table_search_by_streamid(struct stream_table *table, uint64_t key_streamid) +{ + struct stream_node *temp = NULL; + HASH_FIND(hh1, table->streamid_root, &key_streamid, sizeof(key_streamid), temp); + if (!temp) + { + LOG_DEBUG("stream table search: key %lu not exists", key_streamid); + return NULL; + } + + LOG_DEBUG("stream table search: key %lu success", key_streamid); + return temp; +} + +struct stream_node *stream_table_search_by_streamaddr(struct stream_table *table, const struct stream_addr *key_streamaddr) +{ + struct stream_node *temp = NULL; + char *addr_str = stream_addr_to_str(key_streamaddr); + HASH_FIND(hh2, table->streamaddr_root, key_streamaddr, sizeof(*key_streamaddr), temp); + if (!temp) + { + LOG_DEBUG("stream table search: key %s not exists", addr_str); + free(addr_str); + addr_str = NULL; + return NULL; + } + + LOG_DEBUG("stream table search: key %s success", addr_str); + free(addr_str); + addr_str = NULL; + return temp; +} diff --git a/common/test/CMakeLists.txt b/common/test/CMakeLists.txt new file mode 100644 index 0000000..4458795 --- /dev/null +++ b/common/test/CMakeLists.txt @@ -0,0 +1,23 @@ +############################################################################### +# gtest_stream_addr +############################################################################### + +add_executable(gtest_stream_addr gtest_stream_addr.cpp) +target_include_directories(gtest_stream_addr PUBLIC ${CMAKE_SOURCE_DIR}/common/include) +target_link_libraries(gtest_stream_addr common gtest) + +############################################################################### +# gtest_stream_table +############################################################################### + +add_executable(gtest_stream_table gtest_stream_table.cpp) +target_include_directories(gtest_stream_table PUBLIC ${CMAKE_SOURCE_DIR}/common/include) +target_link_libraries(gtest_stream_table common gtest) + +############################################################################### +# gtest_discover_tests +############################################################################### + +include(GoogleTest) +gtest_discover_tests(gtest_stream_addr) +gtest_discover_tests(gtest_stream_table) \ No newline at end of file diff --git a/common/test/gtest_stream_addr.cpp b/common/test/gtest_stream_addr.cpp new file mode 100644 index 0000000..c98b38e --- /dev/null +++ b/common/test/gtest_stream_addr.cpp @@ -0,0 +1,40 @@ +#include +#include + +#include "stream_addr.h" + +TEST(STREAM_ADDR, IPV4) +{ + struct stream_addr addr; + addr.addr_type = STREAM_ADDR_TYPE_V4; + addr.addr_v4.src_port = htons(12345); + addr.addr_v4.dst_port = htons(23456); + inet_pton(AF_INET, "1.2.3.4", &addr.addr_v4.src_addr); + inet_pton(AF_INET, "4.3.2.1", &addr.addr_v4.dst_addr); + + char *ret_str = stream_addr_to_str(&addr); + EXPECT_TRUE(ret_str != nullptr); + EXPECT_STREQ(ret_str, "1.2.3.4 12345 4.3.2.1 23456"); + free(ret_str); +} + +TEST(STREAM_ADDR, IPV6) +{ + struct stream_addr addr; + addr.addr_type = STREAM_ADDR_TYPE_V6; + addr.addr_v6.src_port = htons(12345); + addr.addr_v6.dst_port = htons(23456); + inet_pton(AF_INET6, "1:2::3", &addr.addr_v6.src_addr); + inet_pton(AF_INET6, "a:b::c", &addr.addr_v6.dst_addr); + + char *ret_str = stream_addr_to_str(&addr); + EXPECT_TRUE(ret_str != nullptr); + EXPECT_STREQ(ret_str, "1:2::3 12345 a:b::c 23456"); + free(ret_str); +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/common/test/gtest_stream_table.cpp b/common/test/gtest_stream_table.cpp new file mode 100644 index 0000000..1324596 --- /dev/null +++ b/common/test/gtest_stream_table.cpp @@ -0,0 +1,84 @@ +#include +#include + +#include "stream_table.h" + +#define INIT_ADDR_V4(name, src_addr_str, src_port_num, dst_addr_str, dst_port_num) \ + struct stream_addr name; \ + memset(&name, 0, sizeof(name)); \ + (name).addr_type = STREAM_ADDR_TYPE_V4; \ + (name).addr_v4.src_port = htons((src_port_num)); \ + (name).addr_v4.dst_port = htons((dst_port_num)); \ + inet_pton(AF_INET, (src_addr_str), &(name).addr_v4.src_addr); \ + inet_pton(AF_INET, (dst_addr_str), &(name).addr_v4.dst_addr); + +#define INIT_ADDR_V6(name, src_addr_str, src_port_num, dst_addr_str, dst_port_num) \ + struct stream_addr name; \ + memset(&name, 0, sizeof(name)); \ + (name).addr_type = STREAM_ADDR_TYPE_V6; \ + (name).addr_v6.src_port = htons((src_port_num)); \ + (name).addr_v6.dst_port = htons((dst_port_num)); \ + inet_pton(AF_INET6, (src_addr_str), &(name).addr_v6.src_addr); \ + inet_pton(AF_INET6, (dst_addr_str), &(name).addr_v6.dst_addr); + +TEST(STREAM_TABLE, TEST) +{ + INIT_ADDR_V4(addr1, "1.2.3.4", 1234, "4.3.2.1", 4321); + INIT_ADDR_V6(addr2, "2:3:4::5", 2345, "5:4:3::2", 5342); + struct stream_addr addr3; + char *val_hello = strdup("HELLO"); + char *val_world = strdup("WORLD"); + + struct stream_node *node = NULL; + // TEST Create + struct stream_table *table = stream_table_create(); + EXPECT_TRUE(table != nullptr); + + // TEST Insert + EXPECT_TRUE(stream_table_insert(table, 1, &addr1, val_hello, free) == 0); + EXPECT_TRUE(stream_table_insert(table, 1, &addr1, val_hello, free) == -1); + + EXPECT_TRUE(stream_table_insert(table, 2, &addr2, val_world, free) == 0); + EXPECT_TRUE(stream_table_insert(table, 2, &addr2, val_world, free) == -1); + + // TEST Search + node = stream_table_search_by_streamid(table, 1); + EXPECT_TRUE(node != nullptr); + EXPECT_STREQ((const char *)node->val_data, "HELLO"); + node = stream_table_search_by_streamid(table, 2); + EXPECT_TRUE(node != nullptr); + EXPECT_STREQ((const char *)node->val_data, "WORLD"); + node = stream_table_search_by_streamid(table, 3); + EXPECT_TRUE(node == nullptr); + + node = stream_table_search_by_streamaddr(table, &addr1); + EXPECT_TRUE(node != nullptr); + EXPECT_STREQ((const char *)node->val_data, "HELLO"); + node = stream_table_search_by_streamaddr(table, &addr2); + EXPECT_TRUE(node != nullptr); + EXPECT_STREQ((const char *)node->val_data, "WORLD"); + node = stream_table_search_by_streamaddr(table, &addr3); + EXPECT_TRUE(node == nullptr); + + // TEST Delete + stream_table_delete_by_streamid(table, 1); + node = stream_table_search_by_streamid(table, 1); + EXPECT_TRUE(node == nullptr); + node = stream_table_search_by_streamaddr(table, &addr1); + EXPECT_TRUE(node == nullptr); + + stream_table_delete_by_streamaddr(table, &addr2); + node = stream_table_search_by_streamid(table, 2); + EXPECT_TRUE(node == nullptr); + node = stream_table_search_by_streamaddr(table, &addr1); + EXPECT_TRUE(node == nullptr); + + // TEST Destory + stream_table_destory(table); +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/vendor/CMakeLists.txt b/vendor/CMakeLists.txt new file mode 100644 index 0000000..6799ed0 --- /dev/null +++ b/vendor/CMakeLists.txt @@ -0,0 +1,21 @@ +include(ExternalProject) + +# GoogleTest +ExternalProject_Add(googletest PREFIX googletest + URL ${CMAKE_CURRENT_SOURCE_DIR}/googletest-release-1.8.0.tar.gz + URL_MD5 16877098823401d1bf2ed7891d7dce36 + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}) + +ExternalProject_Get_Property(googletest INSTALL_DIR) +file(MAKE_DIRECTORY ${INSTALL_DIR}/include) + +add_library(gtest STATIC IMPORTED GLOBAL) +add_dependencies(gtest googletest) +set_property(TARGET gtest PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libgtest.a) +set_property(TARGET gtest PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include) +set_property(TARGET gtest PROPERTY INTERFACE_LINK_LIBRARIES pthread) + +add_library(gmock STATIC IMPORTED GLOBAL) +add_dependencies(gmock googletest) +set_property(TARGET gmock PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libgmock.a) +set_property(TARGET gmock PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include) \ No newline at end of file diff --git a/vendor/googletest-release-1.8.0.tar.gz b/vendor/googletest-release-1.8.0.tar.gz new file mode 100644 index 0000000..a40df33 Binary files /dev/null and b/vendor/googletest-release-1.8.0.tar.gz differ