etcp_router: разделить служебные функции и API в хедере + чистка мёртвого кода

- etcp_router.h: 4 секции (протокол / внутренние структуры / API / служебные)
- переименование router_set_max_inflight -> etcp_router_set_max_inflight
- удалены неиспользуемые: input_q_count, waiter_register/cancel, conn_close_async
  (+ поля close_callback/close_callback_arg)
- docs: актуализировать backpressure (on_send_ready на send_q) вместо удалённого waiter API
This commit is contained in:
evgeny committed 2026-09-05 22:34:00 +03:00
1 parent 4b9b0009d8
commit 232ad2de6b
6 files changed
+55 -97

No files matched your search

+23 -22
View File
@@ -66,9 +66,9 @@ subcmd:
ДОП. СОСТОЯНИЯ:
┌─────────────────┐ send_data в ETCP вернул -1 (normalizer полон)
┌─────────────────┐ send_data в ETCP вернул -1 (send_q полон)
│ TX_BACKPRESSURE│ не tcp_recved() → окно lwIP=0 → recv_cb остановлен
│ tx_buf != NULL │ etcp_router_waiter_register() → ждём освобождения
│ tx_buf != NULL │ etcp_router_on_send_ready() → ждём освобождения
│ tx_waiter pend │ waiter_cb: retry send_data → tcp_recved → окно открыто
└─────────────────┘
@@ -147,7 +147,7 @@ subcmd:
ДОП. СОСТОЯНИЯ:
┌─────────────────┐ send_msg в ETCP вернул -1
│ PAUSED │ буферизуем в pause_buf, убираем read_id (пауза чтения)
│ pause_buf>0 │ etcp_router_waiter_register() → ждём освобождения
│ pause_buf>0 │ etcp_router_on_send_ready() → ждём освобождения
│ pause_waiter │ waiter_cb: retry send_msg → resume read_id
└─────────────────┘
@@ -186,7 +186,7 @@ subcmd:
│ │ recv_cb │ │──CONNECT+DATA──► │ │handle_connect│ │
│ │(lwIP→ETCP) │ │ │ │handle_data │ │
│ │ │ │ backpressure: │ └──────┬───────┘ │
│ │ send fail: │ │ waiter на normalizer │ │ sock_send │
│ │ send fail: │ │ waiter на send_q │ │ sock_send │
│ │ tx_buf+ │ │ │ ┌──────▼───────┐ │
│ │ waiter │ │ │ │ out_buf │ │
│ │ окно lwIP=0│ │ │ │ pending_buf │ │
@@ -214,10 +214,10 @@ subcmd:
```
══════════════════════════════════════════════════════════════════════
Используется встроенный механизм ll_queue threshold waiter:
etcp_router_waiter_register(inst, peer_node_id, &waiter)
→ внутри: queue_waiter_wait(normalizer->input_queue, &waiter)
etcp_router_waiter_cancel(inst, peer_node_id, &waiter)
Используется встроенный механизм ll_queue threshold waiter (на router send_q):
etcp_router_on_send_ready(inst, group_id, node_id, svc_id, &waiter, cb, arg)
→ внутри: queue_waiter_wait(rconn->send_q, &waiter)
etcp_router_cancel_send_ready(inst, group_id, node_id, svc_id, &waiter)
CLIENT (lwIP → ETCP):
recv_cb(buf, len):
@@ -226,7 +226,7 @@ subcmd:
if ret < 0:
tx_buf = copy(buf), tx_len = len
НЕ tcp_recved() → окно lwIP = 0, recv_cb больше не вызывается
etcp_router_waiter_register(&tx_waiter)
etcp_router_on_send_ready(inst, group_id, via_node_id, ETCP_RT_ID_TCP_PROXY_SERVER, &tx_waiter, tx_waiter_cb, pc)
tx_waiter callback:
ret = send_data(tx_buf, tx_len)
@@ -234,7 +234,7 @@ subcmd:
tcp_recved(tx_len) → окно открыто, lwIP возобновляет recv_cb
free(tx_buf)
if tun_closed → send_close()
// если ret < 0 → waiter остаётся, normalizer вызовет снова
// если ret < 0 → waiter остаётся, router вызовет снова
SERVER (socket → ETCP):
read_cb(buf, n):
@@ -243,7 +243,7 @@ subcmd:
if ret < 0:
pause_buf = copy(buf), pause_len = n
uasync_remove_socket_t(sock) → пауза чтения с сокета
etcp_router_waiter_register(&pause_waiter)
etcp_router_on_send_ready(inst, group_id, peer_node_id, ETCP_RT_ID_TCP_PROXY_CLIENT, &pause_waiter, pause_waiter_cb, rc)
pause_waiter callback:
ret = send_msg(DATA, pause_buf, pause_len)
@@ -433,7 +433,7 @@ tcp_proxy_client_conn:
pcb — lwIP tcp_pcb
tx_buf — буфер при backpressure lwIP→ETCP (send_data fail)
tx_len — длина tx_buf
tx_waiter — ll_queue waiter на normalizer.input_queue
tx_waiter — waiter на router send_q (etcp_router_on_send_ready)
tcp_proxy_server_conn:
stream_id — уникальный ID потока
@@ -449,7 +449,7 @@ tcp_proxy_server_conn:
out_backoff — backoff для retry send в сокет
pause_buf — буфер при backpressure socket→ETCP (send_msg fail)
pause_len — длина pause_buf
pause_waiter — ll_queue waiter на normalizer.input_queue
pause_waiter — waiter на router send_q (etcp_router_on_send_ready)
close_timer — таймер повтора CLOSE/ERROR
close_backoff — backoff для retry CLOSE/ERROR
sock — OS сокет к адресату
@@ -462,16 +462,17 @@ tcp_proxy_server_conn:
```
// etcp_router.h
void etcp_router_waiter_register(struct UTUN_INSTANCE* inst,
uint64_t peer_node_id, struct queue_waiter_handle* h);
void etcp_router_waiter_cancel(struct UTUN_INSTANCE* inst,
uint64_t peer_node_id, struct queue_waiter_handle* h);
void etcp_router_on_send_ready(struct UTUN_INSTANCE* inst, uint64_t group_id,
uint64_t node_id, uint8_t svc_id, struct queue_waiter_handle* h,
queue_threshold_callback_fn cb, void* arg);
void etcp_router_cancel_send_ready(struct UTUN_INSTANCE* inst, uint64_t group_id,
uint64_t node_id, uint8_t svc_id, struct queue_waiter_handle* h);
// Внутри:
// conn = route_bgp_find_conn_for_node(peer_node_id)
// queue_waiter_wait(conn->normalizer->input, h)
// queue_waiter_cancel(conn->normalizer->input, h)
// rconn = router_conn_find(inst, group_id, node_id, svc_id)
// queue_waiter_wait(rconn->send_q, h, cb, arg)
// queue_waiter_cancel(rconn->send_q, h)
//
// normalizer.input_queue уже имеет threshold=0 (ждёт полного освобождения)
// через queue_set_threshold(input_queue, 0, 0) в etcp.c
// send_q — очередь router conn при полном inflight
// (threshold = ROUTER_MAX_SEND_Q_PACKETS - 1 в router_conn_reset)
```
+1 -1
View File
@@ -124,7 +124,7 @@ URL переписывается в относительный (`/path`), ост
## 5. Зависимости
- `tcp_proxy_server.h` — константы subcmd (`TCP_PROXY_SUBCMD_*`) и размер заголовка (`TCP_PROXY_HDR_SIZE=6`)
- `etcp.h` / `etcp_api.h` — `etcp_route_send()`, `ETCP_RT_ID_TCP_PROXY`
- `etcp_router.h` — `etcp_router_on_send_ready()`, `etcp_router_cancel_send_ready()`, `etcp_router_waiter_cancel()`
- `etcp_router.h` — `etcp_router_on_send_ready()`, `etcp_router_cancel_send_ready()`
- `tcp_io.h` / `tcp_conn` — TCP-соединения (`tcp_conn_create`, `tcp_conn_push_close`, `tcp_conn_push_fin`, write/read очереди)
- `u_async.h` — event loop, `uasync_add_socket_t`
- `ll_queue.h` — очереди (write_queue, read_queue), waiter механизм
+3 -3
View File
@@ -47,7 +47,7 @@ tcp_proxy_client_create(inst, ua, tun_name, tun_ip, mtu, test_mode,
**Client-side lwIP** — чтение данных (`tcp_proxy_client_recv_cb`):
- При получении данных от lwIP (клиент что-то отправляет): копируем pbuf → `tcp_proxy_client_send_data()` → ETCP DATA
- При backpressure (очередь нормализатора переполнена): сохраняем в `tx_buf`, регистрируем waiter через `etcp_router_waiter_register()`. При освобождении очереди `tcp_proxy_client_tx_waiter_cb` досылает данные и вызывает `tcp_recved()` для window update
- При backpressure (router send_q переполнен): сохраняем в `tx_buf`, регистрируем waiter через `etcp_router_on_send_ready()`. При освобождении очереди `tcp_proxy_client_tx_waiter_cb` досылает данные и вызывает `tcp_recved()` для window update
- При p==NULL (FIN от lwIP): выставляется `fin_local`, отправляется ETCP FIN. Если обе стороны закрылись — ETCP CLOSE
**Exit-side data** — приём ответных данных (`tcp_proxy_client_handle_data()`):
@@ -90,7 +90,7 @@ struct tcp_proxy_client_mapping_config {
### Механизмы надёжности
- **Backpressure в нормализатор**: `etcp_router_waiter_register()` — если `etcp_route_send()` не может отправить (очередь переполнена), данные буферизуются в `tx_buf` и досылаются при освобождении
- **Backpressure на router send_q**: `etcp_router_on_send_ready()` — если `etcp_route_send()` не может отправить (inflight полон), данные буферизуются в `tx_buf` и досылаются при освобождении
- **Повтор CLOSE/ERROR**: если отправка CLOSE/ERROR не удалась, выставляется `close_pending=1`. В `poll_cb` повторяется попытка
- **Очередь to_lwip**: буферизует данные от exit до готовности lwIP send buffer, обеспечивая window-based flow control
@@ -180,7 +180,7 @@ struct tcp_proxy_client_mapping_config {
- **`tcp_proxy_client_tun_input()`** — коллбэк очереди output_queue TUN. Парсит IP-пакеты: TCP → lwip_tcp_input (с динамическим listen на целевой порт), UDP/ICMP → соответствующие прокси
- **`tcp_proxy_client_handle_non_tcp()`** — перенаправление UDP в `udp_proxy_send_to_exit()` и ICMP Echo в `icmp_proxy_send_to_exit()`
- **`tcp_proxy_client_feed_from_transport()`** — чтение данных из очереди `to_lwip` и запись в lwIP через `tcp_write()` пока есть место в send buffer. После feed вызывает `tcp_output()`
- **`tcp_proxy_client_tx_waiter_cb()`** — коллбэк backpressure waiter: досылка `tx_buf` при освобождении normalizer очереди, вызов `tcp_recved()` для window update
- **`tcp_proxy_client_tx_waiter_cb()`** — коллбэк backpressure waiter: досылка `tx_buf` при освобождении router send_q, вызов `tcp_recved()` для window update
- **`tcp_proxy_client_ensure_outbound_listen()`** — динамическое создание listen pcb в lwIP для заданного порта (если ещё не создан), нужно для прозрачного проксирования любых исходящих TCP-соединений
#### Управление памятью и соединениями