From ba03cab182279d33a5f3fd5f5d831d486f911fa4 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Sat, 30 May 2026 22:03:37 +0300 Subject: [PATCH] fix tcp_proxy connection lifecycle: closing_sent, destroy transport, shutdown+timer on exit - Add closing_sent flag to proxy_conn (CLOSE sent to exit, no need to wait for reply) - proxy_poll_cb: send CLOSE when done || sndbuf==0; cleanup when tun && (rem||sent) - Destroy transport in proxy_poll_cb cleanup (fix 56-byte leak) - remote_proxy_handle_close: shutdown(SHUT_WR) + 2s timer instead of immediate rp_conn_free - Remove SHUTDOWN subcommand entirely (not needed with new lifecycle) --- src/remote_proxy.c | 12 +++++++++++- src/tcp_proxy.c | 24 ++++++++++++++++-------- src/tcp_proxy.h | 1 + 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/remote_proxy.c b/src/remote_proxy.c index 0051326f..339b5284 100644 --- a/src/remote_proxy.c +++ b/src/remote_proxy.c @@ -225,6 +225,13 @@ int remote_proxy_handle_data(struct UTUN_INSTANCE* inst, struct ll_entry* entry, return 0; } +static void rp_close_timer_cb(void* arg) { + struct remote_proxy_conn* rc = (struct remote_proxy_conn*)arg; + if (!rc || rc->connected == -1) return; + DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "RP CLOSE timer stream=%016llx", (unsigned long long)rc->stream_id); + rp_conn_free(rc); +} + void remote_proxy_handle_close(struct UTUN_INSTANCE* inst, uint64_t stream_id) { if (!inst) return; struct remote_proxy_ctx* ctx = &inst->remote_proxy; @@ -233,8 +240,11 @@ void remote_proxy_handle_close(struct UTUN_INSTANCE* inst, uint64_t stream_id) { struct remote_proxy_conn* rc = *prev; if (rc->stream_id == stream_id) { DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "RP CLOSE stream=%016llx", (unsigned long long)stream_id); + *prev = rc->next; if (rc->sock != SOCKET_INVALID && rc->connected == 1) shutdown(rc->sock, SHUT_WR); - *prev = rc->next; rp_conn_free(rc); return; + if (rc->read_id) { uasync_remove_socket_t(rc->ua, rc->sock); rc->read_id = NULL; } + uasync_set_timeout(rc->ua, 20000, rc, rp_close_timer_cb, "rp_close"); + return; } prev = &rc->next; } diff --git a/src/tcp_proxy.c b/src/tcp_proxy.c index 68aea3db..9adacf83 100644 --- a/src/tcp_proxy.c +++ b/src/tcp_proxy.c @@ -309,18 +309,25 @@ static void proxy_err_cb(void *arg, err_t err) { static err_t proxy_poll_cb(void *arg, struct tcp_pcb *pcb) { struct proxy_conn *pc = (struct proxy_conn *)arg; if (!pc) return LERR_OK; - if (pc->closing_tun && !pc->closing_rem && pc->transport && pc->transport_to_uip - && queue_entry_count(pc->transport_to_uip) == 0) { - DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "PROXY CLOSE stream=%016llx tun=1 (no pending)", (unsigned long long)pc->remote_stream_id); - pc->transport->ops->close(pc->transport); + if (pc->closing_tun && !pc->closing_sent && !pc->closing_rem && pc->transport && pc->pcb) { + uint32_t pending = pc->transport_to_uip ? queue_entry_count(pc->transport_to_uip) : 0; + int done = (pending == 0 && pc->pcb->unsent == NULL && pc->pcb->unacked == NULL); + uint32_t sndbuf = tcp_sndbuf(pc->pcb); + if (done || sndbuf == 0) { + DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "PROXY CLOSE stream=%016llx tun=1 pending=%u done=%d sndbuf=%u", + (unsigned long long)pc->remote_stream_id, pending, done, sndbuf); + pc->transport->ops->close(pc->transport); + } } - if (pc->closing_tun && pc->closing_rem && pc->pcb) { - DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "PROXY CLOSE stream=%016llx tun=1 rem=1", (unsigned long long)pc->remote_stream_id); + if (pc->closing_tun && (pc->closing_rem || pc->closing_sent) && pc->pcb) { + DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "PROXY CLEANUP stream=%016llx tun=1 rem=%d sent=%d", + (unsigned long long)pc->remote_stream_id, pc->closing_rem, pc->closing_sent); struct tcp_pcb *save = pc->pcb; tcp_arg(save, NULL); pc->pcb = NULL; tcp_close(save); struct tcp_proxy *proxy = pc->proxy; struct proxy_conn **prev = &proxy->conns; while (*prev) { if (*prev == pc) { *prev = pc->next; proxy->conn_count--; break; } prev = &(*prev)->next; } + if (pc->transport) { pc->transport->ops->destroy(pc->transport); pc->transport = NULL; } if (pc->eim_mapping) { pc->eim_mapping->delete_at_tb = get_time_tb() + proxy->eim_timeout_tb; pc->eim_mapping = NULL; } if (pc->uip_to_transport) { struct ll_entry *e2; while ((e2 = queue_data_get(pc->uip_to_transport))) { queue_dgram_free(e2); queue_entry_free(e2); } queue_free(pc->uip_to_transport); } if (pc->transport_to_uip) { struct ll_entry *e2; while ((e2 = queue_data_get(pc->transport_to_uip))) { queue_dgram_free(e2); queue_entry_free(e2); } queue_free(pc->transport_to_uip); } @@ -602,8 +609,8 @@ static void etcp_transport_close(struct tcp_proxy_transport* t) { etcp_route_send(et->inst, et->remote_node_id, e); } else queue_entry_free(e); } et->connected = 0; - if (et->conn) { et->conn->transport = NULL; et->conn->closing_rem = 1; - DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "PROXY REM=1 stream=%016llx (transport close)", (unsigned long long)et->conn->remote_stream_id); + if (et->conn) { et->conn->transport = NULL; et->conn->closing_sent = 1; + DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "PROXY SENT=1 stream=%016llx (transport close)", (unsigned long long)et->conn->remote_stream_id); } } @@ -691,6 +698,7 @@ void tcp_proxy_etcp_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) { if (subcmd == TCP_PROXY_SUBCMD_CONNECT) { uint64_t src_node_id = conn ? conn->peer_node_id : (inst ? inst->node_id : 0); + DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "RP CONNECT recv stream=%016llx", (unsigned long long)stream_id); remote_proxy_handle_connect(inst, entry, stream_id, src_node_id); return; } diff --git a/src/tcp_proxy.h b/src/tcp_proxy.h index ed57aa45..4aa10eba 100644 --- a/src/tcp_proxy.h +++ b/src/tcp_proxy.h @@ -59,6 +59,7 @@ struct proxy_conn { uint16_t dest_port; int closing_tun; // 1 = TUN/lwIP side sent FIN (waiting for remote) int closing_rem; // 1 = remote/transport closed (waiting for TUN) + int closing_sent; // 1 = CLOSE sent to exit via transport->close() int active; // 1 = outgoing connection struct tcp_proxy_mapping* eim_mapping; uint64_t remote_stream_id; // stream ID for remote proxy (0=local)