From 9d8ee015195ba72afeba4b0421958819f2922770 Mon Sep 17 00:00:00 2001 From: Jannis Mattheis Date: Tue, 2 May 2023 18:32:38 +0200 Subject: [PATCH] Fix thread safety syncExec synced on the Listener instance, but it modified properties of the WebSocketConnection without synchronizing on the WebSocketConnection. --- .../gotify/service/WebSocketConnection.kt | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/app/src/main/kotlin/com/github/gotify/service/WebSocketConnection.kt b/app/src/main/kotlin/com/github/gotify/service/WebSocketConnection.kt index b76605e..f0b80ec 100644 --- a/app/src/main/kotlin/com/github/gotify/service/WebSocketConnection.kt +++ b/app/src/main/kotlin/com/github/gotify/service/WebSocketConnection.kt @@ -116,13 +116,18 @@ internal class WebSocketConnection( @Synchronized fun close() { if (webSocket != null) { + webSocket?.close(1000, "") + closed() Log.i("WebSocket(${ID.get()}): closing existing connection.") - state = State.Disconnected - webSocket!!.close(1000, "") - webSocket = null } } + @Synchronized + private fun closed() { + webSocket = null + state = State.Disconnected + } + @Synchronized fun scheduleReconnect(seconds: Long) { if (state == State.Connecting || state == State.Connected) { @@ -150,7 +155,7 @@ internal class WebSocketConnection( private inner class Listener(private val id: Long) : WebSocketListener() { override fun onOpen(webSocket: WebSocket, response: Response) { - syncExec { + syncExec(id) { state = State.Connected Log.i("WebSocket($id): opened") onOpen.run() @@ -164,7 +169,7 @@ internal class WebSocketConnection( } override fun onMessage(webSocket: WebSocket, text: String) { - syncExec { + syncExec(id) { Log.i("WebSocket($id): received message $text") val message = Utils.JSON.fromJson(text, Message::class.java) onMessageCallback(message) @@ -173,12 +178,12 @@ internal class WebSocketConnection( } override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { - syncExec { + syncExec(id) { if (state == State.Connected) { Log.w("WebSocket($id): closed") onClose.run() } - state = State.Disconnected + closed() } super.onClosed(webSocket, code, reason) } @@ -187,11 +192,10 @@ internal class WebSocketConnection( val code = if (response != null) "StatusCode: ${response.code()}" else "" val message = if (response != null) response.message() else "" Log.e("WebSocket($id): failure $code Message: $message", t) - syncExec { - state = State.Disconnected + syncExec(id) { + closed() if (response != null && response.code() >= 400 && response.code() <= 499) { onBadRequest.execute(message) - close() return@syncExec } @@ -209,13 +213,12 @@ internal class WebSocketConnection( } super.onFailure(webSocket, t, response) } + } - private fun syncExec(runnable: Runnable) { - synchronized(this) { - if (ID.get() == id) { - runnable.run() - } - } + @Synchronized + private fun syncExec(id: Long, runnable: () -> Unit) { + if (ID.get() == id) { + runnable() } }