@@ -8,7 +8,10 @@ package aws.sdk.kotlin.crt.io
88import aws.sdk.kotlin.crt.*
99import aws.sdk.kotlin.crt.util.ShutdownChannel
1010import aws.sdk.kotlin.crt.util.shutdownChannel
11+ import aws.sdk.kotlin.crt.util.toAwsString
12+ import aws.sdk.kotlin.crt.util.toKString
1113import kotlinx.cinterop.*
14+ import kotlinx.coroutines.channels.Channel
1215import libcrt.*
1316
1417@OptIn(ExperimentalForeignApi ::class )
@@ -59,14 +62,101 @@ public actual class HostResolver private constructor(
5962
6063 if (manageElg) elg.close()
6164 }
65+
66+ public suspend fun resolve (hostname : String ): List <CrtHostAddress > = memScoped {
67+ val awsHostname = hostname.toAwsString()
68+ val resultCallback = staticCFunction(::awsOnHostResolveFn)
69+
70+ val channel: Channel <List <CrtHostAddress >> = Channel (Channel .RENDEZVOUS )
71+ val channelStableRef = StableRef .create(channel)
72+ val userData = channelStableRef.asCPointer()
73+
74+ aws_host_resolver_resolve_host(ptr, awsHostname, resultCallback, aws_host_resolver_init_default_resolution_config(), userData)
75+
76+ return channel.receive().also {
77+ aws_string_destroy(awsHostname)
78+ channelStableRef.dispose()
79+ }
80+ }
6281}
6382
6483@OptIn(ExperimentalForeignApi ::class )
6584private fun onShutdownComplete (userData : COpaquePointer ? ) {
66- if (userData == null ) return
85+ if (userData == null ) {
86+ return
87+ }
6788 val stableRef = userData.asStableRef<ShutdownChannel >()
6889 val ch = stableRef.get()
6990 ch.trySend(Unit )
7091 ch.close()
7192 stableRef.dispose()
7293}
94+
95+ // implementation of `aws_on_host_resolved_result_fn`: https://github.com/awslabs/aws-c-io/blob/db7a1bddc9a29eca18734d0af189c3924775dcf1/include/aws/io/host_resolver.h#L53C14-L53C44
96+ private fun awsOnHostResolveFn (
97+ hostResolver : CPointer <aws_host_resolver>? ,
98+ hostName : CPointer <aws_string>? ,
99+ errCode : Int ,
100+ hostAddresses : CPointer <aws_array_list>? , // list of `aws_host_address`
101+ userData : COpaquePointer ? ,
102+ ): Unit = memScoped {
103+ println (" In callback awsOnHostResolveFn" )
104+ if (errCode != AWS_OP_SUCCESS ) {
105+ throw CrtRuntimeException (" aws_on_host_resolved_result_fn" , ec = errCode)
106+ }
107+ if (userData == null ) {
108+ throw CrtRuntimeException (" aws_on_host_resolved_result_fn: userData unexpectedly null" )
109+ }
110+
111+ val length = aws_array_list_length(hostAddresses)
112+ if (length == 0uL ) {
113+ throw CrtRuntimeException (" Failed to resolve host address for ${hostName?.toKString()} " )
114+ }
115+
116+ val result = ArrayList <CrtHostAddress >(length.toInt())
117+
118+ val element = alloc<COpaquePointerVar >()
119+ for (i in 0uL until length) {
120+ awsAssertOpSuccess(
121+ aws_array_list_get_at_ptr(
122+ hostAddresses,
123+ element.ptr,
124+ i,
125+ ),
126+ ) { " aws_array_list_get_at_ptr failed at index $i " }
127+
128+ val elemOpaque = element.value ? : throw CrtRuntimeException (" aws_host_addresses value at index $i unexpectedly null" )
129+ val addr = elemOpaque.reinterpret< aws_host_address> ().pointed
130+
131+ val hostStr = addr.host?.toKString() ? : throw CrtRuntimeException (" aws_host_addresses `host` at index $i unexpectedly null" )
132+ val addressStr = addr.address?.toKString() ? : throw CrtRuntimeException (" aws_host_addresses `address` at index $i unexpectedly null" )
133+ val addressType = when (addr.record_type) {
134+ aws_address_record_type.AWS_ADDRESS_RECORD_TYPE_A -> AddressType .IpV4
135+ aws_address_record_type.AWS_ADDRESS_RECORD_TYPE_AAAA -> AddressType .IpV6
136+ else -> throw CrtRuntimeException (" received unsupported aws_host_address `aws_address_record_type`: ${addr.record_type} " )
137+ }
138+
139+ result + = CrtHostAddress (host = hostStr, address = addressStr, addressType)
140+ }
141+
142+ // Send results back through the channel
143+ val stableRef = userData.asStableRef<Channel <List <CrtHostAddress >>>()
144+ val channel = stableRef.get()
145+ channel.trySend(result)
146+ channel.close()
147+ }
148+
149+ // Minimal wrapper of aws_host_address
150+ // https://github.com/awslabs/aws-c-io/blob/db7a1bddc9a29eca18734d0af189c3924775dcf1/include/aws/io/host_resolver.h#L31
151+ @InternalApi
152+ public data class CrtHostAddress (
153+ val host : String ,
154+ val address : String ,
155+ val addressType : AddressType ,
156+ )
157+
158+ @InternalApi
159+ public enum class AddressType {
160+ IpV4 ,
161+ IpV6 ,
162+ }
0 commit comments