Test HUP registration failure and teardown with pending TCP writes

This commit is contained in:
evgeny committed 2026-10-24 13:39:50 +02:00
1 parent 1ce285c09b
commit d0edacb7b9
1 file changed
+41 -2
+41 -2
View File
@@ -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]));
}