From 544c77efff3ccbde458290ebeb3db54a7fbc6eb8 Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 10 Aug 2026 12:06:32 +0300 Subject: [PATCH] unify TCP_SOCKET into ETCP_SOCKET with is_tcp flag; add local+remote addr to member detail links with arrow display --- src/chat/chat_channel.c | 2 +- src/chat/chat_headless_control.c | 2 +- src/chat/chat_profile.c | 2 +- src/chat/chat_status.c | 45 +++++---- src/routing_layer/topo_node.c | 6 +- src/transport_layer/auto_socket.c | 65 +++++++------ src/transport_layer/etcp_connections.c | 28 +++--- src/transport_layer/etcp_connections.h | 61 ++++++------ src/transport_layer/stcp_link.c | 8 +- src/transport_layer/stcp_link.h | 5 +- src/utun_instance.h | 5 +- tests/test_etcp_link_stress.c | 6 +- tests/test_invite_group_create.c | 2 +- tests/test_stcp_link.c | 22 ++--- .../jni_bridge/android_jni_bridge.c | 66 +++++-------- tools/chatgui/src/accountlist.cpp | 93 +++++++------------ tools/chatgui/src/accountlist.h | 3 + tools/chatgui/transport/gui_bridge.h | 2 +- tools/chatgui/transport/utun_node.cpp | 2 +- 19 files changed, 197 insertions(+), 228 deletions(-) diff --git a/src/chat/chat_channel.c b/src/chat/chat_channel.c index ece80447..1e9999dc 100644 --- a/src/chat/chat_channel.c +++ b/src/chat/chat_channel.c @@ -86,7 +86,7 @@ static int collect_my_addrs(uint8_t* buf, int max_buf_sz) { s = s->next; } - { struct TCP_SOCKET* ts = g_cc.inst->tcp_sockets; + { struct ETCP_SOCKET* ts = g_cc.inst->tcp_sockets; while (ts) { struct sockaddr_storage* addr = ts->interface_addr.ss_family ? &ts->interface_addr : &ts->local_addr; if (addr && addr->ss_family == AF_INET) { diff --git a/src/chat/chat_headless_control.c b/src/chat/chat_headless_control.c index ed01cc0e..be915d5c 100644 --- a/src/chat/chat_headless_control.c +++ b/src/chat/chat_headless_control.c @@ -352,7 +352,7 @@ static void hc_handle_invite(struct headless_client* cli, int id, const char* js } s = s->next; } - struct TCP_SOCKET* ts = g_hc.inst->tcp_sockets; + struct ETCP_SOCKET* ts = g_hc.inst->tcp_sockets; while (ts && inv.addrCount < INVITE_ADDR_MAX) { if (ts->interface_addr.ss_family == AF_INET) { struct sockaddr_in* sin = (struct sockaddr_in*)&ts->interface_addr; diff --git a/src/chat/chat_profile.c b/src/chat/chat_profile.c index 1538d53e..3fba0058 100644 --- a/src/chat/chat_profile.c +++ b/src/chat/chat_profile.c @@ -161,7 +161,7 @@ void chat_core_sync_my_addresses(void) { "INSERT OR REPLACE INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id)" " VALUES(?,?,2,?,?,?,?)", -1, &tcp_ins, NULL); if (tcp_ins) { - struct TCP_SOCKET* ts = g_cc.inst->tcp_sockets; + struct ETCP_SOCKET* ts = g_cc.inst->tcp_sockets; int tcp_count = 0; while (ts) { if (ts->type == CFG_SERVER_TYPE_PRIVATE || ts->type == CFG_SERVER_TYPE_LOCAL) { ts = ts->next; continue; } tcp_count++; diff --git a/src/chat/chat_status.c b/src/chat/chat_status.c index 689b7c9c..4181e424 100644 --- a/src/chat/chat_status.c +++ b/src/chat/chat_status.c @@ -301,15 +301,17 @@ void chat_core_collect_conn_metrics_trampoline(void* arg) { } /* ── Live-снапшот для панели деталей участника ── - * packet: [node_id:8][flags:1][own_tcp_active:2][link_count:1](link:25B)*[sock_count:1](sock:48B)* + * packet: [node_id:8][flags:1][own_tcp_active:2][link_count:1](link:43B)*[sock_count:1](sock:48B)* * flags: bit0=conn_present bit1=conn_up(links_up) bit2=conn_initialized - * link: [is_tcp:1][link_state:1][link_status:1][tcp_ready:1][is_server:1][family:1][addr_len:1][addr:16][port:2] + * link: [is_tcp:1][link_state:1][link_status:1][tcp_ready:1][is_server:1] + * [local_family:1][local_addr:16][local_port:2] + * [remote_family:1][remote_addr:16][remote_port:2] * sock: [sock_id:4][port:2][link_count:4][ifname:38] * Собирается в worker-потоке — читает живые структуры UTUN_INSTANCE безопасно. */ #define MEMBER_DETAIL_MAX_LINKS 16 #define MEMBER_DETAIL_MAX_SOCKS 16 -#define MEMBER_DETAIL_LINK_SIZE 25 +#define MEMBER_DETAIL_LINK_SIZE 43 #define MEMBER_DETAIL_SOCK_SIZE 48 /* Повторяет Qt: name.lastIndexOf("_v") → name.mid(3, idx - 3) */ @@ -365,7 +367,7 @@ static void collect_member_detail(uint64_t node_id) { uint8_t sock_count = 0; for (struct ETCP_SOCKET* s = inst->etcp_sockets; s && sock_count < MEMBER_DETAIL_MAX_SOCKS; s = s->next) sock_count++; - for (struct TCP_SOCKET* ts = inst->tcp_sockets; ts && sock_count < MEMBER_DETAIL_MAX_SOCKS; ts = ts->next) + for (struct ETCP_SOCKET* ts = inst->tcp_sockets; ts && sock_count < MEMBER_DETAIL_MAX_SOCKS; ts = ts->next) sock_count++; size_t buf_sz = 12 + (size_t)link_count * MEMBER_DETAIL_LINK_SIZE @@ -385,19 +387,28 @@ static void collect_member_detail(uint64_t node_id) { *p++ = lk->link_status; *p++ = (lk->is_tcp && lk->tcp_link && stcp_link_is_ready(lk->tcp_link)) ? 1 : 0; *p++ = lk->is_server; - uint8_t family = 0, addr_len = 0; uint8_t addr[16] = {0}; uint16_t port = 0; - const struct sockaddr_storage* sa = &lk->remote_addr; - if (sa->ss_family == AF_INET) { - struct sockaddr_in* sin = (struct sockaddr_in*)sa; - family = 4; addr_len = 4; memcpy(addr, &sin->sin_addr, 4); port = ntohs(sin->sin_port); - } else if (sa->ss_family == AF_INET6) { - struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa; - family = 6; addr_len = 16; memcpy(addr, &sin6->sin6_addr, 16); port = ntohs(sin6->sin6_port); + + { uint8_t lf = 0; uint8_t la[16] = {0}; uint16_t lp = 0; + if (lk->conn) { + const struct sockaddr_storage* lsa = &lk->conn->local_addr; + if (lsa->ss_family == AF_INET) { + lf = 4; memcpy(la, &((const struct sockaddr_in*)lsa)->sin_addr, 4); lp = ntohs(((const struct sockaddr_in*)lsa)->sin_port); + } else if (lsa->ss_family == AF_INET6) { + lf = 6; memcpy(la, &((const struct sockaddr_in6*)lsa)->sin6_addr, 16); lp = ntohs(((const struct sockaddr_in6*)lsa)->sin6_port); + } + } + *p++ = lf; memcpy(p, la, 16); p += 16; memcpy(p, &lp, 2); p += 2; + } + + { uint8_t rf = 0; uint8_t ra[16] = {0}; uint16_t rp = 0; + const struct sockaddr_storage* sa = &lk->remote_addr; + if (sa->ss_family == AF_INET) { + rf = 4; memcpy(ra, &((const struct sockaddr_in*)sa)->sin_addr, 4); rp = ntohs(((const struct sockaddr_in*)sa)->sin_port); + } else if (sa->ss_family == AF_INET6) { + rf = 6; memcpy(ra, &((const struct sockaddr_in6*)sa)->sin6_addr, 16); rp = ntohs(((const struct sockaddr_in6*)sa)->sin6_port); + } + *p++ = rf; memcpy(p, ra, 16); p += 16; memcpy(p, &rp, 2); p += 2; } - *p++ = family; - *p++ = addr_len; - memcpy(p, addr, 16); p += 16; - memcpy(p, &port, 2); p += 2; } *p++ = sock_count; @@ -414,7 +425,7 @@ static void collect_member_detail(uint64_t node_id) { memcpy(p, &lc, 4); p += 4; memcpy(p, ifname, 38); p += 38; } - for (struct TCP_SOCKET* ts = inst->tcp_sockets; ts && sock_count; ts = ts->next, sock_count--) { + for (struct ETCP_SOCKET* ts = inst->tcp_sockets; ts && sock_count; ts = ts->next, sock_count--) { uint32_t sid = ts->sock_id; uint16_t sp = 0; const struct sockaddr_storage* sa = ts->interface_addr.ss_family ? &ts->interface_addr : &ts->local_addr; diff --git a/src/routing_layer/topo_node.c b/src/routing_layer/topo_node.c index 891286ca..563f447c 100644 --- a/src/routing_layer/topo_node.c +++ b/src/routing_layer/topo_node.c @@ -683,7 +683,7 @@ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GR else if (e_sock->local_addr.ss_family == AF_INET6) { sock6_count++; addr6_count++; } e_sock = e_sock->next; } - { struct TCP_SOCKET* ts = instance->tcp_sockets; + { struct ETCP_SOCKET* ts = instance->tcp_sockets; while (ts) { if (ts->type == CFG_SERVER_TYPE_PRIVATE || ts->type == CFG_SERVER_TYPE_LOCAL) { ts = ts->next; continue; } if (ts->interface_addr.ss_family == AF_INET || ts->local_addr.ss_family == AF_INET) { tcp4_count++; addr_count++; } else if (ts->interface_addr.ss_family == AF_INET6 || ts->local_addr.ss_family == AF_INET6) { tcp6_count++; addr6_count++; } @@ -800,7 +800,7 @@ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GR } e_sock = e_sock->next; } - { struct TCP_SOCKET* ts = instance->tcp_sockets; + { struct ETCP_SOCKET* ts = instance->tcp_sockets; int tcp_iter_cnt = 0; while (ts) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "TOPO_UPD_SELF: tcp_iter[%d] ts=%p type=%d fam=%d next=%p", tcp_iter_cnt, (void*)ts, ts->type, ts->local_addr.ss_family, (void*)ts->next); @@ -907,7 +907,7 @@ void topo_node_update_my_addresses(struct UTUN_INSTANCE* instance) { } e_sock = e_sock->next; } - { struct TCP_SOCKET* ts = instance->tcp_sockets; + { struct ETCP_SOCKET* ts = instance->tcp_sockets; while (ts) { if (ts->type == CFG_SERVER_TYPE_PRIVATE || ts->type == CFG_SERVER_TYPE_LOCAL) { ts = ts->next; continue; } struct sockaddr_storage* addr = ts->interface_addr.ss_family ? &ts->interface_addr : &ts->local_addr; if (!addr || !addr->ss_family) { ts = ts->next; continue; } diff --git a/src/transport_layer/auto_socket.c b/src/transport_layer/auto_socket.c index 3c2ba8eb..64934973 100644 --- a/src/transport_layer/auto_socket.c +++ b/src/transport_layer/auto_socket.c @@ -282,19 +282,6 @@ static struct stcp_server* create_iface_tcp_socket(struct AUTO_SOCKET* as, uint3 for (int attempt = 0; attempt < max_att; attempt++) { uint16_t port = (attempt == 0 && saved_port) ? saved_port : random_port(); - struct stcp_server* tsrv = stcp_server_listen(&scfg, port, tcp_server_on_link, inst); - if (!tsrv) { - if (attempt == 0 && saved_port) - DEBUG_WARN(DEBUG_CATEGORY_AS, "[as] TCP reuse port failed if=%s fam=%d port=%u — trying random", ifname, family, port); - else - DEBUG_WARN(DEBUG_CATEGORY_AS, "[as] TCP socket create failed if=%s fam=%d port=%u att=%d err=%d", - ifname, family, port, attempt + 1, socket_get_error()); - if (socket_get_error() != EADDRINUSE) return NULL; - continue; - } - - stcp_server_list_add(inst, tsrv); - struct CFG_SERVER server; memset(&server, 0, sizeof(server)); snprintf(server.name, sizeof(server.name), "as_%s_%s_tcp", ifname, family == AF_INET6 ? "v6" : "v4"); @@ -303,27 +290,37 @@ static struct stcp_server* create_iface_tcp_socket(struct AUTO_SOCKET* as, uint3 server.transport = 1; if (family == AF_INET) { struct sockaddr_in* sin = (struct sockaddr_in*)&server.ip; - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = INADDR_ANY; - sin->sin_port = htons(port); + sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; sin->sin_port = htons(port); } else { struct sockaddr_in6* sin6 = (struct sockaddr_in6*)&server.ip; - sin6->sin6_family = AF_INET6; - sin6->sin6_addr = in6addr_any; - sin6->sin6_port = htons(port); + sin6->sin6_family = AF_INET6; sin6->sin6_addr = in6addr_any; sin6->sin6_port = htons(port); } - struct TCP_SOCKET* ts = tcp_socket_add(inst, &server); - { const struct sockaddr_storage* ia = (ts && ts->interface_addr.ss_family) ? &ts->interface_addr : &ts->local_addr; - if (!ts || (ia->ss_family == AF_INET && ((struct sockaddr_in*)ia)->sin_addr.s_addr == INADDR_ANY) || - (ia->ss_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6*)ia)->sin6_addr))) { + struct ETCP_SOCKET* ts = tcp_socket_add(inst, &server); + if (!ts) { DEBUG_WARN(DEBUG_CATEGORY_AS, "[as] TCP tcp_socket_add failed if=%s fam=%d port=%u", ifname, family, port); continue; } + + { const struct sockaddr_storage* ia = (ts->interface_addr.ss_family) ? &ts->interface_addr : &ts->local_addr; + if ((ia->ss_family == AF_INET && ((const struct sockaddr_in*)ia)->sin_addr.s_addr == INADDR_ANY) || + (ia->ss_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&((const struct sockaddr_in6*)ia)->sin6_addr))) { DEBUG_INFO(DEBUG_CATEGORY_AS, "[as] TCP socket %s has null addr — removing", server.name); - if (ts) tcp_socket_remove(ts); - stcp_server_list_remove(inst, tsrv); - stcp_link_server_destroy(tsrv); continue; + tcp_socket_remove(ts); continue; } } + struct stcp_server* tsrv = stcp_server_listen(&scfg, port, tcp_server_on_link, ts); + if (!tsrv) { + if (attempt == 0 && saved_port) + DEBUG_WARN(DEBUG_CATEGORY_AS, "[as] TCP reuse port failed if=%s fam=%d port=%u — trying random", ifname, family, port); + else + DEBUG_WARN(DEBUG_CATEGORY_AS, "[as] TCP socket create failed if=%s fam=%d port=%u att=%d err=%d", + ifname, family, port, attempt + 1, socket_get_error()); + tcp_socket_remove(ts); + if (socket_get_error() != EADDRINUSE) return NULL; + continue; + } + + stcp_server_list_add(inst, tsrv); + save_port_to_db(as, ifname, family, AS_PROTO_TCP, port); DEBUG_INFO(DEBUG_CATEGORY_AS, "[as] TCP socket created: if=%s(%u) type=%d port=%u", ifname, ifindex, type, port); @@ -413,12 +410,12 @@ static void remove_iface_sockets(struct AUTO_SOCKET* as, uint32_t ifindex) { if (ifa->v4_tcp) { DEBUG_INFO(DEBUG_CATEGORY_AS, "[as] removing v4 TCP socket ifidx=%u", ifindex); { uint16_t v4_port = load_port_from_db(as, ifname, AF_INET, AS_PROTO_TCP); - struct TCP_SOCKET** tsp = &as->instance->tcp_sockets; + struct ETCP_SOCKET** tsp = &as->instance->tcp_sockets; while (*tsp) { uint16_t tsp_port = 0; const struct sockaddr_storage* addr = (*tsp)->interface_addr.ss_family ? &(*tsp)->interface_addr : &(*tsp)->local_addr; if (addr->ss_family == AF_INET) tsp_port = ntohs(((struct sockaddr_in*)addr)->sin_port); - if (tsp_port == v4_port && v4_port > 0) { struct TCP_SOCKET* rm = *tsp; *tsp = rm->next; u_free(rm); break; } + if (tsp_port == v4_port && v4_port > 0) { struct ETCP_SOCKET* rm = *tsp; *tsp = rm->next; u_free(rm); break; } tsp = &(*tsp)->next; } } @@ -429,12 +426,12 @@ static void remove_iface_sockets(struct AUTO_SOCKET* as, uint32_t ifindex) { if (ifa->v6_tcp) { DEBUG_INFO(DEBUG_CATEGORY_AS, "[as] removing v6 TCP socket ifidx=%u", ifindex); { uint16_t v6_port = load_port_from_db(as, ifname, AF_INET6, AS_PROTO_TCP); - struct TCP_SOCKET** tsp = &as->instance->tcp_sockets; + struct ETCP_SOCKET** tsp = &as->instance->tcp_sockets; while (*tsp) { uint16_t tsp_port = 0; const struct sockaddr_storage* addr = (*tsp)->interface_addr.ss_family ? &(*tsp)->interface_addr : &(*tsp)->local_addr; if (addr->ss_family == AF_INET6) tsp_port = ntohs(((struct sockaddr_in6*)addr)->sin6_port); - if (tsp_port == v6_port && v6_port > 0) { struct TCP_SOCKET* rm = *tsp; *tsp = rm->next; u_free(rm); break; } + if (tsp_port == v6_port && v6_port > 0) { struct ETCP_SOCKET* rm = *tsp; *tsp = rm->next; u_free(rm); break; } tsp = &(*tsp)->next; } } @@ -711,10 +708,10 @@ static void reconcile_iface(struct AUTO_SOCKET* as, uint32_t ifindex, const char DEBUG_INFO(DEBUG_CATEGORY_AS, "[as] v4 TCP removed: %s ifidx=%u", ifname, ifindex); { char buf[IFNAMSIZ]; const char* nm = if_indextoname(ifindex, buf) ? buf : ifname; uint16_t p = load_port_from_db(as, nm, AF_INET, AS_PROTO_TCP); - struct TCP_SOCKET** tsp = &as->instance->tcp_sockets; + struct ETCP_SOCKET** tsp = &as->instance->tcp_sockets; while (*tsp) { uint16_t tp = 0; const struct sockaddr_storage* a = (*tsp)->interface_addr.ss_family ? &(*tsp)->interface_addr : &(*tsp)->local_addr; if (a->ss_family == AF_INET) tp = ntohs(((struct sockaddr_in*)a)->sin_port); - if (tp == p && p > 0) { struct TCP_SOCKET* rm = *tsp; *tsp = rm->next; u_free(rm); break; } tsp = &(*tsp)->next; } + if (tp == p && p > 0) { struct ETCP_SOCKET* rm = *tsp; *tsp = rm->next; u_free(rm); break; } tsp = &(*tsp)->next; } } stcp_server_list_remove(as->instance, srv); stcp_link_server_destroy(srv); @@ -734,10 +731,10 @@ static void reconcile_iface(struct AUTO_SOCKET* as, uint32_t ifindex, const char DEBUG_INFO(DEBUG_CATEGORY_AS, "[as] v6 TCP removed: %s ifidx=%u", ifname, ifindex); { char buf[IFNAMSIZ]; const char* nm = if_indextoname(ifindex, buf) ? buf : ifname; uint16_t p = load_port_from_db(as, nm, AF_INET6, AS_PROTO_TCP); - struct TCP_SOCKET** tsp = &as->instance->tcp_sockets; + struct ETCP_SOCKET** tsp = &as->instance->tcp_sockets; while (*tsp) { uint16_t tp = 0; const struct sockaddr_storage* a = (*tsp)->interface_addr.ss_family ? &(*tsp)->interface_addr : &(*tsp)->local_addr; if (a->ss_family == AF_INET6) tp = ntohs(((struct sockaddr_in6*)a)->sin6_port); - if (tp == p && p > 0) { struct TCP_SOCKET* rm = *tsp; *tsp = rm->next; u_free(rm); break; } tsp = &(*tsp)->next; } + if (tp == p && p > 0) { struct ETCP_SOCKET* rm = *tsp; *tsp = rm->next; u_free(rm); break; } tsp = &(*tsp)->next; } } stcp_server_list_remove(as->instance, srv); stcp_link_server_destroy(srv); diff --git a/src/transport_layer/etcp_connections.c b/src/transport_layer/etcp_connections.c index 359b9781..e723bea8 100644 --- a/src/transport_layer/etcp_connections.c +++ b/src/transport_layer/etcp_connections.c @@ -44,8 +44,8 @@ static void tcp_link_close_cb(struct stcp_link *sl, int err, void *arg); void etcp_link_enter_ready_tcp(struct ETCP_LINK *link); // TCP server: on new incoming connection → create ETCP_LINK + enter ready -void tcp_server_on_link(struct stcp_link *link, void *arg) { - struct UTUN_INSTANCE *inst = (struct UTUN_INSTANCE *)arg; +void tcp_server_on_link(struct stcp_link *link, struct ETCP_SOCKET *tcp_sock) { + struct UTUN_INSTANCE *inst = tcp_sock->instance; const uint8_t *pubkey = stcp_link_get_peer_pubkey(link); if (!pubkey) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: no peer pubkey"); return; } uint64_t node_id = sc_derive_node_id_from_pubkey(pubkey); @@ -86,9 +86,9 @@ void tcp_server_on_link(struct stcp_link *link, void *arg) { DEBUG_INFO(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: new ETCP_CONN peer=0x%016llx", (unsigned long long)node_id); } - struct ETCP_LINK *tlink = etcp_link_new(conn, NULL, NULL, 1); + const struct sockaddr_storage* ra = stcp_link_get_remote_addr(link); + struct ETCP_LINK *tlink = etcp_link_new(conn, tcp_sock, ra, 1); if (!tlink) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: etcp_link_new failed"); return; } - tlink->is_tcp = 1; tlink->tcp_link = link; tlink->is_server = 1; @@ -848,12 +848,14 @@ void etcp_socket_remove(struct ETCP_SOCKET* conn) { /* ── TCP socket management ── */ -struct TCP_SOCKET* tcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SERVER* server) { +struct ETCP_SOCKET* tcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SERVER* server) { if (!instance || !server) return NULL; - struct TCP_SOCKET* ts = u_calloc(1, sizeof(struct TCP_SOCKET)); + struct ETCP_SOCKET* ts = u_calloc(1, sizeof(struct ETCP_SOCKET)); if (!ts) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "tcp_socket_add: alloc failed"); return NULL; } ts->instance = instance; + ts->is_tcp = 1; + ts->fd = SOCKET_INVALID; ts->type = server->type; if (server->name && server->name[0]) { strncpy(ts->name, server->name, MAX_CONN_NAME_LEN - 1); @@ -933,10 +935,10 @@ struct TCP_SOCKET* tcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SER return ts; } -void tcp_socket_remove(struct TCP_SOCKET* sock) { +void tcp_socket_remove(struct ETCP_SOCKET* sock) { if (!sock || !sock->instance) return; struct UTUN_INSTANCE* inst = sock->instance; - struct TCP_SOCKET** pp = &inst->tcp_sockets; + struct ETCP_SOCKET** pp = &inst->tcp_sockets; while (*pp && *pp != sock) pp = &(*pp)->next; if (*pp) *pp = sock->next; DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "tcp_socket_remove: %s sock_id=%u", sock->name, sock->sock_id); @@ -947,7 +949,7 @@ struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn DEBUG_TRACE(DEBUG_CATEGORY_CONNECTION, ""); if (!etcp) { DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "null etcp"); return NULL; } if (etcp->state == 2) { DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "[%s] link_new on deleted conn", etcp->log_name); return NULL; } - int is_tcp = (conn == NULL); + int is_tcp = (conn == NULL) || conn->is_tcp; struct ETCP_LINK* link = u_calloc(1, sizeof(struct ETCP_LINK)); if (!link) { @@ -2428,15 +2430,19 @@ int init_sockets(struct UTUN_INSTANCE* instance) { uint16_t port = 0; if (server->ip.ss_family == AF_INET) port = ntohs(((struct sockaddr_in*)&server->ip)->sin_port); else if (server->ip.ss_family == AF_INET6) port = ntohs(((struct sockaddr_in6*)&server->ip)->sin6_port); + + struct ETCP_SOCKET* ts = tcp_socket_add(instance, server); + if (!ts) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "tcp_socket_add failed for %s", server->name); fail_count++; server = server->next; continue; } + struct stcp_link_config scfg = {.ua = instance->ua, .my_keys = &instance->my_keys, .inst = instance, .listen_family = server->ip.ss_family}; - struct stcp_server *tsrv = stcp_server_listen(&scfg, port, tcp_server_on_link, instance); + struct stcp_server *tsrv = stcp_server_listen(&scfg, port, tcp_server_on_link, ts); if (!tsrv) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create TCP server for %s", server->name); + tcp_socket_remove(ts); fail_count++; } else { stcp_server_list_add(instance, tsrv); - tcp_socket_add(instance, server); success_count++; DEBUG_INFO(DEBUG_CATEGORY_ETCP, "TCP server %s on port %u", server->name, port); } diff --git a/src/transport_layer/etcp_connections.h b/src/transport_layer/etcp_connections.h index 44708053..9cf4480d 100644 --- a/src/transport_layer/etcp_connections.h +++ b/src/transport_layer/etcp_connections.h @@ -132,25 +132,29 @@ struct link_queue_entry { struct ETCP_SOCKET { struct ETCP_SOCKET* next; // Linked list для всех соединений struct UTUN_INSTANCE* instance; - char name[MAX_CONN_NAME_LEN]; // Socket name from config (e.g., "lan1" from [server: lan1]) - socket_t fd; // UDP socket (cross-platform) - struct sockaddr_storage local_addr; // Локальный адрес - int mtu; // MTU для этого сокета - - int errorcode; - size_t pkt_format_errors; - - void* socket_id; // Socket ID from uasync_add_socket - uint8_t type; // CFG_SERVER_TYPE_PUBLIC/NAT/PRIVATE - uint8_t sock_id; // unique socket id (0-255) for NAT matching - uint8_t nat_type; // NAT_TYPE_* (detected by server) - uint32_t local_defaultroute_ip; // auto-detected IPv4 for public servers (network byte order) - uint8_t local_defaultroute_ip6[16]; // auto-detected IPv6 for public servers - uint8_t only_local; // 1 = only local connections, no forwarding - uint32_t netif_index; // индекс интерфейса для sin6_scope_id (0 = не задан) - struct sockaddr_storage interface_addr; // адрес интерфейса: если bind на интерфейс - его IP, если 0.0.0.0 без интерфейса - IP интерфейса через который идет default route, иначе - адрес из конфига - struct sockaddr_storage nat_addr; // NAT адрес (network byte order), ss_family=0 = не определён - struct ll_queue* links_queue; // хеш-очередь линков, ключ = link_queue_entry.key (19 байт) + char name[MAX_CONN_NAME_LEN]; + socket_t fd; // UDP socket / TCP listen socket + int mtu; + + uint8_t type; // CFG_SERVER_TYPE_* + uint8_t sock_id; // unique id (0-255) for NAT matching + uint8_t is_tcp; // 1=TCP (STCP), 0=UDP + uint8_t only_local; // 1 = only local, no forwarding (UDP) + uint32_t netif_index; // для sin6_scope_id + struct sockaddr_storage local_addr; + struct sockaddr_storage interface_addr; + struct sockaddr_storage nat_addr; + + /* ── uasync handle (UDP read_cb / TCP accept_cb) ── */ + void* socket_id; + + /* ── UDP-only ── */ + struct ll_queue* links_queue; // hash-очередь линков + int errorcode; + size_t pkt_format_errors; + uint8_t nat_type; // NAT_TYPE_* + uint32_t local_defaultroute_ip; // auto-detected IPv4 (network byte order) + uint8_t local_defaultroute_ip6[16]; }; // NAT check status @@ -326,23 +330,12 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_S // удаляет сокет и освобождает ресурсы (грохает все его подключения и сокет) void etcp_socket_remove(struct ETCP_SOCKET* conn); -// TCP socket descriptor (analogous to ETCP_SOCKET for UDP) -struct TCP_SOCKET { - struct TCP_SOCKET* next; - struct UTUN_INSTANCE* instance; - char name[MAX_CONN_NAME_LEN]; - uint8_t sock_id; - uint8_t type; // CFG_SERVER_TYPE_* - struct sockaddr_storage local_addr; - struct sockaddr_storage interface_addr; - struct sockaddr_storage nat_addr; -}; - -struct TCP_SOCKET* tcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SERVER* server); -void tcp_socket_remove(struct TCP_SOCKET* sock); +// TCP socket functions (uses unified ETCP_SOCKET with is_tcp=1) +struct ETCP_SOCKET* tcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SERVER* server); +void tcp_socket_remove(struct ETCP_SOCKET* sock); struct stcp_link; -void tcp_server_on_link(struct stcp_link *link, void *arg); +void tcp_server_on_link(struct stcp_link *link, struct ETCP_SOCKET *tcp_sock); // connection functions // создает новый канал связи для etcp подключения (ETCP_CONN) diff --git a/src/transport_layer/stcp_link.c b/src/transport_layer/stcp_link.c index c4d888dc..834eb13a 100644 --- a/src/transport_layer/stcp_link.c +++ b/src/transport_layer/stcp_link.c @@ -20,7 +20,7 @@ struct stcp_server { struct stcp_server *srv; // stcp_server from stcp_server.h struct stcp_link_config cfg; stcp_server_on_link_cb on_link; - void *on_link_arg; + struct ETCP_SOCKET *tcp_sock; }; struct stcp_link { @@ -128,7 +128,7 @@ static void server_accept_cb(struct stcp_conn *conn, void *arg) { stcp_conn_set_tx_queue(conn, link->tx_queue); DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_link: server accepted connection"); - if (ss->on_link) ss->on_link(link, ss->on_link_arg); + if (ss->on_link) ss->on_link(link, ss->tcp_sock); } // ====== client connect → link ====== @@ -161,13 +161,13 @@ static void client_ready_cb(struct stcp_conn *conn, void *arg) { // ====== API ====== struct stcp_server *stcp_server_listen(struct stcp_link_config *cfg, uint16_t port, - stcp_server_on_link_cb on_link, void *arg) { + stcp_server_on_link_cb on_link, struct ETCP_SOCKET *tcp_sock) { if (!cfg || !cfg->ua || !cfg->my_keys) return NULL; struct stcp_server *ss = u_calloc(1, sizeof(struct stcp_server)); if (!ss) return NULL; ss->cfg = *cfg; ss->on_link = on_link; - ss->on_link_arg = arg; + ss->tcp_sock = tcp_sock; ss->srv = stcp_server_create(cfg->ua, port, cfg->my_keys, cfg->inst ? cfg->inst->my_ed25519_pubkey : NULL, cfg->inst, server_accept_cb, ss, NULL, NULL, cfg->listen_family); if (!ss->srv) { u_free(ss); return NULL; } DEBUG_INFO(DEBUG_CATEGORY_ETCP, "port=%u", port); diff --git a/src/transport_layer/stcp_link.h b/src/transport_layer/stcp_link.h index f2de1dad..bcf9a561 100644 --- a/src/transport_layer/stcp_link.h +++ b/src/transport_layer/stcp_link.h @@ -16,6 +16,7 @@ struct stcp_link; // opaque struct stcp_server; // opaque struct ETCP_CONN; struct ETCP_LINK; +struct ETCP_SOCKET; struct UTUN_INSTANCE; // ====== Link config ====== @@ -35,10 +36,10 @@ struct stcp_link_config { // ====== TCP server ====== -typedef void (*stcp_server_on_link_cb)(struct stcp_link *link, void *arg); +typedef void (*stcp_server_on_link_cb)(struct stcp_link *link, struct ETCP_SOCKET *tcp_sock); struct stcp_server *stcp_server_listen(struct stcp_link_config *cfg, uint16_t port, - stcp_server_on_link_cb on_link, void *arg); + stcp_server_on_link_cb on_link, struct ETCP_SOCKET *tcp_sock); void stcp_link_server_destroy(struct stcp_server *srv); /* Server list management (multiple servers per instance) */ diff --git a/src/utun_instance.h b/src/utun_instance.h index 63f9df78..eeebc667 100644 --- a/src/utun_instance.h +++ b/src/utun_instance.h @@ -37,7 +37,6 @@ struct ROUTE_TABLE; struct ETCP_CONN; typedef void (*etcp_new_conn_fn)(struct ETCP_CONN* conn, void* arg); struct ETCP_SOCKET; -struct TCP_SOCKET; struct NODE_CONN_DIRECT; struct tun_if; struct ETCP_BINDINGS; @@ -136,8 +135,8 @@ struct UTUN_INSTANCE { struct memory_pool* ack_pool; // Active sockets (UDP) - struct ETCP_SOCKET* etcp_sockets;// linked-list - struct TCP_SOCKET* tcp_sockets; // linked-list [TCP-only] + struct ETCP_SOCKET* etcp_sockets;// linked-list (UDP + TCP is_tcp=1) + struct ETCP_SOCKET* tcp_sockets; // linked-list (TCP, filtered by is_tcp=1) struct stcp_server *stcp_servers; // TCP servers linked list (via stcp_link.c) void* socket_monitor; // SOCKET_MONITOR* (opaque, transport_layer/socket_monitor.c) void* auto_socket_state; // AUTO_SOCKET* (opaque, transport_layer/auto_socket.c) diff --git a/tests/test_etcp_link_stress.c b/tests/test_etcp_link_stress.c index 5f993978..8d6e6c93 100644 --- a/tests/test_etcp_link_stress.c +++ b/tests/test_etcp_link_stress.c @@ -60,7 +60,7 @@ struct extra_info { int type; int port; struct ETCP_SOCKET* udp_sock; - struct TCP_SOCKET* tcp_sock; + struct ETCP_SOCKET* tcp_sock; struct stcp_server* tcp_srv; struct ETCP_LINK* client_link; uint64_t create_tb; @@ -293,11 +293,11 @@ static int add_tcp_pair(struct ETCP_CONN* conn) { cfg.type = CFG_SERVER_TYPE_PUBLIC; cfg.transport = 1; memcpy(&cfg.ip, &sin, sizeof(sin)); - struct TCP_SOCKET* ts = tcp_socket_add(server_instance, &cfg); + struct ETCP_SOCKET* ts = tcp_socket_add(server_instance, &cfg); if (!ts) { release_tcp_port(port); return -1; } struct stcp_link_config scfg = {.ua = ua, .my_keys = &server_instance->my_keys, .inst = server_instance, .listen_family = AF_INET}; - struct stcp_server* srv = stcp_server_listen(&scfg, port, tcp_server_on_link, server_instance); + struct stcp_server* srv = stcp_server_listen(&scfg, port, (stcp_server_on_link_cb)tcp_server_on_link, ts); if (!srv) { tcp_socket_remove(ts); release_tcp_port(port); return -1; } stcp_server_list_add(server_instance, srv); diff --git a/tests/test_invite_group_create.c b/tests/test_invite_group_create.c index 4c4e75a7..41dbdfd9 100644 --- a/tests/test_invite_group_create.c +++ b/tests/test_invite_group_create.c @@ -88,7 +88,7 @@ int main(void) { /* ── Add a TCP socket (simulating Android STCP server) ── */ { - struct TCP_SOCKET* ts = u_calloc(1, sizeof(*ts)); + struct ETCP_SOCKET* ts = u_calloc(1, sizeof(*ts)); ts->instance = a; ts->type = CFG_SERVER_TYPE_PUBLIC; ts->sock_id = (uint8_t)a->next_socket_id++; diff --git a/tests/test_stcp_link.c b/tests/test_stcp_link.c index ac7835ed..19779933 100644 --- a/tests/test_stcp_link.c +++ b/tests/test_stcp_link.c @@ -33,9 +33,9 @@ static void recv_cb(struct ll_queue *q, void *arg) { queue_resume_callback(q); } -static void on_srv_link(struct stcp_link *link, void *arg) { - struct stcp_link **out = (struct stcp_link **)arg; - *out = link; +static struct stcp_link *g_on_srv_link = NULL; +static void on_srv_link(struct stcp_link *link, struct ETCP_SOCKET *tcp_sock) { + (void)tcp_sock; g_on_srv_link = link; } static void on_cli_ready(struct stcp_link *link, void *arg) { @@ -48,8 +48,8 @@ static int test1_basic(void) { struct UASYNC *ua = uasync_create(); TASSERT(ua); struct stcp_link_config cfg = {.ua = ua, .my_keys = &s_keys, .inst = NULL}; - struct stcp_link *srv_link = NULL; - struct stcp_server *ss = stcp_server_listen(&cfg, BASE_PORT + 1, on_srv_link, &srv_link); + g_on_srv_link = NULL; + struct stcp_server *ss = stcp_server_listen(&cfg, BASE_PORT + 1, (stcp_server_on_link_cb)on_srv_link, NULL); TASSERT(ss); struct sockaddr_in raddr; memset(&raddr, 0, sizeof(raddr)); @@ -63,8 +63,8 @@ static int test1_basic(void) { stcp_link_set_on_ready(cli_link, on_cli_ready, &cli_ready); int ticks = 0; - while ((!srv_link || !cli_ready) && ticks < 5000) { uasync_poll(ua, 10); ticks++; } - TASSERT(srv_link != NULL); TASSERT(cli_ready); + while ((!g_on_srv_link || !cli_ready) && ticks < 5000) { uasync_poll(ua, 10); ticks++; } + TASSERT(g_on_srv_link != NULL); TASSERT(cli_ready); // Verify send works (no crash, data goes through TCP) const char *msg = "hello link!"; @@ -81,8 +81,8 @@ static int test2_wrong_key(void) { struct UASYNC *ua = uasync_create(); TASSERT(ua); struct stcp_link_config cfg = {.ua = ua, .my_keys = &s_keys, .inst = NULL}; - struct stcp_link *srv_link = NULL; - struct stcp_server *ss = stcp_server_listen(&cfg, BASE_PORT + 2, on_srv_link, &srv_link); + g_on_srv_link = NULL; + struct stcp_server *ss = stcp_server_listen(&cfg, BASE_PORT + 2, (stcp_server_on_link_cb)on_srv_link, NULL); TASSERT(ss); struct SC_MYKEYS rogue; TASSERT(sc_generate_keypair(&rogue) == SC_OK); @@ -95,8 +95,8 @@ static int test2_wrong_key(void) { struct stcp_link *cli_link = stcp_link_connect(&cli_cfg); TASSERT(cli_link); int ticks = 0; - while (!srv_link && ticks < 2000) { uasync_poll(ua, 10); ticks++; } - TASSERT(!srv_link); // should NOT connect with wrong key + while (!g_on_srv_link && ticks < 2000) { uasync_poll(ua, 10); ticks++; } + TASSERT(!g_on_srv_link); // should NOT connect with wrong key stcp_link_close(cli_link); stcp_link_server_destroy(ss); diff --git a/tools/chatgui-android/jni_bridge/android_jni_bridge.c b/tools/chatgui-android/jni_bridge/android_jni_bridge.c index 4d80736e..248b21d4 100644 --- a/tools/chatgui-android/jni_bridge/android_jni_bridge.c +++ b/tools/chatgui-android/jni_bridge/android_jni_bridge.c @@ -247,7 +247,7 @@ static int bridge_collect_invite_addrs(struct InviteAddrC* out, int max_cnt) { } s = s->next; } - { struct TCP_SOCKET* ts = g_cc.inst->tcp_sockets; + { struct ETCP_SOCKET* ts = g_cc.inst->tcp_sockets; while (ts) { struct sockaddr_storage* sa = ts->interface_addr.ss_family ? &ts->interface_addr : &ts->local_addr; if (sa && sa->ss_family == AF_INET && cnt < max_cnt) { @@ -1012,50 +1012,32 @@ char* utun_bridge_get_member_links_json(uint64_t node_id) { int first = 1; for (struct ETCP_LINK* lk = conn->links; lk; lk = lk->next) { if (pos >= (int)sizeof(buf) - 100) break; - const struct sockaddr_storage* sa = &lk->remote_addr; - char ip[INET6_ADDRSTRLEN] = ""; - int fm = 0; - uint16_t po = 0; - if (sa->ss_family == AF_INET) { - struct sockaddr_in* sin = (struct sockaddr_in*)sa; - inet_ntop(AF_INET, &sin->sin_addr, ip, sizeof(ip)); - fm = 4; po = ntohs(sin->sin_port); - } else if (sa->ss_family == AF_INET6) { - struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa; - inet_ntop(AF_INET6, &sin6->sin6_addr, ip, sizeof(ip)); - fm = 6; po = ntohs(sin6->sin6_port); - } else continue; + char la[INET6_ADDRSTRLEN] = ""; int lf = 0; uint16_t lp = 0; + if (lk->conn) { + const struct sockaddr_storage* lsa = &lk->conn->local_addr; + if (lsa->ss_family == AF_INET) { + inet_ntop(AF_INET, &((struct sockaddr_in*)lsa)->sin_addr, la, sizeof(la)); lf = 4; lp = ntohs(((struct sockaddr_in*)lsa)->sin_port); + } else if (lsa->ss_family == AF_INET6) { + inet_ntop(AF_INET6, &((struct sockaddr_in6*)lsa)->sin6_addr, la, sizeof(la)); lf = 6; lp = ntohs(((struct sockaddr_in6*)lsa)->sin6_port); + } + } + + char ra[INET6_ADDRSTRLEN] = ""; int rf = 0; uint16_t rp = 0; + int st = lk->link_state, ls = lk->link_status; + if (lk->is_tcp && lk->tcp_link && stcp_link_is_ready(lk->tcp_link)) { st = 3; ls = 1; } + const struct sockaddr_storage* rsa = &lk->remote_addr; + + if (rsa->ss_family == AF_INET) { + inet_ntop(AF_INET, &((struct sockaddr_in*)rsa)->sin_addr, ra, sizeof(ra)); rf = 4; rp = ntohs(((struct sockaddr_in*)rsa)->sin_port); + } else if (rsa->ss_family == AF_INET6) { + inet_ntop(AF_INET6, &((struct sockaddr_in6*)rsa)->sin6_addr, ra, sizeof(ra)); rf = 6; rp = ntohs(((struct sockaddr_in6*)rsa)->sin6_port); + } - if (!ip[0]) continue; - const char* sep = first ? "" : ","; first = 0; - pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, - "%s{\"fm\":%d,\"ad\":\"%s\",\"po\":%d,\"st\":%d,\"ls\":%d,\"is\":%d}", - sep, fm, ip, (int)po, lk->link_state, lk->link_status, lk->is_server); - } - for (struct ETCP_LINK* lk2 = conn->links; lk2; lk2 = lk2->next) { - if (!lk2->is_tcp || !lk2->tcp_link) continue; - if (pos >= (int)sizeof(buf) - 100) break; - struct stcp_link* tcp = lk2->tcp_link; - const struct sockaddr_storage* sa = stcp_link_get_remote_addr(tcp); - if (!sa) continue; - char ip[INET6_ADDRSTRLEN] = ""; - int fm = 0; uint16_t po = 0; - if (sa->ss_family == AF_INET) { - struct sockaddr_in* sin = (struct sockaddr_in*)sa; - inet_ntop(AF_INET, &sin->sin_addr, ip, sizeof(ip)); - fm = 4; po = ntohs(sin->sin_port); - } else if (sa->ss_family == AF_INET6) { - struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa; - inet_ntop(AF_INET6, &sin6->sin6_addr, ip, sizeof(ip)); - fm = 6; po = ntohs(sin6->sin6_port); - } else continue; - if (!ip[0]) continue; - int ready = stcp_link_is_ready(tcp); const char* sep = first ? "" : ","; first = 0; pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, - "%s{\"fm\":%d,\"ad\":\"%s\",\"po\":%d,\"st\":%d,\"ls\":%d,\"is\":%d}", - sep, fm, ip, (int)po, ready ? 3 : 1, ready ? 1 : 0, lk2->is_server); + "%s{\"lf\":%d,\"la\":\"%s\",\"lp\":%d,\"rf\":%d,\"ra\":\"%s\",\"rp\":%d,\"st\":%d,\"ls\":%d,\"is\":%d}", + sep, lf, la, (int)lp, rf, ra, (int)rp, st, ls, lk->is_server); } if (pos < (int)sizeof(buf)) pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, "]}"); @@ -1108,7 +1090,7 @@ char* utun_bridge_get_local_sockets_json(void) { bridge_log(BLEV_INFO, "getLocalSockets: tcp_sockets=%p etcp_sockets=%p conns=%d links=%d", (void*)inst->tcp_sockets, (void*)inst->etcp_sockets, active_conns, active_links); /* TCP sockets */ - { struct TCP_SOCKET* ts = inst->tcp_sockets; + { struct ETCP_SOCKET* ts = inst->tcp_sockets; while (ts) { char ip_str[INET6_ADDRSTRLEN] = ""; int port = 0; const struct sockaddr_storage* addr = ts->interface_addr.ss_family ? &ts->interface_addr : &ts->local_addr; diff --git a/tools/chatgui/src/accountlist.cpp b/tools/chatgui/src/accountlist.cpp index de604755..26c8165e 100644 --- a/tools/chatgui/src/accountlist.cpp +++ b/tools/chatgui/src/accountlist.cpp @@ -258,10 +258,12 @@ void AccountList::onMemberDetailData(uint64_t nodeId, const uint8_t* data, int l lk.linkStatus = p[2]; lk.tcpReady = p[3] != 0; lk.isServer = p[4] != 0; - lk.family = p[5]; - int addrLen = p[6]; - lk.addr = QByteArray((const char*)p + 7, qMin(addrLen, 16)); - memcpy(&lk.port, p + 23, 2); + lk.localFamily = p[5]; + lk.localAddr = QByteArray((const char*)p + 6, 16); + memcpy(&lk.localPort, p + 22, 2); + lk.family = p[24]; + lk.addr = QByteArray((const char*)p + 25, 16); + memcpy(&lk.port, p + 41, 2); p += MEMBER_DETAIL_LINK_SIZE; m_snapLinks.append(lk); } @@ -314,65 +316,40 @@ void AccountList::updateDetailDisplay() { bool isSelf = m_db ? (m_detailNodeId == m_db->myNodeId()) : false; - for (const auto& a : m_detailAddrs) { - QString proto; - switch (a.protocol) { case 1: proto = "UDP"; break; case 2: proto = "TCP"; break; default: proto = "UDP/TCP"; break; } - QString linkColor = "#9E9E9E"; QString scRole; - if (m_snapConnPresent) { - for (const auto& lk : m_snapLinks) { - if (lk.family == a.family && lk.port == a.port - && lk.addr == a.addr) { - linkColor = (lk.linkState == 3 && lk.linkStatus == 1) ? "#4CAF50" : "#E53935"; - scRole = lk.isServer ? " S" : " C"; - break; - } - } - if (linkColor == "#9E9E9E" && a.protocol == 2) { - for (const auto& lk : m_snapLinks) { - if (lk.isTcp && lk.tcpReady) { linkColor = "#4CAF50"; scRole = lk.isServer ? " S" : " C"; break; } - } - } + if (isSelf) { + for (const auto& a : m_detailAddrs) { + QString proto; + switch (a.protocol) { case 1: proto = "UDP"; break; case 2: proto = "TCP"; break; default: proto = "UDP/TCP"; break; } + int lc = 0; + if (a.protocol == 1) { for (const auto& s : m_snapSocks) { if (s.port == a.port) { lc = s.linkCount; break; } } } + else if (a.protocol == 2) lc = m_snapOwnTcpActive; + QString prefix = lc > 0 ? QString("[%1] ").arg(lc) : ""; + if (!a.ifname.isEmpty()) + lines.append(QString("%1● %2 %3").arg(prefix, proto, a.ifname)); + else + lines.append(QString("%1● %2:%3:%4").arg(prefix, proto, addrStr(a.addr.constData(), a.family)).arg(a.port)); } - - QString prefix; - if (isSelf) { - int linkCount = 0; - if (a.protocol == 1) { - for (const auto& s : m_snapSocks) { - if (s.port == a.port) { linkCount = s.linkCount; break; } - } - } else if (a.protocol == 2) { - linkCount = m_snapOwnTcpActive; - } - if (linkCount > 0) prefix = QString("[%1] ").arg(linkCount); - } - - if (!a.ifname.isEmpty()) { - lines.append(QString("%1● %3%4 %5") - .arg(prefix, linkColor, proto, scRole, a.ifname)); - lines.append(QString("  %1:%2") - .arg(addrStr(a.addr.constData(), a.family)).arg(a.port)); - } else { - lines.append(QString("%1● %3%4:%5:%6") - .arg(prefix, linkColor, proto, scRole, addrStr(a.addr.constData(), a.family)).arg(a.port)); + } else { + /* all live links with arrows */ + for (const auto& lk : m_snapLinks) { + QString proto = lk.isTcp ? "TCP" : "UDP"; + QString lc = (lk.linkState == 3 && lk.linkStatus == 1) ? "#4CAF50" : "#E53935"; + QString left = QString("%1:%2").arg(addrStr(lk.localAddr.constData(), lk.localFamily)).arg(lk.localPort); + QString right = QString("%1:%2").arg(addrStr(lk.addr.constData(), lk.family)).arg(lk.port); + lines.append(QString("● %2 %3 → %4") + .arg(lc, proto, left, right)); } - } - - /* Show snapshot links that are not in DB (non-self) */ - if (m_snapConnPresent && m_snapLinks.size() > 0) { - for (int li = 0; li < m_snapLinks.size(); li++) { - const auto& lk = m_snapLinks[li]; + /* DB addresses without live link */ + for (const auto& a : m_detailAddrs) { bool matched = false; - for (const auto& a : m_detailAddrs) { - if (lk.family == a.family && lk.port == a.port - && lk.addr == a.addr) { matched = true; break; } + for (const auto& lk : m_snapLinks) { + if (lk.family == a.family && lk.port == a.port && lk.addr == a.addr) { matched = true; break; } } if (matched) continue; - QString proto = lk.isTcp ? "TCP" : "UDP"; - QString sc = lk.isServer ? " S" : " C"; - QString lc = (lk.linkState == 3 && lk.linkStatus == 1) ? "#4CAF50" : "#E53935"; - lines.append(QString("● %2%3:%4:%5 [link]") - .arg(lc, proto, sc, addrStr(lk.addr.constData(), lk.family)).arg(lk.port)); + QString proto; + switch (a.protocol) { case 1: proto = "UDP"; break; case 2: proto = "TCP"; break; default: proto = "UDP/TCP"; break; } + lines.append(QString("● %1 %2:%3") + .arg(proto, addrStr(a.addr.constData(), a.family)).arg(a.port)); } } diff --git a/tools/chatgui/src/accountlist.h b/tools/chatgui/src/accountlist.h index 302a7fce..4ffa15e1 100644 --- a/tools/chatgui/src/accountlist.h +++ b/tools/chatgui/src/accountlist.h @@ -27,6 +27,9 @@ struct MemberLinkSnap { int linkStatus; bool tcpReady; bool isServer; + int localFamily; + QByteArray localAddr; + uint16_t localPort; int family; QByteArray addr; uint16_t port; diff --git a/tools/chatgui/transport/gui_bridge.h b/tools/chatgui/transport/gui_bridge.h index 8aaf45c4..b18cb4d7 100644 --- a/tools/chatgui/transport/gui_bridge.h +++ b/tools/chatgui/transport/gui_bridge.h @@ -36,7 +36,7 @@ struct TOPO_GROUP_NODE; #define GUI_EVT_MEMBER_REMOVED 25 /* data: [ch_id_len:1][ch_id:var][node_id:8] — мембер удалён из канала */ /* Размеры элементов пакета GUI_EVT_MEMBER_DETAIL (должны совпадать с chat_status.c) */ -#define MEMBER_DETAIL_LINK_SIZE 25 +#define MEMBER_DETAIL_LINK_SIZE 43 #define MEMBER_DETAIL_SOCK_SIZE 48 #define MEMBER_DETAIL_MAX_LINKS 16 #define MEMBER_DETAIL_MAX_SOCKS 16 diff --git a/tools/chatgui/transport/utun_node.cpp b/tools/chatgui/transport/utun_node.cpp index b1bd0a83..fc1735ee 100644 --- a/tools/chatgui/transport/utun_node.cpp +++ b/tools/chatgui/transport/utun_node.cpp @@ -217,7 +217,7 @@ QList UtunNode::getInviteAddresses(DbManager* db) { /* 3) TCP from local TCP sockets */ { - struct TCP_SOCKET* ts = m_instance->tcp_sockets; + struct ETCP_SOCKET* ts = m_instance->tcp_sockets; while (ts) { struct sockaddr_storage* sa = &ts->interface_addr; if (sa->ss_family == AF_INET) {