diff --git a/tests/Makefile.am b/tests/Makefile.am index c4a7227d..462f20ca 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1073,7 +1073,8 @@ test_etcp_windows_SOURCES = test_etcp_windows.c $(test_clock_sources) test_dummynet_channels_SOURCES = test_dummynet_channels.c $(test_clock_sources) test_dummynet_channels_LDADD = $(LIBUTUN) $(COMMON_LIBS) test_dummynet_channels_LDFLAGS = $(test_clock_ldflags) -Wl,--wrap=uasync_set_timeout -Wl,--wrap=queue_entry_new_from_pool \ - -Wl,--wrap=u_malloc_impl -Wl,--wrap=socket_sendto + -Wl,--wrap=u_malloc_impl -Wl,--wrap=socket_sendto -Wl,--wrap=u_calloc_impl -Wl,--wrap=memory_pool_init \ + -Wl,--wrap=queue_new -Wl,--wrap=uasync_add_socket_t test_etcp_multipath_SOURCES = test_etcp_multipath.c $(test_clock_sources) test_etcp_multipath_LDADD = $(LIBUTUN) $(COMMON_LIBS) test_etcp_multipath_LDFLAGS = $(test_clock_ldflags) -Wl,--wrap=etcp_dump_pkt_sections -Wl,--wrap=bbr_main \ diff --git a/tests/test_dummynet_channels.c b/tests/test_dummynet_channels.c index f78bdb10..8884f96d 100644 --- a/tests/test_dummynet_channels.c +++ b/tests/test_dummynet_channels.c @@ -7,6 +7,7 @@ #include "etcp.h" #include "../lib/platform_compat.h" #include "../lib/mem.h" +#include "../lib/memory_pool.h" #define CHECK(x) do { if (!(x)) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "FAIL %s:%d: %s", __func__, __LINE__, #x); exit(1); } } while (0) static struct UASYNC* ua; @@ -18,6 +19,33 @@ static uint64_t bytes[2], last_rx[2]; static uint8_t seen[2][512]; static int fail_delay, fail_shaper, fail_packet, fail_delay_arg, fail_send; static socket_t fail_fd = SOCKET_INVALID; +static int fail_context, fail_pool, fail_queue, fail_registration; + +void* __real_u_calloc_impl(uint32_t, uint32_t, const char*); +void* __wrap_u_calloc_impl(uint32_t count, uint32_t size, const char* location) { + if (fail_context && strstr(location, "dummynet.c")) return NULL; + return __real_u_calloc_impl(count, size, location); +} + +struct memory_pool* __real_memory_pool_init(size_t, const char*); +struct memory_pool* __wrap_memory_pool_init(size_t size, const char* name) { + if (fail_pool && !strcmp(name, "pkt_pool")) return NULL; + return __real_memory_pool_init(size, name); +} + +struct ll_queue* __real_queue_new(struct UASYNC*, size_t, uint16_t, uint16_t, char*); +struct ll_queue* __wrap_queue_new(struct UASYNC* loop, size_t hash, uint16_t offset, uint16_t size, char* name) { + if (fail_queue && !strncmp(name, "dummynet", 8) && !--fail_queue) return NULL; + return __real_queue_new(loop, hash, offset, size, name); +} + +void* __real_uasync_add_socket_t(struct UASYNC*, socket_t, socket_t_callback_t, socket_t_callback_t, + socket_t_callback_t, const char*, void*); +void* __wrap_uasync_add_socket_t(struct UASYNC* loop, socket_t fd, socket_t_callback_t read, socket_t_callback_t write, + socket_t_callback_t error, const char* name, void* arg) { + if (fail_registration && !strcmp(name, "dummynet")) return NULL; + return __real_uasync_add_socket_t(loop, fd, read, write, error, name, arg); +} void* __real_uasync_set_timeout(struct UASYNC*, int, void*, timeout_callback_t, const char*); void* __wrap_uasync_set_timeout(struct UASYNC* loop, int delay, void* arg, timeout_callback_t fn, const char* name) { @@ -286,6 +314,32 @@ static void inline_filter(void) { DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "PASS inline UDP loss/block/zero/send failure, exclusive hook and independent link/core lifetime"); } +/* Все частично созданные ресурсы возвращаются до уничтожения общего event loop. */ +static void startup_failures(void) { + ua = uasync_create(); CHECK(ua); + size_t baseline = u_get_allocated_count(); + CHECK(!dummynet_create(NULL, "127.0.0.1", 0)); + for (unsigned i = 0; i < 5; i++) { + fail_context = i == 0; fail_pool = i == 1; fail_queue = i == 2 ? 1 : i == 3 ? 2 : 0; fail_registration = i == 4; + CHECK(!dummynet_create(ua, "127.0.0.1", 0)); + fail_context = fail_pool = fail_queue = fail_registration = 0; + uasync_poll(ua, 0); + CHECK(u_get_allocated_count() == baseline); + CHECK(ua->socket_alloc_count == ua->socket_free_count); + } + CHECK(!dummynet_create(ua, "invalid IP", 0)); + CHECK(u_get_allocated_count() == baseline); + dn = dummynet_create(ua, "127.0.0.1", 0); CHECK(dn); + size_t live = u_get_allocated_count(); + CHECK(!dummynet_create(ua, "127.0.0.1", dummynet_get_listen_port(dn))); + CHECK(u_get_allocated_count() == live); + dummynet_destroy(dn); dn = NULL; + uasync_poll(ua, 0); + CHECK(ua->socket_alloc_count == ua->socket_free_count && ua->timer_alloc_count == ua->timer_free_count); + uasync_destroy(ua, 0); + DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "PASS partial startup rollback: context/pool/two queues/socket registration, invalid IP and occupied port"); +} + int main(int argc, char** argv) { debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN); debug_set_category_level(DEBUG_CATEGORY_DEBUG, DEBUG_LEVEL_INFO); test_clock_init(10); @@ -297,7 +351,8 @@ int main(int argc, char** argv) { hold_drop(); CHECK(u_get_allocated_count() == baseline); } struct { const char* name; void (*run)(void); } cases[] = { - {"configuration", configuration}, {"packet_bounds", packet_bounds}, {"failures", failures}, {"inline", inline_filter} + {"configuration", configuration}, {"packet_bounds", packet_bounds}, {"failures", failures}, + {"inline", inline_filter}, {"startup", startup_failures} }; unsigned selected = 0; for (unsigned i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {