|
|
|
|
@ -94,6 +94,7 @@ static int tcp_proxy_client_send_data(struct tcp_proxy_client_conn* pc, const ui
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int tcp_proxy_client_send_close(struct tcp_proxy_client_conn* pc) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_TRAFFIC, "PROXY SEND sid=%08x", pc->stream_id); |
|
|
|
|
int ret = tcp_proxy_client_send_msg(pc->proxy->inst, pc->proxy->via_node_id, |
|
|
|
|
TCP_PROXY_SUBCMD_CLOSE, pc->stream_id, NULL, 0, 1); |
|
|
|
|
if (ret < 0) { pc->close_pending = 1; return -1; } |
|
|
|
|
@ -111,6 +112,12 @@ static int tcp_proxy_client_send_error(struct tcp_proxy_client_conn* pc) {
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int tcp_proxy_client_send_fin(struct tcp_proxy_client_conn* pc) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_TRAFFIC, "PROXY FIN RELAY sid=%08x", pc->stream_id); |
|
|
|
|
return tcp_proxy_client_send_msg(pc->proxy->inst, pc->proxy->via_node_id, |
|
|
|
|
TCP_PROXY_SUBCMD_FIN, pc->stream_id, NULL, 0, 1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ====================================================================
|
|
|
|
|
// Вывод: lwIP TCP отправляет IP пакеты через этот callback
|
|
|
|
|
// ====================================================================
|
|
|
|
|
@ -248,7 +255,7 @@ static void tcp_proxy_client_tx_waiter_cb(struct ll_queue* q, void* arg) {
|
|
|
|
|
tcp_recved(pc->pcb, pc->tx_len); |
|
|
|
|
u_free(pc->tx_buf); pc->tx_buf = NULL; pc->tx_len = 0; |
|
|
|
|
if (pc->tun_closed && !pc->close_sent && !pc->close_pending) |
|
|
|
|
tcp_proxy_client_send_close(pc); |
|
|
|
|
tcp_proxy_client_send_fin(pc); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -257,15 +264,13 @@ static err_t tcp_proxy_client_recv_cb(void *arg, struct tcp_pcb *pcb, struct pbu
|
|
|
|
|
if (!pc) { if (p) pbuf_free(p); return LERR_OK; } |
|
|
|
|
|
|
|
|
|
if (p == NULL || err != LERR_OK) { |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "PROXY FIN sid=%08x pcb_state=%u sndbuf=%u cwnd=%u unsent=%p unacked=%p close_sent=%d", |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "PROXY FIN sid=%08x pcb_state=%u sndbuf=%u cwnd=%u unsent=%p unacked=%p", |
|
|
|
|
pc->stream_id, pcb->state, pcb->snd_buf, pcb->cwnd, |
|
|
|
|
(void*)pcb->unsent, (void*)pcb->unacked, pc->close_sent); |
|
|
|
|
(void*)pcb->unsent, (void*)pcb->unacked); |
|
|
|
|
{ uint16_t wnd_gap = TCP_WND_MAX(pcb) - pcb->rcv_wnd; |
|
|
|
|
if (wnd_gap > 0) tcp_recved(pcb, wnd_gap); } |
|
|
|
|
pc->tun_closed = 1; |
|
|
|
|
if (!pc->tx_buf && !pc->close_sent && !pc->close_pending) { |
|
|
|
|
if (tcp_proxy_client_send_close(pc) < 0) DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "PROXY FIN send_close failed sid=%08x", pc->stream_id); |
|
|
|
|
} |
|
|
|
|
if (!pc->tx_buf) tcp_proxy_client_send_fin(pc); |
|
|
|
|
return LERR_OK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -314,35 +319,16 @@ static err_t tcp_proxy_client_poll_cb(void *arg, struct tcp_pcb *pcb) {
|
|
|
|
|
if (!pc) return LERR_OK; |
|
|
|
|
|
|
|
|
|
if (pc->error) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "PROXY CLEANUP error sid=%08x tun_closed=%d rem_closed=%d", pc->stream_id, pc->tun_closed, pc->rem_closed); |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "PROXY CLEANUP error sid=%08x", pc->stream_id); |
|
|
|
|
if (pc->pcb) { tcp_arg(pc->pcb, NULL); tcp_abort(pc->pcb); pc->pcb = NULL; } |
|
|
|
|
tcp_proxy_client_conn_free(pc); |
|
|
|
|
return LERR_OK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Retry pending CLOSE/ERROR if previous send failed */ |
|
|
|
|
if (pc->close_pending) { |
|
|
|
|
if (pc->error) tcp_proxy_client_send_error(pc); |
|
|
|
|
else tcp_proxy_client_send_close(pc); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (pc->tun_closed && pc->rem_closed && pc->pcb) { |
|
|
|
|
uint32_t pending = pc->to_lwip ? queue_entry_count(pc->to_lwip) : 0; |
|
|
|
|
int done = (pending == 0 && pcb->unsent == NULL && pcb->unacked == NULL); |
|
|
|
|
uint32_t sndbuf = tcp_sndbuf(pcb); |
|
|
|
|
if (done || sndbuf == 0) { |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "PROXY CLEANUP sid=%08x state=%u sndbuf=%u cwnd=%u pending=%u unsent=%p unacked=%p", |
|
|
|
|
pc->stream_id, pcb->state, pcb->snd_buf, pcb->cwnd, |
|
|
|
|
pending, (void*)pcb->unsent, (void*)pcb->unacked); |
|
|
|
|
struct tcp_pcb *save = pc->pcb; pc->pcb = NULL; |
|
|
|
|
tcp_arg(save, NULL); |
|
|
|
|
{ uint16_t wnd_gap = TCP_WND_MAX(save) - save->rcv_wnd; |
|
|
|
|
if (wnd_gap > 0) tcp_recved(save, wnd_gap); } |
|
|
|
|
while (save->unsent) { struct tcp_seg *seg = save->unsent; save->unsent = seg->next; u_free(seg); } |
|
|
|
|
tcp_close(save); |
|
|
|
|
tcp_proxy_client_conn_free(pc); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return LERR_OK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -403,6 +389,11 @@ static void tcp_proxy_client_conn_free(struct tcp_proxy_client_conn *pc) {
|
|
|
|
|
uint32_t pending = pc->to_lwip ? queue_entry_count(pc->to_lwip) : 0; |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "PROXY FREE sid=%08x total_conns=%d to_lwip_q=%u", |
|
|
|
|
pc->stream_id, p->conn_count, pending); |
|
|
|
|
if (pc->close_pending && p && p->inst) { |
|
|
|
|
pc->close_pending = 0; |
|
|
|
|
uint8_t subcmd = pc->error ? TCP_PROXY_SUBCMD_ERROR : TCP_PROXY_SUBCMD_CLOSE; |
|
|
|
|
tcp_proxy_client_send_msg(p->inst, p->via_node_id, subcmd, pc->stream_id, NULL, 0, 1); |
|
|
|
|
} |
|
|
|
|
struct tcp_proxy_client_conn **prev = &p->conns; |
|
|
|
|
while (*prev) { if (*prev == pc) { *prev = pc->next; p->conn_count--; break; } prev = &(*prev)->next; } |
|
|
|
|
if (pc->to_lwip) { |
|
|
|
|
@ -427,7 +418,7 @@ static struct tcp_proxy_client_conn* tcp_proxy_client_find_conn(struct tcp_proxy
|
|
|
|
|
static void tcp_proxy_client_handle_data(struct tcp_proxy_client* p, struct ETCP_CONN* conn, uint32_t stream_id, struct ll_entry* entry) { |
|
|
|
|
struct tcp_proxy_client_conn* pc = tcp_proxy_client_find_conn(p, stream_id); |
|
|
|
|
if (!pc || pc->rem_closed || pc->error || pc->tun_closed) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_SOCKET, "PROXY DATA sid=%08x — no conn/closed, dropping", stream_id); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "PROXY DATA sid=%08x — no conn/closed, dropping", stream_id); |
|
|
|
|
queue_dgram_free(entry); queue_entry_free(entry); return; |
|
|
|
|
} |
|
|
|
|
size_t data_len = entry->len - TCP_PROXY_HDR_SIZE; |
|
|
|
|
@ -442,24 +433,26 @@ static void tcp_proxy_client_handle_data(struct tcp_proxy_client* p, struct ETCP
|
|
|
|
|
|
|
|
|
|
static void tcp_proxy_client_handle_close(struct tcp_proxy_client* p, uint32_t stream_id) { |
|
|
|
|
struct tcp_proxy_client_conn* pc = tcp_proxy_client_find_conn(p, stream_id); |
|
|
|
|
if (pc) { |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "PROXY REM_CLOSED sid=%08x tun_closed=%d", |
|
|
|
|
stream_id, pc->tun_closed); |
|
|
|
|
pc->rem_closed = 1; |
|
|
|
|
} else { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_SOCKET, "PROXY CLOSE sid=%08x — no conn, dropping", stream_id); |
|
|
|
|
} |
|
|
|
|
if (!pc) { DEBUG_WARN(DEBUG_CATEGORY_SOCKET, "PROXY CLOSE sid=%08x — no conn, dropping", stream_id); return; } |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "PROXY REM_CLOSED sid=%08x tun_closed=%d", stream_id, pc->tun_closed); |
|
|
|
|
pc->rem_closed = 1; |
|
|
|
|
if (pc->tx_buf) { u_free(pc->tx_buf); pc->tx_buf = NULL; pc->tx_len = 0; } |
|
|
|
|
etcp_router_waiter_cancel(pc->proxy->inst, pc->proxy->via_node_id, &pc->tx_waiter); |
|
|
|
|
if (pc->pcb) { tcp_arg(pc->pcb, NULL); tcp_close(pc->pcb); pc->pcb = NULL; } |
|
|
|
|
tcp_proxy_client_conn_free(pc); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void tcp_proxy_client_handle_error(struct tcp_proxy_client* p, uint32_t stream_id) { |
|
|
|
|
struct tcp_proxy_client_conn* pc = tcp_proxy_client_find_conn(p, stream_id); |
|
|
|
|
if (pc) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "PROXY ERROR from exit sid=%08x tun_closed=%d rem_closed=%d", |
|
|
|
|
stream_id, pc->tun_closed, pc->rem_closed); |
|
|
|
|
if (!pc->error) { pc->error = 1; tcp_proxy_client_send_close(pc); } |
|
|
|
|
} else { |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "PROXY ERROR sid=%08x — no conn, silent drop", stream_id); |
|
|
|
|
} |
|
|
|
|
if (!pc) { DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "PROXY ERROR sid=%08x — no conn, dropping", stream_id); return; } |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "PROXY ERROR from exit sid=%08x tun_closed=%d", stream_id, pc->tun_closed); |
|
|
|
|
tcp_proxy_client_handle_close(p, stream_id); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void tcp_proxy_client_handle_fin(struct tcp_proxy_client* p, uint32_t stream_id) { |
|
|
|
|
struct tcp_proxy_client_conn* pc = tcp_proxy_client_find_conn(p, stream_id); |
|
|
|
|
if (!pc || !pc->pcb) return; |
|
|
|
|
tcp_shutdown(pc->pcb, 0, 1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ====================================================================
|
|
|
|
|
@ -506,13 +499,15 @@ void tcp_proxy_client_etcp_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entr
|
|
|
|
|
if (rc) { |
|
|
|
|
if (subcmd == TCP_PROXY_SUBCMD_DATA) { tcp_proxy_server_handle_data(inst, conn, entry, stream_id); return; } |
|
|
|
|
if (subcmd == TCP_PROXY_SUBCMD_CLOSE) { tcp_proxy_server_handle_close(inst, stream_id); queue_dgram_free(entry); queue_entry_free(entry); return; } |
|
|
|
|
if (subcmd == TCP_PROXY_SUBCMD_ERROR) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "RP ERROR recv sid=%08x", stream_id); tcp_proxy_server_conn_free(rc); queue_dgram_free(entry); queue_entry_free(entry); return; } |
|
|
|
|
if (subcmd == TCP_PROXY_SUBCMD_ERROR) { tcp_proxy_server_handle_error(inst, stream_id); queue_dgram_free(entry); queue_entry_free(entry); return; } |
|
|
|
|
if (subcmd == TCP_PROXY_SUBCMD_FIN) { tcp_proxy_server_handle_fin(inst, stream_id); queue_dgram_free(entry); queue_entry_free(entry); return; } |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (proxy) { |
|
|
|
|
if (subcmd == TCP_PROXY_SUBCMD_DATA) { tcp_proxy_client_handle_data(proxy, conn, stream_id, entry); return; } |
|
|
|
|
if (subcmd == TCP_PROXY_SUBCMD_CLOSE) { tcp_proxy_client_handle_close(proxy, stream_id); queue_dgram_free(entry); queue_entry_free(entry); return; } |
|
|
|
|
if (subcmd == TCP_PROXY_SUBCMD_ERROR) { tcp_proxy_client_handle_error(proxy, stream_id); queue_dgram_free(entry); queue_entry_free(entry); return; } |
|
|
|
|
if (subcmd == TCP_PROXY_SUBCMD_CLOSE) { tcp_proxy_client_handle_close(proxy, stream_id); queue_dgram_free(entry); queue_entry_free(entry); return; } |
|
|
|
|
if (subcmd == TCP_PROXY_SUBCMD_ERROR) { tcp_proxy_client_handle_error(proxy, stream_id); queue_dgram_free(entry); queue_entry_free(entry); return; } |
|
|
|
|
if (subcmd == TCP_PROXY_SUBCMD_FIN) { tcp_proxy_client_handle_fin(proxy, stream_id); queue_dgram_free(entry); queue_entry_free(entry); return; } |
|
|
|
|
} |
|
|
|
|
if (subcmd == TCP_PROXY_SUBCMD_ERROR) { |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "PROXY ERROR sid=%08x — conn not found, silent drop", stream_id); |
|
|
|
|
|