907 lines
44 KiB
C
907 lines
44 KiB
C
// etcp_router.c — Сервисный слой маршрутизации поверх ETCP
|
|
// Упрощённый TCP: восстановление порядка (recv_q), дедупликация, без переповторов
|
|
// ACK: периодическая отправка rx_seq (не чаще 100ms), idle-таймер для последнего seq
|
|
// Inflight контроль через send_q: при переполнении — очередь + retry-таймер, без дропов
|
|
#include "etcp_router.h"
|
|
#include "etcp.h"
|
|
#include "utun_instance.h"
|
|
#include "route_bgp.h"
|
|
#include "../lib/debug_config.h"
|
|
#include "../lib/mem.h"
|
|
#include "../lib/ll_queue.h"
|
|
#include "../lib/u_async.h"
|
|
#include <string.h>
|
|
|
|
// ====================================================================
|
|
// Внутренние forward declarations
|
|
// ====================================================================
|
|
static void router_ack_timer_cb(void* arg);
|
|
static void router_idle_ack_timer_cb(void* arg);
|
|
static void router_send_ack(struct ETCP_ROUTER_CONN* rconn);
|
|
static void router_schedule_ack(struct ETCP_ROUTER_CONN* rconn);
|
|
static void router_try_assembly(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn);
|
|
static void router_deliver(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn, const uint8_t* payload, size_t payload_len);
|
|
static int router_send_one(struct ETCP_ROUTER_CONN* rconn, const uint8_t* payload, size_t pl_len);
|
|
static int router_send_one_flags(struct ETCP_ROUTER_CONN* rconn, const uint8_t* payload, size_t pl_len, uint32_t seq_flags, int is_signed);
|
|
static void router_send_to(struct UTUN_INSTANCE* inst, uint64_t dst, uint8_t svc_id, uint32_t seq_flags);
|
|
static void router_drain_send_q(struct ETCP_ROUTER_CONN* rconn);
|
|
static void router_send_resume_cb(void* arg);
|
|
static void router_send_close_to_service(struct ETCP_ROUTER_CONN* rconn);
|
|
static void router_close_and_notify(struct ETCP_ROUTER_CONN* rconn);
|
|
|
|
// ====================================================================
|
|
// Управление ROUTER_CONN
|
|
// ====================================================================
|
|
|
|
static struct ETCP_ROUTER_CONN* router_conn_find(struct UTUN_INSTANCE* inst,
|
|
uint64_t remote_node_id, uint8_t svc_id) {
|
|
if (!inst || !inst->router_conns) return NULL;
|
|
uint8_t key[9];
|
|
memcpy(key, &remote_node_id, 8);
|
|
key[8] = svc_id;
|
|
return (struct ETCP_ROUTER_CONN*)queue_find_data_by_index(inst->router_conns, key);
|
|
}
|
|
|
|
// ====================================================================
|
|
// Отправка: router_send_one + send_q
|
|
// ====================================================================
|
|
|
|
static int router_send_one(struct ETCP_ROUTER_CONN* rconn, const uint8_t* payload, size_t pl_len) {
|
|
return router_send_one_flags(rconn, payload, pl_len, 0, 0);
|
|
}
|
|
|
|
static int router_send_one_flags(struct ETCP_ROUTER_CONN* rconn, const uint8_t* payload, size_t pl_len, uint32_t seq_flags, int is_signed) {
|
|
struct UTUN_INSTANCE* inst = rconn->inst;
|
|
uint32_t seq = (seq_flags & (ROUTER_SEQ_CLOSE_FLAG | ROUTER_SEQ_RST_FLAG))
|
|
? 0 : rconn->tx_seq++;
|
|
seq |= seq_flags;
|
|
size_t sig_len = is_signed ? SC_SIGN_SIZE : 0;
|
|
size_t total_len = SVC_ROUTE_HDR_SIZE + pl_len + sig_len;
|
|
uint8_t* dgram = u_malloc(total_len);
|
|
if (!dgram) { if (!seq_flags) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1; }
|
|
struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)dgram;
|
|
hdr->cmd = ETCP_ID_SVC_ROUTE;
|
|
hdr->dst_node_id = rconn->remote_node_id;
|
|
hdr->src_node_id = inst->node_id;
|
|
hdr->seq = seq;
|
|
hdr->svc_id = rconn->svc_id;
|
|
{
|
|
uint8_t f = (rconn->sess_id << ROUTER_SESS_ID_SHIFT);
|
|
if (!rconn->start_sent && pl_len > 0 && !(seq_flags & (ROUTER_SEQ_CLOSE_FLAG | ROUTER_SEQ_RST_FLAG))) {
|
|
f |= ROUTER_FLAG_START;
|
|
rconn->start_sent = 1;
|
|
}
|
|
if (is_signed) f |= ROUTER_FLAG_SIGNED;
|
|
hdr->flags = f;
|
|
}
|
|
if (pl_len > 0) memcpy(dgram + SVC_ROUTE_HDR_SIZE, payload, pl_len);
|
|
|
|
struct ETCP_CONN* conn = NULL;
|
|
struct ROUTE_BGP* bgp = inst->bgp;
|
|
if (bgp) {
|
|
struct NODEINFO_Q* nq = nodeinfo_find_by_id(bgp, rconn->remote_node_id);
|
|
if (nq && nq->conn_mgr_type == CONN_TYPE_INDIRECT && nq->conn_mgr_intermediariy_count > 0) {
|
|
for (uint8_t i = 0; i < nq->conn_mgr_intermediariy_count; i++) {
|
|
conn = route_bgp_find_conn_for_node(bgp, nq->conn_mgr_intermediaries[i]);
|
|
if (conn) break;
|
|
}
|
|
}
|
|
}
|
|
if (!conn) conn = route_bgp_find_conn_for_node(bgp, rconn->remote_node_id);
|
|
if (!conn) {
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router_send_one: no route to %016llx svc_id=%u",
|
|
(unsigned long long)rconn->remote_node_id, rconn->svc_id);
|
|
u_free(dgram); if (!seq_flags) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1;
|
|
}
|
|
|
|
if (is_signed) {
|
|
struct sc_stream_sign_state sign_state;
|
|
if (sc_stream_sign_init(&conn->crypto_ctx, &sign_state) != SC_OK) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_send_one: sign_init failed svc_id=%u", rconn->svc_id);
|
|
u_free(dgram); if (!seq_flags) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1;
|
|
}
|
|
size_t data_len = SVC_ROUTE_HDR_SIZE + pl_len;
|
|
if (sc_stream_sign_update(&sign_state, dgram, data_len) != SC_OK) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_send_one: sign_update failed svc_id=%u", rconn->svc_id);
|
|
sc_stream_sign_cleanup(&sign_state); u_free(dgram); if (!seq_flags) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1;
|
|
}
|
|
size_t actual_sig_len = SC_SIGN_SIZE;
|
|
if (sc_stream_sign_final(&sign_state, dgram + data_len, &actual_sig_len) != SC_OK) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_send_one: sign_final failed svc_id=%u", rconn->svc_id);
|
|
u_free(dgram); if (!seq_flags) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1;
|
|
}
|
|
}
|
|
|
|
struct ll_entry* entry = queue_entry_new(0);
|
|
if (!entry) { u_free(dgram); if (!seq_flags) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1; }
|
|
entry->dgram = dgram;
|
|
entry->len = total_len;
|
|
|
|
rconn->last_dgram_ts = get_current_timestamp();
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCPROUTE, "ETCP_SEND: svc_id=%u seq=%u len=%zu inflight=%d signed=%d → %016llx",
|
|
rconn->svc_id, seq, pl_len,
|
|
(int32_t)(rconn->tx_seq - rconn->tx_acked),
|
|
is_signed,
|
|
(unsigned long long)rconn->remote_node_id);
|
|
int ret = etcp_send(conn, entry);
|
|
if (ret != 0) {
|
|
if (!seq_flags) rconn->tx_seq--;
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
rconn->c_pkts_send_err++;
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_send_one: etcp_send failed ret=%d svc_id=%u seq=%u", ret, rconn->svc_id, seq);
|
|
} else {
|
|
rconn->c_pkts_sent++;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// Отправка без conn (RST для неизвестного src)
|
|
static void router_send_to(struct UTUN_INSTANCE* inst, uint64_t dst, uint8_t svc_id, uint32_t seq_flags) {
|
|
struct ETCP_CONN* conn = route_bgp_find_conn_for_node(inst->bgp, dst);
|
|
if (!conn) return;
|
|
struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)u_malloc(SVC_ROUTE_HDR_SIZE);
|
|
if (!hdr) return;
|
|
hdr->cmd = ETCP_ID_SVC_ROUTE;
|
|
hdr->dst_node_id = dst;
|
|
hdr->src_node_id = inst->node_id;
|
|
hdr->seq = seq_flags;
|
|
hdr->svc_id = svc_id;
|
|
struct ll_entry* entry = queue_entry_new(0);
|
|
if (!entry) { u_free(hdr); return; }
|
|
entry->dgram = (uint8_t*)hdr;
|
|
entry->len = SVC_ROUTE_HDR_SIZE;
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCPROUTE, "router_send_to: seq_flags=0x%08x → %016llx svc_id=%u",
|
|
seq_flags, (unsigned long long)dst, svc_id);
|
|
int ret = etcp_send(conn, entry);
|
|
if (ret != 0) {
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_send_to: etcp_send failed ret=%d", ret);
|
|
}
|
|
}
|
|
|
|
static void router_send_close_to_service(struct ETCP_ROUTER_CONN* rconn) {
|
|
struct UTUN_INSTANCE* inst = rconn->inst;
|
|
etcp_recv_fn cb = inst->router_bindings.callbacks[rconn->svc_id];
|
|
if (!cb) return;
|
|
struct ll_entry* e = queue_entry_new(0);
|
|
if (!e) return;
|
|
e->dgram = u_malloc(9);
|
|
if (!e->dgram) { queue_entry_free(e); return; }
|
|
e->dgram[0] = rconn->svc_id;
|
|
memcpy(e->dgram + 1, &rconn->remote_node_id, 8);
|
|
e->len = 9;
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "router_close_svc: svc_id=%u remote=%016llx",
|
|
rconn->svc_id, (unsigned long long)rconn->remote_node_id);
|
|
cb(NULL, e);
|
|
}
|
|
|
|
// Закрыть conn: отправить CLOSE удалённой стороне, уведомить локальный сервис, очистить
|
|
static void router_close_and_notify(struct ETCP_ROUTER_CONN* rconn) {
|
|
if (!rconn) return;
|
|
struct UTUN_INSTANCE* inst = rconn->inst;
|
|
router_send_close_to_service(rconn);
|
|
// Отправляем CLOSE удалённой стороне
|
|
struct ETCP_CONN* conn = route_bgp_find_conn_for_node(inst->bgp, rconn->remote_node_id);
|
|
if (conn) router_send_one_flags(rconn, NULL, 0, ROUTER_SEQ_CLOSE_FLAG, 0);
|
|
// Таймеры
|
|
if (rconn->ack_timer) { uasync_cancel_timeout(inst->ua, rconn->ack_timer); rconn->ack_timer = NULL; }
|
|
if (rconn->idle_ack_timer) { uasync_cancel_timeout(inst->ua, rconn->idle_ack_timer); rconn->idle_ack_timer = NULL; }
|
|
if (rconn->send_resume_timer) { uasync_cancel_timeout(inst->ua, rconn->send_resume_timer); rconn->send_resume_timer = NULL; }
|
|
if (rconn->recv_q) {
|
|
struct ll_entry* f;
|
|
while ((f = queue_data_get(rconn->recv_q)) != NULL) { queue_dgram_free(f); queue_entry_free(f); }
|
|
queue_free(rconn->recv_q); rconn->recv_q = NULL;
|
|
}
|
|
if (rconn->send_q) {
|
|
struct ll_entry* f;
|
|
while ((f = queue_data_get(rconn->send_q)) != NULL) { queue_dgram_free(f); queue_entry_free(f); }
|
|
queue_free(rconn->send_q); rconn->send_q = NULL;
|
|
}
|
|
if (inst->router_conns)
|
|
queue_remove_data(inst->router_conns, &rconn->ll);
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "router_conn: closed remote=%016llx svc_id=%u",
|
|
(unsigned long long)rconn->remote_node_id, rconn->svc_id);
|
|
queue_entry_free(&rconn->ll);
|
|
}
|
|
|
|
static void router_drain_send_q(struct ETCP_ROUTER_CONN* rconn) {
|
|
int sq = queue_entry_count(rconn->send_q);
|
|
if (sq > 0) DEBUG_DEBUG(DEBUG_CATEGORY_ETCPROUTE, "SEND_Q_DRAIN: svc_id=%u send_q=%d inflight=%d",
|
|
rconn->svc_id, sq, (int32_t)(rconn->tx_seq - rconn->tx_acked));
|
|
while (1) {
|
|
if ((int32_t)(rconn->tx_seq - rconn->tx_acked) >= ROUTER_MAX_INFLIGHT) break;
|
|
struct ll_entry* e = queue_data_get(rconn->send_q);
|
|
if (!e) { rconn->send_blocked = 0; break; }
|
|
u_check(e, "drain:after_get", "router");
|
|
int s_err = router_send_one(rconn, e->dgram, e->len);
|
|
u_check(e, "drain:after_send", "router");
|
|
queue_dgram_free(e); queue_entry_free(e);
|
|
if (s_err != 0 && (int32_t)(rconn->tx_seq - rconn->tx_acked) >= ROUTER_MAX_INFLIGHT) break;
|
|
}
|
|
if (rconn->send_blocked && !rconn->send_resume_timer)
|
|
rconn->send_resume_timer = uasync_set_timeout(rconn->inst->ua,
|
|
ROUTER_SEND_RESUME_TB, rconn, router_send_resume_cb, "router_send_resume");
|
|
if (!rconn->send_blocked && rconn->send_resume_timer) {
|
|
uasync_cancel_timeout(rconn->inst->ua, rconn->send_resume_timer);
|
|
rconn->send_resume_timer = NULL;
|
|
}
|
|
}
|
|
|
|
static void router_send_resume_cb(void* arg) {
|
|
struct ETCP_ROUTER_CONN* rconn = (struct ETCP_ROUTER_CONN*)arg;
|
|
rconn->send_resume_timer = NULL;
|
|
router_drain_send_q(rconn);
|
|
}
|
|
|
|
static int router_enqueue_send(struct ETCP_ROUTER_CONN* rconn, const uint8_t* payload, size_t pl_len, int force) {
|
|
if (!force && queue_entry_count(rconn->send_q) >= ROUTER_MAX_SEND_Q_PACKETS) {
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "router_send_q: FULL svc_id=%u count=%d — backpressure",
|
|
rconn->svc_id, queue_entry_count(rconn->send_q));
|
|
return -1;
|
|
}
|
|
struct ll_entry* qe = queue_entry_new(0);
|
|
if (!qe) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_enqueue_send: queue_entry_new failed"); return -1; }
|
|
qe->dgram = u_malloc(pl_len);
|
|
if (!qe->dgram) { queue_entry_free(qe); return -1; }
|
|
qe->len = pl_len;
|
|
if (pl_len > 0) memcpy(qe->dgram, payload, pl_len);
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCPROUTE, "router_send_q: queued svc_id=%u inflight=%d send_q=%d",
|
|
rconn->svc_id, (int32_t)(rconn->tx_seq - rconn->tx_acked), queue_entry_count(rconn->send_q));
|
|
queue_data_put(rconn->send_q, qe);
|
|
u_check(qe, "enqueue_send:after_put", "router");
|
|
rconn->send_blocked = 1;
|
|
if (!rconn->send_resume_timer)
|
|
rconn->send_resume_timer = uasync_set_timeout(rconn->inst->ua,
|
|
ROUTER_SEND_RESUME_TB, rconn, router_send_resume_cb, "router_send_resume");
|
|
return 0;
|
|
}
|
|
|
|
// ====================================================================
|
|
// ACK timers
|
|
// ====================================================================
|
|
|
|
static void router_ack_do_send(struct ETCP_ROUTER_CONN* rconn) {
|
|
router_send_ack(rconn);
|
|
}
|
|
|
|
static void router_send_ack(struct ETCP_ROUTER_CONN* rconn) {
|
|
struct UTUN_INSTANCE* inst = rconn->inst;
|
|
struct ETCP_CONN* conn = route_bgp_find_conn_for_node(inst->bgp, rconn->remote_node_id);
|
|
if (!conn) {
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router_ack: no route to %016llx svc_id=%u",
|
|
(unsigned long long)rconn->remote_node_id, rconn->svc_id);
|
|
rconn->last_ack_sent_tb = get_time_tb();
|
|
return;
|
|
}
|
|
struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)u_malloc(SVC_ROUTE_HDR_SIZE);
|
|
if (!hdr) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_ack: u_malloc failed"); return; }
|
|
hdr->cmd = ETCP_ID_SVC_ROUTE;
|
|
hdr->dst_node_id = rconn->remote_node_id;
|
|
hdr->src_node_id = inst->node_id;
|
|
hdr->seq = rconn->rx_seq;
|
|
hdr->svc_id = rconn->svc_id;
|
|
hdr->flags = (rconn->sess_id << ROUTER_SESS_ID_SHIFT);
|
|
|
|
struct ll_entry* entry = queue_entry_new(0);
|
|
if (!entry) { u_free(hdr); return; }
|
|
entry->dgram = (uint8_t*)hdr;
|
|
entry->len = SVC_ROUTE_HDR_SIZE;
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCPROUTE, "ACK_SEND: svc_id=%u rx_seq=%u → %016llx",
|
|
rconn->svc_id, rconn->rx_seq, (unsigned long long)rconn->remote_node_id);
|
|
int ret = etcp_send(conn, entry);
|
|
if (ret != 0) {
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_ack: etcp_send failed ret=%d svc_id=%u rx_seq=%u", ret, rconn->svc_id, rconn->rx_seq);
|
|
return;
|
|
}
|
|
rconn->c_ack_sent++;
|
|
rconn->last_sent_ack_seq = rconn->rx_seq;
|
|
rconn->last_ack_sent_tb = get_time_tb();
|
|
}
|
|
|
|
static void router_schedule_ack(struct ETCP_ROUTER_CONN* rconn) {
|
|
if (rconn->idle_ack_timer) {
|
|
uasync_cancel_timeout(rconn->inst->ua, rconn->idle_ack_timer);
|
|
rconn->idle_ack_timer = NULL;
|
|
}
|
|
if (rconn->rx_seq == rconn->last_sent_ack_seq) return;
|
|
uint64_t now = get_time_tb();
|
|
uint64_t elapsed = now - rconn->last_ack_sent_tb;
|
|
if (elapsed >= ROUTER_ACK_INTERVAL_TB) {
|
|
router_ack_do_send(rconn);
|
|
return;
|
|
}
|
|
if (!rconn->ack_timer)
|
|
rconn->ack_timer = uasync_set_timeout(rconn->inst->ua,
|
|
ROUTER_ACK_INTERVAL_TB - (uint32_t)elapsed, rconn, router_ack_timer_cb, "router_ack");
|
|
}
|
|
|
|
static void router_ack_timer_cb(void* arg) {
|
|
struct ETCP_ROUTER_CONN* rconn = (struct ETCP_ROUTER_CONN*)arg;
|
|
rconn->ack_timer = NULL;
|
|
if (rconn->rx_seq != rconn->last_sent_ack_seq)
|
|
router_ack_do_send(rconn);
|
|
if (rconn->rx_seq != rconn->last_sent_ack_seq) {
|
|
if (!rconn->ack_timer)
|
|
rconn->ack_timer = uasync_set_timeout(rconn->inst->ua,
|
|
ROUTER_ACK_INTERVAL_TB, rconn, router_ack_timer_cb, "router_ack");
|
|
} else if (!rconn->idle_ack_timer) {
|
|
rconn->idle_ack_timer = uasync_set_timeout(rconn->inst->ua,
|
|
ROUTER_ACK_IDLE_TB, rconn, router_idle_ack_timer_cb, "router_idle_ack");
|
|
}
|
|
}
|
|
|
|
static void router_idle_ack_timer_cb(void* arg) {
|
|
struct ETCP_ROUTER_CONN* rconn = (struct ETCP_ROUTER_CONN*)arg;
|
|
rconn->idle_ack_timer = NULL;
|
|
if (rconn->rx_seq != rconn->last_sent_ack_seq)
|
|
router_ack_do_send(rconn);
|
|
}
|
|
|
|
// ====================================================================
|
|
// Reorder / assembly (аналог etcp_output_try_assembly)
|
|
// ====================================================================
|
|
|
|
static void router_deliver(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn,
|
|
const uint8_t* payload, size_t payload_len) {
|
|
struct UTUN_INSTANCE* inst = rconn->inst;
|
|
etcp_recv_fn cb = inst->router_bindings.callbacks[rconn->svc_id];
|
|
if (!cb) {
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router_deliver: no handler for svc_id=%u", rconn->svc_id);
|
|
return;
|
|
}
|
|
size_t entry_len = 1 + payload_len;
|
|
struct ll_entry* svc_entry = queue_entry_new(0);
|
|
if (!svc_entry) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_deliver: queue_entry_new failed"); return; }
|
|
svc_entry->len = entry_len;
|
|
svc_entry->dgram = u_malloc(entry_len);
|
|
if (!svc_entry->dgram) { queue_entry_free(svc_entry); return; }
|
|
svc_entry->dgram[0] = rconn->svc_id;
|
|
if (payload_len > 0) memcpy(svc_entry->dgram + 1, payload, payload_len);
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCPROUTE, "router_deliver: svc_id=%u len=%zu from remote=%016llx",
|
|
rconn->svc_id, payload_len, (unsigned long long)rconn->remote_node_id);
|
|
rconn->c_pkts_rcvd++;
|
|
cb(conn, svc_entry);
|
|
}
|
|
|
|
static void router_try_assembly(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn) {
|
|
uint32_t next = rconn->rx_seq;
|
|
while (1) {
|
|
struct ll_entry* entry = queue_find_data_by_index(rconn->recv_q, &next);
|
|
if (!entry) break;
|
|
queue_remove_data(rconn->recv_q, entry);
|
|
router_deliver(rconn, conn, entry->dgram, entry->len);
|
|
rconn->rx_seq = next + 1;
|
|
next++;
|
|
queue_dgram_free(entry);
|
|
queue_entry_free(entry);
|
|
}
|
|
}
|
|
|
|
// ====================================================================
|
|
// etcp_router_recv_cb — обработчик ETCP_ID_SVC_ROUTE
|
|
// ====================================================================
|
|
|
|
static void etcp_router_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
|
|
if (!entry) return;
|
|
struct UTUN_INSTANCE* inst = conn ? conn->instance : NULL;
|
|
if (!inst || entry->len < SVC_ROUTE_HDR_SIZE) {
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "etcp_router: invalid packet inst=%p len=%zu min=%u",
|
|
(void*)inst, entry->len, (unsigned)SVC_ROUTE_HDR_SIZE);
|
|
if (entry) { queue_dgram_free(entry); queue_entry_free(entry); }
|
|
return;
|
|
}
|
|
struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)entry->dgram;
|
|
size_t pl_len = entry->len - SVC_ROUTE_HDR_SIZE;
|
|
uint8_t* pl = entry->dgram + SVC_ROUTE_HDR_SIZE;
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCPROUTE, "ETCP_RECV: svc_id=%u seq=%u len=%zu from %016llx",
|
|
hdr->svc_id, hdr->seq, pl_len, (unsigned long long)hdr->src_node_id);
|
|
|
|
if (hdr->dst_node_id == inst->node_id) {
|
|
// ========== Проверка подписи (если флаг ROUTER_FLAG_SIGNED) ==========
|
|
size_t actual_payload = pl_len;
|
|
if (hdr->flags & ROUTER_FLAG_SIGNED) {
|
|
if (pl_len < SC_SIGN_SIZE) {
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router: SIGNED packet too short len=%zu from %016llx", pl_len, (unsigned long long)hdr->src_node_id);
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
return;
|
|
}
|
|
actual_payload = pl_len - SC_SIGN_SIZE;
|
|
uint8_t* sig = pl + actual_payload;
|
|
struct ROUTE_BGP* bgp = inst->bgp;
|
|
struct NODEINFO_Q* nq = bgp ? nodeinfo_find_by_id(bgp, hdr->src_node_id) : NULL;
|
|
if (!nq) {
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router: SIGNED packet from unknown node %016llx — dropping", (unsigned long long)hdr->src_node_id);
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
return;
|
|
}
|
|
{
|
|
uint8_t zero[SC_PUBKEY_SIZE] = {0};
|
|
if (memcmp(nq->node.ed25519_public_key, zero, SC_PUBKEY_SIZE) == 0) {
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router: no Ed25519 pubkey for node %016llx — dropping", (unsigned long long)hdr->src_node_id);
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
return;
|
|
}
|
|
}
|
|
struct sc_stream_sign_state vfy_state;
|
|
if (sc_stream_sign_verify_init(&vfy_state, nq->node.ed25519_public_key) != SC_OK) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router: sign_verify_init failed for node %016llx", (unsigned long long)hdr->src_node_id);
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
return;
|
|
}
|
|
size_t signed_len = SVC_ROUTE_HDR_SIZE + actual_payload;
|
|
if (sc_stream_sign_update(&vfy_state, entry->dgram, signed_len) != SC_OK) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router: sign_update failed for node %016llx", (unsigned long long)hdr->src_node_id);
|
|
sc_stream_sign_cleanup(&vfy_state); queue_dgram_free(entry); queue_entry_free(entry);
|
|
return;
|
|
}
|
|
if (sc_stream_sign_verify(&vfy_state, sig, SC_SIGN_SIZE) != SC_OK) {
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router: signature verification FAILED for node %016llx svc_id=%u — dropping", (unsigned long long)hdr->src_node_id, hdr->svc_id);
|
|
{
|
|
struct ETCP_ROUTER_CONN* sr = router_conn_find(inst, hdr->src_node_id, hdr->svc_id);
|
|
if (sr) sr->c_sign_fail++;
|
|
}
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
return;
|
|
}
|
|
pl_len = actual_payload;
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCPROUTE, "router: signature verified for node %016llx svc_id=%u", (unsigned long long)hdr->src_node_id, hdr->svc_id);
|
|
}
|
|
|
|
// ========== Мы — целевая нода ==========
|
|
struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, hdr->src_node_id, hdr->svc_id);
|
|
|
|
// CLOSE или RST — pl_len==0 и флаг в seq (закрываем conn)
|
|
if (pl_len == 0 && (hdr->seq & (ROUTER_SEQ_CLOSE_FLAG | ROUTER_SEQ_RST_FLAG))) {
|
|
if (rconn) router_close_and_notify(rconn);
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
return;
|
|
}
|
|
|
|
if (pl_len == 0) {
|
|
if (rconn) {
|
|
if ((int32_t)(hdr->seq - rconn->tx_acked) >= 0) {
|
|
rconn->tx_acked = hdr->seq;
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCPROUTE, "SEND_Q_ACKED: svc_id=%u ack=%u inflight=%d send_q=%d from %016llx",
|
|
rconn->svc_id, hdr->seq, (int32_t)(rconn->tx_seq - rconn->tx_acked),
|
|
queue_entry_count(rconn->send_q),
|
|
(unsigned long long)hdr->src_node_id);
|
|
rconn->c_ack_recv++;
|
|
} else {
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router: stale ACK seq=%u tx_acked=%u from %016llx, ignoring",
|
|
hdr->seq, rconn->tx_acked, (unsigned long long)hdr->src_node_id);
|
|
rconn->c_stale_ack++;
|
|
}
|
|
rconn->last_dgram_ts = get_current_timestamp();
|
|
if (rconn->send_blocked) router_drain_send_q(rconn);
|
|
}
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
return;
|
|
}
|
|
|
|
// Data-пакет — авто-создаём conn если ещё нет
|
|
if (!rconn) {
|
|
rconn = etcp_router_conn_get(inst, hdr->src_node_id, hdr->svc_id);
|
|
if (!rconn) { queue_dgram_free(entry); queue_entry_free(entry); return; }
|
|
rconn->peer_sess_id = (hdr->flags >> ROUTER_SESS_ID_SHIFT) & 0x3;
|
|
}
|
|
|
|
// Обнаружение перезапуска peer'а: новый sess_id или START-флаг
|
|
{
|
|
uint8_t incoming_sess = (hdr->flags >> ROUTER_SESS_ID_SHIFT) & 0x3;
|
|
if (pl_len > 0 && (incoming_sess != rconn->peer_sess_id ||
|
|
((hdr->flags & ROUTER_FLAG_START) && rconn->rx_seq > 0))) {
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE,
|
|
"router: peer restart sess_id=%u→%u svc_id=%u from %016llx",
|
|
rconn->peer_sess_id, incoming_sess, hdr->svc_id,
|
|
(unsigned long long)hdr->src_node_id);
|
|
etcp_router_conn_restart(inst, hdr->src_node_id, hdr->svc_id);
|
|
rconn = etcp_router_conn_get(inst, hdr->src_node_id, hdr->svc_id);
|
|
if (!rconn) { queue_dgram_free(entry); queue_entry_free(entry); return; }
|
|
rconn->peer_sess_id = incoming_sess;
|
|
}
|
|
// RST-флаг — peer сигналит нарушение последовательности
|
|
if (hdr->flags & ROUTER_FLAG_RST) {
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE,
|
|
"router: RST from %016llx svc_id=%u",
|
|
(unsigned long long)hdr->src_node_id, hdr->svc_id);
|
|
router_close_and_notify(rconn);
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Seq-состояние есть — reorder
|
|
rconn->last_dgram_ts = get_current_timestamp();
|
|
uint32_t seq = hdr->seq;
|
|
|
|
// Синхронизация после авто-создания/рестарта: принимаем первый пришедший seq
|
|
if (!rconn->peer_sync_done) {
|
|
rconn->peer_sync_done = 1;
|
|
rconn->rx_seq = seq;
|
|
}
|
|
|
|
// Проверка границ (32-bit circular, аналог ETCP MAX_INFLIGHT_SIZE)
|
|
{
|
|
int32_t d = (int32_t)(seq - rconn->rx_seq);
|
|
if (d > ROUTER_MAX_INFLIGHT || d < -ROUTER_MAX_INFLIGHT) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router: seq=%u out of bounds, rx_seq=%u (d=%d), dropping",
|
|
seq, rconn->rx_seq, d);
|
|
rconn->c_oob_dropped++;
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Дубликат (seq уже доставлен или в recv_q)
|
|
if (((int32_t)(rconn->rx_seq - seq) > 0) ||
|
|
queue_find_data_by_index(rconn->recv_q, &seq)) {
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCPROUTE, "router: dup seq=%u rx_seq=%u, dropping", seq, rconn->rx_seq);
|
|
rconn->c_dup_dropped++;
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
return;
|
|
}
|
|
|
|
// Кладём в recv_q
|
|
struct ll_entry* qe = queue_entry_new(4);
|
|
if (!qe) { queue_dgram_free(entry); queue_entry_free(entry); return; }
|
|
*(uint32_t*)qe->data = seq;
|
|
qe->dgram = u_malloc(pl_len);
|
|
if (!qe->dgram) { queue_entry_free(qe); queue_dgram_free(entry); queue_entry_free(entry); return; }
|
|
qe->len = pl_len;
|
|
memcpy(qe->dgram, pl, pl_len);
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCPROUTE, "router: queued seq=%u rx_seq=%u recv_q=%d from %016llx svc_id=%u",
|
|
seq, rconn->rx_seq, queue_entry_count(rconn->recv_q),
|
|
(unsigned long long)hdr->src_node_id, rconn->svc_id);
|
|
queue_data_put_with_index(rconn->recv_q, qe);
|
|
|
|
if (seq == rconn->rx_seq)
|
|
router_try_assembly(rconn, conn);
|
|
|
|
router_schedule_ack(rconn);
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
} else {
|
|
// ========== Транзит ==========
|
|
struct ETCP_CONN* next = route_bgp_find_conn_for_node(inst->bgp, hdr->dst_node_id);
|
|
if (!next) {
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "etcp_router: no route to %016llx svc_id=%u, dropping",
|
|
(unsigned long long)hdr->dst_node_id, hdr->svc_id);
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
return;
|
|
}
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCPROUTE, "etcp_router: forwarding svc_id=%u → %016llx via %s",
|
|
hdr->svc_id, (unsigned long long)hdr->dst_node_id, next->log_name);
|
|
int fwd_err = etcp_send(next, entry);
|
|
if (fwd_err != 0) {
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "etcp_router: transit etcp_send failed ret=%d", fwd_err);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ====================================================================
|
|
// Public API
|
|
// ====================================================================
|
|
|
|
int etcp_router_init(struct UTUN_INSTANCE* inst) {
|
|
if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "etcp_router_init: NULL instance"); return -1; }
|
|
memset(&inst->router_bindings, 0, sizeof(inst->router_bindings));
|
|
inst->router_conns = queue_new(inst->ua,
|
|
ROUTER_CONN_HASH_SIZE, 0, 9, "router_conns");
|
|
if (!inst->router_conns) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "etcp_router_init: queue_new(router_conns) failed");
|
|
return -1;
|
|
}
|
|
int ret = etcp_bind(inst, ETCP_ID_SVC_ROUTE, etcp_router_recv_cb);
|
|
if (ret != 0) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "etcp_router_init: etcp_bind failed, ret=%d", ret);
|
|
queue_free(inst->router_conns); inst->router_conns = NULL;
|
|
return -1;
|
|
}
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "etcp_router initialized for node %016llx", (unsigned long long)inst->node_id);
|
|
return 0;
|
|
}
|
|
|
|
void etcp_router_destroy(struct UTUN_INSTANCE* inst) {
|
|
if (!inst) return;
|
|
etcp_unbind(inst, ETCP_ID_SVC_ROUTE);
|
|
if (inst->router_conns) {
|
|
struct ll_entry* entry;
|
|
while ((entry = queue_data_get(inst->router_conns)) != NULL) {
|
|
struct ETCP_ROUTER_CONN* rconn = (struct ETCP_ROUTER_CONN*)entry;
|
|
router_send_close_to_service(rconn);
|
|
if (rconn->ack_timer) { uasync_cancel_timeout(inst->ua, rconn->ack_timer); rconn->ack_timer = NULL; }
|
|
if (rconn->idle_ack_timer) { uasync_cancel_timeout(inst->ua, rconn->idle_ack_timer); rconn->idle_ack_timer = NULL; }
|
|
if (rconn->send_resume_timer) { uasync_cancel_timeout(inst->ua, rconn->send_resume_timer); rconn->send_resume_timer = NULL; }
|
|
if (rconn->recv_q) {
|
|
struct ll_entry* f;
|
|
while ((f = queue_data_get(rconn->recv_q)) != NULL) { queue_dgram_free(f); queue_entry_free(f); }
|
|
queue_free(rconn->recv_q);
|
|
}
|
|
if (rconn->send_q) {
|
|
struct ll_entry* f;
|
|
while ((f = queue_data_get(rconn->send_q)) != NULL) { queue_dgram_free(f); queue_entry_free(f); }
|
|
queue_free(rconn->send_q);
|
|
}
|
|
queue_entry_free(entry);
|
|
}
|
|
queue_free(inst->router_conns);
|
|
inst->router_conns = NULL;
|
|
}
|
|
memset(&inst->router_bindings, 0, sizeof(inst->router_bindings));
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "etcp_router destroyed");
|
|
}
|
|
|
|
int etcp_router_bind(struct UTUN_INSTANCE* inst, uint8_t svc_id, etcp_recv_fn callback) {
|
|
if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "etcp_router_bind: NULL instance"); return -1; }
|
|
if (!callback) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "etcp_router_bind: NULL callback for svc_id=%u", svc_id); return -1; }
|
|
if (inst->router_bindings.callbacks[svc_id])
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "etcp_router_bind: overwriting svc_id=%u", svc_id);
|
|
inst->router_bindings.callbacks[svc_id] = callback;
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "etcp_router_bind: svc_id=%u → cb=%p", svc_id, (void*)callback);
|
|
return 0;
|
|
}
|
|
|
|
int etcp_router_unbind(struct UTUN_INSTANCE* inst, uint8_t svc_id) {
|
|
if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "etcp_router_unbind: NULL instance"); return -1; }
|
|
if (!inst->router_bindings.callbacks[svc_id]) {
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "etcp_router_unbind: svc_id=%u not bound", svc_id);
|
|
return -1;
|
|
}
|
|
inst->router_bindings.callbacks[svc_id] = NULL;
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "etcp_router_unbind: svc_id=%u", svc_id);
|
|
return 0;
|
|
}
|
|
|
|
int etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t dst_node_id, struct ll_entry* entry, int force) {
|
|
if (!inst || !entry) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "etcp_route_send: NULL inst=%p entry=%p", (void*)inst, (void*)entry);
|
|
if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } return -1;
|
|
}
|
|
if (!entry->dgram || entry->len < 1) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "etcp_route_send: empty entry"); queue_dgram_free(entry); queue_entry_free(entry); return -1;
|
|
}
|
|
uint8_t svc_id = entry->dgram[0];
|
|
size_t payload_len = entry->len - 1;
|
|
|
|
if (dst_node_id == inst->node_id) {
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCPROUTE, "etcp_route_send: loopback svc_id=%u len=%zu", svc_id, payload_len);
|
|
if (inst->router_bindings.callbacks[svc_id])
|
|
inst->router_bindings.callbacks[svc_id](NULL, entry);
|
|
else { queue_dgram_free(entry); queue_entry_free(entry); }
|
|
return 0;
|
|
}
|
|
|
|
struct ETCP_CONN* etcp_conn = route_bgp_find_conn_for_node(inst->bgp, dst_node_id);
|
|
if (!etcp_conn) {
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "etcp_route_send: no BGP route to %016llx svc_id=%u, dropping",
|
|
(unsigned long long)dst_node_id, svc_id);
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
return -1;
|
|
}
|
|
|
|
struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(inst, dst_node_id, svc_id);
|
|
if (!rconn) { queue_dgram_free(entry); queue_entry_free(entry); return -1; }
|
|
|
|
if ((int32_t)(rconn->tx_seq - rconn->tx_acked) >= ROUTER_MAX_INFLIGHT) {
|
|
int eq_ret = router_enqueue_send(rconn, entry->dgram + 1, payload_len, force);
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
return eq_ret;
|
|
}
|
|
|
|
int ret = router_send_one(rconn, entry->dgram + 1, payload_len);
|
|
queue_dgram_free(entry); queue_entry_free(entry);
|
|
return ret;
|
|
}
|
|
|
|
int etcp_router_input_q_count(struct UTUN_INSTANCE* inst, uint64_t node_id) {
|
|
if (!inst || !inst->bgp) return -1;
|
|
struct ETCP_CONN* conn = route_bgp_find_conn_for_node(inst->bgp, node_id);
|
|
if (!conn || !conn->normalizer || !conn->normalizer->input) return -1;
|
|
return queue_entry_count(conn->normalizer->input);
|
|
}
|
|
|
|
void etcp_router_waiter_register(struct UTUN_INSTANCE* inst, uint64_t peer_node_id,
|
|
struct queue_waiter_handle* h,
|
|
queue_threshold_callback_fn callback, void* arg) {
|
|
if (!inst || !inst->bgp || !h) return;
|
|
struct ETCP_CONN* conn = route_bgp_find_conn_for_node(inst->bgp, peer_node_id);
|
|
if (!conn || !conn->normalizer || !conn->normalizer->input) return;
|
|
queue_waiter_wait(conn->normalizer->input, h, callback, arg);
|
|
}
|
|
|
|
void etcp_router_waiter_cancel(struct UTUN_INSTANCE* inst, uint64_t peer_node_id,
|
|
struct queue_waiter_handle* h) {
|
|
if (!inst || !inst->bgp || !h) return;
|
|
struct ETCP_CONN* conn = route_bgp_find_conn_for_node(inst->bgp, peer_node_id);
|
|
if (!conn || !conn->normalizer || !conn->normalizer->input) return;
|
|
queue_waiter_cancel(conn->normalizer->input, h);
|
|
}
|
|
|
|
void etcp_router_conn_restart(struct UTUN_INSTANCE* inst, uint64_t remote_node_id, uint8_t svc_id) {
|
|
struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, remote_node_id, svc_id);
|
|
if (!rconn) return;
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "router_restart: svc_id=%u remote=%016llx — resetting local state",
|
|
svc_id, (unsigned long long)remote_node_id);
|
|
|
|
etcp_recv_fn cb = inst->router_bindings.callbacks[svc_id];
|
|
if (cb) {
|
|
struct ll_entry* e = queue_entry_new(0);
|
|
if (e) {
|
|
e->dgram = u_malloc(9);
|
|
if (e->dgram) {
|
|
e->dgram[0] = svc_id;
|
|
memcpy(e->dgram + 1, &remote_node_id, 8);
|
|
e->len = 9;
|
|
cb(NULL, e);
|
|
} else { queue_entry_free(e); }
|
|
}
|
|
}
|
|
|
|
if (rconn->ack_timer) { uasync_cancel_timeout(inst->ua, rconn->ack_timer); rconn->ack_timer = NULL; }
|
|
if (rconn->idle_ack_timer) { uasync_cancel_timeout(inst->ua, rconn->idle_ack_timer); rconn->idle_ack_timer = NULL; }
|
|
if (rconn->send_resume_timer) { uasync_cancel_timeout(inst->ua, rconn->send_resume_timer); rconn->send_resume_timer = NULL; }
|
|
|
|
struct ll_entry* f;
|
|
if (rconn->send_q) {
|
|
while ((f = queue_data_get(rconn->send_q)) != NULL) { u_check(f, "restart:send_q", "router"); queue_dgram_free(f); queue_entry_free(f); }
|
|
queue_free(rconn->send_q);
|
|
}
|
|
if (rconn->recv_q) {
|
|
while ((f = queue_data_get(rconn->recv_q)) != NULL) { u_check(f, "restart:recv_q", "router"); queue_dgram_free(f); queue_entry_free(f); }
|
|
queue_free(rconn->recv_q);
|
|
}
|
|
rconn->send_q = queue_new(inst->ua, 0, 0, 0, "router_send_q");
|
|
rconn->recv_q = queue_new(inst->ua, ROUTER_RECVQ_HASH_SIZE, 0, 4, "router_recv_q");
|
|
queue_set_threshold(rconn->send_q, ROUTER_MAX_SEND_Q_PACKETS / 2, 0);
|
|
|
|
rconn->tx_seq = 0;
|
|
rconn->rx_seq = 0;
|
|
rconn->tx_acked = 0;
|
|
rconn->last_sent_ack_seq = 0;
|
|
rconn->last_ack_sent_tb = 0;
|
|
rconn->peer_sess_id = 0;
|
|
rconn->send_blocked = 0;
|
|
rconn->peer_sync_done = 0;
|
|
rconn->c_pkts_sent = 0;
|
|
rconn->c_pkts_send_err = 0;
|
|
rconn->c_pkts_rcvd = 0;
|
|
rconn->c_ack_sent = 0;
|
|
rconn->c_ack_recv = 0;
|
|
rconn->c_dup_dropped = 0;
|
|
rconn->c_oob_dropped = 0;
|
|
rconn->c_stale_ack = 0;
|
|
rconn->c_sign_fail = 0;
|
|
}
|
|
|
|
void etcp_router_on_send_ready(struct UTUN_INSTANCE* inst, uint64_t node_id, uint8_t svc_id,
|
|
struct queue_waiter_handle* h,
|
|
queue_threshold_callback_fn callback, void* arg) {
|
|
if (!inst || !h) return;
|
|
struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, node_id, svc_id);
|
|
if (!rconn || !rconn->send_q) return;
|
|
queue_waiter_wait(rconn->send_q, h, callback, arg);
|
|
}
|
|
|
|
void etcp_router_cancel_send_ready(struct UTUN_INSTANCE* inst, uint64_t node_id, uint8_t svc_id,
|
|
struct queue_waiter_handle* h) {
|
|
if (!inst || !h) return;
|
|
struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, node_id, svc_id);
|
|
if (!rconn || !rconn->send_q) return;
|
|
queue_waiter_cancel(rconn->send_q, h);
|
|
}
|
|
|
|
// ====================================================================
|
|
// Seq-connection API
|
|
// ====================================================================
|
|
|
|
struct ETCP_ROUTER_CONN* etcp_router_conn_get(struct UTUN_INSTANCE* inst,
|
|
uint64_t remote_node_id, uint8_t svc_id) {
|
|
if (!inst || !inst->router_conns) return NULL;
|
|
struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, remote_node_id, svc_id);
|
|
if (rconn) return rconn;
|
|
|
|
size_t data_size = sizeof(struct ETCP_ROUTER_CONN) - sizeof(struct ll_entry);
|
|
rconn = (struct ETCP_ROUTER_CONN*)queue_entry_new(data_size);
|
|
if (!rconn) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_conn_get: queue_entry_new failed"); return NULL; }
|
|
rconn->remote_node_id = remote_node_id;
|
|
rconn->svc_id = svc_id;
|
|
rconn->last_dgram_ts = get_current_timestamp();
|
|
rconn->tx_seq = 0;
|
|
rconn->rx_seq = 0;
|
|
rconn->tx_acked = 0;
|
|
rconn->last_sent_ack_seq = 0;
|
|
rconn->last_ack_sent_tb = 0;
|
|
rconn->inst = inst;
|
|
rconn->ack_timer = NULL;
|
|
rconn->idle_ack_timer = NULL;
|
|
rconn->send_blocked = 0;
|
|
rconn->send_resume_timer = NULL;
|
|
rconn->sess_id = 0;
|
|
rconn->start_sent = 0;
|
|
rconn->peer_sync_done = 0;
|
|
rconn->c_pkts_sent = 0;
|
|
rconn->c_pkts_send_err = 0;
|
|
rconn->c_pkts_rcvd = 0;
|
|
rconn->c_ack_sent = 0;
|
|
rconn->c_ack_recv = 0;
|
|
rconn->c_dup_dropped = 0;
|
|
rconn->c_oob_dropped = 0;
|
|
rconn->c_stale_ack = 0;
|
|
rconn->c_sign_fail = 0;
|
|
rconn->recv_q = queue_new(inst->ua, ROUTER_RECVQ_HASH_SIZE, 0, 4, "router_recv_q");
|
|
if (!rconn->recv_q) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_conn_get: queue_new(recv_q) failed"); queue_entry_free(&rconn->ll); return NULL; }
|
|
rconn->send_q = queue_new(inst->ua, 0, 0, 0, "router_send_q");
|
|
if (!rconn->send_q) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_conn_get: queue_new(send_q) failed"); queue_free(rconn->recv_q); queue_entry_free(&rconn->ll); return NULL; }
|
|
queue_set_threshold(rconn->send_q, ROUTER_MAX_SEND_Q_PACKETS / 2, 0);
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "router_conn: new conn remote=%016llx svc_id=%u",
|
|
(unsigned long long)remote_node_id, svc_id);
|
|
queue_data_put_with_index(inst->router_conns, &rconn->ll);
|
|
return rconn;
|
|
}
|
|
|
|
int etcp_router_conn_send(struct ETCP_ROUTER_CONN* rconn,
|
|
const uint8_t* data, size_t len) {
|
|
if (!rconn || !data || len == 0) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_conn_send: invalid args rconn=%p data=%p len=%zu",
|
|
(void*)rconn, (const void*)data, len);
|
|
return -1;
|
|
}
|
|
if ((int32_t)(rconn->tx_seq - rconn->tx_acked) >= ROUTER_MAX_INFLIGHT) {
|
|
return router_enqueue_send(rconn, data, len, 0);
|
|
}
|
|
return router_send_one(rconn, data, len);
|
|
}
|
|
|
|
int etcp_router_conn_send_signed(struct ETCP_ROUTER_CONN* rconn,
|
|
const uint8_t* data, size_t len) {
|
|
if (!rconn || !data || len == 0) {
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_conn_send_signed: invalid args rconn=%p data=%p len=%zu",
|
|
(void*)rconn, (const void*)data, len);
|
|
return -1;
|
|
}
|
|
if ((int32_t)(rconn->tx_seq - rconn->tx_acked) >= ROUTER_MAX_INFLIGHT) {
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router_conn_send_signed: inflight full svc_id=%u", rconn->svc_id);
|
|
return -1;
|
|
}
|
|
return router_send_one_flags(rconn, data, len, 0, 1);
|
|
}
|
|
|
|
void etcp_router_conn_close(struct ETCP_ROUTER_CONN* rconn) {
|
|
router_close_and_notify(rconn);
|
|
}
|
|
|
|
void etcp_router_conn_close_all_for_node(struct UTUN_INSTANCE* inst, uint64_t remote_node_id) {
|
|
if (!inst || !inst->router_conns) return;
|
|
struct ll_entry* entry;
|
|
while ((entry = queue_data_get(inst->router_conns)) != NULL) {
|
|
struct ETCP_ROUTER_CONN* rconn = (struct ETCP_ROUTER_CONN*)entry;
|
|
if (rconn->remote_node_id == remote_node_id) {
|
|
router_send_close_to_service(rconn);
|
|
if (rconn->ack_timer) { uasync_cancel_timeout(inst->ua, rconn->ack_timer); rconn->ack_timer = NULL; }
|
|
if (rconn->idle_ack_timer) { uasync_cancel_timeout(inst->ua, rconn->idle_ack_timer); rconn->idle_ack_timer = NULL; }
|
|
if (rconn->send_resume_timer) { uasync_cancel_timeout(inst->ua, rconn->send_resume_timer); rconn->send_resume_timer = NULL; }
|
|
if (rconn->recv_q) {
|
|
struct ll_entry* f;
|
|
while ((f = queue_data_get(rconn->recv_q)) != NULL) { queue_dgram_free(f); queue_entry_free(f); }
|
|
queue_free(rconn->recv_q);
|
|
}
|
|
if (rconn->send_q) {
|
|
struct ll_entry* f;
|
|
while ((f = queue_data_get(rconn->send_q)) != NULL) { queue_dgram_free(f); queue_entry_free(f); }
|
|
queue_free(rconn->send_q);
|
|
}
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "router_conn: closed by node remote=%016llx svc_id=%u",
|
|
(unsigned long long)rconn->remote_node_id, rconn->svc_id);
|
|
queue_entry_free(&rconn->ll);
|
|
} else {
|
|
queue_data_put(inst->router_conns, entry);
|
|
}
|
|
}
|
|
}
|