diff --git a/.idea/artifacts/library_jvm.xml b/.idea/artifacts/library_jvm.xml
index 757db4f6..3c630d1e 100644
--- a/.idea/artifacts/library_jvm.xml
+++ b/.idea/artifacts/library_jvm.xml
@@ -1,8 +1,6 @@
$PROJECT_DIR$/library/build/libs
-
-
-
+
\ No newline at end of file
diff --git a/.idea/artifacts/samples_multiplatform_kotlin_shared_jvm.xml b/.idea/artifacts/samples_multiplatform_kotlin_shared_jvm.xml
index 036e9d10..5f695921 100644
--- a/.idea/artifacts/samples_multiplatform_kotlin_shared_jvm.xml
+++ b/.idea/artifacts/samples_multiplatform_kotlin_shared_jvm.xml
@@ -1,8 +1,6 @@
$PROJECT_DIR$/samples/multiplatform-kotlin/shared/build/libs
-
-
-
+
\ No newline at end of file
diff --git a/library/src/appleMain/kotlin/com/tidal/networktime/internal/HostNameResolver.kt b/library/src/appleMain/kotlin/com/tidal/networktime/internal/HostNameResolver.kt
index 6951eb24..585a7322 100644
--- a/library/src/appleMain/kotlin/com/tidal/networktime/internal/HostNameResolver.kt
+++ b/library/src/appleMain/kotlin/com/tidal/networktime/internal/HostNameResolver.kt
@@ -6,6 +6,7 @@ import kotlinx.cinterop.ByteVar
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.alloc
import kotlinx.cinterop.allocArray
+import kotlinx.cinterop.convert
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.pointed
import kotlinx.cinterop.ptr
@@ -51,8 +52,8 @@ internal actual class HostNameResolver {
timeout: Duration,
includeINET: Boolean,
includeINET6: Boolean,
- ): Iterable> {
- var ret: Iterable>? = emptySet()
+ ): Iterable {
+ var ret: Iterable? = emptySet()
try {
ret = withTimeoutOrNull(timeout) { invokeInternal(hostName, includeINET, includeINET6) }
} finally {
@@ -70,7 +71,7 @@ internal actual class HostNameResolver {
hostName: String,
includeINET: Boolean,
includeINET6: Boolean,
- ): Iterable> {
+ ): Iterable {
hostReference = CFBridgingRetain(hostName as NSString)
cfHost = CFHostCreateWithName(kCFAllocatorDefault, hostReference as CFStringRef)
CFHostStartInfoResolution(cfHost, kCFHostAddresses, null)
@@ -82,11 +83,11 @@ internal actual class HostNameResolver {
addresses.takeIf { hasResolved.value }
addresses ?: return emptySet()
val count = CFArrayGetCount(addresses)
- val ret = mutableSetOf>()
+ val ret = mutableSetOf()
(0 until count).forEach {
val socketAddressData = CFArrayGetValueAtIndex(addresses, it) as CFDataRef
val sockAddr = CFDataGetBytePtr(socketAddressData)!!.reinterpret().pointed
- val addrPrettyToProtocolFamily = when (sockAddr.sa_family.toInt()) {
+ val addrPretty = when (sockAddr.sa_family.toInt()) {
AF_INET -> {
if (includeINET) {
val buffer = allocArray(INET_ADDRSTRLEN)
@@ -94,9 +95,9 @@ internal actual class HostNameResolver {
AF_INET,
sockAddr.reinterpret().sin_addr.readValue(),
buffer,
- INET_ADDRSTRLEN.toUInt(),
+ INET_ADDRSTRLEN.convert(),
)
- buffer.toKString() to ProtocolFamily.INET
+ buffer.toKString()
} else {
null
}
@@ -109,9 +110,9 @@ internal actual class HostNameResolver {
AF_INET6,
sockAddr.reinterpret().sin6_addr.readValue(),
buffer,
- INET6_ADDRSTRLEN.toUInt(),
+ INET6_ADDRSTRLEN.convert(),
)
- buffer.toKString() to ProtocolFamily.INET6
+ buffer.toKString()
} else {
null
}
@@ -121,8 +122,8 @@ internal actual class HostNameResolver {
null
}
}
- if (addrPrettyToProtocolFamily != null) {
- ret.add(addrPrettyToProtocolFamily)
+ if (addrPretty != null) {
+ ret.add(addrPretty)
}
}
ret
@@ -130,6 +131,7 @@ internal actual class HostNameResolver {
}
private fun clear() {
+ cfHost?.let { CFRelease(it) }
cfHost = null
hostReference?.let { CFRelease(it) }
hostReference = null
diff --git a/library/src/appleMain/kotlin/com/tidal/networktime/internal/NTPUDPSocketOperations.kt b/library/src/appleMain/kotlin/com/tidal/networktime/internal/NTPUDPSocketOperations.kt
index ce2f74b8..b34f6c76 100644
--- a/library/src/appleMain/kotlin/com/tidal/networktime/internal/NTPUDPSocketOperations.kt
+++ b/library/src/appleMain/kotlin/com/tidal/networktime/internal/NTPUDPSocketOperations.kt
@@ -1,158 +1,106 @@
package com.tidal.networktime.internal
-import com.tidal.networktime.ProtocolFamily
+import kotlinx.cinterop.ByteVar
+import kotlinx.cinterop.CPointer
import kotlinx.cinterop.ExperimentalForeignApi
-import kotlinx.cinterop.StableRef
-import kotlinx.cinterop.alloc
-import kotlinx.cinterop.asStableRef
+import kotlinx.cinterop.allocArray
+import kotlinx.cinterop.convert
import kotlinx.cinterop.memScoped
-import kotlinx.cinterop.pointed
-import kotlinx.cinterop.ptr
import kotlinx.cinterop.refTo
import kotlinx.cinterop.reinterpret
-import kotlinx.cinterop.sizeOf
-import kotlinx.cinterop.staticCFunction
-import kotlinx.cinterop.toCPointer
-import kotlinx.cinterop.toLong
-import kotlinx.cinterop.value
-import kotlinx.coroutines.delay
+import kotlinx.cinterop.set
+import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.withTimeout
-import platform.CoreFoundation.CFDataCreate
-import platform.CoreFoundation.CFDataGetBytes
-import platform.CoreFoundation.CFDataGetLength
-import platform.CoreFoundation.CFDataRefVar
-import platform.CoreFoundation.CFRangeMake
-import platform.CoreFoundation.CFSocketCallBack
-import platform.CoreFoundation.CFSocketConnectToAddress
-import platform.CoreFoundation.CFSocketContext
-import platform.CoreFoundation.CFSocketCreate
-import platform.CoreFoundation.CFSocketInvalidate
-import platform.CoreFoundation.CFSocketRef
-import platform.CoreFoundation.CFSocketSendData
-import platform.CoreFoundation.kCFAllocatorDefault
-import platform.CoreFoundation.kCFSocketDataCallBack
-import platform.darwin.inet_aton
-import platform.darwin.inet_pton
-import platform.posix.AF_INET
-import platform.posix.AF_INET6
-import platform.posix.IPPROTO_UDP
-import platform.posix.PF_INET
-import platform.posix.PF_INET6
-import platform.posix.SIGPIPE
-import platform.posix.SIG_IGN
-import platform.posix.SOCK_DGRAM
-import platform.posix.signal
-import platform.posix.sockaddr_in
-import platform.posix.sockaddr_in6
+import platform.Network.NW_CONNECTION_FINAL_MESSAGE_CONTEXT
+import platform.Network.NW_PARAMETERS_DEFAULT_CONFIGURATION
+import platform.Network.NW_PARAMETERS_DISABLE_PROTOCOL
+import platform.Network.nw_connection_create
+import platform.Network.nw_connection_force_cancel
+import platform.Network.nw_connection_receive
+import platform.Network.nw_connection_send
+import platform.Network.nw_connection_set_queue
+import platform.Network.nw_connection_set_state_changed_handler
+import platform.Network.nw_connection_start
+import platform.Network.nw_connection_state_cancelled
+import platform.Network.nw_connection_state_failed
+import platform.Network.nw_connection_state_ready
+import platform.Network.nw_connection_state_t
+import platform.Network.nw_connection_t
+import platform.Network.nw_endpoint_create_host
+import platform.Network.nw_error_t
+import platform.Network.nw_parameters_create_secure_udp
+import platform.darwin._dispatch_data_destructor_free
+import platform.darwin.dispatch_data_apply
+import platform.darwin.dispatch_data_create
+import platform.darwin.dispatch_data_t
+import platform.darwin.dispatch_get_current_queue
+import platform.posix.memcpy
+import kotlin.test.assertEquals
+import kotlin.test.assertNull
import kotlin.time.Duration
-import kotlin.time.Duration.Companion.seconds
-import kotlin.time.DurationUnit
-@OptIn(ExperimentalForeignApi::class)
@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
internal actual class NTPUDPSocketOperations {
- private var cfSocket: CFSocketRef? = null
- private var userDataRef: StableRef? = null
+ private var connection: nw_connection_t = null
- actual suspend fun prepareSocket(
- address: String,
- protocolFamily: ProtocolFamily,
- portNumber: Int,
- connectTimeout: Duration,
- ) {
- userDataRef = StableRef.create(UserData())
- val callback: CFSocketCallBack = staticCFunction { _, callbackType, _, data, info ->
- val userData = info!!.asStableRef().get()
- if (callbackType != kCFSocketDataCallBack) {
- return@staticCFunction
- }
- val reinterpretedData = data!!.reinterpret().pointed.value
- val length = CFDataGetLength(reinterpretedData)
- val range = CFRangeMake(0, length)
- val bridgeBuffer = UByteArray(length.toInt())
- CFDataGetBytes(reinterpretedData, range, bridgeBuffer.refTo(0))
- userData.apply {
- buffer = bridgeBuffer.toByteArray()
- exchangeCompleted = true
+ actual suspend fun prepare(address: String, portNumber: Int, connectTimeout: Duration) {
+ val parameters = nw_parameters_create_secure_udp(
+ NW_PARAMETERS_DISABLE_PROTOCOL,
+ NW_PARAMETERS_DEFAULT_CONFIGURATION
+ )
+ val endpoint = nw_endpoint_create_host(address, portNumber.toString())
+ connection = nw_connection_create(endpoint, parameters)
+ nw_connection_set_queue(connection, dispatch_get_current_queue())
+ val connectionStateDeferred = CompletableDeferred()
+ nw_connection_set_state_changed_handler(connection) { state: nw_connection_state_t, _ ->
+ when (state) {
+ nw_connection_state_ready, nw_connection_state_failed, nw_connection_state_cancelled ->
+ connectionStateDeferred.complete(state)
}
}
- signal(SIGPIPE, SIG_IGN)
- cfSocket = memScoped {
- val socketContext = alloc {
- version = 0
- info = userDataRef!!.asCPointer()
- retain = null
- release = null
- copyDescription = null
- }
- val socket = CFSocketCreate(
- kCFAllocatorDefault,
- when (protocolFamily) {
- ProtocolFamily.INET -> PF_INET
- ProtocolFamily.INET6 -> PF_INET6
- },
- SOCK_DGRAM,
- IPPROTO_UDP,
- kCFSocketDataCallBack,
- callback,
- socketContext.ptr,
- )
- val addrCFDataRef = when (protocolFamily) {
- ProtocolFamily.INET -> alloc {
- sin_family = AF_INET.toUByte()
- sin_port = portNumber.toUShort()
- inet_aton(address, sin_addr.ptr)
- }.run {
- CFDataCreate(kCFAllocatorDefault, ptr.toLong().toCPointer(), sizeOf())
- }
-
- ProtocolFamily.INET6 -> {
- alloc {
- sin6_family = AF_INET6.toUByte()
- sin6_port = portNumber.toUShort()
- inet_pton(AF_INET6, address, sin6_addr.ptr)
- }.run {
- CFDataCreate(kCFAllocatorDefault, ptr.toLong().toCPointer(), sizeOf())
- }
- }
- }
- CFSocketConnectToAddress(
- socket,
- addrCFDataRef,
- connectTimeout.toDouble(DurationUnit.MILLISECONDS),
- )
- socket
+ nw_connection_start(connection)
+ withTimeout(connectTimeout) {
+ assertEquals(nw_connection_state_ready, connectionStateDeferred.await())
}
}
- actual suspend fun exchangeInPlace(buffer: ByteArray, readTimeout: Duration) {
- val bufferCFDataRef = CFDataCreate(
- kCFAllocatorDefault,
- buffer.asUByteArray().refTo(0),
- buffer.size.toLong(),
- )
- CFSocketSendData(
- cfSocket,
- null,
- bufferCFDataRef,
- Duration.INFINITE.toDouble(DurationUnit.MILLISECONDS),
- )
- withTimeout(readTimeout) {
- while (!userDataRef!!.get().exchangeCompleted) {
- delay(1.seconds)
+ @OptIn(ExperimentalForeignApi::class)
+ actual suspend fun exchange(buffer: ByteArray, readTimeout: Duration) {
+ val toSendData = memScoped {
+ val cArray = allocArray(buffer.size)
+ buffer.forEachIndexed { i, it ->
+ cArray[i] = it
}
+ cArray
+ }
+ nw_connection_send(
+ connection,
+ dispatch_data_create(toSendData, buffer.size.convert(), null, _dispatch_data_destructor_free),
+ NW_CONNECTION_FINAL_MESSAGE_CONTEXT,
+ true
+ ) {
+ assertNull(it)
+ }
+ val connectionReceptionDeferred = CompletableDeferred()
+ nw_connection_receive(
+ connection,
+ 1.convert(),
+ buffer.size.convert()
+ ) { content: dispatch_data_t, _, _, error: nw_error_t ->
+ assertNull(error)
+ connectionReceptionDeferred.complete(content)
+ }
+ val receivedData = withTimeout(readTimeout) {
+ connectionReceptionDeferred.await()
+ }
+ dispatch_data_apply(receivedData) { _, _, regionPointer, _ ->
+ memcpy(buffer.refTo(0), regionPointer!!.reinterpret(), buffer.size.convert())
+ false
}
}
- actual fun closeSocket() {
- CFSocketInvalidate(cfSocket)
- cfSocket = null
- userDataRef?.dispose()
- userDataRef = null
- }
-
- private class UserData {
- var exchangeCompleted = false
- var buffer: ByteArray = byteArrayOf()
+ actual fun tearDown() {
+ nw_connection_force_cancel(connection)
+ connection = null
}
}
diff --git a/library/src/commonMain/kotlin/com/tidal/networktime/SNTPClient.kt b/library/src/commonMain/kotlin/com/tidal/networktime/SNTPClient.kt
index 6107da81..ca0b6404 100644
--- a/library/src/commonMain/kotlin/com/tidal/networktime/SNTPClient.kt
+++ b/library/src/commonMain/kotlin/com/tidal/networktime/SNTPClient.kt
@@ -1,9 +1,6 @@
package com.tidal.networktime
import com.tidal.networktime.internal.SNTPClientImpl
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.DelicateCoroutinesApi
-import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import okio.Path.Companion.toPath
import kotlin.time.Duration
@@ -14,7 +11,6 @@ import kotlin.time.Duration.Companion.seconds
* [ntpServers] to obtain information about their provided time.
*
* @param ntpServers Representation of supported unicast NTP sources.
- * @param coroutineScope The scope where synchronization will run on.
* @param synchronizationInterval The amount of time to wait between a sync finishing and the next
* one being started.
* @param backupFilePath A path to a file that will be used to save the selected received NTP
@@ -23,17 +19,13 @@ import kotlin.time.Duration.Companion.seconds
* packet has been received and processed. If not `null` but writing or reading fail when attempted,
* program execution will continue as if it had been `null` until the next attempt.
*/
-class SNTPClient
-@OptIn(DelicateCoroutinesApi::class)
-constructor(
+class SNTPClient(
vararg val ntpServers: NTPServer,
- val coroutineScope: CoroutineScope = GlobalScope,
val synchronizationInterval: Duration = 64.seconds,
val backupFilePath: String? = null,
) {
private val delegate = SNTPClientImpl(
ntpServers,
- coroutineScope,
backupFilePath?.toPath(),
synchronizationInterval,
)
diff --git a/library/src/commonMain/kotlin/com/tidal/networktime/internal/HostNameResolver.kt b/library/src/commonMain/kotlin/com/tidal/networktime/internal/HostNameResolver.kt
index acec66cf..f798f5b2 100644
--- a/library/src/commonMain/kotlin/com/tidal/networktime/internal/HostNameResolver.kt
+++ b/library/src/commonMain/kotlin/com/tidal/networktime/internal/HostNameResolver.kt
@@ -1,6 +1,5 @@
package com.tidal.networktime.internal
-import com.tidal.networktime.ProtocolFamily
import kotlin.time.Duration
@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
@@ -10,5 +9,5 @@ internal expect class HostNameResolver() {
timeout: Duration,
includeINET: Boolean,
includeINET6: Boolean,
- ): Iterable>
+ ): Iterable
}
diff --git a/library/src/commonMain/kotlin/com/tidal/networktime/internal/NTPExchanger.kt b/library/src/commonMain/kotlin/com/tidal/networktime/internal/NTPExchanger.kt
index f37940be..9173b30a 100644
--- a/library/src/commonMain/kotlin/com/tidal/networktime/internal/NTPExchanger.kt
+++ b/library/src/commonMain/kotlin/com/tidal/networktime/internal/NTPExchanger.kt
@@ -1,6 +1,5 @@
package com.tidal.networktime.internal
-import com.tidal.networktime.ProtocolFamily
import kotlin.time.Duration
internal class NTPExchanger(
@@ -10,25 +9,24 @@ internal class NTPExchanger(
) {
suspend operator fun invoke(
address: String,
- protocolFamily: ProtocolFamily,
connectTimeout: Duration,
queryReadTimeout: Duration,
ntpVersion: UByte,
): NTPExchangeResult? {
val ntpUdpSocketOperations = NTPUDPSocketOperations()
return try {
- ntpUdpSocketOperations.prepareSocket(address, protocolFamily, NTP_PORT_NUMBER, connectTimeout)
+ ntpUdpSocketOperations.prepare(address, NTP_PORT_NUMBER, connectTimeout)
val ntpPacket = NTPPacket(versionNumber = ntpVersion.toInt(), mode = NTP_MODE_CLIENT)
val requestTime = referenceClock.referenceEpochTime
ntpPacket.transmitEpochTimestamp = EpochTimestamp(requestTime).asNTPTimestamp
val buffer = ntpPacketSerializer(ntpPacket)
- ntpUdpSocketOperations.exchangeInPlace(buffer, queryReadTimeout)
+ ntpUdpSocketOperations.exchange(buffer, queryReadTimeout)
val returnTime = referenceClock.referenceEpochTime
ntpPacketDeserializer(buffer)?.let { NTPExchangeResult(returnTime, it) }
} catch (_: Throwable) {
null
} finally {
- ntpUdpSocketOperations.closeSocket()
+ ntpUdpSocketOperations.tearDown()
}
}
diff --git a/library/src/commonMain/kotlin/com/tidal/networktime/internal/NTPUDPSocketOperations.kt b/library/src/commonMain/kotlin/com/tidal/networktime/internal/NTPUDPSocketOperations.kt
index d31e8945..49d1df4c 100644
--- a/library/src/commonMain/kotlin/com/tidal/networktime/internal/NTPUDPSocketOperations.kt
+++ b/library/src/commonMain/kotlin/com/tidal/networktime/internal/NTPUDPSocketOperations.kt
@@ -1,18 +1,12 @@
package com.tidal.networktime.internal
-import com.tidal.networktime.ProtocolFamily
import kotlin.time.Duration
@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
internal expect class NTPUDPSocketOperations() {
- suspend fun prepareSocket(
- address: String,
- protocolFamily: ProtocolFamily,
- portNumber: Int,
- connectTimeout: Duration,
- )
+ suspend fun prepare(address: String, portNumber: Int, connectTimeout: Duration)
- suspend fun exchangeInPlace(buffer: ByteArray, readTimeout: Duration)
+ suspend fun exchange(buffer: ByteArray, readTimeout: Duration)
- fun closeSocket()
+ fun tearDown()
}
diff --git a/library/src/commonMain/kotlin/com/tidal/networktime/internal/SNTPClientImpl.kt b/library/src/commonMain/kotlin/com/tidal/networktime/internal/SNTPClientImpl.kt
index 9d31a207..a4f9386c 100644
--- a/library/src/commonMain/kotlin/com/tidal/networktime/internal/SNTPClientImpl.kt
+++ b/library/src/commonMain/kotlin/com/tidal/networktime/internal/SNTPClientImpl.kt
@@ -1,15 +1,15 @@
package com.tidal.networktime.internal
import com.tidal.networktime.NTPServer
-import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.IO
import okio.Path
import kotlin.time.Duration
-internal class SNTPClientImpl(
+internal class SNTPClientImpl @OptIn(DelicateCoroutinesApi::class) constructor(
ntpServers: Array,
- coroutineScope: CoroutineScope,
backupFilePath: Path?,
syncInterval: Duration,
private val referenceClock: KotlinXDateTimeSystemClock = KotlinXDateTimeSystemClock(),
@@ -23,7 +23,7 @@ internal class SNTPClientImpl(
OperationCoordinator(
mutableState,
synchronizationResultProcessor,
- coroutineScope,
+ GlobalScope,
Dispatchers.IO,
syncInterval,
ntpServers.asIterable(),
diff --git a/library/src/commonMain/kotlin/com/tidal/networktime/internal/SyncSingular.kt b/library/src/commonMain/kotlin/com/tidal/networktime/internal/SyncSingular.kt
index 302672a8..c8b28991 100644
--- a/library/src/commonMain/kotlin/com/tidal/networktime/internal/SyncSingular.kt
+++ b/library/src/commonMain/kotlin/com/tidal/networktime/internal/SyncSingular.kt
@@ -3,9 +3,8 @@ package com.tidal.networktime.internal
import com.tidal.networktime.NTPServer
import com.tidal.networktime.NTPVersion
import com.tidal.networktime.ProtocolFamily
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.IO
import kotlinx.coroutines.async
+import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
@@ -18,7 +17,7 @@ internal class SyncSingular(
) {
suspend operator fun invoke() {
val selectedResult = ntpServers.map {
- withContext(Dispatchers.IO) {
+ withContext(currentCoroutineContext()) {
async { pickNTPPacketWithShortestRoundTrip(it) }
}
}.flatMap {
@@ -45,11 +44,10 @@ internal class SyncSingular(
dnsResolutionTimeout,
ProtocolFamily.INET in protocolFamilies,
ProtocolFamily.INET6 in protocolFamilies,
- ).map { (resolvedName, resolvedProtocolFamily) ->
+ ).map { resolvedName ->
(1..queriesPerResolvedAddress).mapNotNull {
val ret = ntpExchanger(
resolvedName,
- resolvedProtocolFamily,
queryConnectTimeout,
queryReadTimeout,
when (ntpVersion) {
diff --git a/library/src/jvmMain/kotlin/com/tidal/networktime/internal/HostNameResolver.kt b/library/src/jvmMain/kotlin/com/tidal/networktime/internal/HostNameResolver.kt
index 8c7c8449..4c52465b 100644
--- a/library/src/jvmMain/kotlin/com/tidal/networktime/internal/HostNameResolver.kt
+++ b/library/src/jvmMain/kotlin/com/tidal/networktime/internal/HostNameResolver.kt
@@ -14,7 +14,7 @@ internal actual class HostNameResolver {
timeout: Duration,
includeINET: Boolean,
includeINET6: Boolean,
- ): Iterable> = withTimeoutOrNull(timeout) {
+ ): Iterable = withTimeoutOrNull(timeout) {
InetAddress.getAllByName(hostName)
}?.mapNotNull {
val protocolFamily = when (it) {
@@ -24,7 +24,7 @@ internal actual class HostNameResolver {
}
when {
protocolFamily == ProtocolFamily.INET && includeINET ||
- protocolFamily == ProtocolFamily.INET6 && includeINET6 -> it.hostAddress to protocolFamily
+ protocolFamily == ProtocolFamily.INET6 && includeINET6 -> it.hostAddress
else -> null
}
diff --git a/library/src/jvmMain/kotlin/com/tidal/networktime/internal/NTPUDPSocketOperations.kt b/library/src/jvmMain/kotlin/com/tidal/networktime/internal/NTPUDPSocketOperations.kt
index 9dfcdcfe..8874155f 100644
--- a/library/src/jvmMain/kotlin/com/tidal/networktime/internal/NTPUDPSocketOperations.kt
+++ b/library/src/jvmMain/kotlin/com/tidal/networktime/internal/NTPUDPSocketOperations.kt
@@ -1,8 +1,5 @@
package com.tidal.networktime.internal
-import com.tidal.networktime.ProtocolFamily
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeout
import java.net.DatagramPacket
import java.net.DatagramSocket
@@ -10,30 +7,25 @@ import java.net.InetAddress
import kotlin.time.Duration
import kotlin.time.DurationUnit
-@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
+@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING", "BlockingMethodInNonBlockingContext")
internal actual class NTPUDPSocketOperations {
- private lateinit var datagramSocket: DatagramSocket
+ private var datagramSocket: DatagramSocket? = null
- actual suspend fun prepareSocket(
- address: String,
- protocolFamily: ProtocolFamily,
- portNumber: Int,
- connectTimeout: Duration,
- ) = withTimeout(connectTimeout) {
+ actual suspend fun prepare(address: String, portNumber: Int, connectTimeout: Duration) {
datagramSocket = DatagramSocket()
- datagramSocket.connect(InetAddress.getByName(address), portNumber)
+ withTimeout(connectTimeout) {
+ datagramSocket!!.connect(InetAddress.getByName(address), portNumber)
+ }
}
- actual suspend fun exchangeInPlace(buffer: ByteArray, readTimeout: Duration) {
+ actual suspend fun exchange(buffer: ByteArray, readTimeout: Duration) {
val exchangePacket = DatagramPacket(buffer, buffer.size)
- withContext(Dispatchers.IO) {
- datagramSocket.send(exchangePacket)
- datagramSocket.soTimeout = readTimeout.toInt(DurationUnit.MILLISECONDS)
- datagramSocket.receive(exchangePacket)
- }
+ datagramSocket!!.send(exchangePacket)
+ datagramSocket!!.soTimeout = readTimeout.toInt(DurationUnit.MILLISECONDS)
+ datagramSocket!!.receive(exchangePacket)
}
- actual fun closeSocket() {
- datagramSocket.close()
+ actual fun tearDown() {
+ datagramSocket?.close()
}
}
diff --git a/samples/multiplatform-kotlin/iOS.xcodeproj/project.xcworkspace/xcuserdata/jantonio.xcuserdatad/UserInterfaceState.xcuserstate b/samples/multiplatform-kotlin/iOS.xcodeproj/project.xcworkspace/xcuserdata/jantonio.xcuserdatad/UserInterfaceState.xcuserstate
index 1d9413c7..178ec82d 100644
Binary files a/samples/multiplatform-kotlin/iOS.xcodeproj/project.xcworkspace/xcuserdata/jantonio.xcuserdatad/UserInterfaceState.xcuserstate and b/samples/multiplatform-kotlin/iOS.xcodeproj/project.xcworkspace/xcuserdata/jantonio.xcuserdatad/UserInterfaceState.xcuserstate differ