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
 vNEXT (in development)
1
 vNEXT (in development)
2
 
2
 
3
+v1.0.1
4
+
3
  * Fixed issue with very long packets not fitting in buffers
5
  * Fixed issue with very long packets not fitting in buffers
4
    after TLS decryption.
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
 v1.0.0
16
 v1.0.0
7
 
17
 

+ 1
- 1
build.gradle.kts View File

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

+ 1
- 1
docs/index.adoc View File

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

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

17
 import kotlinx.coroutines.*
17
 import kotlinx.coroutines.*
18
 import kotlinx.coroutines.channels.Channel
18
 import kotlinx.coroutines.channels.Channel
19
 import kotlinx.coroutines.channels.map
19
 import kotlinx.coroutines.channels.map
20
+import kotlinx.coroutines.sync.Mutex
20
 import java.net.Inet6Address
21
 import java.net.Inet6Address
21
 import java.net.InetAddress
22
 import java.net.InetAddress
22
 import java.time.Duration
23
 import java.time.Duration
23
-import java.util.concurrent.atomic.AtomicBoolean
24
 import java.util.logging.Level
24
 import java.util.logging.Level
25
 
25
 
26
 /**
26
 /**
53
     private val parser = MessageParser()
53
     private val parser = MessageParser()
54
     private var socket: LineBufferedSocket? = null
54
     private var socket: LineBufferedSocket? = null
55
 
55
 
56
-    private val connecting = AtomicBoolean(false)
56
+    private val connecting = Mutex(false)
57
 
57
 
58
     @Deprecated("Use structured send instead", ReplaceWith("send(command, arguments)"))
58
     @Deprecated("Use structured send instead", ReplaceWith("send(command, arguments)"))
59
     @RemoveIn("2.0.0")
59
     @RemoveIn("2.0.0")
85
     }
85
     }
86
 
86
 
87
     override fun connect() {
87
     override fun connect() {
88
-        check(!connecting.getAndSet(true))
88
+        check(connecting.tryLock()) { "IrcClient is already connected to a server" }
89
 
89
 
90
         val ip: String
90
         val ip: String
91
         try {
91
         try {
124
     }
124
     }
125
 
125
 
126
     override fun disconnect() {
126
     override fun disconnect() {
127
-        socket?.disconnect()
127
+        runBlocking {
128
+            socket?.disconnect()
129
+            connecting.lock()
130
+            connecting.unlock()
131
+        }
128
     }
132
     }
129
 
133
 
130
     override fun onEvent(handler: (IrcEvent) -> Unit) = messageHandler.addEmitter(handler)
134
     override fun onEvent(handler: (IrcEvent) -> Unit) = messageHandler.addEmitter(handler)
160
         channelState.clear()
164
         channelState.clear()
161
         userState.reset()
165
         userState.reset()
162
         socket = null
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
     }
67
     }
68
 
68
 
69
     override fun disconnect() {
69
     override fun disconnect() {
70
-        log.info { "Disconnecting..." }
71
         socket.close()
70
         socket.close()
71
+        sendChannel.close()
72
         coroutineContext.cancel()
72
         coroutineContext.cancel()
73
     }
73
     }
74
 
74
 
78
                 while (socket.isOpen) {
78
                 while (socket.isOpen) {
79
                     defaultPool.borrow { buffer ->
79
                     defaultPool.borrow { buffer ->
80
                         val bytesRead = socket.read(buffer)
80
                         val bytesRead = socket.read(buffer)
81
+                        if (bytesRead == -1) {
82
+                            return@produce
83
+                        }
81
                         var lastLine = 0
84
                         var lastLine = 0
82
                         for (i in 0 until bytesRead) {
85
                         for (i in 0 until bytesRead) {
83
                             if (buffer[i] == CARRIAGE_RETURN || buffer[i] == LINE_FEED) {
86
                             if (buffer[i] == CARRIAGE_RETURN || buffer[i] == LINE_FEED) {

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

3
 import com.dmdirc.ktirc.util.logger
3
 import com.dmdirc.ktirc.util.logger
4
 import kotlinx.coroutines.CoroutineScope
4
 import kotlinx.coroutines.CoroutineScope
5
 import kotlinx.coroutines.channels.Channel
5
 import kotlinx.coroutines.channels.Channel
6
+import kotlinx.coroutines.channels.ClosedReceiveChannelException
6
 import kotlinx.coroutines.io.ByteChannel
7
 import kotlinx.coroutines.io.ByteChannel
7
 import kotlinx.coroutines.io.ByteWriteChannel
8
 import kotlinx.coroutines.io.ByteWriteChannel
8
 import kotlinx.coroutines.launch
9
 import kotlinx.coroutines.launch
96
         }
97
         }
97
     }
98
     }
98
 
99
 
99
-    override suspend fun read(buffer: ByteBuffer): Int {
100
+    override suspend fun read(buffer: ByteBuffer) = try {
100
         val nextBuffer = outgoingAppBuffers.receive()
101
         val nextBuffer = outgoingAppBuffers.receive()
101
         val bytes = nextBuffer.limit()
102
         val bytes = nextBuffer.limit()
102
         buffer.put(nextBuffer)
103
         buffer.put(nextBuffer)
103
         defaultPool.recycle(nextBuffer)
104
         defaultPool.recycle(nextBuffer)
104
-        return bytes
105
+        bytes
106
+    } catch (_: ClosedReceiveChannelException) {
107
+        -1
105
     }
108
     }
106
 
109
 
107
     private suspend fun wrap(): SSLEngineResult? {
110
     private suspend fun wrap(): SSLEngineResult? {
153
 
156
 
154
     override fun close() {
157
     override fun close() {
155
         socket.close()
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
         outgoingAppBuffers.close()
167
         outgoingAppBuffers.close()
157
     }
168
     }
158
 
169
 

Loading…
Cancel
Save