mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 05:25:20 +00:00
patches: wifi aware mesh refactor core (#549)
* Refactor WifiAware memory management and lifecycle handling * Fix Wi-Fi Aware reconnection by ensuring callback unregistration and session watchdog * fix(wifiaware): allow WifiAwareController to restart service if session drops * Enhance WiFi Aware logging with network request timeouts and detailed callback status * Ensure explicit release of WiFi Aware network callbacks on failure or disconnection --------- Co-authored-by: aidenvalue <>
This commit is contained in:
co-authored by
aidenvalue <>
parent
ee4b2610f9
commit
3a1589972b
@@ -227,6 +227,7 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
||||
override fun onPublishStarted(pub: PublishDiscoverySession) {
|
||||
publishSession = pub
|
||||
Log.d(TAG, "PUBLISH: onPublishStarted()")
|
||||
try { com.bitchat.android.ui.debug.DebugSettingsManager.getInstance().addDebugMessage(com.bitchat.android.ui.debug.DebugMessage.SystemMessage("Wi-Fi Aware Publish Started")) } catch (_: Exception) {}
|
||||
}
|
||||
override fun onServiceDiscovered(
|
||||
peerHandle: PeerHandle,
|
||||
@@ -235,7 +236,10 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
||||
) {
|
||||
val peerId = try { String(serviceSpecificInfo) } catch (_: Exception) { "" }
|
||||
handleToPeerId[peerHandle] = peerId
|
||||
if (peerId.isNotBlank()) discoveredTimestamps[peerId] = System.currentTimeMillis()
|
||||
if (peerId.isNotBlank()) {
|
||||
discoveredTimestamps[peerId] = System.currentTimeMillis()
|
||||
Log.i(TAG, "PUBLISH: Discovered subscriber '$peerId' via Aware")
|
||||
}
|
||||
Log.d(TAG, "PUBLISH: onServiceDiscovered ssi='${peerId.take(16)}' len=${serviceSpecificInfo.size}")
|
||||
}
|
||||
|
||||
@@ -250,9 +254,19 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
||||
|
||||
handleToPeerId[peerHandle] = subscriberId
|
||||
if (subscriberId.isNotBlank()) discoveredTimestamps[subscriberId] = System.currentTimeMillis()
|
||||
Log.d(TAG, "PUBLISH: got ping from $subscriberId; spinning up server")
|
||||
Log.i(TAG, "PUBLISH: Received discovery ping from subscriber '$subscriberId'")
|
||||
handleSubscriberPing(publishSession!!, peerHandle)
|
||||
}
|
||||
|
||||
override fun onSessionTerminated() {
|
||||
Log.e(TAG, "PUBLISH: onSessionTerminated()")
|
||||
publishSession = null
|
||||
if (isActive) {
|
||||
Log.i(TAG, "PUBLISH: Attempting to restart publish session...")
|
||||
// Delay and check if we need to restart services entirely
|
||||
serviceScope.launch { delay(2000); if (isActive) startServices() }
|
||||
}
|
||||
}
|
||||
},
|
||||
Handler(Looper.getMainLooper())
|
||||
)
|
||||
@@ -266,6 +280,7 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
||||
override fun onSubscribeStarted(sub: SubscribeDiscoverySession) {
|
||||
subscribeSession = sub
|
||||
Log.d(TAG, "SUBSCRIBE: onSubscribeStarted()")
|
||||
try { com.bitchat.android.ui.debug.DebugSettingsManager.getInstance().addDebugMessage(com.bitchat.android.ui.debug.DebugMessage.SystemMessage("Wi-Fi Aware Subscribe Started")) } catch (_: Exception) {}
|
||||
}
|
||||
override fun onServiceDiscovered(
|
||||
peerHandle: PeerHandle,
|
||||
@@ -289,9 +304,18 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
||||
val peerId = handleToPeerId[peerHandle] ?: return
|
||||
if (peerId == myPeerID) return
|
||||
|
||||
Log.d(TAG, "SUBSCRIBE: onMessageReceived() → server-ready from ${peerId.take(8)} payload=${message.size}B")
|
||||
Log.d(TAG, "SUBSCRIBE: onMessageReceived() \u2192 server-ready from ${peerId.take(8)} payload=${message.size}B")
|
||||
handleServerReady(peerHandle, message)
|
||||
}
|
||||
|
||||
override fun onSessionTerminated() {
|
||||
Log.e(TAG, "SUBSCRIBE: onSessionTerminated()")
|
||||
subscribeSession = null
|
||||
if (isActive) {
|
||||
Log.i(TAG, "SUBSCRIBE: Attempting to restart subscribe session...")
|
||||
serviceScope.launch { delay(2000); if (isActive) startServices() }
|
||||
}
|
||||
}
|
||||
},
|
||||
Handler(Looper.getMainLooper())
|
||||
)
|
||||
@@ -299,6 +323,13 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
||||
override fun onAttachFailed() {
|
||||
Log.e(TAG, "Wi-Fi Aware attach failed")
|
||||
}
|
||||
|
||||
override fun onAwareSessionTerminated() {
|
||||
Log.e(TAG, "Aware Session Terminated unexpectedly")
|
||||
wifiAwareSession = null
|
||||
isActive = false
|
||||
if (com.bitchat.android.wifiaware.WifiAwareController.enabled.value) { serviceScope.launch { delay(3000); com.bitchat.android.wifiaware.WifiAwareController.startIfPossible() } }
|
||||
}
|
||||
}, Handler(Looper.getMainLooper()))
|
||||
|
||||
meshCore.startCore()
|
||||
@@ -366,7 +397,7 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
||||
for (peerId in disconnectedPeers) {
|
||||
// Find the PeerHandle for this peerId
|
||||
val handle = handleToPeerId.entries.find { it.value == peerId }?.key ?: continue
|
||||
|
||||
|
||||
// Check tracker policy
|
||||
if (!connectionTracker.isConnectionAttemptAllowed(peerId)) continue
|
||||
|
||||
@@ -407,14 +438,14 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
||||
return
|
||||
}
|
||||
|
||||
val ss = ServerSocket(0)
|
||||
connectionTracker.addServerSocket(peerId, ss)
|
||||
val port = ss.localPort
|
||||
|
||||
// Ensure port is set to reuse if connection was recently closed (TIME_WAIT)
|
||||
val ss = ServerSocket()
|
||||
try {
|
||||
ss.reuseAddress = true
|
||||
} catch (_: Exception) {}
|
||||
ss.bind(java.net.InetSocketAddress(0))
|
||||
} catch (e: Exception) { Log.e(TAG, "Failed to bind server socket", e) }
|
||||
|
||||
connectionTracker.addServerSocket(peerId, ss)
|
||||
val port = ss.localPort
|
||||
|
||||
Log.d(TAG, "SERVER: listening for ${peerId.take(8)} on port $port")
|
||||
|
||||
@@ -431,20 +462,23 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
||||
|
||||
val cb = object : ConnectivityManager.NetworkCallback() {
|
||||
override fun onAvailable(network: Network) {
|
||||
Log.i(TAG, "SERVER: onAvailable() - Aware network is ready for ${peerId.take(8)}")
|
||||
try {
|
||||
val client = ss.accept()
|
||||
Log.i(TAG, "SERVER: Accepted raw TCP connection from ${peerId.take(8)}")
|
||||
try { network.bindSocket(client) } catch (e: Exception) { Log.w(TAG, "Server bindSocket EPERM: ${e.message}") }
|
||||
client.keepAlive = true
|
||||
Log.d(TAG, "SERVER: accepted TCP from ${peerId.take(8)} addr=${client.inetAddress?.hostAddress}")
|
||||
Log.i(TAG, "SERVER: Bound and established TCP with ${peerId.take(8)} addr=${client.inetAddress?.hostAddress}")
|
||||
connectionTracker.onClientConnected(peerId, client)
|
||||
try { meshCore.setDirectConnection(peerId, true) } catch (_: Exception) {}
|
||||
try { meshCore.addOrUpdatePeer(peerId, peerId) } catch (_: Exception) {}
|
||||
listenerExec.execute { listenToPeer(client, peerId) }
|
||||
handleSubscriberKeepAlive(client, peerId, pubSession, peerHandle)
|
||||
|
||||
// Kick off Noise handshake for this logical peer
|
||||
if (myPeerID < peerId) {
|
||||
meshCore.initiateNoiseHandshake(peerId)
|
||||
Log.d(TAG, "SERVER: initiating Noise handshake to ${peerId.take(8)} (lower ID)")
|
||||
Log.i(TAG, "SERVER: Initiating Noise handshake to ${peerId.take(8)}")
|
||||
}
|
||||
// Ensure fast presence even before handshake settles
|
||||
serviceScope.launch { delay(150); sendBroadcastAnnounce() }
|
||||
@@ -452,15 +486,27 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
||||
Log.e(TAG, "SERVER: accept failed for ${peerId.take(8)}", ioe)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUnavailable() {
|
||||
Log.e(TAG, "SERVER: onUnavailable() - Failed to acquire Aware network for ${peerId.take(8)} (timeout or refused)")
|
||||
handleNetworkFailure(peerId)
|
||||
}
|
||||
|
||||
override fun onLost(network: Network) {
|
||||
connectionTracker.networkCallbacks.remove(peerId)
|
||||
Log.d(TAG, "SERVER: network lost for ${peerId.take(8)}")
|
||||
handlePeerDisconnection(peerId)
|
||||
Log.i(TAG, "SERVER: WiFi Aware network lost for ${peerId.take(8)}")
|
||||
}
|
||||
}
|
||||
|
||||
connectionTracker.addNetworkCallback(peerId, cb)
|
||||
Log.d(TAG, "SERVER: requesting Aware network for ${peerId.take(8)}")
|
||||
cm.requestNetwork(req, cb)
|
||||
Log.i(TAG, "SERVER: [Calling requestNetwork] for ${peerId.take(8)} with port $port")
|
||||
try {
|
||||
// use requestNetwork with a timeout to trigger onUnavailable if it fails
|
||||
cm.requestNetwork(req, cb, 30_000)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "SERVER: ConnectivityManager.requestNetwork threw exception", e)
|
||||
connectionTracker.disconnect(peerId)
|
||||
}
|
||||
|
||||
val readyId = (System.nanoTime() and 0x7fffffff).toInt()
|
||||
val portBytes = ByteBuffer.allocate(4)
|
||||
@@ -530,7 +576,7 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
||||
}
|
||||
|
||||
val port = ByteBuffer.wrap(payload).order(ByteOrder.BIG_ENDIAN).int
|
||||
Log.d(TAG, "CLIENT: connecting to ${peerId.take(8)} port=$port")
|
||||
Log.i(TAG, "CLIENT: Received server-ready from ${peerId.take(8)} on port $port. Requesting network...")
|
||||
|
||||
val spec = WifiAwareNetworkSpecifier.Builder(subscribeSession!!, peerHandle)
|
||||
.setPskPassphrase(PSK)
|
||||
@@ -542,12 +588,19 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
||||
|
||||
val cb = object : ConnectivityManager.NetworkCallback() {
|
||||
override fun onAvailable(network: Network) {
|
||||
Log.i(TAG, "CLIENT: onAvailable() - Aware network is ready for ${peerId.take(8)}")
|
||||
// Do not bind process for Aware; use per-socket binding instead
|
||||
}
|
||||
|
||||
override fun onUnavailable() {
|
||||
Log.e(TAG, "CLIENT: onUnavailable() - Failed to acquire Aware network for ${peerId.take(8)}")
|
||||
handleNetworkFailure(peerId)
|
||||
}
|
||||
|
||||
override fun onCapabilitiesChanged(network: Network, nc: NetworkCapabilities) {
|
||||
if (connectionTracker.peerSockets.containsKey(peerId)) return
|
||||
val info = (nc.transportInfo as? WifiAwareNetworkInfo) ?: return
|
||||
val addr = info.peerIpv6Addr as? Inet6Address ?: return
|
||||
Log.i(TAG, "CLIENT: onCapabilitiesChanged() - Peer IPv6 discovered: $addr")
|
||||
|
||||
val lp = cm.getLinkProperties(network)
|
||||
val iface = lp?.interfaceName
|
||||
@@ -570,17 +623,18 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
||||
}
|
||||
|
||||
sock.connect(java.net.InetSocketAddress(scopedAddr, port), 7000)
|
||||
Log.d(TAG, "CLIENT: TCP connected to ${peerId.take(8)} addr=$scopedAddr:$port (iface=$iface)")
|
||||
Log.i(TAG, "CLIENT: TCP connected to ${peerId.take(8)} at $scopedAddr:$port")
|
||||
|
||||
connectionTracker.onClientConnected(peerId, sock)
|
||||
try { meshCore.setDirectConnection(peerId, true) } catch (_: Exception) {}
|
||||
try { meshCore.addOrUpdatePeer(peerId, peerId) } catch (_: Exception) {}
|
||||
listenerExec.execute { listenToPeer(sock, peerId) }
|
||||
handleServerKeepAlive(sock, peerId, peerHandle)
|
||||
|
||||
// Kick off Noise handshake for this logical peer
|
||||
if (myPeerID < peerId) {
|
||||
meshCore.initiateNoiseHandshake(peerId)
|
||||
Log.d(TAG, "CLIENT: initiating Noise handshake to ${peerId.take(8)} (lower ID)")
|
||||
Log.i(TAG, "CLIENT: Initiating Noise handshake to ${peerId.take(8)}")
|
||||
}
|
||||
// Ensure fast presence even before handshake settles
|
||||
serviceScope.launch { delay(150); sendBroadcastAnnounce() }
|
||||
@@ -589,14 +643,19 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
||||
}
|
||||
}
|
||||
override fun onLost(network: Network) {
|
||||
connectionTracker.networkCallbacks.remove(peerId)
|
||||
Log.d(TAG, "CLIENT: network lost for ${peerId.take(8)}")
|
||||
handlePeerDisconnection(peerId)
|
||||
Log.i(TAG, "CLIENT: WiFi Aware network lost for ${peerId.take(8)}")
|
||||
}
|
||||
}
|
||||
|
||||
connectionTracker.addNetworkCallback(peerId, cb)
|
||||
Log.d(TAG, "CLIENT: requesting Aware network for ${peerId.take(8)}")
|
||||
cm.requestNetwork(req, cb)
|
||||
Log.i(TAG, "CLIENT: [Calling requestNetwork] for ${peerId.take(8)}")
|
||||
try {
|
||||
cm.requestNetwork(req, cb, 30_000)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "CLIENT: ConnectivityManager.requestNetwork threw exception", e)
|
||||
connectionTracker.disconnect(peerId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -673,6 +732,15 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
||||
socket.closeQuietly()
|
||||
}
|
||||
|
||||
private fun handleNetworkFailure(peerId: String) {
|
||||
serviceScope.launch {
|
||||
Log.d(TAG, "Network failure cleanup for: $peerId")
|
||||
// Specifically release the callback if it didn't happen automatically
|
||||
connectionTracker.releaseNetworkRequest(peerId)
|
||||
meshCore.removePeer(peerId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handlePeerDisconnection(initialId: String) {
|
||||
serviceScope.launch {
|
||||
Log.d(TAG, "Cleaning up peer: $initialId")
|
||||
|
||||
Reference in New Issue
Block a user