Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop support for anycast NTP servers #8

Merged
merged 2 commits into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
build/
.gradle
local.properties
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion .idea/artifacts/library_js.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 0 additions & 17 deletions .idea/gradle.xml

This file was deleted.

5 changes: 5 additions & 0 deletions .idea/jarRepositories.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 1 addition & 4 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ buildscript {

allprojects {
repositories {
google()
mavenCentral()
}
}

tasks.register("clean", Delete::class) {
delete(rootProject.buildDir)
}
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
52 changes: 32 additions & 20 deletions library/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,40 @@ kotlin {
targetHierarchy.default()

jvm()
androidTarget()
ios()
linuxX64()
macosX64()
macosArm64()
iosSimulatorArm64()
iosX64()
linuxArm64()
watchosSimulatorArm64()
watchosX64()
watchosArm32()
watchosArm64()
tvosSimulatorArm64()
tvosX64()
tvosArm64()
iosArm64()
androidTarget {
compilations.all {
kotlinOptions {
jvmTarget = "1.8"
}
}
}
androidNativeArm32()
androidNativeArm64()
androidNativeX86()
androidNativeX64()
mingwX64()
watchosDeviceArm64()
listOf(
macosX64(),
macosArm64(),
iosX64(),
watchosSimulatorArm64(),
watchosX64(),
watchosArm32(),
watchosArm64(),
tvosSimulatorArm64(),
tvosX64(),
tvosArm64(),
iosArm64(),
watchosDeviceArm64(),
).forEach {
it.binaries.framework {
baseName = project.name
}
}
js(IR) {
browser()
nodejs()
binaries.executable()
}

sourceSets {
val commonMain by getting {
Expand All @@ -42,9 +54,9 @@ kotlin {
}

android {
compileSdk = 34
compileSdk = 33
defaultConfig {
minSdk = 1
}
namespace = group.toString()
namespace = "com.tidal.networktime"
}
59 changes: 29 additions & 30 deletions library/src/commonMain/kotlin/com/tidal/networktime/NTPServer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,39 @@ package com.tidal.networktime
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

sealed interface NTPServer {
val hostName: String
val responseTimeout: Duration
val dnsResolutionStrategy: DNSResolutionStrategy

sealed interface Unicast : NTPServer {
class Sequential(
override val hostName: String,
override val responseTimeout: Duration = RESPONSE_TIMEOUT_DEFAULT_SECONDS.seconds,
override val dnsResolutionStrategy: DNSResolutionStrategy = DNSResolutionStrategy.ALL,
val outgoingRequestGap: Duration = OUTGOING_REQUEST_GAP_DEFAULT_SECONDS.seconds,
) : Unicast

class Concurrent(
override val hostName: String,
override val responseTimeout: Duration = RESPONSE_TIMEOUT_DEFAULT_SECONDS.seconds,
override val dnsResolutionStrategy: DNSResolutionStrategy = DNSResolutionStrategy.ALL,
) : Unicast

companion object {
private const val RESPONSE_TIMEOUT_DEFAULT_SECONDS = 5
private const val OUTGOING_REQUEST_GAP_DEFAULT_SECONDS = 2
}
}

class Anycast(
override val hostName: String,
override val responseTimeout: Duration = 68.seconds,
override val dnsResolutionStrategy: DNSResolutionStrategy = DNSResolutionStrategy.ALL,
) : NTPServer
/**
* Describes a host name that can resolve to any number of NTP unicast servers.
*
* @param hostName The host name.
* @param responseTimeout The timeout for receiving responses from servers resolved from [hostName].
* @param dnsResolutionStrategy Can be used for filtering resolved address on [hostName] based on
* IP version.
* @param perAddressRequestGap The amount of time to wait before consecutive requests to the same
* resolved address.
* @param pinnedPortNumber The port number to send packets on. If null, a random choice of port
* be made for every packet, as recommended by RFC 9109.
* @param ntpVersion The version number to write in packets.
*/
class NTPServer(
val hostName: String,
val responseTimeout: Duration = 5.seconds,
val dnsResolutionStrategy: DNSResolutionStrategy = DNSResolutionStrategy.ALL,
val perAddressRequestGap: Duration = 2.seconds,
val pinnedPortNumber: Int? = null,
val ntpVersion: NTPVersion = NTPVersion.FOUR,
) {

enum class DNSResolutionStrategy {
IP_V4,
IP_V6,
ALL,
}

enum class NTPVersion(val descriptor: Short) {
ZERO(0),
ONE(1),
TWO(2),
THREE(3),
FOUR(4),
}
}
35 changes: 4 additions & 31 deletions library/src/commonMain/kotlin/com/tidal/networktime/SNTPClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,20 @@ package com.tidal.networktime

import kotlinx.coroutines.CoroutineScope
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

/**
* Construct a new SNTP client that can be requested to periodically interact with the provided
* [ntpServers] to obtain information about their provided time.
*
* @param ntpServers Representation of supported NTP sources.
* @param ntpServers Representation of supported unicast NTP sources.
* @param coroutineScope The scope where synchronization will run on.
* @param ntpVersion The version number to write in packets.
* @param portSelectionStrategy The strategy for selecting a port to operate on.
* @param minimumSynchronizationInterval The minimum amount of time between performing time queries
* on all unicast sources. The actual value used may be larger than this on occasion based on
* changes to the difference between the time provided by [ntpServers] and [referenceClock] (if it
* ever changes), but will never be lower than this value.
* @param referenceClock A clock used to calculate timing differences with the information obtained
* from [ntpServers]. This clock will never be modified directly.
* @param referenceClock A provider of UNIX time, used to calculate timing differences with the
* information obtained from [ntpServers].
*/
class SNTPClient(
vararg val ntpServers: NTPServer,
val coroutineScope: CoroutineScope,
val ntpVersion: NTPVersion = NTPVersion.FOUR,
val portSelectionStrategy: PortSelectionStrategy = PortSelectionStrategy.RFC9109,
val minimumSynchronizationInterval: Duration = 64.seconds,
val referenceClock: () -> Long,
val referenceClock: () -> Duration,
) {

val time: Long?
Expand All @@ -34,21 +24,4 @@ class SNTPClient(
fun startSynchronization(): Unit = TODO("Start or return")

fun stopSynchronization(): Unit = TODO("Stop or return")

enum class NTPVersion(val descriptor: Short) {
ZERO(0),
ONE(1),
TWO(2),
THREE(3),
FOUR(4),
}

sealed class PortSelectionStrategy(val pinnedPortNumber: Int?) {
data object RFC5905 : PortSelectionStrategy(123)

/**
* Make a new selection of a random available port every time a socket is opened.
*/
data object RFC9109 : PortSelectionStrategy(null)
}
}