Files
utun2/src/routing_layer/etcp_router_doc.md
T
evgeny 38c9f229bc stcp: ed25519 pubkey exchange in handshake, fix instance destroy segfault, fix chat_tcp_test
- u_async.c: process immediate_queue BEFORE epoll_wait in uasync_poll
- stcp_link.c: defensive NULL etcp_conn/etcp_link in stcp_link_close
- utun_instance.c: move stcp_server_list_destroy_all to Phase J (before ETCP),
  add deferred drain in both Phase J and L
- stcp.h/c: STCP_HS_ENC_CLIENT 6→38, STCP_HS_ENC_SERVER 7→39,
  exchange ed25519_pubkey in both handshake directions
- etcp_connections.c: copy peer_ed25519 from STCP to ETCP_CONN in
  etcp_link_enter_ready_tcp; guard link->etcp in tcp_link_close_cb
- chat_sync.c: fix lk->conn NULL dereference for TCP links
- test_stcp.c: update stcp_server_create/stcp_client_connect callsites
- tools/chat_tcp_test: change transport udp→tcp
2026-08-07 00:48:27 +03:00

7.4 KiB
Raw Blame History

ETCP Router (etcp_router)

1. Назначение

Сервисный слой маршрутизации поверх ETCP — упрощённый TCP с восстановлением порядка доставки, дедупликацией и контролем inflight. Мультиплексирует до 256 сервисов (svc_id) на одном ETCP-соединении. Поддерживает transit (многошаговую маршрутизацию через промежуточные узлы), ретрансмиты, minRTT-измерения и подписи Ed25519.

2. Как пользоваться

Инициализация

// В utun_instance_init():
etcp_router_init(inst);

// Зарегистрировать обработчик сервиса (svc_id 0..255)
etcp_router_bind(inst, svc_id, my_service_callback);

Отправка

// Простой способ: сформировать ll_entry с svc_id в первом байте
struct ll_entry* e = queue_entry_new(0);
e->dgram = u_malloc(1 + payload_len);
e->dgram[0] = svc_id;
memcpy(e->dgram + 1, payload, payload_len);
e->len = 1 + payload_len;
etcp_route_send(inst, dst_node_id, e, force);

// Или через существующий ROUTER_CONN:
struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(inst, remote_node_id, svc_id);
etcp_router_conn_send(rconn, data, len);

Приём

void my_service_callback(struct ETCP_CONN* conn, struct ll_entry* entry) {
    if (!entry) { /* соединение закрыто */ return; }
    uint8_t  svc_id = entry->dgram[0];
    uint64_t from   = *(uint64_t*)(entry->dgram + 1); // remote_node_id
    // ... данные начиная с entry->dgram[9] ...
    queue_dgram_free(entry);
    queue_entry_free(entry);
}

Backpressure

// На send_q (inflight переполнен):
struct queue_waiter_handle h;
etcp_router_on_send_ready(inst, node_id, svc_id, &h, my_ready_cb, my_arg);
// Когда send_q освободится — вызовется my_ready_cb

// На normalizer->input (сетевая очередь):
etcp_router_waiter_register(inst, node_id, &h, my_ready_cb, my_arg);

Подписанные сообщения

etcp_router_conn_send_signed(rconn, data, len);  // добавляет Ed25519-подпись

3. API

Ключевые структуры

SVC_ROUTE_HDR (25 байт) — заголовок пакета: cmd(1) + dst_node_id(8) + src_node_id(8) + seq(4) + svc_id(1) + flags(1) + timestamp(2)

Флаги: ROUTER_FLAG_START (0x80), ROUTER_FLAG_RST (0x40), ROUTER_FLAG_SIGNED (0x08), ROUTER_FLAG_CLOSE (0x02). Sess_id в bits 5-4.

