From 80fc81de63a5e25f8ded81f6d9414813ca76b756 Mon Sep 17 00:00:00 2001 From: Janne Koschinski <janne@kuschku.de> Date: Wed, 17 Apr 2019 20:11:06 +0200 Subject: [PATCH] Connection handling improvements --- .../libquassel/connection/CoreConnection.kt | 7 ++- .../util/compatibility/CompatibilityUtils.kt | 24 ++------- ...BackportedSyncFlushDeflaterOutputStream.kt | 54 +++++++++++++++++++ ...rlyClosingSyncFlushDeflaterOutputStream.kt | 35 ++++++++++++ .../libquassel/util/nio/WrappedChannel.kt | 37 +++++++++---- 5 files changed, 122 insertions(+), 35 deletions(-) create mode 100644 lib/src/main/java/de/kuschku/libquassel/util/compatibility/backport/BackportedSyncFlushDeflaterOutputStream.kt create mode 100644 lib/src/main/java/de/kuschku/libquassel/util/compatibility/backport/ProperlyClosingSyncFlushDeflaterOutputStream.kt diff --git a/lib/src/main/java/de/kuschku/libquassel/connection/CoreConnection.kt b/lib/src/main/java/de/kuschku/libquassel/connection/CoreConnection.kt index 668c0546f..4f1ffca97 100644 --- a/lib/src/main/java/de/kuschku/libquassel/connection/CoreConnection.kt +++ b/lib/src/main/java/de/kuschku/libquassel/connection/CoreConnection.kt @@ -172,13 +172,12 @@ class CoreConnection( override fun close() { try { setState(ConnectionState.CLOSED) - channel?.flush() channel?.close() - setHandlers(null, null, null) - interrupt() } catch (e: Throwable) { log(WARN, TAG, "Error encountered while closing connection: $e") } + setHandlers(null, null, null) + interrupt() } fun dispatch(message: HandshakeMessage) { @@ -218,7 +217,7 @@ class CoreConnection( connect() sendHandshake() readHandshake() - while (!isInterrupted && state != ConnectionState.CLOSED) { + while (!isInterrupted && state.value != ConnectionState.CLOSED) { sizeBuffer.clear() if (channel?.read(sizeBuffer) == -1) break diff --git a/lib/src/main/java/de/kuschku/libquassel/util/compatibility/CompatibilityUtils.kt b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/CompatibilityUtils.kt index 663c9ab7b..9c531d84f 100644 --- a/lib/src/main/java/de/kuschku/libquassel/util/compatibility/CompatibilityUtils.kt +++ b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/CompatibilityUtils.kt @@ -19,6 +19,8 @@ package de.kuschku.libquassel.util.compatibility +import de.kuschku.libquassel.util.compatibility.backport.BackportedSyncFlushDeflaterOutputStream +import de.kuschku.libquassel.util.compatibility.backport.ProperlyClosingSyncFlushDeflaterOutputStream import java.io.OutputStream import java.util.zip.Deflater import java.util.zip.DeflaterOutputStream @@ -36,27 +38,9 @@ object CompatibilityUtils { */ fun createDeflaterOutputStream(rawOut: OutputStream?): DeflaterOutputStream { return if (supportsCompression) { - DeflaterOutputStream(rawOut, true) + ProperlyClosingSyncFlushDeflaterOutputStream(rawOut) } else { - DeflaterOutputStream(rawOut, createSyncFlushDeflater()) + BackportedSyncFlushDeflaterOutputStream(rawOut) } } - - /** - * Creates a SyncFlush Deflater for use on pre-KitKat Android - * - * @return The modified Deflater, or null if the creation failed - */ - private fun createSyncFlushDeflater(): Deflater? { - val def = Deflater() - try { - val f = def.javaClass.getDeclaredField("flushParm") - f.isAccessible = true - f.setInt(def, 2) // Z_SYNC_FLUSH - } catch (e: Exception) { - return null - } - - return def - } } diff --git a/lib/src/main/java/de/kuschku/libquassel/util/compatibility/backport/BackportedSyncFlushDeflaterOutputStream.kt b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/backport/BackportedSyncFlushDeflaterOutputStream.kt new file mode 100644 index 000000000..d222c3418 --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/backport/BackportedSyncFlushDeflaterOutputStream.kt @@ -0,0 +1,54 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2019 Janne Koschinski + * Copyright (c) 2019 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.libquassel.util.compatibility.backport + +import java.io.OutputStream +import java.util.zip.Deflater +import java.util.zip.DeflaterOutputStream + +class BackportedSyncFlushDeflaterOutputStream( + rawOut: OutputStream?, + private val deflater: Deflater? = createSyncFlushDeflater() +) : DeflaterOutputStream(rawOut, deflater) { + override fun close() { + deflater?.end() + super.close() + } + + companion object { + /** + * Creates a SyncFlush Deflater for use on pre-KitKat Android + * + * @return The modified Deflater, or null if the creation failed + */ + private fun createSyncFlushDeflater(): Deflater? { + val def = Deflater() + try { + val f = def.javaClass.getDeclaredField("flushParm") + f.isAccessible = true + f.setInt(def, 2) // Z_SYNC_FLUSH + } catch (e: Exception) { + return null + } + + return def + } + } +} diff --git a/lib/src/main/java/de/kuschku/libquassel/util/compatibility/backport/ProperlyClosingSyncFlushDeflaterOutputStream.kt b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/backport/ProperlyClosingSyncFlushDeflaterOutputStream.kt new file mode 100644 index 000000000..a5630d8ed --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/backport/ProperlyClosingSyncFlushDeflaterOutputStream.kt @@ -0,0 +1,35 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2019 Janne Koschinski + * Copyright (c) 2019 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.libquassel.util.compatibility.backport + +import java.io.OutputStream +import java.util.zip.DeflaterOutputStream + +class ProperlyClosingSyncFlushDeflaterOutputStream( + stream: OutputStream? +) : DeflaterOutputStream(stream, true) { + override fun close() { + try { + super.close() + } finally { + def.end() + } + } +} diff --git a/lib/src/main/java/de/kuschku/libquassel/util/nio/WrappedChannel.kt b/lib/src/main/java/de/kuschku/libquassel/util/nio/WrappedChannel.kt index 9c8bbaf72..d47bea712 100644 --- a/lib/src/main/java/de/kuschku/libquassel/util/nio/WrappedChannel.kt +++ b/lib/src/main/java/de/kuschku/libquassel/util/nio/WrappedChannel.kt @@ -19,14 +19,15 @@ package de.kuschku.libquassel.util.nio +import de.kuschku.libquassel.connection.CoreConnection import de.kuschku.libquassel.connection.HostnameVerifier import de.kuschku.libquassel.connection.SocketAddress import de.kuschku.libquassel.util.compatibility.CompatibilityUtils +import de.kuschku.libquassel.util.compatibility.LoggingHandler +import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log +import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.* import de.kuschku.libquassel.util.compatibility.StreamChannelFactory -import java.io.Flushable -import java.io.IOException -import java.io.InputStream -import java.io.OutputStream +import java.io.* import java.net.Socket import java.net.SocketException import java.nio.ByteBuffer @@ -42,11 +43,12 @@ import javax.net.ssl.SSLSocket import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager -class WrappedChannel( +class WrappedChannel private constructor( private val socket: Socket, private var rawInStream: InputStream? = null, private var rawOutStream: OutputStream? = null, - private var flusher: (() -> Unit)? = null + private var flusher: (() -> Unit)? = null, + private val closeListeners: List<Closeable> = emptyList() ) : Flushable, ByteChannel, InterruptibleChannel { private var rawIn: ReadableByteChannel? = null private var rawOut: WritableByteChannel? = null @@ -62,10 +64,12 @@ class WrappedChannel( } companion object { - fun ofSocket(s: Socket): WrappedChannel { + fun ofSocket(s: Socket, closeListeners: List<Closeable> = emptyList()): WrappedChannel { return WrappedChannel( - s, s.getInputStream(), - s.getOutputStream() + s, + s.getInputStream(), + s.getOutputStream(), + closeListeners = closeListeners + s.getInputStream() + s.getOutputStream() ) } } @@ -74,7 +78,8 @@ class WrappedChannel( val deflaterOutputStream = CompatibilityUtils.createDeflaterOutputStream(rawOutStream) return WrappedChannel( socket, InflaterInputStream(rawInStream), deflaterOutputStream, - deflaterOutputStream::flush + deflaterOutputStream::flush, + closeListeners = closeListeners + deflaterOutputStream ) } @@ -96,7 +101,7 @@ class WrappedChannel( ) } socket.startHandshake() - return WrappedChannel.ofSocket(socket) + return ofSocket(socket) } /** @@ -206,6 +211,16 @@ class WrappedChannel( rawOut?.close() rawOut = null socket.close() + /* + for (listener in closeListeners + socket) { + try { + log(INFO, "WrappedChannel", "Closing: ${listener::class.java}") + listener.close() + } catch (e: Throwable) { + log(WARN, "WrappedChannel", "Error encountered while closing connection: $e") + } + } + */ } /** -- GitLab