-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
233 additions
and
145 deletions.
There are no files selected for viewing
26 changes: 26 additions & 0 deletions
26
library/src/commonMain/kotlin/com/tidal/networktime/internal/FromEpochNtpTimestampFactory.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package com.tidal.networktime.internal | ||
|
||
import kotlin.time.Duration | ||
import kotlin.time.Duration.Companion.milliseconds | ||
|
||
internal class FromEpochNtpTimestampFactory { | ||
operator fun invoke(epochTime: Duration) = NtpTimestamp(epochTime.epochTimeAsNtpTime) | ||
|
||
private val Duration.epochTimeAsNtpTime: Duration | ||
get() { | ||
val millis = inWholeMilliseconds | ||
val useBase1 = millis < NtpPacket.NTP_TIMESTAMP_BASE_WITH_EPOCH_MSB_0_MILLISECONDS | ||
val baseTimeMillis = millis - | ||
if (useBase1) { | ||
NtpPacket.NTP_TIMESTAMP_BASE_WITH_EPOCH_MSB_1_MILLISECONDS | ||
} else { | ||
NtpPacket.NTP_TIMESTAMP_BASE_WITH_EPOCH_MSB_0_MILLISECONDS | ||
} | ||
var seconds = baseTimeMillis / 1_000 | ||
if (useBase1) { | ||
seconds = seconds or 0x80000000L | ||
} | ||
val fraction = baseTimeMillis % 1_000 * 0x100000000L / 1_000 | ||
return (seconds shl 32 or fraction).milliseconds | ||
} | ||
} |
67 changes: 53 additions & 14 deletions
67
library/src/commonMain/kotlin/com/tidal/networktime/internal/NtpExchangeResult.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,66 @@ | ||
@file:Suppress("DuplicatedCode") // We need the duplicated variable list for performance reasons | ||
|
||
package com.tidal.networktime.internal | ||
|
||
import kotlin.time.Duration | ||
import kotlin.time.Duration.Companion.milliseconds | ||
|
||
internal data class NtpExchangeResult( | ||
val timeMeasured: Duration, | ||
val returnTime: Duration, | ||
val ntpPacket: NtpPacket, | ||
) { | ||
val roundTripDelay: Duration | ||
get() = timeMeasured - ntpPacket.run { | ||
originateEpochTimestamp - | ||
( | ||
transmitEpochTimestamp - | ||
receiveEpochTimestamp | ||
) | ||
get() = ntpPacket.run { | ||
val originEpochMillis = originateEpochTimestamp.epochTime.inWholeMilliseconds | ||
val receiveNtpMillis = receiveEpochTimestamp.ntpTime.inWholeMilliseconds | ||
val receiveEpochMillis = receiveEpochTimestamp.epochTime.inWholeMilliseconds | ||
val transmitNtpMillis = transmitEpochTimestamp.ntpTime.inWholeMilliseconds | ||
val transmitEpochMillis = transmitEpochTimestamp.epochTime.inWholeMilliseconds | ||
val returnTimeMillis = returnTime.inWholeMilliseconds | ||
if (receiveNtpMillis == 0L || transmitNtpMillis == 0L) { | ||
return@run if (returnTimeMillis >= originEpochMillis) { | ||
(returnTimeMillis - originEpochMillis).milliseconds | ||
} else { | ||
Duration.INFINITE | ||
} | ||
} | ||
var delayMillis = returnTimeMillis - originEpochMillis | ||
val deltaMillis = transmitEpochMillis - receiveEpochMillis | ||
if (deltaMillis <= delayMillis) { | ||
delayMillis -= deltaMillis | ||
} else if (deltaMillis - delayMillis == 1L) { | ||
if (delayMillis != 0L) { | ||
delayMillis = 0 | ||
} | ||
} | ||
delayMillis.milliseconds | ||
} | ||
|
||
val clockOffset: Duration | ||
get() = ntpPacket.run { | ||
( | ||
receiveEpochTimestamp - | ||
originateEpochTimestamp + | ||
transmitEpochTimestamp - | ||
timeMeasured | ||
) | ||
} / 2 | ||
val originNtpMillis = originateEpochTimestamp.ntpTime.inWholeMilliseconds | ||
val originEpochMillis = originateEpochTimestamp.epochTime.inWholeMilliseconds | ||
val receiveNtpMillis = receiveEpochTimestamp.ntpTime.inWholeMilliseconds | ||
val receiveEpochMillis = receiveEpochTimestamp.epochTime.inWholeMilliseconds | ||
val transmitNtpMillis = transmitEpochTimestamp.ntpTime.inWholeMilliseconds | ||
val transmitEpochMillis = transmitEpochTimestamp.epochTime.inWholeMilliseconds | ||
val returnTimeMillis = returnTime.inWholeMilliseconds | ||
if (originNtpMillis == 0L) { | ||
if (transmitNtpMillis != 0L) { | ||
return@run (transmitEpochMillis - returnTimeMillis).milliseconds | ||
} | ||
return@run Duration.INFINITE | ||
} | ||
if (receiveNtpMillis == 0L || transmitNtpMillis == 0L) { | ||
if (receiveNtpMillis != 0L) { | ||
return@run (receiveEpochMillis - originEpochMillis).milliseconds | ||
} | ||
if (transmitNtpMillis != 0L) { | ||
return@run (transmitEpochMillis - returnTimeMillis).milliseconds | ||
} | ||
return@run Duration.INFINITE | ||
} | ||
((receiveEpochMillis - originEpochMillis + transmitEpochMillis - returnTimeMillis) / 2) | ||
.milliseconds | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 11 additions & 17 deletions
28
library/src/commonMain/kotlin/com/tidal/networktime/internal/NtpPacket.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,25 @@ | ||
package com.tidal.networktime.internal | ||
|
||
import kotlin.time.Duration | ||
import kotlin.time.Duration.Companion.days | ||
|
||
internal data class NtpPacket( | ||
val leapIndicator: Int = 0, | ||
val versionNumber: Int, | ||
val mode: Int, | ||
val stratum: Byte = 0, | ||
val poll: Byte = 0, | ||
val precision: Byte = 0, | ||
val stratum: Int = 0, | ||
val poll: Duration = Duration.INFINITE, | ||
val precision: Duration = Duration.INFINITE, | ||
val rootDelay: Duration = Duration.INFINITE, | ||
val rootDispersion: Duration = Duration.INFINITE, | ||
val referenceIdentifier: Int = 0, | ||
val referenceEpochTimestamp: Duration = Duration.INFINITE, | ||
val originateEpochTimestamp: Duration = Duration.INFINITE, | ||
val receiveEpochTimestamp: Duration = Duration.INFINITE, | ||
val transmitEpochTimestamp: Duration = Duration.INFINITE, | ||
val referenceIdentifier: String = "", | ||
val referenceEpochTimestamp: NtpTimestamp = NtpTimestamp(Duration.ZERO), | ||
val originateEpochTimestamp: NtpTimestamp = NtpTimestamp(Duration.ZERO), | ||
val receiveEpochTimestamp: NtpTimestamp = NtpTimestamp(Duration.ZERO), | ||
/** Keep this mutable to minimize delay (avoids an allocation) **/ | ||
var transmitEpochTimestamp: NtpTimestamp = NtpTimestamp(Duration.ZERO), | ||
) { | ||
init { | ||
// Check sizes of fields whose type does not match their corresponding size in the actual packet | ||
check(leapIndicator <= 0b0011) | ||
check(versionNumber <= 0b0111) | ||
check(mode <= 0b0111) | ||
} | ||
|
||
companion object { | ||
val NTP_EPOCH_OFFSET_WITH_EPOCH = (365.days * 70 + 17.days) | ||
const val NTP_TIMESTAMP_BASE_WITH_EPOCH_MSB_0_MILLISECONDS = 2085978496000 | ||
const val NTP_TIMESTAMP_BASE_WITH_EPOCH_MSB_1_MILLISECONDS = -2208988800000 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.