ETCP_ROUTER_CONN — состояние логического подключения (remote_node_id + svc_id):

  • tx_seq, rx_seq, tx_acked — seq-нумерация для порядка и inflight
  • recv_q — reorder-очередь с хеш-индексом по seq (восстановление порядка)
  • send_q — очередь ожидания при полном inflight (backpressure)
  • inflight_q — копии отправленных пакетов для ретрансмита (хеш по seq)
  • incoming_q — FIFO между сетевым приёмом и recv_q (защита от гонок)
  • rtt, rtt_jitter, minrtt — измерения задержки
  • inflight_limit — текущий лимит пакетов в полёте (minrtt_probe снижает до 4)
  • no_ack_count — последовательные ретрансмиты без ACK (при 17 — закрытие)
  • start_sent, peer_sync_done — синхронизация после (пере)подключения
  • closed — флаг закрытия (игнорирование таймеров)

ROUTER_INFLIGHT — запись в inflight_q: seq, last_sent_tb, send_count, payload*

TRANSIT_QUEUE — per (src,dst) пара на промежуточном узле:

  • q — FIFO транзитных пакетов
  • waiter — backpressure на send_input_q next_hop'а
  • conn — ETCP_CONN следующего шага

Внутренняя архитектура

Приём: сеть → incoming_q (FIFO) → router_incoming_q_cb → recv_q (хеш по seq)
                                                              ↓
                                                    router_try_assembly → deliver (rx_seq++)

Отправка: router_enqueue_send → send_q (FIFO, backpressure)
          router_drain_send_q → router_send_one → etcp_send + inflight_q (копия)
                                                   ↓
                                      router_track_inflight_state + retrans_schedule
ACK: периодический (10ms) + idle (500ms) → router_send_ack(rx_seq)

Константы

Константа Значение Описание
ROUTER_MAX_INFLIGHT 256 Макс. пакетов в полёте
ROUTER_ACK_INTERVAL_TB 100 ACK интервал 10ms (0.1ms timebase)
ROUTER_ACK_IDLE_TB 5000 Idle таймаут 500ms
ROUTER_RETRANS_TIMEOUT_TB 3000 Таймаут ретрансмита 300ms
ROUTER_NO_ACK_MAX_RETRANS 17 Макс. ретрансмитов без ACK (≈5s)
ROUTER_MAX_SEND_Q_PACKETS 64 Порог backpressure send_q

Функции

Функция Описание
etcp_router_init(inst) Инициализация: bind ETCP_ID_SVC_ROUTE, создание router_conns
etcp_router_destroy(inst) Деинициализация: unbind + close_all + free
etcp_router_bind(inst, svc_id, cb) Зарегистрировать обработчик сервиса
etcp_router_unbind(inst, svc_id) Удалить обработчик сервиса
etcp_route_send(inst, dst, entry, force) Отправить пакет (loopback/transit/direct)
etcp_router_conn_get(inst, remote, svc_id) Найти или создать ROUTER_CONN
etcp_router_conn_send(rconn, data, len) Отправить данные с авто-seq и inflight-контролем
etcp_router_conn_send_signed(rconn, data, len) Отправить с Ed25519-подписью
etcp_router_conn_close(rconn) Закрыть seq-подключение (CLOSE + уведомление сервиса)
etcp_router_conn_close_async(rconn, cb, arg) Асинхронное закрытие с коллбэком
etcp_router_conn_close_all_for_node(inst, node_id) Закрыть все conn к узлу
etcp_router_conn_restart(inst, remote, svc_id) Сброс состояния (перезапуск удалённой стороны)
etcp_router_pause_retrans_for_node(inst, node_id) Сбросить ретрансмиты без закрытия (для conn reinit)
router_set_max_inflight(rconn, new_max) Установить рабочий max_inflight
etcp_router_input_q_count(inst, node_id) Размер normalizer->input очереди узла
etcp_router_waiter_register/cancel(inst, node_id, h, cb, arg) Backpressure на normalizer->input
etcp_router_on_send_ready/cancel_send_ready(inst, node, svc, h, cb, arg) Backpressure на send_q
etcp_router_transit_queues_destroy(conn) Удалить все транзитные очереди ETCP_CONN