mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 11:05: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
@@ -511,6 +511,8 @@ class MainActivity : OrientationAwareActivity() {
|
|||||||
Log.d("MainActivity", "Location services enabled by user")
|
Log.d("MainActivity", "Location services enabled by user")
|
||||||
mainViewModel.updateLocationLoading(false)
|
mainViewModel.updateLocationLoading(false)
|
||||||
mainViewModel.updateLocationStatus(LocationStatus.ENABLED)
|
mainViewModel.updateLocationStatus(LocationStatus.ENABLED)
|
||||||
|
// Ensure Wi-Fi Aware starts now that location is enabled
|
||||||
|
com.bitchat.android.wifiaware.WifiAwareController.startIfPossible()
|
||||||
checkBatteryOptimizationAndProceed()
|
checkBatteryOptimizationAndProceed()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -780,6 +782,9 @@ class MainActivity : OrientationAwareActivity() {
|
|||||||
mainViewModel.updateLocationStatus(currentLocationStatus)
|
mainViewModel.updateLocationStatus(currentLocationStatus)
|
||||||
mainViewModel.updateOnboardingState(OnboardingState.LOCATION_CHECK)
|
mainViewModel.updateOnboardingState(OnboardingState.LOCATION_CHECK)
|
||||||
mainViewModel.updateLocationLoading(false)
|
mainViewModel.updateLocationLoading(false)
|
||||||
|
} else {
|
||||||
|
// If location is enabled, ensure Wi-Fi Aware starts if it was blocked by location earlier
|
||||||
|
com.bitchat.android.wifiaware.WifiAwareController.startIfPossible()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,9 +43,19 @@ class WifiAwareConnectionTracker(
|
|||||||
try { it.close() } catch (e: Exception) { Log.w(TAG, "Error closing server socket for $id: ${e.message}") }
|
try { it.close() } catch (e: Exception) { Log.w(TAG, "Error closing server socket for $id: ${e.message}") }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Unregister network callback
|
// Ensure any pending/active network request is explicitly released
|
||||||
|
releaseNetworkRequest(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun releaseNetworkRequest(id: String) {
|
||||||
|
if (!networkCallbacks.containsKey(id)) return
|
||||||
|
|
||||||
|
// 3. Unregister network callback properly from ConnectivityManager
|
||||||
networkCallbacks.remove(id)?.let {
|
networkCallbacks.remove(id)?.let {
|
||||||
try { cm.unregisterNetworkCallback(it) } catch (e: Exception) { Log.w(TAG, "Error unregistering callback for $id: ${e.message}") }
|
try {
|
||||||
|
Log.d(TAG, "Unregistering network callback for $id")
|
||||||
|
cm.unregisterNetworkCallback(it)
|
||||||
|
} catch (e: Exception) { Log.w(TAG, "Error unregistering callback for $id: ${e.message}") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,13 +71,36 @@ object WifiAwareController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun startIfPossible() {
|
fun startIfPossible() {
|
||||||
if (_running.value) return
|
if (_running.value) {
|
||||||
|
if (!_enabled.value) return
|
||||||
|
// If already marked running but we are calling this (e.g. after a drop),
|
||||||
|
// ensure we clean up the old service before restarting.
|
||||||
|
stop()
|
||||||
|
}
|
||||||
|
if (!_enabled.value) return
|
||||||
val ctx = appContext ?: return
|
val ctx = appContext ?: return
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||||
Log.w(TAG, "Wi‑Fi Aware requires Android 10 (Q)+; disabled.")
|
Log.w(TAG, "Wi‑Fi Aware requires Android 10 (Q)+; disabled.")
|
||||||
try { com.bitchat.android.ui.debug.DebugSettingsManager.getInstance().addDebugMessage(com.bitchat.android.ui.debug.DebugMessage.SystemMessage("Wi‑Fi Aware not supported on this device (requires Android 10+)")) } catch (_: Exception) {}
|
try { com.bitchat.android.ui.debug.DebugSettingsManager.getInstance().addDebugMessage(com.bitchat.android.ui.debug.DebugMessage.SystemMessage("Wi‑Fi Aware not supported on this device (requires Android 10+)")) } catch (_: Exception) {}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check system location setting: WifiAwareManager.attach() throws SecurityException if disabled
|
||||||
|
val lm = ctx.getSystemService(Context.LOCATION_SERVICE) as? android.location.LocationManager
|
||||||
|
val locationEnabled = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
lm?.isLocationEnabled == true
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
lm?.isProviderEnabled(android.location.LocationManager.GPS_PROVIDER) == true ||
|
||||||
|
lm?.isProviderEnabled(android.location.LocationManager.NETWORK_PROVIDER) == true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!locationEnabled) {
|
||||||
|
Log.w(TAG, "Location services are disabled; Wi-Fi Aware cannot start.")
|
||||||
|
try { com.bitchat.android.ui.debug.DebugSettingsManager.getInstance().addDebugMessage(com.bitchat.android.ui.debug.DebugMessage.SystemMessage("Enable Location Services to start Wi-Fi Aware")) } catch (_: Exception) {}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Android 13+: require NEARBY_WIFI_DEVICES runtime permission
|
// Android 13+: require NEARBY_WIFI_DEVICES runtime permission
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
val granted = androidx.core.content.ContextCompat.checkSelfPermission(ctx, android.Manifest.permission.NEARBY_WIFI_DEVICES) == android.content.pm.PackageManager.PERMISSION_GRANTED
|
val granted = androidx.core.content.ContextCompat.checkSelfPermission(ctx, android.Manifest.permission.NEARBY_WIFI_DEVICES) == android.content.pm.PackageManager.PERMISSION_GRANTED
|
||||||
@@ -89,6 +112,7 @@ object WifiAwareController {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
service = WifiAwareMeshService(ctx).also {
|
service = WifiAwareMeshService(ctx).also {
|
||||||
|
Log.i(TAG, "Instantiating WifiAwareMeshService...")
|
||||||
it.startServices()
|
it.startServices()
|
||||||
_running.value = true
|
_running.value = true
|
||||||
try { com.bitchat.android.ui.debug.DebugSettingsManager.getInstance().addDebugMessage(com.bitchat.android.ui.debug.DebugMessage.SystemMessage("Wi‑Fi Aware started")) } catch (_: Exception) {}
|
try { com.bitchat.android.ui.debug.DebugSettingsManager.getInstance().addDebugMessage(com.bitchat.android.ui.debug.DebugMessage.SystemMessage("Wi‑Fi Aware started")) } catch (_: Exception) {}
|
||||||
|
|||||||
@@ -227,6 +227,7 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
|||||||
override fun onPublishStarted(pub: PublishDiscoverySession) {
|
override fun onPublishStarted(pub: PublishDiscoverySession) {
|
||||||
publishSession = pub
|
publishSession = pub
|
||||||
Log.d(TAG, "PUBLISH: onPublishStarted()")
|
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(
|
override fun onServiceDiscovered(
|
||||||
peerHandle: PeerHandle,
|
peerHandle: PeerHandle,
|
||||||
@@ -235,7 +236,10 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
|||||||
) {
|
) {
|
||||||
val peerId = try { String(serviceSpecificInfo) } catch (_: Exception) { "" }
|
val peerId = try { String(serviceSpecificInfo) } catch (_: Exception) { "" }
|
||||||
handleToPeerId[peerHandle] = peerId
|
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}")
|
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
|
handleToPeerId[peerHandle] = subscriberId
|
||||||
if (subscriberId.isNotBlank()) discoveredTimestamps[subscriberId] = System.currentTimeMillis()
|
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)
|
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())
|
Handler(Looper.getMainLooper())
|
||||||
)
|
)
|
||||||
@@ -266,6 +280,7 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
|||||||
override fun onSubscribeStarted(sub: SubscribeDiscoverySession) {
|
override fun onSubscribeStarted(sub: SubscribeDiscoverySession) {
|
||||||
subscribeSession = sub
|
subscribeSession = sub
|
||||||
Log.d(TAG, "SUBSCRIBE: onSubscribeStarted()")
|
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(
|
override fun onServiceDiscovered(
|
||||||
peerHandle: PeerHandle,
|
peerHandle: PeerHandle,
|
||||||
@@ -289,9 +304,18 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
|||||||
val peerId = handleToPeerId[peerHandle] ?: return
|
val peerId = handleToPeerId[peerHandle] ?: return
|
||||||
if (peerId == myPeerID) 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)
|
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())
|
Handler(Looper.getMainLooper())
|
||||||
)
|
)
|
||||||
@@ -299,6 +323,13 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
|||||||
override fun onAttachFailed() {
|
override fun onAttachFailed() {
|
||||||
Log.e(TAG, "Wi-Fi Aware attach failed")
|
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()))
|
}, Handler(Looper.getMainLooper()))
|
||||||
|
|
||||||
meshCore.startCore()
|
meshCore.startCore()
|
||||||
@@ -407,14 +438,14 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val ss = ServerSocket(0)
|
val ss = ServerSocket()
|
||||||
connectionTracker.addServerSocket(peerId, ss)
|
|
||||||
val port = ss.localPort
|
|
||||||
|
|
||||||
// Ensure port is set to reuse if connection was recently closed (TIME_WAIT)
|
|
||||||
try {
|
try {
|
||||||
ss.reuseAddress = true
|
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")
|
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() {
|
val cb = object : ConnectivityManager.NetworkCallback() {
|
||||||
override fun onAvailable(network: Network) {
|
override fun onAvailable(network: Network) {
|
||||||
|
Log.i(TAG, "SERVER: onAvailable() - Aware network is ready for ${peerId.take(8)}")
|
||||||
try {
|
try {
|
||||||
val client = ss.accept()
|
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}") }
|
try { network.bindSocket(client) } catch (e: Exception) { Log.w(TAG, "Server bindSocket EPERM: ${e.message}") }
|
||||||
client.keepAlive = true
|
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)
|
connectionTracker.onClientConnected(peerId, client)
|
||||||
try { meshCore.setDirectConnection(peerId, true) } catch (_: Exception) {}
|
try { meshCore.setDirectConnection(peerId, true) } catch (_: Exception) {}
|
||||||
try { meshCore.addOrUpdatePeer(peerId, peerId) } catch (_: Exception) {}
|
try { meshCore.addOrUpdatePeer(peerId, peerId) } catch (_: Exception) {}
|
||||||
listenerExec.execute { listenToPeer(client, peerId) }
|
listenerExec.execute { listenToPeer(client, peerId) }
|
||||||
handleSubscriberKeepAlive(client, peerId, pubSession, peerHandle)
|
handleSubscriberKeepAlive(client, peerId, pubSession, peerHandle)
|
||||||
|
|
||||||
// Kick off Noise handshake for this logical peer
|
// Kick off Noise handshake for this logical peer
|
||||||
if (myPeerID < peerId) {
|
if (myPeerID < peerId) {
|
||||||
meshCore.initiateNoiseHandshake(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
|
// Ensure fast presence even before handshake settles
|
||||||
serviceScope.launch { delay(150); sendBroadcastAnnounce() }
|
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)
|
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) {
|
override fun onLost(network: Network) {
|
||||||
connectionTracker.networkCallbacks.remove(peerId)
|
handlePeerDisconnection(peerId)
|
||||||
Log.d(TAG, "SERVER: network lost for ${peerId.take(8)}")
|
Log.i(TAG, "SERVER: WiFi Aware network lost for ${peerId.take(8)}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionTracker.addNetworkCallback(peerId, cb)
|
connectionTracker.addNetworkCallback(peerId, cb)
|
||||||
Log.d(TAG, "SERVER: requesting Aware network for ${peerId.take(8)}")
|
Log.i(TAG, "SERVER: [Calling requestNetwork] for ${peerId.take(8)} with port $port")
|
||||||
cm.requestNetwork(req, cb)
|
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 readyId = (System.nanoTime() and 0x7fffffff).toInt()
|
||||||
val portBytes = ByteBuffer.allocate(4)
|
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
|
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)
|
val spec = WifiAwareNetworkSpecifier.Builder(subscribeSession!!, peerHandle)
|
||||||
.setPskPassphrase(PSK)
|
.setPskPassphrase(PSK)
|
||||||
@@ -542,12 +588,19 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
|||||||
|
|
||||||
val cb = object : ConnectivityManager.NetworkCallback() {
|
val cb = object : ConnectivityManager.NetworkCallback() {
|
||||||
override fun onAvailable(network: Network) {
|
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
|
// 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) {
|
override fun onCapabilitiesChanged(network: Network, nc: NetworkCapabilities) {
|
||||||
if (connectionTracker.peerSockets.containsKey(peerId)) return
|
|
||||||
val info = (nc.transportInfo as? WifiAwareNetworkInfo) ?: return
|
val info = (nc.transportInfo as? WifiAwareNetworkInfo) ?: return
|
||||||
val addr = info.peerIpv6Addr as? Inet6Address ?: return
|
val addr = info.peerIpv6Addr as? Inet6Address ?: return
|
||||||
|
Log.i(TAG, "CLIENT: onCapabilitiesChanged() - Peer IPv6 discovered: $addr")
|
||||||
|
|
||||||
val lp = cm.getLinkProperties(network)
|
val lp = cm.getLinkProperties(network)
|
||||||
val iface = lp?.interfaceName
|
val iface = lp?.interfaceName
|
||||||
@@ -570,17 +623,18 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
|||||||
}
|
}
|
||||||
|
|
||||||
sock.connect(java.net.InetSocketAddress(scopedAddr, port), 7000)
|
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)
|
connectionTracker.onClientConnected(peerId, sock)
|
||||||
try { meshCore.setDirectConnection(peerId, true) } catch (_: Exception) {}
|
try { meshCore.setDirectConnection(peerId, true) } catch (_: Exception) {}
|
||||||
try { meshCore.addOrUpdatePeer(peerId, peerId) } catch (_: Exception) {}
|
try { meshCore.addOrUpdatePeer(peerId, peerId) } catch (_: Exception) {}
|
||||||
listenerExec.execute { listenToPeer(sock, peerId) }
|
listenerExec.execute { listenToPeer(sock, peerId) }
|
||||||
handleServerKeepAlive(sock, peerId, peerHandle)
|
handleServerKeepAlive(sock, peerId, peerHandle)
|
||||||
|
|
||||||
// Kick off Noise handshake for this logical peer
|
// Kick off Noise handshake for this logical peer
|
||||||
if (myPeerID < peerId) {
|
if (myPeerID < peerId) {
|
||||||
meshCore.initiateNoiseHandshake(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
|
// Ensure fast presence even before handshake settles
|
||||||
serviceScope.launch { delay(150); sendBroadcastAnnounce() }
|
serviceScope.launch { delay(150); sendBroadcastAnnounce() }
|
||||||
@@ -589,14 +643,19 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
override fun onLost(network: Network) {
|
override fun onLost(network: Network) {
|
||||||
connectionTracker.networkCallbacks.remove(peerId)
|
handlePeerDisconnection(peerId)
|
||||||
Log.d(TAG, "CLIENT: network lost for ${peerId.take(8)}")
|
Log.i(TAG, "CLIENT: WiFi Aware network lost for ${peerId.take(8)}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionTracker.addNetworkCallback(peerId, cb)
|
connectionTracker.addNetworkCallback(peerId, cb)
|
||||||
Log.d(TAG, "CLIENT: requesting Aware network for ${peerId.take(8)}")
|
Log.i(TAG, "CLIENT: [Calling requestNetwork] for ${peerId.take(8)}")
|
||||||
cm.requestNetwork(req, cb)
|
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()
|
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) {
|
private fun handlePeerDisconnection(initialId: String) {
|
||||||
serviceScope.launch {
|
serviceScope.launch {
|
||||||
Log.d(TAG, "Cleaning up peer: $initialId")
|
Log.d(TAG, "Cleaning up peer: $initialId")
|
||||||
|
|||||||
Reference in New Issue
Block a user