From d0edacb7b91c895b8c8053e6d9695678042ca60a Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 24 Oct 2026 13:39:50 +0200 Subject: [PATCH] Test HUP registration failure and teardown with pending TCP writes --- tests/test_proxy_lifecycle.c | 43 ++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/tests/test_proxy_lifecycle.c b/tests/test_proxy_lifecycle.c index 5f84b6c3..9be89301 100644 --- a/tests/test_proxy_lifecycle.c +++ b/tests/test_proxy_lifecycle.c @@ -38,7 +38,8 @@ void* __real_uasync_add_socket_t(struct UASYNC*, socket_t, socket_t_callback_t, socket_t_callback_t, const char*, void*); void* __wrap_uasync_add_socket_t(struct UASYNC* ua, 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_read && (!strcmp(name, "udp_flow") || !strcmp(name, "icmp_raw"))) { fail_read = 0; return NULL; } + if ((fail_read == 1 && (!strcmp(name, "udp_flow") || !strcmp(name, "icmp_raw"))) || + (fail_read == 2 && !strcmp(name, "tcp_io"))) { fail_read = 0; return NULL; } return __real_uasync_add_socket_t(ua, fd, read, write, error, name, arg); } void* __real_uasync_set_timeout(struct UASYNC*, int, void*, timeout_callback_t, const char*); @@ -227,6 +228,43 @@ static int instance_rollback(int kind) { free_config(cfg); uasync_destroy(ua, 0); return 0; } +struct tcp_owner { struct tcp_conn* tc; int error; }; +static void tcp_failed(struct tcp_conn* tc, int err, void* arg) { + struct tcp_owner* owner = arg; owner->tc = NULL; owner->error = err; tcp_conn_destroy(tc); +} + +// Проверяем destroy из ошибки восстановления poll и независимую ошибку ожидающей записи при HUP. +static int tcp_hup_failure(int writing) { + struct UASYNC* ua = uasync_create(); CHECK(ua); + int fds[2]; CHECK_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, fds), 0); + CHECK_EQ(socket_set_nonblocking(fds[0]), 0); CHECK_EQ(socket_set_nonblocking(fds[1]), 0); + int sndbuf = 1024; CHECK_EQ(setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)), 0); + struct tcp_owner owner = {0}; + owner.tc = tcp_conn_create(ua, fds[0], 64, 32768, 2, 0, 0, NULL, tcp_failed, &owner); CHECK(owner.tc); + if (writing) { + tcp_conn_pause_read(owner.tc); + struct ll_entry* e = queue_entry_new_from_pool(owner.tc->entry_pool); CHECK(e); + e->dgram = memory_pool_alloc(owner.tc->data_pool); CHECK(e->dgram); memset(e->dgram, 0, 32768); e->len = 32768; + queue_data_put(owner.tc->write_queue, e); CHECK(owner.tc && owner.tc->write_buf); + close(fds[1]); + for (int i = 0; i < 20 && owner.tc; i++) uasync_poll(ua, 0); + CHECK(!owner.tc && (owner.error == EPIPE || owner.error == ECONNRESET)); + } else { + uint8_t bytes[512] = {0}; CHECK_EQ(send(fds[1], bytes, sizeof(bytes), MSG_NOSIGNAL), sizeof(bytes)); + close(fds[1]); for (int i = 0; i < 10; i++) uasync_poll(ua, 0); + CHECK(owner.tc && owner.tc->hup_received && !owner.tc->socket_id); + CHECK_EQ(owner.tc->read_queue->count, 2); fail_read = 2; + while (owner.tc && owner.tc->read_queue->head) { + struct memory_pool* pool = owner.tc->data_pool; + struct ll_entry* e = queue_data_get(owner.tc->read_queue); CHECK(e); + memory_pool_free(pool, e->dgram); queue_entry_free(e); + } + CHECK(!owner.tc && owner.error == ENOMEM && !fail_read); + } + uasync_drain_immediate(ua); CHECK_EQ(ua->socket_alloc_count, ua->socket_free_count); + uasync_destroy(ua, 0); return 0; +} + int main(int argc, char** argv) { const struct regression_case cases[] = { {"UDP flow allocation", udp_failures, 0}, {"UDP socket", udp_failures, 1}, @@ -240,7 +278,8 @@ int main(int argc, char** argv) { {"ICMP expiry and renewal", icmp_failures, 3}, {"Shared contexts and listener rollback", ownership, 0}, {"Instance UDP rollback", instance_rollback, 0}, {"Instance ICMP rollback", instance_rollback, 1}, {"Instance listener rollback", instance_rollback, 2}, {"Instance optional ICMP", instance_rollback, 3}, - {"Instance raw registration rollback", instance_rollback, 4} + {"Instance raw registration rollback", instance_rollback, 4}, + {"TCP HUP restore failure", tcp_hup_failure, 0}, {"TCP HUP pending write failure", tcp_hup_failure, 1} }; return regression_run(argc, argv, cases, sizeof(cases) / sizeof(cases[0])); }