chat: invite-ссылки с выбором достижимого узла + tcp_io фикс half-close FIN
- Общий модуль invite_build: сборка utun://-ссылок, авто-выбор лучшего достижимого узла, список кандидатов (вынесено из android jni_bridge) - chatgui: диалог invite с выбором узла (комбобокс), события INVITE_CANDIDATES / INVITE_LINK_READY через gui_bridge - headless/chatcli: invite <ch_id> [node_id], команда invite_nodes - tcp_io: error_cb отличает грациозный EPOLLHUP (SO_ERROR==0) от реальной ошибки — при приостановленном чтении FIN не роняет недослейные данные (фикс flaky half-close) - run_test.sh: half-close echo на выделенном порту 19190 + отдельный DNAT (был недостижим)
This commit is contained in:
1 parent
a17a85a383
commit
1345f44e10
23 files changed
+872
-539
No files matched your search
@@ -2,14 +2,9 @@
|
||||
#include "utun_node.h"
|
||||
#include <cinttypes>
|
||||
#include <QDir>
|
||||
#include <QMap>
|
||||
#include <QPair>
|
||||
#include <csignal>
|
||||
#include "../../lib/socket_compat.h"
|
||||
|
||||
#include "../db/db_manager.h"
|
||||
#include "../src/invite_link.h"
|
||||
|
||||
// === C headers ===
|
||||
extern "C" {
|
||||
#include "utun_instance.h"
|
||||
@@ -139,116 +134,6 @@ bool UtunNode::ntpEnabled() const {
|
||||
return m_instance ? m_instance->ntp.enabled : false;
|
||||
}
|
||||
|
||||
QList<NodeAddr> UtunNode::getInviteAddresses(DbManager* db) {
|
||||
(void)db;
|
||||
QList<NodeAddr> addrs;
|
||||
QMap<QPair<QByteArray, quint16>, uint8_t> addrProto; // key=(addr,port) → proto bits
|
||||
|
||||
auto add_addr = [&](const QByteArray& addr, quint16 port, int family,
|
||||
int sockId, uint8_t proto) {
|
||||
QPair<QByteArray, quint16> key(addr, port);
|
||||
uint8_t existing = addrProto.value(key, 0);
|
||||
addrProto[key] = existing | proto;
|
||||
// Store sockId/family for serialization (overwrite is fine — same port)
|
||||
};
|
||||
|
||||
auto append_from_addr_proto = [&](const QByteArray& addr, quint16 port,
|
||||
int family, int sockId, uint8_t proto) {
|
||||
NodeAddr a;
|
||||
a.family = family;
|
||||
a.address = addr;
|
||||
a.port = port;
|
||||
a.socketId = sockId;
|
||||
a.protocol = proto;
|
||||
addrs.append(a);
|
||||
};
|
||||
if (m_instance) {
|
||||
/* 1) UDP from active ETCP links */
|
||||
struct ll_entry* entry = m_instance->connections->head;
|
||||
while (entry) {
|
||||
struct conn_queue_entry* ce = (struct conn_queue_entry*)entry->data;
|
||||
struct ETCP_CONN* conn = ce->conn;
|
||||
if (conn && conn->initialized && conn->links_up > 0) {
|
||||
struct ETCP_LINK* link = conn->links;
|
||||
while (link) {
|
||||
if (!link->is_tcp && link->link_state == 3 && link->nat_type == NAT_TYPE_DIRECT) {
|
||||
struct sockaddr_storage* sa = &link->remote_addr;
|
||||
if (sa->ss_family == AF_INET) {
|
||||
struct sockaddr_in* sin = (struct sockaddr_in*)sa;
|
||||
QByteArray addr((const char*)&sin->sin_addr, 4);
|
||||
add_addr(addr, ntohs(sin->sin_port), 4,
|
||||
link->conn ? (int)link->conn->sock_id : 0, INVITE_PROTO_UDP);
|
||||
} else {
|
||||
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
|
||||
QByteArray addr((const char*)&sin6->sin6_addr, 16);
|
||||
add_addr(addr, ntohs(sin6->sin6_port), 6,
|
||||
link->conn ? (int)link->conn->sock_id : 0, INVITE_PROTO_UDP);
|
||||
}
|
||||
}
|
||||
link = link->next;
|
||||
}
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
/* 2) UDP from local ETCP sockets (fallback) */
|
||||
{
|
||||
struct ETCP_SOCKET* sock = m_instance->etcp_sockets;
|
||||
while (sock) {
|
||||
if (sock->is_tcp) { sock = sock->next; continue; }
|
||||
struct sockaddr_storage* sa = NULL;
|
||||
if (sock->nat_addr.ss_family != 0)
|
||||
sa = &sock->nat_addr;
|
||||
else if (sock->interface_addr.ss_family != 0)
|
||||
sa = &sock->interface_addr;
|
||||
if (sa) {
|
||||
if (sa->ss_family == AF_INET) {
|
||||
struct sockaddr_in* sin = (struct sockaddr_in*)sa;
|
||||
QByteArray addr((const char*)&sin->sin_addr, 4);
|
||||
add_addr(addr, ntohs(sin->sin_port), 4, (int)sock->sock_id, INVITE_PROTO_UDP);
|
||||
} else {
|
||||
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
|
||||
QByteArray addr((const char*)&sin6->sin6_addr, 16);
|
||||
add_addr(addr, ntohs(sin6->sin6_port), 6, (int)sock->sock_id, INVITE_PROTO_UDP);
|
||||
}
|
||||
}
|
||||
sock = sock->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* 3) TCP from local TCP sockets */
|
||||
{
|
||||
struct ETCP_SOCKET* s = m_instance->etcp_sockets;
|
||||
while (s) {
|
||||
if (!s->is_tcp) { s = s->next; continue; }
|
||||
struct sockaddr_storage* sa = &s->interface_addr;
|
||||
if (sa->ss_family == AF_INET) {
|
||||
struct sockaddr_in* sin = (struct sockaddr_in*)sa;
|
||||
QByteArray addr((const char*)&sin->sin_addr, 4);
|
||||
add_addr(addr, ntohs(sin->sin_port), 4, (int)s->sock_id, INVITE_PROTO_TCP);
|
||||
} else if (sa->ss_family == AF_INET6) {
|
||||
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
|
||||
QByteArray addr((const char*)&sin6->sin6_addr, 16);
|
||||
add_addr(addr, ntohs(sin6->sin6_port), 6, (int)s->sock_id, INVITE_PROTO_TCP);
|
||||
}
|
||||
s = s->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* 4) Dedup by (addr,port); emit one entry per proto (UDP и TCP раздельно, без BOTH) */
|
||||
for (auto it = addrProto.begin(); it != addrProto.end(); ++it) {
|
||||
QByteArray addr = it.key().first;
|
||||
quint16 port = it.key().second;
|
||||
uint8_t proto = it.value();
|
||||
int family = (addr.size() == 16) ? 6 : 4;
|
||||
if (proto & INVITE_PROTO_UDP) append_from_addr_proto(addr, port, family, 0, INVITE_PROTO_UDP);
|
||||
if (proto & INVITE_PROTO_TCP) append_from_addr_proto(addr, port, family, 0, INVITE_PROTO_TCP);
|
||||
}
|
||||
}
|
||||
|
||||
return addrs;
|
||||
}
|
||||
|
||||
void UtunNode::recvCallback(struct ETCP_CONN* conn, struct ll_entry* entry) {
|
||||
if (!g_currentNode || !entry || !entry->dgram || entry->len < ROUTER_SVC_HDR_SIZE) return;
|
||||
uint64_t src;
|
||||
|
||||
Reference in new issue
Block a user