From 2894e0601402b632f3a4f1baa195a1aef6c6dbd0 Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 24 Oct 2026 13:41:16 +0200 Subject: [PATCH] Document HUP polling contract and isolate ICMP fault injection --- lib/tcp_io.h | 5 ++++- tests/test_proxy_lifecycle.c | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/tcp_io.h b/lib/tcp_io.h index 658e8638..710369d8 100644 --- a/lib/tcp_io.h +++ b/lib/tcp_io.h @@ -27,6 +27,9 @@ // Для записи выделить entry из tc->entry_pool и dgram из tc->data_pool, заполнить len и dgram_pool; // затем queue_data_put(tc->write_queue, e). Длина должна помещаться в буфер и uint16_t. // После принятого FIN новые данные не добавлять; закрывать сокет через push_close/destroy. +// HUP не снимает backpressure/явную pause_read: регистрация без доступной работы временно удаляется, +// low_water восстанавливает её с новым поколением uasync. FD/очереди сохраняются до решения владельца. +// Ошибка восстановления/ожидания очереди вызывает on_error, как остальные ошибки TCP. #ifndef TCP_IO_H #define TCP_IO_H @@ -52,7 +55,7 @@ struct tcp_conn { int read_high_water; // Число входных entry для приостановки чтения int read_low_water; // Порог очереди для возобновления чтения int rcvbuf_size; // Запрошенный SO_RCVBUF; <=0 — не настраивать буферы - uint8_t read_paused; // Чтение отключено backpressure или pause_read + uint8_t read_paused; // Чтение приостановлено; low_water снимает только автоматическую паузу uint8_t read_stopped; // Владелец запретил чтение; low_water/HUP не снимает запрет uint8_t hup_received; // Получен HUP с SO_ERROR=0; idle registration снимается до готовности очереди diff --git a/tests/test_proxy_lifecycle.c b/tests/test_proxy_lifecycle.c index 9be89301..f9d7f308 100644 --- a/tests/test_proxy_lifecycle.c +++ b/tests/test_proxy_lifecycle.c @@ -18,10 +18,11 @@ static void* expiry_arg; int __real_socket(int, int, int); int __wrap_socket(int domain, int type, int protocol) { - if ((deny_raw && type == SOCK_RAW) || fail_socket) { + int icmp = domain == AF_INET && type == SOCK_RAW && protocol == IPPROTO_ICMP; + if ((deny_raw && icmp) || fail_socket) { fail_socket = 0; errno = type == SOCK_RAW ? EPERM : EMFILE; return -1; } - if (mock_raw && type == SOCK_RAW) return raw_fd = __real_socket(AF_INET, SOCK_DGRAM, 0); + if (mock_raw && icmp) return raw_fd = __real_socket(AF_INET, SOCK_DGRAM, 0); return __real_socket(domain, type, protocol); } int __real_socket_set_nonblocking(socket_t); @@ -224,6 +225,7 @@ static int instance_rollback(int kind) { utun_instance_destroy(inst); uasync_destroy(ua, 0); return 0; } if (kind < 2) CHECK(regression_fault_hit()); + if (kind == 4) CHECK(!fail_read && raw_fd >= 0 && fcntl(raw_fd, F_GETFD) == -1); regression_fault_reset(); CHECK(!inst); CHECK_EQ(cfg->global.tcp_proxy_server_enabled, 1); free_config(cfg); uasync_destroy(ua, 0); return 0; }