feat: send_q backpressure + ll_queue on_get callback + consumer_ack flow control

etcp_router: ROUTER_MAX_SEND_Q_PACKETS=256, router_enqueue_send returns
error when send_q full, etcp_route_send propagates -1 on backpressure.

ll_queue: queue_set_on_get — deferred callback after each queue_data_get.
Replaces manual consumer_ack polling with queue-driven notification.

tcp_proxy_server: consumer_ack=1, write_on_get_cb triggers ACK on
each write_queue dequeue. Full backpressure chain:
  write_queue full → no dequeue → no ACK → sender stops → all queues pause
  write_queue drains → dequeue → on_get → ACK → sender resumes
This commit is contained in:
Evgeny committed 2026-06-03 18:51:12 +03:00
1 parent a0da29f1eb
commit bbf39c091d
5 files changed
+69 -10

No files matched your search

+27 -3
View File
@@ -100,9 +100,16 @@ static void send_error(struct tcp_proxy_server_conn* rc) {
}
// ====================================================================
// Коллбэки tcp_io
// Коллбэки tcp_io + очередь
// ====================================================================
static void write_on_get_cb(struct ll_queue* q, void* arg) {
(void)q;
struct tcp_proxy_server_conn* rc = (struct tcp_proxy_server_conn*)arg;
struct UTUN_INSTANCE* inst = rc->ctx ? rc->ctx->inst : NULL;
if (inst) etcp_router_consumer_ack(inst, rc->peer_node_id, ETCP_ID_TCP_PROXY);
}
static void on_fin_cb(struct tcp_conn* tc, void* arg) {
struct tcp_proxy_server_conn* rc = (struct tcp_proxy_server_conn*)arg;
if (write_pending(tc))
@@ -112,6 +119,7 @@ static void on_fin_cb(struct tcp_conn* tc, void* arg) {
}
static void on_flushed_cb(struct tcp_conn* tc, void* arg) {
(void)tc;
struct tcp_proxy_server_conn* rc = (struct tcp_proxy_server_conn*)arg;
if (rc->cli_closed) { tcp_proxy_server_conn_free(rc); return; }
send_close(rc);
@@ -168,7 +176,11 @@ static void read_queue_drain_cb(struct ll_queue* q, void* arg) {
if (ret == 0) {
queue_resume_callback(q);
} else {
etcp_router_waiter_register(inst, rc->peer_node_id, &rc->pause_waiter, pause_resume_cb, rc);
struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(inst, rc->peer_node_id, ETCP_ID_TCP_PROXY);
if (rconn && rconn->send_q)
queue_waiter_wait(rconn->send_q, &rc->pause_waiter, pause_resume_cb, rc);
else
etcp_router_waiter_register(inst, rc->peer_node_id, &rc->pause_waiter, pause_resume_cb, rc);
}
}
@@ -202,7 +214,12 @@ void tcp_proxy_server_conn_free(struct tcp_proxy_server_conn* rc) {
if (rc->tc) { tcp_conn_destroy(rc->tc); rc->tc = NULL; }
if (rc->close_timer) { uasync_cancel_timeout(rc->ua, rc->close_timer); rc->close_timer = NULL; }
if (rc->diag_timer) { uasync_cancel_timeout(rc->ua, rc->diag_timer); rc->diag_timer = NULL; }
if (rc->ctx && rc->ctx->inst) etcp_router_waiter_cancel(rc->ctx->inst, rc->peer_node_id, &rc->pause_waiter);
if (rc->ctx && rc->ctx->inst) {
struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(rc->ctx->inst, rc->peer_node_id, ETCP_ID_TCP_PROXY);
if (rconn && rconn->send_q) queue_waiter_cancel(rconn->send_q, &rc->pause_waiter);
else etcp_router_waiter_cancel(rc->ctx->inst, rc->peer_node_id, &rc->pause_waiter);
}
if (rc->tc) queue_set_on_get(rc->tc->write_queue, NULL, NULL);
u_free(rc);
}
@@ -254,6 +271,13 @@ int tcp_proxy_server_handle_connect(struct UTUN_INSTANCE* inst, struct ll_entry*
rc->next = ctx->conns; ctx->conns = rc;
rc->diag_timer = uasync_set_timeout(rc->ua, 10000, rc, diag_timer_cb, "tps_diag");
{
struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(inst, src_node_id, ETCP_ID_TCP_PROXY);
if (rconn) rconn->consumer_ack = 1;
}
queue_set_on_get(rc->tc->write_queue, write_on_get_cb, rc);
queue_dgram_free(entry); queue_entry_free(entry);
return 0;
}