|
@@ -1,11 +1,11 @@
|
1
|
1
|
package com.dmdirc.ktirc.io
|
2
|
2
|
|
|
3
|
+import com.dmdirc.ktirc.util.logger
|
3
|
4
|
import kotlinx.coroutines.CoroutineScope
|
|
5
|
+import kotlinx.coroutines.channels.Channel
|
4
|
6
|
import kotlinx.coroutines.io.ByteChannel
|
5
|
7
|
import kotlinx.coroutines.io.ByteWriteChannel
|
6
|
8
|
import kotlinx.coroutines.launch
|
7
|
|
-import kotlinx.coroutines.sync.Mutex
|
8
|
|
-import kotlinx.coroutines.sync.withLock
|
9
|
9
|
import java.net.SocketAddress
|
10
|
10
|
import java.nio.ByteBuffer
|
11
|
11
|
import java.security.cert.CertificateException
|
|
@@ -25,12 +25,12 @@ internal class TlsSocket(
|
25
|
25
|
private val hostname: String
|
26
|
26
|
) : Socket {
|
27
|
27
|
|
|
28
|
+ private val log by logger()
|
28
|
29
|
private var engine: SSLEngine = sslContext.createSSLEngine()
|
29
|
30
|
|
30
|
31
|
private var incomingNetBuffer = ByteBuffer.allocate(0)
|
31
|
|
- private var outgoingAppBuffer = ByteBuffer.allocate(0)
|
32
|
32
|
private var incomingAppBuffer = ByteBuffer.allocate(0)
|
33
|
|
- private val outgoingAppBufferMutex = Mutex(false)
|
|
33
|
+ private var outgoingAppBuffers = Channel<ByteBuffer>(capacity = Channel.UNLIMITED)
|
34
|
34
|
|
35
|
35
|
private var writeChannel = ByteChannel(autoFlush = true)
|
36
|
36
|
|
|
@@ -52,7 +52,7 @@ internal class TlsSocket(
|
52
|
52
|
}
|
53
|
53
|
|
54
|
54
|
incomingNetBuffer = ByteBuffer.allocate(engine.session.packetBufferSize)
|
55
|
|
- outgoingAppBuffer = ByteBuffer.allocate(engine.session.applicationBufferSize)
|
|
55
|
+ outgoingAppBuffers = Channel(capacity = Channel.UNLIMITED)
|
56
|
56
|
incomingAppBuffer = ByteBuffer.allocate(engine.session.applicationBufferSize)
|
57
|
57
|
|
58
|
58
|
socket.connect(socketAddress)
|
|
@@ -96,11 +96,11 @@ internal class TlsSocket(
|
96
|
96
|
}
|
97
|
97
|
}
|
98
|
98
|
|
99
|
|
- override suspend fun read(buffer: ByteBuffer) = outgoingAppBufferMutex.withLock<Int> {
|
100
|
|
- outgoingAppBuffer.flip()
|
101
|
|
- val bytes = outgoingAppBuffer.limit()
|
102
|
|
- buffer.put(outgoingAppBuffer)
|
103
|
|
- outgoingAppBuffer.clear()
|
|
99
|
+ override suspend fun read(buffer: ByteBuffer): Int {
|
|
100
|
+ val nextBuffer = outgoingAppBuffers.receive()
|
|
101
|
+ val bytes = nextBuffer.limit()
|
|
102
|
+ buffer.put(nextBuffer)
|
|
103
|
+ defaultPool.recycle(nextBuffer)
|
104
|
104
|
return bytes
|
105
|
105
|
}
|
106
|
106
|
|
|
@@ -120,8 +120,8 @@ internal class TlsSocket(
|
120
|
120
|
return result
|
121
|
121
|
}
|
122
|
122
|
|
123
|
|
- private suspend fun unwrap(): SSLEngineResult? {
|
124
|
|
- if (incomingNetBuffer.position() == 0) {
|
|
123
|
+ private suspend fun unwrap(networkRead: Boolean = incomingNetBuffer.position() == 0): SSLEngineResult? {
|
|
124
|
+ if (networkRead) {
|
125
|
125
|
val bytes = socket.read(incomingNetBuffer.slice())
|
126
|
126
|
if (bytes == -1) {
|
127
|
127
|
close()
|
|
@@ -131,15 +131,29 @@ internal class TlsSocket(
|
131
|
131
|
}
|
132
|
132
|
|
133
|
133
|
incomingNetBuffer.flip()
|
134
|
|
- outgoingAppBufferMutex.withLock {
|
135
|
|
- val result = engine.unwrap(incomingNetBuffer, outgoingAppBuffer)
|
136
|
|
- incomingNetBuffer.compact()
|
137
|
|
- return result
|
|
134
|
+
|
|
135
|
+ val buffer = defaultPool.borrow()
|
|
136
|
+ val result = engine.unwrap(incomingNetBuffer, buffer)
|
|
137
|
+ incomingNetBuffer.compact()
|
|
138
|
+ if (buffer.position() > 0) {
|
|
139
|
+ buffer.flip()
|
|
140
|
+ outgoingAppBuffers.send(buffer)
|
|
141
|
+ } else {
|
|
142
|
+ defaultPool.recycle(buffer)
|
|
143
|
+ }
|
|
144
|
+
|
|
145
|
+ return if (result?.status == SSLEngineResult.Status.BUFFER_UNDERFLOW && !networkRead) {
|
|
146
|
+ // We didn't do a network read, but SSLEngine is unhappy; force a read.
|
|
147
|
+ log.finest { "Incoming net buffer underflowed, forcing re-read" }
|
|
148
|
+ unwrap(true)
|
|
149
|
+ } else {
|
|
150
|
+ result
|
138
|
151
|
}
|
139
|
152
|
}
|
140
|
153
|
|
141
|
154
|
override fun close() {
|
142
|
155
|
socket.close()
|
|
156
|
+ outgoingAppBuffers.close()
|
143
|
157
|
}
|
144
|
158
|
|
145
|
159
|
private suspend fun readLoop() {
|