Browse Source

etcp: перепривязка/своп remote_link_id при INIT со сменённым адресом (NAT)

v2
evgeny 3 weeks ago
parent
commit
ab6773a313
  1. 47
      src/transport_layer/etcp_connections.c

47
src/transport_layer/etcp_connections.c

@ -402,6 +402,27 @@ struct ETCP_LINK* etcp_link_find_by_addr(struct ETCP_SOCKET* e_sock, struct sock
return lqe->link; return lqe->link;
} }
/* Перепривязывает UDP-линк на новый remote-адрес (пир сменил NAT-адрес, линк ещё down).
* Пере-индексирует линк в socket->links_queue под новым ключом. */
static void etcp_link_update_remote_addr(struct ETCP_LINK* link, struct ETCP_SOCKET* e_sock,
const struct sockaddr_storage* new_addr) {
if (!link || !e_sock || !new_addr) return;
if (link->is_tcp) {
DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "[%s] update_remote_addr: TCP link skip", link->etcp->log_name);
return;
}
if (link->conn != e_sock) {
DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "[%s] update_remote_addr: link socket [%s] != recv socket [%s], skip",
link->etcp->log_name, link->conn ? link->conn->name : "-", e_sock->name);
return;
}
remove_link_from_queue(link);
memcpy(&link->remote_addr, new_addr, sizeof(struct sockaddr_storage));
if (insert_link_queue(e_sock, link) < 0)
DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "[%s] update_remote_addr: re-index FAILED at %s",
link->etcp->log_name, sockaddr_storage_to_str(new_addr).str);
}
struct ETCP_LINK* etcp_link_find_by_remote_id(struct ETCP_CONN* conn, uint8_t remote_link_id) { struct ETCP_LINK* etcp_link_find_by_remote_id(struct ETCP_CONN* conn, uint8_t remote_link_id) {
DEBUG_TRACE(DEBUG_CATEGORY_CONNECTION, ""); DEBUG_TRACE(DEBUG_CATEGORY_CONNECTION, "");
if (!conn || remote_link_id == 0) return NULL; if (!conn || remote_link_id == 0) return NULL;
@ -2115,6 +2136,32 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
// Check if link already exists (for CHANNEL_INIT recovery) // Check if link already exists (for CHANNEL_INIT recovery)
struct ETCP_LINK* existing_link = etcp_link_find_by_remote_id(conn, req->link_id); struct ETCP_LINK* existing_link = etcp_link_find_by_remote_id(conn, req->link_id);
/* Правила 1+2: найден по id, линк down, адрес сменился */
if (existing_link && existing_link->link_status == 0
&& !sockaddr_equal(&existing_link->remote_addr, &addr)) {
struct ETCP_LINK* L_addr = etcp_link_find_by_addr(e_sock, &addr, 0);
if (L_addr && L_addr != existing_link && L_addr->etcp == conn && L_addr->link_status == 0) {
/* Правило 2: своп remote_link_id, дальше работаем с L_addr */
uint8_t id_old = existing_link->remote_link_id;
uint8_t id_swap = L_addr->remote_link_id;
existing_link->remote_link_id = id_swap;
L_addr->remote_link_id = id_old;
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] swap remote_link_id: id=%u @ %s <-> id=%u @ %s",
conn->log_name, id_old, sockaddr_storage_to_str(&existing_link->remote_addr).str,
id_swap, sockaddr_storage_to_str(&L_addr->remote_addr).str);
existing_link = L_addr;
} else if (!L_addr) {
/* Правило 1: перепривязать адрес */
etcp_link_update_remote_addr(existing_link, e_sock, &addr);
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] remote addr updated: id=%u -> %s",
conn->log_name, existing_link->remote_link_id, sockaddr_storage_to_str(&addr).str);
} else {
DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "[%s] addr %s busy (up/foreign) — link id=%u left as-is",
conn->log_name, sockaddr_storage_to_str(&addr).str, existing_link->remote_link_id);
}
}
if (!existing_link) { if (!existing_link) {
existing_link = etcp_link_find_by_addr(e_sock, &addr, 0); existing_link = etcp_link_find_by_addr(e_sock, &addr, 0);
if (existing_link && existing_link->etcp == conn) { if (existing_link && existing_link->etcp == conn) {

Loading…
Cancel
Save