Improvements to connection publishing for sync.

This commit is contained in:
Koen J 2025-06-05 10:31:13 +02:00
commit 4d170db5e0
3 changed files with 46 additions and 23 deletions

View file

@ -339,6 +339,33 @@ fun ByteArray.fromGzip(): ByteArray {
return outputStream.toByteArray() return outputStream.toByteArray()
} }
fun findCandidateAddresses(): List<InetAddress> {
val candidates = NetworkInterface.getNetworkInterfaces()
.toList()
.asSequence()
.filter(::isUsableInterface)
.flatMap { nif ->
nif.interfaceAddresses
.asSequence()
.mapNotNull { ia ->
ia.address.takeIf(::isUsableAddress)?.let { addr ->
nif to ia
}
}
}
.toList()
return candidates
.sortedWith(
compareBy<Pair<NetworkInterface, InterfaceAddress>>(
{ addressScore(it.second.address) },
{ interfaceScore(it.first) },
{ -it.second.networkPrefixLength.toInt() },
{ -it.first.mtu }
)
).map { it.second.address }
}
fun findPreferredAddress(): InetAddress? { fun findPreferredAddress(): InetAddress? {
val candidates = NetworkInterface.getNetworkInterfaces() val candidates = NetworkInterface.getNetworkInterfaces()
.toList() .toList()

View file

@ -328,7 +328,7 @@ class SyncService(
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
synchronized(_mdnsCache) { synchronized(_mdnsCache) {
for ((pkey, info) in _mdnsCache) { for ((pkey, info) in _mdnsCache) {
if (!database.isAuthorized(pkey) || isConnected(pkey)) continue if (!database.isAuthorized(pkey) || getLinkType(pkey) == LinkType.Direct) continue
val last = synchronized(_lastConnectTimesMdns) { val last = synchronized(_lastConnectTimesMdns) {
_lastConnectTimesMdns[pkey] ?: 0L _lastConnectTimesMdns[pkey] ?: 0L
@ -360,8 +360,8 @@ class SyncService(
while (_started) { while (_started) {
val authorizedDevices = database.getAllAuthorizedDevices() ?: arrayOf() val authorizedDevices = database.getAllAuthorizedDevices() ?: arrayOf()
val addressesToConnect = authorizedDevices.mapNotNull { val addressesToConnect = authorizedDevices.mapNotNull {
val connected = isConnected(it) val connectedDirectly = getLinkType(it) == LinkType.Direct
if (connected) { if (connectedDirectly) {
return@mapNotNull null return@mapNotNull null
} }
@ -468,8 +468,13 @@ class SyncService(
while (_started && !socketClosed) { while (_started && !socketClosed) {
val unconnectedAuthorizedDevices = val unconnectedAuthorizedDevices =
database.getAllAuthorizedDevices() database.getAllAuthorizedDevices()
?.filter { !isConnected(it) }?.toTypedArray() ?.filter {
?: arrayOf() if (Settings.instance.synchronization.connectLocalDirectThroughRelay) {
getLinkType(it) != LinkType.Direct
} else {
!isConnected(it)
}
}?.toTypedArray() ?: arrayOf()
relaySession.publishConnectionInformation( relaySession.publishConnectionInformation(
unconnectedAuthorizedDevices, unconnectedAuthorizedDevices,
settings.listenerPort, settings.listenerPort,
@ -497,7 +502,7 @@ class SyncService(
val potentialLocalAddresses = val potentialLocalAddresses =
connectionInfo.ipv4Addresses connectionInfo.ipv4Addresses
.filter { it != connectionInfo.remoteIp } .filter { it != connectionInfo.remoteIp }
if (connectionInfo.allowLocalDirect && Settings.instance.synchronization.connectLocalDirectThroughRelay) { if (getLinkType(targetKey) != LinkType.Direct && connectionInfo.allowLocalDirect && Settings.instance.synchronization.connectLocalDirectThroughRelay) {
Thread { Thread {
try { try {
Log.v( Log.v(
@ -529,7 +534,7 @@ class SyncService(
// TODO: Implement hole punching if needed // TODO: Implement hole punching if needed
} }
if (connectionInfo.allowRemoteRelayed && Settings.instance.synchronization.connectThroughRelay) { if (getLinkType(targetKey) == LinkType.None && connectionInfo.allowRemoteRelayed && Settings.instance.synchronization.connectThroughRelay) {
try { try {
Logger.v( Logger.v(
TAG, TAG,
@ -741,6 +746,7 @@ class SyncService(
) )
} }
fun getLinkType(publicKey: String): LinkType = synchronized(_sessions) { _sessions[publicKey]?.linkType ?: LinkType.None }
fun isConnected(publicKey: String): Boolean = synchronized(_sessions) { _sessions[publicKey]?.connected ?: false } fun isConnected(publicKey: String): Boolean = synchronized(_sessions) { _sessions[publicKey]?.connected ?: false }
fun isAuthorized(publicKey: String): Boolean = database.isAuthorized(publicKey) fun isAuthorized(publicKey: String): Boolean = database.isAuthorized(publicKey)
fun getSession(publicKey: String): SyncSession? = synchronized(_sessions) { _sessions[publicKey] } fun getSession(publicKey: String): SyncSession? = synchronized(_sessions) { _sessions[publicKey] }

View file

@ -2,6 +2,7 @@ package com.futo.platformplayer.sync.internal
import android.os.Build import android.os.Build
import com.futo.platformplayer.ensureNotMainThread import com.futo.platformplayer.ensureNotMainThread
import com.futo.platformplayer.findCandidateAddresses
import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.noise.protocol.CipherStatePair import com.futo.platformplayer.noise.protocol.CipherStatePair
import com.futo.platformplayer.noise.protocol.DHState import com.futo.platformplayer.noise.protocol.DHState
@ -1078,20 +1079,9 @@ class SyncSocketSession {
) { ) {
if (authorizedKeys.size > 255) throw IllegalArgumentException("Number of authorized keys exceeds 255") if (authorizedKeys.size > 255) throw IllegalArgumentException("Number of authorized keys exceeds 255")
val ipv4Addresses = mutableListOf<String>() val candidateAddresses = findCandidateAddresses()
val ipv6Addresses = mutableListOf<String>() val ipv4Addresses = candidateAddresses.filterIsInstance<Inet4Address>()
for (nic in NetworkInterface.getNetworkInterfaces()) { val ipv6Addresses = candidateAddresses.filterIsInstance<Inet6Address>()
if (nic.isUp) {
for (addr in nic.inetAddresses) {
if (!addr.isLoopbackAddress) {
when (addr) {
is Inet4Address -> ipv4Addresses.add(addr.hostAddress)
is Inet6Address -> ipv6Addresses.add(addr.hostAddress)
}
}
}
}
}
val deviceName = getDeviceName() val deviceName = getDeviceName()
val nameBytes = getLimitedUtf8Bytes(deviceName, 255) val nameBytes = getLimitedUtf8Bytes(deviceName, 255)
@ -1103,12 +1093,12 @@ class SyncSocketSession {
data.put(nameBytes) data.put(nameBytes)
data.put(ipv4Addresses.size.toByte()) data.put(ipv4Addresses.size.toByte())
for (addr in ipv4Addresses) { for (addr in ipv4Addresses) {
val addrBytes = InetAddress.getByName(addr).address val addrBytes = addr.address
data.put(addrBytes) data.put(addrBytes)
} }
data.put(ipv6Addresses.size.toByte()) data.put(ipv6Addresses.size.toByte())
for (addr in ipv6Addresses) { for (addr in ipv6Addresses) {
val addrBytes = InetAddress.getByName(addr).address val addrBytes = addr.address
data.put(addrBytes) data.put(addrBytes)
} }
data.put(if (allowLocalDirect) 1 else 0) data.put(if (allowLocalDirect) 1 else 0)