desktop: pick a free port for the call server if 50395 is in use (#6963)

* desktop: pick a free port for the call server if 50395 is in use

startServer() bound a hard-coded port (50395); when it was already in use,
NanoWSD threw "BindException: Address already in use: bind" and the call
failed. It now falls back to an OS-assigned free port, and WebRTCController
opens the browser at the actually-bound port (server.listeningPort) -- still
50395 in the normal case, so browser camera/mic permission stays put.

* plans: justify call server port-bind fix
This commit is contained in:
Narasimha-sc
2026-05-12 09:12:39 +00:00
committed by GitHub
parent eb4f601c8b
commit 5d597faf7e
3 changed files with 192 additions and 15 deletions
@@ -17,6 +17,7 @@ import org.nanohttpd.protocols.http.response.Response.newFixedLengthResponse
import org.nanohttpd.protocols.http.response.Status
import org.nanohttpd.protocols.websockets.*
import java.io.IOException
import java.net.BindException
import java.net.URI
private const val SERVER_HOST = "localhost"
@@ -157,17 +158,18 @@ fun WebRTCController(callCommand: SnapshotStateList<WCallCommand>, onResponse: (
if (call != null) withBGApi { chatModel.callManager.endCall(call) }
}
val server = remember {
try {
uriHandler.openUri("http://${SERVER_HOST}:$SERVER_PORT/simplex/call/")
} catch (e: Exception) {
Log.e(TAG, "Unable to open browser: ${e.stackTraceToString()}")
AlertManager.shared.showAlertMsg(
title = generalGetString(MR.strings.unable_to_open_browser_title),
text = generalGetString(MR.strings.unable_to_open_browser_desc)
)
endCall()
startServer(onResponse).apply {
try {
uriHandler.openUri("http://${SERVER_HOST}:${listeningPort}/simplex/call/")
} catch (e: Exception) {
Log.e(TAG, "Unable to open browser: ${e.stackTraceToString()}")
AlertManager.shared.showAlertMsg(
title = generalGetString(MR.strings.unable_to_open_browser_title),
text = generalGetString(MR.strings.unable_to_open_browser_desc)
)
endCall()
}
}
startServer(onResponse)
}
fun processCommand(cmd: WCallCommand) {
val apiCall = WVAPICall(command = cmd)
@@ -206,8 +208,8 @@ fun WebRTCController(callCommand: SnapshotStateList<WCallCommand>, onResponse: (
}
}
fun startServer(onResponse: (WVAPIMessage) -> Unit): NanoWSD {
val server = object: NanoWSD(SERVER_HOST, SERVER_PORT) {
fun startServer(onResponse: (WVAPIMessage) -> Unit, port: Int = SERVER_PORT): NanoWSD {
val server = object: NanoWSD(SERVER_HOST, port) {
override fun openWebSocket(session: IHTTPSession): WebSocket = MyWebSocket(onResponse, session)
fun resourcesToResponse(path: String): Response {
@@ -231,7 +233,14 @@ fun startServer(onResponse: (WVAPIMessage) -> Unit): NanoWSD {
}
}
}
server.start(60_000_000)
try {
server.start(60_000_000)
} catch (e: BindException) {
if (port == 0) throw e
Log.w(TAG, "Call server port $port is busy, using a random port: ${e.message}")
server.stop()
return startServer(onResponse, port = 0)
}
return server
}