-
Notifications
You must be signed in to change notification settings - Fork 31
kn: HostResolver #1229
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
kn: HostResolver #1229
Changes from 11 commits
a4734c7
7911a94
7085c8a
4575023
b0a4bac
80f4538
e9d16a9
48849a1
ded3a4b
d97e8ba
78f17f3
d06ee0a
d2e7c91
5a2df8f
003633b
5f5ec8f
3fe1b5e
0bba308
52e4439
e0c25d6
14e0958
ed95d7b
a4ace35
15e5f0c
447ac10
0f8db44
8b33693
03badf9
9f44cdb
97ac447
b7e50e3
df89e93
746881d
be248ae
5ab633d
e6357f9
94e5878
2363e26
a47da0a
57c52c5
272b6a0
3de8e8c
0a5beac
2ba120e
aa069f7
334b41c
5eb2d76
d0e6c3d
115a818
c7487fe
aa2a657
a175933
c234561
c325a4c
044b74c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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.5-bin.zip | ||
| distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip | ||
| networkTimeout=10000 | ||
| zipStoreBase=GRADLE_USER_HOME | ||
| zipStorePath=wrapper/dists |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |
| import aws.sdk.kotlin.gradle.dsl.configurePublishing | ||
| import aws.sdk.kotlin.gradle.kmp.* | ||
| import aws.sdk.kotlin.gradle.util.typedProp | ||
| import org.gradle.kotlin.dsl.withType | ||
| import org.jetbrains.kotlin.gradle.dsl.JvmTarget | ||
|
|
||
| plugins { | ||
|
|
@@ -111,4 +112,6 @@ subprojects { | |
| } | ||
| } | ||
| } | ||
|
|
||
| configureIosSimulatorTasks() | ||
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| /* | ||
| * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
| package aws.smithy.kotlin.runtime.net | ||
|
|
||
| import kotlinx.coroutines.test.runTest | ||
| import kotlin.test.* | ||
|
|
||
| class HostResolverTest { | ||
| @Test | ||
| fun testResolveLocalhost() = runTest { | ||
| val addresses = HostResolver.Default.resolve("localhost") | ||
| assertTrue(addresses.isNotEmpty()) | ||
|
|
||
| addresses.forEach { addr -> | ||
| assertEquals("localhost", addr.hostname) | ||
|
|
||
| val localHostAddr = when (addr.address) { | ||
| is IpV4Addr -> IpV4Addr.LOCALHOST | ||
| is IpV6Addr -> IpV6Addr.LOCALHOST | ||
| } | ||
| assertEquals(addr.address, localHostAddr) | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| fun testResolveIpv4Address() = runTest { | ||
| val addresses = HostResolver.Default.resolve("127.0.0.1") | ||
| assertTrue(addresses.isNotEmpty()) | ||
|
|
||
| addresses.forEach { addr -> | ||
| assertTrue(addr.address is IpV4Addr) | ||
| assertContentEquals(byteArrayOf(127, 0, 0, 1), addr.address.octets) | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| fun testResolveIpv6Address() = runTest { | ||
| val addresses = HostResolver.Default.resolve("::1") | ||
| assertTrue(addresses.isNotEmpty()) | ||
|
|
||
| addresses.forEach { addr -> | ||
| assertTrue(addr.address is IpV6Addr) | ||
| val expectedBytes = ByteArray(16) { 0 } | ||
| expectedBytes[15] = 1 | ||
| assertContentEquals(expectedBytes, addr.address.octets) | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| fun testResolveExampleDomain() = runTest { | ||
| val addresses = HostResolver.Default.resolve("example.com") | ||
| assertNotNull(addresses) | ||
| assertTrue(addresses.isNotEmpty()) | ||
|
|
||
| addresses.forEach { addr -> | ||
| assertEquals("example.com", addr.hostname) | ||
| when (val ip = addr.address) { | ||
| is IpV4Addr -> assertEquals(4, ip.octets.size) | ||
| is IpV6Addr -> assertEquals(16, ip.octets.size) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| fun testResolveInvalidDomain() = runTest { | ||
| assertFails { | ||
| HostResolver.Default.resolve("this-domain-definitely-does-not-exist-12345.local") | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| fun testNoopMethods() { | ||
| // Test no-op methods don't throw | ||
| val dummyAddr = HostAddress("test.com", IpV4Addr(ByteArray(4))) | ||
| val resolver = HostResolver.Default | ||
| resolver.reportFailure(dummyAddr) | ||
| resolver.purgeCache(null) | ||
| resolver.purgeCache(dummyAddr) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,19 +4,59 @@ | |
| */ | ||
| package aws.smithy.kotlin.runtime.net | ||
|
|
||
| import aws.smithy.kotlin.runtime.InternalApi | ||
| import kotlinx.cinterop.* | ||
| import platform.posix.* | ||
|
|
||
| internal actual object DefaultHostResolver : HostResolver { | ||
| actual override suspend fun resolve(hostname: String): List<HostAddress> { | ||
| TODO("Not yet implemented") | ||
| actual override suspend fun resolve(hostname: String): List<HostAddress> = memScoped { | ||
| val hints = alloc<addrinfo>().apply { | ||
| ai_family = AF_UNSPEC // Allow both IPv4 and IPv6 | ||
| ai_socktype = SOCK_STREAM // TCP stream sockets | ||
| ai_flags = AI_PASSIVE // For wildcard IP address | ||
| } | ||
|
|
||
| val result = allocPointerTo<addrinfo>() | ||
|
|
||
| try { | ||
| // Perform the DNS lookup | ||
| val status = getaddrinfo(hostname, null, hints.ptr, result.ptr) | ||
| check(status == 0) { "Failed to resolve host $hostname: ${gai_strerror(status)?.toKString()}" } | ||
|
|
||
| return generateSequence(result.value) { it.pointed.ai_next } | ||
| .map { it.pointed.ai_addr!!.pointed.toIpAddr() } | ||
| .map { HostAddress(hostname, it) } | ||
| .toList() | ||
| } finally { | ||
| freeaddrinfo(result.value) | ||
| } | ||
| } | ||
|
|
||
| @OptIn(UnsafeNumber::class) | ||
| private fun sockaddr.toIpAddr(): IpAddr { | ||
| val (size, addrPtr, constructor) = when (sa_family.toInt()) { | ||
| AF_INET -> Triple( | ||
| 4, | ||
| reinterpret<sockaddr_in>().sin_addr.ptr, | ||
| { bytes: ByteArray -> IpV4Addr(bytes) }, | ||
| ) | ||
| AF_INET6 -> Triple( | ||
| 16, | ||
| reinterpret<sockaddr_in6>().sin6_addr.ptr, | ||
| { bytes: ByteArray -> IpV6Addr(bytes) }, | ||
| ) | ||
| else -> throw IllegalArgumentException("Unsupported sockaddr family $sa_family") | ||
| } | ||
|
Comment on lines
+36
to
+48
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment: Nice! I wish non- |
||
|
|
||
| val ipBytes = ByteArray(size) | ||
| memcpy(ipBytes.refTo(0), addrPtr, size.toULong()) | ||
| return constructor(ipBytes) | ||
| } | ||
|
|
||
| actual override fun reportFailure(addr: HostAddress) { | ||
| TODO("Not yet implemented") | ||
| // No-op, same as JVM implementation | ||
| } | ||
|
|
||
| @InternalApi | ||
| actual override fun purgeCache(addr: HostAddress?) { | ||
| TODO("Not yet implemented") | ||
| // No-op, same as JVM implementation | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: Was this version change necessary for some reason? Or just hygiene?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was necessary because CI fails with deprecated errors when using v3