Skip to content

Commit 5fc13c8

Browse files
authored
Run DTLS session lifecycle probes asynchronously (#25)
* Call metrics callbacks asynchronously * Fixing tests * Set finish timestamp on handshake failure
1 parent 3f0c028 commit 5fc13c8

File tree

5 files changed

+34
-32
lines changed

5 files changed

+34
-32
lines changed

kotlin-mbedtls-metrics/src/main/kotlin/org/opencoap/ssl/transport/metrics/micrometer/DtlsServerMetricsCallbacks.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ class DtlsServerMetricsCallbacks(
5454
handshakesInitiated.increment()
5555
}
5656

57-
override fun handshakeFinished(adr: InetSocketAddress, hanshakeStartTimestamp: Long, reason: DtlsSessionLifecycleCallbacks.Reason, throwable: Throwable?) = when {
57+
override fun handshakeFinished(adr: InetSocketAddress, hanshakeStartTimestamp: Long, hanshakeFinishTimestamp: Long, reason: DtlsSessionLifecycleCallbacks.Reason, throwable: Throwable?) = when {
5858
throwable is HelloVerifyRequired -> {} // Skip HelloVerifyRequired handshake states
5959
reason == DtlsSessionLifecycleCallbacks.Reason.SUCCEEDED ->
60-
handshakesSucceeded.record(System.currentTimeMillis() - hanshakeStartTimestamp, TimeUnit.MILLISECONDS)
60+
handshakesSucceeded.record(hanshakeFinishTimestamp - hanshakeStartTimestamp, TimeUnit.MILLISECONDS)
6161
reason == DtlsSessionLifecycleCallbacks.Reason.FAILED ->
6262
handshakesFailedBuilder.reasonTag(throwable).register(registry).increment()
6363
reason == DtlsSessionLifecycleCallbacks.Reason.EXPIRED ->

kotlin-mbedtls/src/main/kotlin/org/opencoap/ssl/SslContext.kt

+4-1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class SslHandshakeContext internal constructor(
6868
) : SslContext {
6969
private val logger = LoggerFactory.getLogger(javaClass)
7070
val startTimestamp: Long = System.currentTimeMillis()
71+
var finishTimestamp: Long = 0
7172
private var stepTimeout: Duration = Duration.ZERO
7273

7374
fun step(send: (ByteBuffer) -> Unit): SslContext = step0(null, send)
@@ -86,10 +87,12 @@ class SslHandshakeContext internal constructor(
8687
MbedtlsApi.MBEDTLS_ERR_SSL_WANT_READ -> return this
8788
MbedtlsApi.MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED -> throw HelloVerifyRequired
8889
0 -> SslSession(conf, sslContext, cid).also {
89-
logger.info("[{}] DTLS connected in {}ms {}", peerAdr, System.currentTimeMillis() - startTimestamp, it)
90+
finishTimestamp = System.currentTimeMillis()
91+
logger.info("[{}] DTLS connected in {}ms {}", peerAdr, finishTimestamp - startTimestamp, it)
9092
}
9193

9294
else -> throw SslException.from(ret).also {
95+
finishTimestamp = System.currentTimeMillis()
9396
logger.debug("[{}] DTLS failed handshake: {}", peerAdr, it.message)
9497
}
9598
}

kotlin-mbedtls/src/main/kotlin/org/opencoap/ssl/transport/DtlsServer.kt

+10-10
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,8 @@ class DtlsServer(
172172
}
173173

174174
is SslSession -> {
175-
reportHandshakeFinished(DtlsSessionLifecycleCallbacks.Reason.SUCCEEDED)
176175
sessions[peerAddress] = DtlsSession(newCtx, peerAddress)
176+
reportHandshakeFinished(DtlsSessionLifecycleCallbacks.Reason.SUCCEEDED)
177177
}
178178
}
179179
} catch (ex: Exception) {
@@ -185,28 +185,28 @@ class DtlsServer(
185185
else ->
186186
logger.error(ex.toString(), ex)
187187
}
188-
reportHandshakeFinished(DtlsSessionLifecycleCallbacks.Reason.FAILED, ex)
189188
closeAndRemove()
189+
reportHandshakeFinished(DtlsSessionLifecycleCallbacks.Reason.FAILED, ex)
190190
}
191191
return ReceiveResult.Handled
192192
}
193193

194194
fun timeout() {
195-
reportHandshakeFinished(DtlsSessionLifecycleCallbacks.Reason.EXPIRED)
196195
closeAndRemove()
197196
logger.warn("[{}] DTLS handshake expired", peerAddress)
197+
reportHandshakeFinished(DtlsSessionLifecycleCallbacks.Reason.EXPIRED)
198198
}
199199

200200
override fun storeAndClose0() = close()
201201

202202
override fun close() = ctx.close()
203203

204204
private fun reportHandshakeStarted() {
205-
lifecycleCallbacks.handshakeStarted(peerAddress)
205+
executor.supply { lifecycleCallbacks.handshakeStarted(peerAddress) }
206206
}
207207

208208
private fun reportHandshakeFinished(reason: DtlsSessionLifecycleCallbacks.Reason, err: Throwable? = null) {
209-
lifecycleCallbacks.handshakeFinished(peerAddress, ctx.startTimestamp, reason, err)
209+
executor.supply { lifecycleCallbacks.handshakeFinished(peerAddress, ctx.startTimestamp, ctx.finishTimestamp, reason, err) }
210210
}
211211
}
212212

