Fix thread safety

syncExec synced on the Listener instance, but it modified properties of
the WebSocketConnection without synchronizing on the WebSocketConnection.
This commit is contained in:
Jannis Mattheis
2023-05-02 18:32:38 +02:00
parent dae7834488
commit 9d8ee01519

View File

@@ -116,13 +116,18 @@ internal class WebSocketConnection(
@Synchronized @Synchronized
fun close() { fun close() {
if (webSocket != null) { if (webSocket != null) {
webSocket?.close(1000, "")
closed()
Log.i("WebSocket(${ID.get()}): closing existing connection.") 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 @Synchronized
fun scheduleReconnect(seconds: Long) { fun scheduleReconnect(seconds: Long) {
if (state == State.Connecting || state == State.Connected) { if (state == State.Connecting || state == State.Connected) {
@@ -150,7 +155,7 @@ internal class WebSocketConnection(
private inner class Listener(private val id: Long) : WebSocketListener() { private inner class Listener(private val id: Long) : WebSocketListener() {
override fun onOpen(webSocket: WebSocket, response: Response) { override fun onOpen(webSocket: WebSocket, response: Response) {
syncExec { syncExec(id) {
state = State.Connected state = State.Connected
Log.i("WebSocket($id): opened") Log.i("WebSocket($id): opened")
onOpen.run() onOpen.run()
@@ -164,7 +169,7 @@ internal class WebSocketConnection(
} }
override fun onMessage(webSocket: WebSocket, text: String) { override fun onMessage(webSocket: WebSocket, text: String) {
syncExec { syncExec(id) {
Log.i("WebSocket($id): received message $text") Log.i("WebSocket($id): received message $text")
val message = Utils.JSON.fromJson(text, Message::class.java) val message = Utils.JSON.fromJson(text, Message::class.java)
onMessageCallback(message) onMessageCallback(message)
@@ -173,12 +178,12 @@ internal class WebSocketConnection(
} }
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
syncExec { syncExec(id) {
if (state == State.Connected) { if (state == State.Connected) {
Log.w("WebSocket($id): closed") Log.w("WebSocket($id): closed")
onClose.run() onClose.run()
} }
state = State.Disconnected closed()
} }
super.onClosed(webSocket, code, reason) super.onClosed(webSocket, code, reason)
} }
@@ -187,11 +192,10 @@ internal class WebSocketConnection(
val code = if (response != null) "StatusCode: ${response.code()}" else "" val code = if (response != null) "StatusCode: ${response.code()}" else ""
val message = if (response != null) response.message() else "" val message = if (response != null) response.message() else ""
Log.e("WebSocket($id): failure $code Message: $message", t) Log.e("WebSocket($id): failure $code Message: $message", t)
syncExec { syncExec(id) {
state = State.Disconnected closed()
if (response != null && response.code() >= 400 && response.code() <= 499) { if (response != null && response.code() >= 400 && response.code() <= 499) {
onBadRequest.execute(message) onBadRequest.execute(message)
close()
return@syncExec return@syncExec
} }
@@ -209,13 +213,12 @@ internal class WebSocketConnection(
} }
super.onFailure(webSocket, t, response) super.onFailure(webSocket, t, response)
} }
}
private fun syncExec(runnable: Runnable) { @Synchronized
synchronized(this) { private fun syncExec(id: Long, runnable: () -> Unit) {
if (ID.get() == id) { if (ID.get() == id) {
runnable.run() runnable()
}
}
} }
} }