Cover partial dummynet startup rollback without resource leaks
This commit is contained in:
1 parent
0df339c384
commit
8d035a065a
2 files changed
+58
-2
No files matched your search
+2
-1
@@ -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 \
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
Reference in new issue
Block a user