Browse Source

Fix various disconnection issues, 1.0.1.

tags/v1.0.1
Chris Smith 5 years ago
parent
commit
9cd759d547

+ 10
- 0
CHANGELOG View File

@@ -1,7 +1,17 @@
1 1
 vNEXT (in development)
2 2
 
3
+v1.0.1
4
+
3 5
  * Fixed issue with very long packets not fitting in buffers
4 6
    after TLS decryption.
7
+ * Improved error message when IrcClient.connect() is called
8
+   while already connected
9
+ * Made IrcClient.disconnect() block until the disconnect has
10
+   been processed. This will be a very short period of time,
11
+   and allows callers to immediately call connect() again
12
+   afterwards if they wish
13
+ * Fixed various issues with disconnecting TLS connections
14
+   not behaving correctly
5 15
 
6 16
 v1.0.0
7 17
 

+ 1
- 1
build.gradle.kts View File

@@ -2,7 +2,7 @@ import org.jetbrains.dokka.gradle.DokkaTask
2 2
 import org.jetbrains.dokka.gradle.LinkMapping
3 3
 import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
4 4
 
5
-version = "1.0.0"
5
+version = "1.0.1"
6 6
 group = "com.dmdirc.ktirc"
7 7
 
8 8
 plugins {

+ 1
- 1
docs/index.adoc View File

@@ -1,6 +1,6 @@
1 1
 = KtIrc {version}
2 2
 Chris Smith
3
-:version: 1.0.0
3
+:version: 1.0.1
4 4
 :toc: left
5 5
 :toc-position: left
6 6
 :toclevels: 5

+ 9
- 5
src/main/kotlin/com/dmdirc/ktirc/IrcClientImpl.kt View File

@@ -17,10 +17,10 @@ import com.dmdirc.ktirc.util.logger
17 17
 import kotlinx.coroutines.*
18 18
 import kotlinx.coroutines.channels.Channel
19 19
 import kotlinx.coroutines.channels.map
20
+import kotlinx.coroutines.sync.Mutex
20 21
 import java.net.Inet6Address
21 22
 import java.net.InetAddress
22 23
 import java.time.Duration
23
-import java.util.concurrent.atomic.AtomicBoolean
24 24
 import java.util.logging.Level
25 25
 
26 26
 /**
@@ -53,7 +53,7 @@ internal class IrcClientImpl(private val config: IrcClientConfig) : Experimental
53 53
     private val parser = MessageParser()
54 54
     private var socket: LineBufferedSocket? = null
55 55
 
56
-    private val connecting = AtomicBoolean(false)
56
+    private val connecting = Mutex(false)
57 57
 
58 58
     @Deprecated("Use structured send instead", ReplaceWith("send(command, arguments)"))
59 59
     @RemoveIn("2.0.0")
@@ -85,7 +85,7 @@ internal class IrcClientImpl(private val config: IrcClientConfig) : Experimental
85 85
     }
86 86
 
87 87
     override fun connect() {
88
-        check(!connecting.getAndSet(true))
88
+        check(connecting.tryLock()) { "IrcClient is already connected to a server" }
89 89
 
90 90
         val ip: String
91 91
         try {
@@ -124,7 +124,11 @@ internal class IrcClientImpl(private val config: IrcClientConfig) : Experimental
124 124
     }
125 125
 
126 126
     override fun disconnect() {
127
-        socket?.disconnect()
127
+        runBlocking {
128
+            socket?.disconnect()
129
+            connecting.lock()
130
+            connecting.unlock()
131
+        }
128 132
     }
129 133
 
130 134
     override fun onEvent(handler: (IrcEvent) -> Unit) = messageHandler.addEmitter(handler)
@@ -160,7 +164,7 @@ internal class IrcClientImpl(private val config: IrcClientConfig) : Experimental
160 164
         channelState.clear()
161 165
         userState.reset()
162 166
         socket = null
163
-        connecting.set(false)
167
+        connecting.unlock()
164 168
     }
165 169
 
166 170
 }

+ 4
- 1
src/main/kotlin/com/dmdirc/ktirc/io/LineBufferedSocket.kt View File

@@ -67,8 +67,8 @@ internal class LineBufferedSocketImpl(coroutineScope: CoroutineScope, private va
67 67
     }
68 68
 
69 69
     override fun disconnect() {
70
-        log.info { "Disconnecting..." }
71 70
         socket.close()
71
+        sendChannel.close()
72 72
         coroutineContext.cancel()
73 73
     }
74 74
 
@@ -78,6 +78,9 @@ internal class LineBufferedSocketImpl(coroutineScope: CoroutineScope, private va
78 78
                 while (socket.isOpen) {
79 79
                     defaultPool.borrow { buffer ->
80 80
                         val bytesRead = socket.read(buffer)
81
+                        if (bytesRead == -1) {
82
+                            return@produce
83
+                        }
81 84
                         var lastLine = 0
82 85
                         for (i in 0 until bytesRead) {
83 86
                             if (buffer[i] == CARRIAGE_RETURN || buffer[i] == LINE_FEED) {

+ 13
- 2
src/main/kotlin/com/dmdirc/ktirc/io/Tls.kt View File

@@ -3,6 +3,7 @@ package com.dmdirc.ktirc.io
3 3
 import com.dmdirc.ktirc.util.logger
4 4
 import kotlinx.coroutines.CoroutineScope
5 5
 import kotlinx.coroutines.channels.Channel
6
+import kotlinx.coroutines.channels.ClosedReceiveChannelException
6 7
 import kotlinx.coroutines.io.ByteChannel
7 8
 import kotlinx.coroutines.io.ByteWriteChannel
8 9
 import kotlinx.coroutines.launch
@@ -96,12 +97,14 @@ internal class TlsSocket(
96 97
         }
97 98
     }
98 99
 
99
-    override suspend fun read(buffer: ByteBuffer): Int {
100
+    override suspend fun read(buffer: ByteBuffer) = try {
100 101
         val nextBuffer = outgoingAppBuffers.receive()
101 102
         val bytes = nextBuffer.limit()
102 103
         buffer.put(nextBuffer)
103 104
         defaultPool.recycle(nextBuffer)
104
-        return bytes
105
+        bytes
106
+    } catch (_: ClosedReceiveChannelException) {
107
+        -1
105 108
     }
106 109
 
107 110
     private suspend fun wrap(): SSLEngineResult? {
@@ -153,6 +156,14 @@ internal class TlsSocket(
153 156
 
154 157
     override fun close() {
155 158
         socket.close()
159
+
160
+        // Release any buffers we've got queued up
161
+        while(true) {
162
+            outgoingAppBuffers.poll()?.let {
163
+                defaultPool.recycle(it)
164
+            } ?: break
165
+        }
166
+
156 167
         outgoingAppBuffers.close()
157 168
     }
158 169
 

Loading…
Cancel
Save