Browse Source

tcp_proxy: гарантированная доставка CLOSE/ERROR через retry при сбое маршрута

- proxy_conn.close_pending: флаг недоставленного CLOSE/ERROR
- send_close/send_error: при возврате -1 выставляют close_pending=1
- proxy_poll_cb: периодический retry close_pending → CLOSE дойдёт при восстановлении ETCP
- proxy_recv_cb: проверка !close_pending перед повторной отправкой close
etcp-inflight-fix
Evgeny 4 months ago
parent
commit
b43de4c1f0
  1. 26
      src/tcp_proxy.c
  2. 1
      src/tcp_proxy.h

26
src/tcp_proxy.c

@ -93,13 +93,21 @@ static int send_data(struct proxy_conn* pc, const uint8_t* data, uint16_t len) {
}
static int send_close(struct proxy_conn* pc) {
return proxy_send_msg(pc->proxy->inst, pc->proxy->via_node_id,
TCP_PROXY_SUBCMD_CLOSE, pc->stream_id, NULL, 0);
int ret = proxy_send_msg(pc->proxy->inst, pc->proxy->via_node_id,
TCP_PROXY_SUBCMD_CLOSE, pc->stream_id, NULL, 0);
if (ret < 0) { pc->close_pending = 1; return -1; }
pc->close_pending = 0;
pc->close_sent = 1;
return 0;
}
static int send_error(struct proxy_conn* pc) {
return proxy_send_msg(pc->proxy->inst, pc->proxy->via_node_id,
TCP_PROXY_SUBCMD_ERROR, pc->stream_id, NULL, 0);
int ret = proxy_send_msg(pc->proxy->inst, pc->proxy->via_node_id,
TCP_PROXY_SUBCMD_ERROR, pc->stream_id, NULL, 0);
if (ret < 0) { pc->close_pending = 1; return -1; }
pc->close_pending = 0;
pc->close_sent = 1;
return 0;
}
// ====================================================================
@ -238,9 +246,8 @@ static err_t proxy_recv_cb(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t
{ 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->close_sent) {
if (!pc->close_sent && !pc->close_pending) {
if (send_close(pc) < 0) DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "PROXY FIN send_close failed sid=%08x", pc->stream_id);
pc->close_sent = 1;
}
return LERR_OK;
}
@ -276,7 +283,6 @@ static void proxy_err_cb(void *arg, err_t err) {
err, pc->stream_id, pc->pcb ? pc->pcb->state : 0, pc->tun_closed, pc->rem_closed, pc->connected);
pc->error = 1;
if (send_error(pc) < 0) DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "PROXY send_error failed sid=%08x", pc->stream_id);
pc->close_sent = 1;
}
static err_t proxy_poll_cb(void *arg, struct tcp_pcb *pcb) {
@ -290,6 +296,12 @@ static err_t proxy_poll_cb(void *arg, struct tcp_pcb *pcb) {
return LERR_OK;
}
/* Retry pending CLOSE/ERROR if previous send failed */
if (pc->close_pending) {
if (pc->error) send_error(pc);
else 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);

1
src/tcp_proxy.h

@ -32,6 +32,7 @@ struct proxy_conn {
uint8_t rem_closed; // exit отправил CLOSE
uint8_t error; // ошибка, немедленная очистка
uint8_t close_sent; // отправили CLOSE/ERROR в exit
uint8_t close_pending; // CLOSE/ERROR не доставлен, ждём повтора
uint8_t connected; // CONNECTED(OK) получен от exit
uint8_t dest_ip[4];

Loading…
Cancel
Save