@@ -272,26 +272,26 @@ class DtlsServer(
272272
try {
273273
return ctx.encrypt(plainPacket)
274274
} catch (ex: SslException) {
275+
closeAndRemove()
275276
logger.warn("[{}] DTLS failed: {}", peerAddress, ex.message)
276277
reportSessionFinished(DtlsSessionLifecycleCallbacks.Reason.FAILED, ex)
277-
closeAndRemove()
278278
throw ex
279279
}
280280
}
281281

282282
fun timeout() {
283-
lifecycleCallbacks.sessionFinished(peerAddress, DtlsSessionLifecycleCallbacks.Reason.EXPIRED)
284283
sessions.remove(peerAddress, this)
285-
logger.info("[{}] DTLS connection expired", peerAddress)
286284
storeAndClose()
285+
logger.info("[{}] DTLS connection expired", peerAddress)
286+
lifecycleCallbacks.sessionFinished(peerAddress, DtlsSessionLifecycleCallbacks.Reason.EXPIRED)
287287
}
288288

289289
private fun reportSessionStarted() {
290-
lifecycleCallbacks.sessionStarted(peerAddress, ctx.cipherSuite, ctx.reloaded)
290+
executor.supply { lifecycleCallbacks.sessionStarted(peerAddress, ctx.cipherSuite, ctx.reloaded) }
291291
}
292292

293293
private fun reportSessionFinished(reason: DtlsSessionLifecycleCallbacks.Reason, err: Throwable? = null) {
294-
lifecycleCallbacks.sessionFinished(peerAddress, reason, err)
294+
executor.supply { lifecycleCallbacks.sessionFinished(peerAddress, reason, err) }
295295
}
296296
}
297297
}

kotlin-mbedtls/src/main/kotlin/org/opencoap/ssl/transport/DtlsSessionLifecycleCallbacks.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ interface DtlsSessionLifecycleCallbacks {
2323
SUCCEEDED, FAILED, CLOSED, EXPIRED
2424
}
2525
fun handshakeStarted(adr: InetSocketAddress) = Unit
26-
fun handshakeFinished(adr: InetSocketAddress, hanshakeStartTimestamp: Long, reason: Reason, throwable: Throwable? = null) = Unit
26+
fun handshakeFinished(adr: InetSocketAddress, hanshakeStartTimestamp: Long, hanshakeFinishTimestamp: Long, reason: Reason, throwable: Throwable? = null) = Unit
2727
fun sessionStarted(adr: InetSocketAddress, cipherSuite: String, reloaded: Boolean) = Unit
2828
fun sessionFinished(adr: InetSocketAddress, reason: Reason, throwable: Throwable? = null) = Unit
2929
}

