Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wasi/src/p2/ip_name_lookup.rs
1692 views
1
use crate::p2::SocketError;
2
use crate::p2::bindings::sockets::ip_name_lookup::{Host, HostResolveAddressStream};
3
use crate::p2::bindings::sockets::network::{ErrorCode, IpAddress, Network};
4
use crate::runtime::{AbortOnDropJoinHandle, spawn_blocking};
5
use crate::sockets::WasiSocketsCtxView;
6
use anyhow::Result;
7
use std::mem;
8
use std::net::ToSocketAddrs;
9
use std::pin::Pin;
10
use std::vec;
11
use wasmtime::component::Resource;
12
use wasmtime_wasi_io::poll::{DynPollable, Pollable, subscribe};
13
14
use crate::sockets::util::{from_ipv4_addr, from_ipv6_addr, parse_host};
15
16
pub enum ResolveAddressStream {
17
Waiting(AbortOnDropJoinHandle<Result<Vec<IpAddress>, SocketError>>),
18
Done(Result<vec::IntoIter<IpAddress>, SocketError>),
19
}
20
21
impl Host for WasiSocketsCtxView<'_> {
22
fn resolve_addresses(
23
&mut self,
24
network: Resource<Network>,
25
name: String,
26
) -> Result<Resource<ResolveAddressStream>, SocketError> {
27
let network = self.table.get(&network)?;
28
29
let host = parse_host(&name)?;
30
31
if !network.allow_ip_name_lookup {
32
return Err(ErrorCode::PermanentResolverFailure.into());
33
}
34
35
let task = spawn_blocking(move || blocking_resolve(&host));
36
let resource = self.table.push(ResolveAddressStream::Waiting(task))?;
37
Ok(resource)
38
}
39
}
40
41
impl HostResolveAddressStream for WasiSocketsCtxView<'_> {
42
fn resolve_next_address(
43
&mut self,
44
resource: Resource<ResolveAddressStream>,
45
) -> Result<Option<IpAddress>, SocketError> {
46
let stream: &mut ResolveAddressStream = self.table.get_mut(&resource)?;
47
loop {
48
match stream {
49
ResolveAddressStream::Waiting(future) => {
50
match crate::runtime::poll_noop(Pin::new(future)) {
51
Some(result) => {
52
*stream = ResolveAddressStream::Done(result.map(|v| v.into_iter()));
53
}
54
None => return Err(ErrorCode::WouldBlock.into()),
55
}
56
}
57
ResolveAddressStream::Done(slot @ Err(_)) => {
58
mem::replace(slot, Ok(Vec::new().into_iter()))?;
59
unreachable!();
60
}
61
ResolveAddressStream::Done(Ok(iter)) => return Ok(iter.next()),
62
}
63
}
64
}
65
66
fn subscribe(
67
&mut self,
68
resource: Resource<ResolveAddressStream>,
69
) -> Result<Resource<DynPollable>> {
70
subscribe(self.table, resource)
71
}
72
73
fn drop(&mut self, resource: Resource<ResolveAddressStream>) -> Result<()> {
74
self.table.delete(resource)?;
75
Ok(())
76
}
77
}
78
79
#[async_trait::async_trait]
80
impl Pollable for ResolveAddressStream {
81
async fn ready(&mut self) {
82
if let ResolveAddressStream::Waiting(future) = self {
83
*self = ResolveAddressStream::Done(future.await.map(|v| v.into_iter()));
84
}
85
}
86
}
87
88
fn blocking_resolve(host: &url::Host) -> Result<Vec<IpAddress>, SocketError> {
89
match host {
90
url::Host::Ipv4(v4addr) => Ok(vec![IpAddress::Ipv4(from_ipv4_addr(*v4addr))]),
91
url::Host::Ipv6(v6addr) => Ok(vec![IpAddress::Ipv6(from_ipv6_addr(*v6addr))]),
92
url::Host::Domain(domain) => {
93
// For now use the standard library to perform actual resolution through
94
// the usage of the `ToSocketAddrs` trait. This is only
95
// resolving names, not ports, so force the port to be 0.
96
let addresses = (domain.as_str(), 0)
97
.to_socket_addrs()
98
.map_err(|_| ErrorCode::NameUnresolvable)? // If/when we use `getaddrinfo` directly, map the error properly.
99
.map(|addr| addr.ip().to_canonical().into())
100
.collect();
101
102
Ok(addresses)
103
}
104
}
105
}
106
107