Browse Source

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)
congestion
Evgeny 4 months ago
parent
commit
ba03cab182
  1. 12
      src/remote_proxy.c
  2. 24
      src/tcp_proxy.c
  3. 1
      src/tcp_proxy.h

12
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;
}

24
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;
}

1
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)

Loading…
Cancel
Save