silk.net.resolver.
Turn a host and a port into a list of endpoints to connect to.
When to use#
Make a ResolveRequest from a Host and a Port, and call Resolver.resolve. A numeric
host gives one endpoint without a lookup. A domain name goes to the Resolver provider. Use
silk.net.resolver_native in a native program, or give your own provider, for example in tests.
Details#
The result keeps the order of the provider, removes exact duplicates, and keeps only the
addresses of the FamilySelection. It holds at most the maxResults of the request, and
never more than 64.
Errors#
NoAddressif no address of the selected family remains.LimitExceededif there are more distinct endpoints thanmaxResults. The result is never cut short.Timeoutif the deadline of a numeric request has passed.Other
ResolverErrorvalues come from the provider.
Gotchas#
For a domain name, the provider decides how to use the deadline. NativeSystemResolver cannot
stop a lookup, so it returns DeadlineUnsupported for a domain request with a deadline.
maxResults limits only the result, not the work of the provider.
Examples#
Resolve with a test provider#
This provider returns the same endpoints for every name. The duplicate and the IPv6 address are removed from the result.
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.core.effect { Effect }
import silk.system.monotonic_clock { MonotonicClock }
import silk.net.address {
AddressError,
DomainHost,
Endpoint,
Host,
IpAddress,
Ipv4Address,
Ipv6Address,
Port
}
import silk.core.option { Option }
import silk.core.result { Result }
import silk.net.resolver { FamilySelection, ResolveRequest, ResolvedEndpoints, Resolver, ResolverError }
import silk.system.system_clock { Instant, SystemClock }
import silk.num.u64
struct FixedResolver {}
impl FixedResolver {
effect fn resolveDomain(
self: &mut Self,
request: &ResolveRequest,
domain: &DomainHost,
) -> ResolvedEndpoints
! ResolverError | OutOfMemoryError
? &mut Allocator {
drop domain
let port = ResolveRequest.port(request)
let mut result = match ResolvedEndpoints.make(8) {
Result<ResolvedEndpoints, ResolverError>.Success { value } => move value
Result<ResolvedEndpoints, ResolverError>.Failure { error } => {
fail move error
}
}
let first = IpAddress.V4 { value: Ipv4Address.fromOctets([192, 0, 2, 1]) }
let second = IpAddress.V6 { value: Ipv6Address.fromOctets([0; 16]) }
let added = run ResolvedEndpoints.admit(&mut result, Endpoint.make(first, port))
let same = run ResolvedEndpoints.admit(&mut result, Endpoint.make(first, port))
let other = run ResolvedEndpoints.admit(&mut result, Endpoint.make(second, port))
return move result
}
}
impl Resolver for FixedResolver {
resolveDomain: FixedResolver.resolveDomain
}
struct FixedMonotonic {}
impl MonotonicClock for FixedMonotonic {
effect fn now(self: &mut Self) -> Instant {
return SystemClock.make(0, 0)
}
effect fn getResolution(self: &mut Self) -> u64 {
return u64.toU64(1)
}
effect fn waitUntil(self: &mut Self, when: Instant) -> () {
drop when
return ()
}
effect fn waitFor(self: &mut Self, howLong: u64) -> () {
drop howLong
return ()
}
}
effect fn program() -> i32
! ResolverError | OutOfMemoryError {
let host = match Host.parse("example.com") {
Result<Host, AddressError>.Success { value } => value
Result<Host, AddressError>.Failure { error: _ } => {
return 1
}
}
let request = match ResolveRequest.make(
host,
Port.fromU16(443),
FamilySelection.V4,
4,
Option<Instant>.none(),
) {
Result<ResolveRequest, ResolverError>.Success { value } => move value
Result<ResolveRequest, ResolverError>.Failure { error: _ } => {
return 1
}
}
let mut allocator = Allocator.systemAllocatorProvider()
let mut resolver = FixedResolver {}
let mut clock = FixedMonotonic {}
let endpoints = run Resolver.resolve(&request) |> Effect.provideMut<Resolver>(&mut resolver)
|> Effect.provideMut<MonotonicClock>(&mut clock)
|> Effect.provideMut<Allocator>(&mut allocator)
if ResolvedEndpoints.length(&endpoints) != 1 {
return 1
}
let endpoint = ResolvedEndpoints.get(&endpoints, 0)
let address = Endpoint.address(&endpoint)
if !IpAddress.isV4(&address) || Port.value(&Endpoint.port(&endpoint)) != 443 {
return 1
}
return 0
}
effect fn failed<E>(error: E) -> i32 {
drop error
return 1
}
pub fn main() -> i32 {
return run Effect.catchAll(program(), failed)
}Import as Resolver with import silk.net.resolver { Resolver }.
Public declarations: 9.
FamilySelection#
pub enum FamilySelectionThe address families to keep in a result.
Any#
AnyKeep IPv4 and IPv6 addresses.
V4#
V4Keep only IPv4 addresses.
V6#
V6Keep only IPv6 addresses.
ResolverInputReason#
pub enum ResolverInputReasonThe reason that a maxResults value is not valid.
ZeroResults#
ZeroResultsmaxResults is 0.
TooManyResults#
TooManyResultsmaxResults is more than 64.
Implementation Debug for ResolverInputReason#
impl Debug for ResolverInputReasonOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as ZeroResults.
NativeResolverOperation#
pub enum NativeResolverOperationThe system call that failed in a native provider.
GetAddrInfo#
GetAddrInfoThe getaddrinfo call.
Implementation Debug for NativeResolverOperation#
impl Debug for NativeResolverOperationOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as GetAddrInfo.
NativeResultReason#
pub enum NativeResultReasonThe reason that a native provider rejected a successful getaddrinfo result.
NullChain#
NullChainA successful native lookup returned no result chain.
UnknownFamily#
UnknownFamilyA native result contains an unsupported address family.
NullAddress#
NullAddressA native result has no address pointer.
ShortAddress#
ShortAddressA native address is shorter than its family requires.
Implementation Debug for NativeResultReason#
impl Debug for NativeResultReasonOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as NullChain.
ResolverError#
pub union ResolverErrorThe error from a resolution.
InvalidInput#
InvalidInputThe maxResults of the request is not valid.
Field reason#
pub reason: ResolverInputReasonThe rule that failed.
Field value#
pub value: usizeThe maxResults that you gave.
UnsupportedForm#
UnsupportedFormThe provider does not support this form of host.
Timeout#
TimeoutThe deadline of the request has passed.
DeadlineUnsupported#
DeadlineUnsupportedThe provider cannot stop a lookup at a deadline, so it did not start.
NoAddress#
NoAddressNo address of the selected family was found.
NameNotFound#
NameNotFoundThe name does not exist.
TemporaryFailure#
TemporaryFailureThe lookup failed for a temporary reason, for example a DNS server timeout. Try again later.
FamilyUnsupported#
FamilyUnsupportedThe system does not support the selected family.
SystemResources#
SystemResourcesThe system did not have the resources, such as memory, for the lookup.
Provider#
ProviderA host resolver failed with a provider-specific code, such as a WASI network error ordinal.
Field code#
pub code: i32The code reported by the provider. Its provider module defines the domain.
LimitExceeded#
LimitExceededThe lookup found more distinct endpoints than maxResults.
Field maximum#
pub maximum: usizeThe maxResults of the request.
InvalidNativeResult#
InvalidNativeResultThe system returned a result that is not valid.
Field reason#
pub reason: NativeResultReasonThe problem in the result.
Field index#
pub index: usizeThe position of the bad entry in the result list, from 0.
NativeFailure#
NativeFailureThe system lookup failed with a code that has no other variant.
Field operation#
pub operation: NativeResolverOperationThe call that failed.
Field eai#
pub eai: i32The EAI_* code from getaddrinfo.
Field errno#
pub errno: Option<i32>The errno value, when the code is EAI_SYSTEM.
Implementation Debug for ResolverError#
impl Debug for ResolverErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant and its fields, such as InvalidInput { ... }.
ResolveRequest#
pub struct ResolveRequestWhat to resolve: a host, a port, the families to keep, the maximum result count, and an optional
deadline. Make it with ResolveRequest.make.
ResolvedEndpoints#
pub struct ResolvedEndpointsThe endpoints of a resolution, without duplicates, in the order of the provider.
Admission#
pub enum AdmissionThe result of ResolvedEndpoints.admit.
Added#
AddedThe endpoint was added.
Duplicate#
DuplicateAn equal endpoint is already in the list, so nothing changed.
Implementation ResolveRequest#
impl ResolveRequestAssociated function make#
pub fn make(
host: Host,
port: Port,
family: FamilySelection,
maxResults: usize,
deadline: Option<Instant>,
) -> Result<ResolveRequest, ResolverError>Returns a request.
maxResults is from 1 to 64. deadline is a time on the MonotonicClock.
Errors#
InvalidInputifmaxResultsis 0 or more than 64.
Method host#
pub fn host(self: &Self) -> HostReturns the host.
Method port#
pub fn port(self: &Self) -> PortReturns the port.
Method family#
pub fn family(self: &Self) -> FamilySelectionReturns the families to keep.
Method maxResults#
pub fn maxResults(self: &Self) -> usizeReturns the maximum number of endpoints in the result.
Method hasDeadline#
pub fn hasDeadline(self: &Self) -> boolReturns true if the request has a deadline.
Method deadline#
pub fn deadline(self: &Self) -> Option<Instant>Returns the deadline, if there is one. A provider that cannot keep it returns
DeadlineUnsupported.
Implementation ResolvedEndpoints#
impl ResolvedEndpointsAssociated function make#
pub fn make(maximum: usize) -> Result<ResolvedEndpoints, ResolverError>Returns an empty list that holds at most maximum endpoints, from 1 to 64.
Method length#
pub fn length(self: &Self) -> usizeReturns the number of endpoints.
Method get#
pub fn get(self: &Self, index: usize) -> EndpointReturns the endpoint at index. index must be less than ResolvedEndpoints.length.
Method asSlice#
pub fn asSlice(self: &Self) -> &[Endpoint]Returns the endpoints as a slice.
Method admit#
pub effect fn admit(self: &mut Self, endpoint: Endpoint) -> Admission
! ResolverError | OutOfMemoryError
? &mut AllocatorAdds endpoint to the end of the list, if it is not in the list yet.
Errors#
LimitExceededif the list is full andendpointis new.
Resolver#
pub service ResolverThe service that looks up domain names. Resolver.resolve calls it only for domain names.
When to use#
Require &mut Resolver in code that connects by name, and call Resolver.resolve. Provide
silk.net.resolver_native.NativeSystemResolver in a native program, or your own provider, for
example in tests.
Gotchas#
For a domain name, the provider decides how to use the deadline. NativeSystemResolver cannot
stop a lookup, so it returns DeadlineUnsupported for a domain request with a deadline.
Operation resolveDomain#
effect fn resolveDomain(
request: &ResolveRequest,
domain: &DomainHost,
) -> ResolvedEndpoints
! ResolverError | OutOfMemoryError
? &mut Resolver | &mut AllocatorLooks up domain and returns its endpoints, with the port of request. Resolver.resolve
filters the families and removes duplicates after this call.
Implementation Resolver#
impl ResolverAssociated function resolve#
pub effect fn resolve(request: &ResolveRequest) -> ResolvedEndpoints
! ResolverError | OutOfMemoryError
? &mut Resolver | &mut Allocator | &mut MonotonicClockReturns the endpoints for request.
A numeric host gives one endpoint, without the provider. A domain name calls
Resolver.resolveDomain on the provider. The result keeps the order of the provider,
removes exact duplicates, and keeps only the addresses of the FamilySelection. It holds at
most the maxResults of the request, and never more than 64.
Errors#
NoAddressif no address of the selected family remains.LimitExceededif there are more distinct endpoints thanmaxResults. The result is never cut short.Timeoutif the deadline of a numeric request has passed.Other
ResolverErrorvalues come from the provider.OutOfMemoryErrorif theAllocatorcannot supply the result.
Gotchas#
maxResults limits only the result, not the work of the provider.
Category: Networking.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.