fix(android): preserve measured profiles in member address details

This commit is contained in:
evgeny committed 2026-10-17 23:20:55 +02:00
1 parent 3f7cfe1c86
commit cb8e654639
3 files changed
+38 -20

No files matched your search

+12
View File
@@ -75,7 +75,19 @@ static int check_addresses(const char *channel) {
REQUIRE(!extract(json, "$.adr[1].pt", value, sizeof(value)) && !strcmp(value, "TCP"));
REQUIRE(!extract(json, "$.adr[1].po", value, sizeof(value)) && !strcmp(value, "443"));
REQUIRE(!extract(json, "$.adr[1].si", value, sizeof(value)) && !strcmp(value, "6"));
REQUIRE(!extract(json, "$.adr[0].nmapping", value, sizeof(value)) && !strcmp(value, "0"));
REQUIRE(!extract(json, "$.adr[0].nsource", value, sizeof(value)) && !strcmp(value, "0"));
u_free(json);
/* addr_type=0 остаётся тем же, но измеренный UNCHANGED должен дойти до GUI отдельно. */
meta4.address_profile = (struct address_profile){ADDRESS_MAP_UNCHANGED, ADDRESS_IN_UNKNOWN, ADDRESS_SOURCE_ETCP};
REQUIRE(!topo_node_sqlite_addrs_put(instance->topo_sqlite_db, instance->node_id, &node));
json = utun_bridge_get_member_detail_json(channel, instance->node_id);
REQUIRE(json && !extract(json, "$.adr[0].at", value, sizeof(value)) && !strcmp(value, "0"));
REQUIRE(!extract(json, "$.adr[0].nmapping", value, sizeof(value)) && !strcmp(value, "1"));
REQUIRE(!extract(json, "$.adr[0].ninbound", value, sizeof(value)) && !strcmp(value, "0"));
REQUIRE(!extract(json, "$.adr[0].nsource", value, sizeof(value)) && !strcmp(value, "1"));
u_free(json);
meta4.address_profile.mapping = ADDRESS_MAP_UNKNOWN;
addr4.type = TOPO_ADDR_NAT; meta4.address_profile.source = ADDRESS_SOURCE_ETCP;
REQUIRE(!topo_node_sqlite_addrs_put(instance->topo_sqlite_db, instance->node_id, &node));
json = utun_bridge_get_member_detail_json(channel, instance->node_id);
@@ -99,13 +99,22 @@ data class MemberDetail(val nodeId: Long, val name: String = "",
val inviterId: Long? = null, val inviterName: String = "")
data class MemberAddr(val family: Int = 0, val protocol: String = "", val address: String = "",
val port: Int = 0, val socketId: Int = 0, val addrType: Int = 0, val rtt: Int = 0) {
val roleLabelRes: Int get() = when (addrType) {
0 -> R.string.address_local; 1 -> R.string.address_public
2 -> R.string.address_nat_eim; 3 -> R.string.address_nat_dependent
4 -> R.string.address_nat_unknown; 6 -> R.string.address_nat_eim_unverified
5 -> R.string.address_contact; else -> R.string.address_unknown
}
val port: Int = 0, val socketId: Int = 0, val addrType: Int = 0, val rtt: Int = 0,
val natMapping: Int = 0, val natInbound: Int = 0, val natSource: Int = 0) {
val natLabelRes: Int get() = natProfileLabelRes(natMapping, natInbound, natSource)
}
// Происхождение адреса не определяет NAT: результат берём из измеренного профиля сокета.
private fun natProfileLabelRes(mapping: Int, inbound: Int, source: Int): Int = when {
source == 0 -> R.string.socket_nat_unmeasured
mapping == 1 && inbound == 1 -> R.string.socket_no_nat_open
mapping == 1 && inbound == 2 -> R.string.socket_no_nat_filtered
mapping == 1 -> R.string.socket_no_nat
mapping == 2 && inbound == 1 -> R.string.socket_eim_open
mapping == 2 && inbound == 2 -> R.string.socket_eim_filtered
mapping == 2 -> R.string.address_nat_eim_unverified
mapping == 3 -> R.string.address_nat_dependent
else -> R.string.address_nat_unknown
}
data class LinkStatus(val linkId: Int = 0, val localFamily: Int = 0, val localAddr: String = "", val localPort: Int = 0,
@@ -127,15 +136,7 @@ data class LocalSocketState(
val natMapping: Int = 0, val natInbound: Int = 0, val natSource: Int = 0,
val externalIp: String = "", val externalPort: Int = 0
) {
val natLabelRes: Int get() = when {
natSource == 0 -> R.string.socket_nat_unmeasured
natMapping == 1 -> R.string.socket_no_nat
natMapping == 2 && natInbound == 1 -> R.string.socket_eim_open
natMapping == 2 && natInbound == 2 -> R.string.socket_eim_filtered
natMapping == 2 -> R.string.address_nat_eim_unverified
natMapping == 3 -> R.string.address_nat_dependent
else -> R.string.address_nat_unknown
}
val natLabelRes: Int get() = natProfileLabelRes(natMapping, natInbound, natSource)
val stateLabel: String get() = AppLanguage.text(when (state) {
2 -> R.string.connection_up; 1 -> R.string.connection_connecting; else -> R.string.connection_down
})
@@ -488,7 +489,10 @@ class ChatRepository {
port = a.optInt("po", 0),
socketId = a.optInt("si", 0),
addrType = a.optInt("at", 0),
rtt = a.optInt("rt", 0)
rtt = a.optInt("rt", 0),
natMapping = a.getInt("nmapping"),
natInbound = a.getInt("ninbound"),
natSource = a.getInt("nsource")
))
}
}
@@ -885,7 +885,7 @@ char* utun_bridge_get_member_detail_json(const char* channel_id, uint64_t node_i
if (member_detail_append(buf, sizeof(buf), &pos, ",\"adr\":[") < 0) return u_strdup("{}");
if (sqlite3_prepare_v2(db,
"SELECT family, protocol, address, port, socket_id, addr_type, COALESCE(rtt,0)"
"SELECT family, protocol, address, port, socket_id, addr_type, COALESCE(rtt,0), nat_mapping, nat_inbound, nat_source"
" FROM node_addresses WHERE node_id=? ORDER BY socket_id, addr_type, family, port",
-1, &st, NULL) == SQLITE_OK) {
sqlite3_bind_int64(st, 1, (sqlite3_int64)node_id);
@@ -914,8 +914,10 @@ char* utun_bridge_get_member_detail_json(const char* channel_id, uint64_t node_i
if (proto & 0x04) pn = "TCP+REALITY";
else switch (proto) { case 1: pn = "UDP"; break; case 2: pn = "TCP"; break; default: pn = "UDP/TCP"; break; }
if (member_detail_append(buf, sizeof(buf), &pos,
"%s{\"fm\":%d,\"pt\":\"%s\",\"ad\":\"%s\",\"po\":%d,\"si\":%d,\"at\":%d,\"rt\":%d}",
af ? "" : ",", family, pn, addr_str[0] ? addr_str : "?", port, sid, at, rtt) < 0) {
"%s{\"fm\":%d,\"pt\":\"%s\",\"ad\":\"%s\",\"po\":%d,\"si\":%d,\"at\":%d,\"rt\":%d,"
"\"nmapping\":%d,\"ninbound\":%d,\"nsource\":%d}",
af ? "" : ",", family, pn, addr_str[0] ? addr_str : "?", port, sid, at, rtt,
sqlite3_column_int(st, 7), sqlite3_column_int(st, 8), sqlite3_column_int(st, 9)) < 0) {
sqlite3_finalize(st); return u_strdup("{}");
}
af = 0;