android: member list screen + link status dots, ipv6 autoconnect fixes
Android chatgui: - New MemberListScreen with member list, detail card, edit dialog - Link status dots (green/red/grey) per address in detail card (1s poll) - Self-node name coloured green - ChatScreen: people icon in TopAppBar IPv6 autoconnect fixes (3 bugs in conn_mgr/topo): - topo_node_sqlite_node_load: load v6 addresses from DB - topo_node_registry_store: merge v6_addrs into existing node - cm_sock_v6_classify: wildcard [::] treated as CM_V6_DIR - cm_add_v6_link: htons(port) was missing Memory fixes: - strdup→u_strdup in bridge (7 instances) - u_realloc cap update before success check (3 instances) - char sql[256]→[512] for truncated SELECT Chat member hash now includes addresses for change detection Linux chatgui: - Link status dots in AccountList detail panel (1s poll) - Self-node name in green in member list
This commit is contained in:
1 parent
6719a1e23c
commit
50156e12af
19 files changed
+1022
-23
No files matched your search
+25
-1
@@ -126,8 +126,32 @@ static int _member_update_bucket_hash(void* ctx, const char* ns, uint8_t level,
|
||||
const char* atags = (const char*)sqlite3_column_text(stmt, 7);
|
||||
const uint8_t* atsig = (const uint8_t*)sqlite3_column_blob(stmt, 8);
|
||||
if (!x25 || !ed) continue;
|
||||
|
||||
uint8_t addrs[2048]; int addr_off = 0; int addr_count = 0;
|
||||
sqlite3_stmt* as = NULL;
|
||||
sqlite3_prepare_v2(db,
|
||||
"SELECT family, socket_id, address, port FROM node_addresses WHERE node_id=? AND addr_type=0"
|
||||
" ORDER BY family, address, port", -1, &as, NULL);
|
||||
if (as) {
|
||||
sqlite3_bind_int64(as, 1, (sqlite3_int64)nid);
|
||||
while (sqlite3_step(as) == SQLITE_ROW && addr_off < (int)sizeof(addrs) - 8) {
|
||||
int fam = sqlite3_column_int(as, 0);
|
||||
int sid = sqlite3_column_int(as, 1);
|
||||
addrs[addr_off++] = (uint8_t)fam;
|
||||
addrs[addr_off++] = (uint8_t)sid;
|
||||
int ip_sz = fam == 4 ? 4 : 16;
|
||||
memcpy(addrs + addr_off, sqlite3_column_blob(as, 2), (size_t)ip_sz);
|
||||
addr_off += ip_sz;
|
||||
uint16_t p = (uint16_t)sqlite3_column_int(as, 3);
|
||||
addrs[addr_off++] = (uint8_t)(p >> 8);
|
||||
addrs[addr_off++] = (uint8_t)(p & 0xFF);
|
||||
addr_count++;
|
||||
}
|
||||
sqlite3_finalize(as);
|
||||
}
|
||||
|
||||
uint8_t mh[MT_HASH_SIZE];
|
||||
_compute_member_hash(nid, x25, ed, sig, jts, usig, uts, NULL, 0, atags, atsig, mh);
|
||||
_compute_member_hash(nid, x25, ed, sig, jts, usig, uts, addrs, addr_count, atags, atsig, mh);
|
||||
EVP_DigestUpdate(sha_ctx, mh, MT_HASH_SIZE);
|
||||
count++;
|
||||
}
|
||||
|
||||
@@ -94,7 +94,10 @@ uint8_t cm_classify_v6_addr(const uint8_t addr[16]) {
|
||||
|
||||
uint8_t cm_sock_v6_classify(const struct ETCP_SOCKET* s) {
|
||||
if (s->local_addr.ss_family != AF_INET6) return CM_V6_OTH;
|
||||
return cm_classify_v6_addr(((const struct sockaddr_in6*)&s->local_addr)->sin6_addr.s6_addr);
|
||||
const uint8_t* a6 = ((const struct sockaddr_in6*)&s->local_addr)->sin6_addr.s6_addr;
|
||||
static const uint8_t z[16];
|
||||
if (!memcmp(a6, z, 16)) return CM_V6_DIR;
|
||||
return cm_classify_v6_addr(a6);
|
||||
}
|
||||
|
||||
void cm_add_v4_link(struct ETCP_CONN* conn, const uint8_t* addr, uint16_t port, struct ETCP_SOCKET* s) {
|
||||
@@ -106,7 +109,7 @@ void cm_add_v4_link(struct ETCP_CONN* conn, const uint8_t* addr, uint16_t port,
|
||||
|
||||
void cm_add_v6_link(struct ETCP_CONN* conn, const uint8_t addr[16], uint16_t port, struct ETCP_SOCKET* s) {
|
||||
struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6;
|
||||
memcpy(&sin6.sin6_addr, addr, 16); sin6.sin6_port = port;
|
||||
memcpy(&sin6.sin6_addr, addr, 16); sin6.sin6_port = htons(port);
|
||||
if (cm_classify_v6_addr(addr) == CM_V6_LL) { struct sockaddr_in6* our = (struct sockaddr_in6*)&s->local_addr; sin6.sin6_scope_id = our->sin6_scope_id; }
|
||||
struct sockaddr_storage sa; memcpy(&sa, &sin6, sizeof(sin6));
|
||||
etcp_link_new(conn, s, &sa, 0);
|
||||
|
||||
@@ -107,6 +107,8 @@ struct TOPO_NODE* topo_node_registry_store(struct TOPO_GROUPS* groups, struct TO
|
||||
struct TOPO_NODE* existing = topo_node_registry_find(groups, ni->node_id);
|
||||
if (existing) {
|
||||
topo_node_ref(existing);
|
||||
if (!existing->v4_addrs && ni->v4_addrs) { existing->v4_addrs = ni->v4_addrs; ni->v4_addrs = NULL; }
|
||||
if (!existing->v6_addrs && ni->v6_addrs) { existing->v6_addrs = ni->v6_addrs; ni->v6_addrs = NULL; }
|
||||
topo_node_free_raw(groups, ni);
|
||||
return existing;
|
||||
}
|
||||
|
||||
@@ -154,17 +154,17 @@ int topo_node_sqlite_node_put(sqlite3* db, struct TOPO_GROUPS* groups, struct TO
|
||||
|
||||
/* delete stale addresses for socket_ids no longer present */
|
||||
{
|
||||
char del_sql[256];
|
||||
char del_sql[512];
|
||||
if (sock_count > 0) {
|
||||
int pos = snprintf(del_sql, sizeof(del_sql),
|
||||
"DELETE FROM node_addresses WHERE node_id=? AND socket_id NOT IN (");
|
||||
"DELETE FROM node_addresses WHERE node_id=? AND addr_type!=0 AND socket_id NOT IN (");
|
||||
for (uint8_t i = 0; i < sock_count; i++) {
|
||||
if (i > 0) pos += snprintf(del_sql + pos, sizeof(del_sql) - (size_t)pos, ",");
|
||||
pos += snprintf(del_sql + pos, sizeof(del_sql) - (size_t)pos, "%d", (int)sock_ids[i]);
|
||||
}
|
||||
pos += snprintf(del_sql + pos, sizeof(del_sql) - (size_t)pos, ") AND socket_id != 0");
|
||||
} else {
|
||||
snprintf(del_sql, sizeof(del_sql), "DELETE FROM node_addresses WHERE node_id=? AND socket_id != 0");
|
||||
snprintf(del_sql, sizeof(del_sql), "DELETE FROM node_addresses WHERE node_id=? AND addr_type!=0 AND socket_id != 0");
|
||||
}
|
||||
sqlite3_stmt* del_stmt = NULL;
|
||||
if (sqlite3_prepare_v2(db, del_sql, -1, &del_stmt, NULL) == SQLITE_OK) {
|
||||
@@ -757,7 +757,35 @@ struct TOPO_NODE* topo_node_sqlite_node_load(sqlite3* db, struct TOPO_GROUPS* gr
|
||||
sqlite3_finalize(s);
|
||||
}
|
||||
}
|
||||
if (!v4_head) { u_free(name); DEBUG_ERROR(DEBUG_CATEGORY_BGP, "node_load: node 0x%016llx has no IPv4/UDP addresses", (unsigned long long)node_id); return NULL; }
|
||||
/* IPv6 addresses */
|
||||
struct TOPO_ADDR6* v6_head = NULL; struct TOPO_ADDR6* v6_tail = NULL;
|
||||
{
|
||||
sqlite3_stmt* s = NULL;
|
||||
if (sqlite3_prepare_v2(db,
|
||||
"SELECT address,port,addr_type,socket_id FROM node_addresses"
|
||||
" WHERE node_id=? AND family=6 AND protocol=1 ORDER BY addr_type",
|
||||
-1, &s, NULL) == SQLITE_OK) {
|
||||
sqlite3_bind_int64(s, 1, (sqlite3_int64)node_id);
|
||||
while (sqlite3_step(s) == SQLITE_ROW) {
|
||||
const void* addr = sqlite3_column_blob(s, 0);
|
||||
if (!addr || sqlite3_column_bytes(s, 0) < 16) continue;
|
||||
int port = sqlite3_column_int(s, 1);
|
||||
int at = sqlite3_column_int(s, 2);
|
||||
int sock_id_raw = sqlite3_column_int(s, 3);
|
||||
uint8_t sock_id = (uint8_t)(sock_id_raw ? sock_id_raw : ++sock_id_counter);
|
||||
uint8_t type = (at == ADDR_TYPE_NETIF) ? TOPO_ADDR_INTERFACE : TOPO_ADDR_NAT;
|
||||
struct TOPO_ADDR6* a6 = memory_pool_alloc(groups->v6_addr_pool);
|
||||
if (!a6) continue;
|
||||
memset(a6, 0, sizeof(*a6));
|
||||
memcpy(a6->addr, addr, 16); a6->port = (uint16_t)port;
|
||||
a6->type = type; a6->socket_id = sock_id; a6->protocol = TOPO_PROTO_UDP;
|
||||
if (!v6_head) v6_head = v6_tail = a6;
|
||||
else { v6_tail->next = a6; v6_tail = a6; }
|
||||
}
|
||||
sqlite3_finalize(s);
|
||||
}
|
||||
}
|
||||
if (!v4_head && !v6_head) { u_free(name); DEBUG_ERROR(DEBUG_CATEGORY_BGP, "node_load: node 0x%016llx has no addresses", (unsigned long long)node_id); return NULL; }
|
||||
|
||||
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE));
|
||||
if (!ni) { u_free(name); return NULL; }
|
||||
@@ -765,9 +793,12 @@ struct TOPO_NODE* topo_node_sqlite_node_load(sqlite3* db, struct TOPO_GROUPS* gr
|
||||
memcpy(ni->public_key, pubkey, 32); memcpy(ni->ed25519_public_key, ed_pubkey, 32);
|
||||
ni->node_name = name;
|
||||
ni->v4_addrs = v4_head;
|
||||
ni->v6_addrs = v6_head;
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "node_load: node 0x%016llx loaded from DB name=%s v4_addrs=%d",
|
||||
(unsigned long long)node_id, name ? name : "", topo_list_count((struct _topo_head*)v4_head));
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "node_load: node 0x%016llx loaded from DB name=%s v4=%d v6=%d",
|
||||
(unsigned long long)node_id, name ? name : "",
|
||||
topo_list_count((struct _topo_head*)v4_head),
|
||||
topo_list_count((struct _topo_head*)v6_head));
|
||||
return ni;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user