kotlin-mbedtls/src/test/kotlin/org/opencoap/ssl/transport/DtlsServerTransportTest.kt

+17-18
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import io.mockk.clearMocks
2020
import io.mockk.confirmVerified
2121
import io.mockk.mockk
2222
import io.mockk.verify
23-
import io.mockk.verifyOrder
2423
import org.awaitility.kotlin.await
2524
import org.junit.jupiter.api.AfterEach
2625
import org.junit.jupiter.api.Assertions.assertEquals
@@ -113,11 +112,11 @@ class DtlsServerTransportTest {
113112
val clientAddress = client.localAddress()
114113
client.close()
115114

116-
verifyOrder {
115+
verify {
117116
sslLifecycleCallbacks.handshakeStarted(clientAddress)
118-
sslLifecycleCallbacks.handshakeFinished(clientAddress, any(), DtlsSessionLifecycleCallbacks.Reason.FAILED, ofType(HelloVerifyRequired::class))
117+
sslLifecycleCallbacks.handshakeFinished(clientAddress, any(), any(), DtlsSessionLifecycleCallbacks.Reason.FAILED, ofType(HelloVerifyRequired::class))
119118
sslLifecycleCallbacks.handshakeStarted(clientAddress)
120-
sslLifecycleCallbacks.handshakeFinished(clientAddress, any(), DtlsSessionLifecycleCallbacks.Reason.SUCCEEDED)
119+
sslLifecycleCallbacks.handshakeFinished(clientAddress, any(), any(), DtlsSessionLifecycleCallbacks.Reason.SUCCEEDED)
121120
sslLifecycleCallbacks.sessionStarted(clientAddress, any(), false)
122121
}
123122

@@ -165,11 +164,11 @@ class DtlsServerTransportTest {
165164
assertEquals(0, server.numberOfSessions())
166165
}
167166
assertFalse(srvReceive.isDone)
168-
verifyOrder {
167+
verify {
169168
sslLifecycleCallbacks.handshakeStarted(any())
170-
sslLifecycleCallbacks.handshakeFinished(any(), any(), DtlsSessionLifecycleCallbacks.Reason.FAILED, ofType(HelloVerifyRequired::class))
169+
sslLifecycleCallbacks.handshakeFinished(any(), any(), any(), DtlsSessionLifecycleCallbacks.Reason.FAILED, ofType(HelloVerifyRequired::class))
171170
sslLifecycleCallbacks.handshakeStarted(any())
172-
sslLifecycleCallbacks.handshakeFinished(any(), any(), DtlsSessionLifecycleCallbacks.Reason.FAILED, ofType(SslException::class))
171+
sslLifecycleCallbacks.handshakeFinished(any(), any(), any(), DtlsSessionLifecycleCallbacks.Reason.FAILED, ofType(SslException::class))
173172
}
174173

175174
verify(exactly = 0) {
@@ -193,9 +192,9 @@ class DtlsServerTransportTest {
193192

194193
client.close()
195194

196-
verifyOrder {
195+
verify {
197196
sslLifecycleCallbacks.handshakeStarted(any())
198-
sslLifecycleCallbacks.handshakeFinished(any(), any(), DtlsSessionLifecycleCallbacks.Reason.SUCCEEDED)
197+
sslLifecycleCallbacks.handshakeFinished(any(), any(), any(), DtlsSessionLifecycleCallbacks.Reason.SUCCEEDED)
199198
sslLifecycleCallbacks.sessionStarted(any(), any(), any())
200199
}
201200
}
@@ -237,11 +236,11 @@ class DtlsServerTransportTest {
237236
cliChannel.close()
238237

239238
verify(atMost = 100) {
240-
sslLifecycleCallbacks.handshakeFinished(any(), any(), DtlsSessionLifecycleCallbacks.Reason.FAILED, ofType(SslException::class))
239+
sslLifecycleCallbacks.handshakeFinished(any(), any(), any(), DtlsSessionLifecycleCallbacks.Reason.FAILED, ofType(SslException::class))
241240
}
242241

243242
verify(exactly = 0) {
244-
sslLifecycleCallbacks.handshakeFinished(any(), any(), DtlsSessionLifecycleCallbacks.Reason.FAILED, ofType(HelloVerifyRequired::class))
243+
sslLifecycleCallbacks.handshakeFinished(any(), any(), any(), DtlsSessionLifecycleCallbacks.Reason.FAILED, ofType(HelloVerifyRequired::class))
245244
}
246245
}
247246

@@ -286,7 +285,7 @@ class DtlsServerTransportTest {
286285
assertEquals(0, server.numberOfSessions())
287286
}
288287

289-
verifyOrder {
288+
verify {
290289
sslLifecycleCallbacks.sessionStarted(any(), any(), any())
291290
sslLifecycleCallbacks.sessionFinished(any(), DtlsSessionLifecycleCallbacks.Reason.CLOSED)
292291
}
@@ -308,12 +307,12 @@ class DtlsServerTransportTest {
308307

309308
// No handshake failures other than HelloVerifyRequired
310309
verify(exactly = 0) {
311-
sslLifecycleCallbacks.handshakeFinished(any(), any(), DtlsSessionLifecycleCallbacks.Reason.FAILED, not(ofType(HelloVerifyRequired::class)))
310+
sslLifecycleCallbacks.handshakeFinished(any(), any(), any(), DtlsSessionLifecycleCallbacks.Reason.FAILED, not(ofType(HelloVerifyRequired::class)))
312311
}
313312

314313
// One successful handshake must happen
315314
verify(exactly = 1) {
316-
sslLifecycleCallbacks.handshakeFinished(any(), any(), DtlsSessionLifecycleCallbacks.Reason.SUCCEEDED)
315+
sslLifecycleCallbacks.handshakeFinished(any(), any(), any(), DtlsSessionLifecycleCallbacks.Reason.SUCCEEDED)
317316
}
318317
}
319318

@@ -335,7 +334,7 @@ class DtlsServerTransportTest {
335334
cli.close()
336335

337336
verify(exactly = 1) {
338-
sslLifecycleCallbacks.handshakeFinished(any(), any(), DtlsSessionLifecycleCallbacks.Reason.FAILED, and(ofType(SslException::class), not(ofType(HelloVerifyRequired::class))))
337+
sslLifecycleCallbacks.handshakeFinished(any(), any(), any(), DtlsSessionLifecycleCallbacks.Reason.FAILED, and(ofType(SslException::class), not(ofType(HelloVerifyRequired::class))))
339338
}
340339
}
341340

@@ -387,11 +386,11 @@ class DtlsServerTransportTest {
387386
}
388387
client.close()
389388

390-
verifyOrder() {
389+
verify() {
391390
sslLifecycleCallbacks.handshakeStarted(any())
392-
sslLifecycleCallbacks.handshakeFinished(any(), any(), DtlsSessionLifecycleCallbacks.Reason.FAILED, ofType(HelloVerifyRequired::class))
391+
sslLifecycleCallbacks.handshakeFinished(any(), any(), any(), DtlsSessionLifecycleCallbacks.Reason.FAILED, ofType(HelloVerifyRequired::class))
393392
sslLifecycleCallbacks.handshakeStarted(any())
394-
sslLifecycleCallbacks.handshakeFinished(any(), any(), DtlsSessionLifecycleCallbacks.Reason.SUCCEEDED)
393+
sslLifecycleCallbacks.handshakeFinished(any(), any(), any(), DtlsSessionLifecycleCallbacks.Reason.SUCCEEDED)
395394
sslLifecycleCallbacks.sessionStarted(any(), any(), false)
396395
sslLifecycleCallbacks.sessionFinished(any(), DtlsSessionLifecycleCallbacks.Reason.EXPIRED)
397396
sslLifecycleCallbacks.sessionStarted(any(), any(), true)

0 commit comments

Comments
 (0)