Path: blob/main/crates/wasi/src/sockets/mod.rs
1692 views
use core::future::Future;1use core::ops::Deref;2use std::net::SocketAddr;3use std::pin::Pin;4use std::sync::Arc;5use wasmtime::component::{HasData, ResourceTable};67mod tcp;8mod udp;9pub(crate) mod util;1011#[cfg(feature = "p3")]12pub(crate) use tcp::NonInheritedOptions;13pub use tcp::TcpSocket;14pub use udp::UdpSocket;1516/// A helper struct which implements [`HasData`] for the `wasi:sockets` APIs.17///18/// This can be useful when directly calling `add_to_linker` functions directly,19/// such as [`wasmtime_wasi::p2::bindings::sockets::tcp::add_to_linker`] as the20/// `D` type parameter. See [`HasData`] for more information about the type21/// parameter's purpose.22///23/// When using this type you can skip the [`WasiSocketsView`] trait, for24/// example.25///26/// # Examples27///28/// ```29/// use wasmtime::component::{Linker, ResourceTable};30/// use wasmtime::{Engine, Result, Config};31/// use wasmtime_wasi::sockets::*;32///33/// struct MyStoreState {34/// table: ResourceTable,35/// sockets: WasiSocketsCtx,36/// }37///38/// fn main() -> Result<()> {39/// let mut config = Config::new();40/// config.async_support(true);41/// let engine = Engine::new(&config)?;42/// let mut linker = Linker::new(&engine);43///44/// wasmtime_wasi::p2::bindings::sockets::tcp::add_to_linker::<MyStoreState, WasiSockets>(45/// &mut linker,46/// |state| WasiSocketsCtxView {47/// ctx: &mut state.sockets,48/// table: &mut state.table,49/// },50/// )?;51/// Ok(())52/// }53/// ```54pub struct WasiSockets;5556impl HasData for WasiSockets {57type Data<'a> = WasiSocketsCtxView<'a>;58}5960/// Value taken from rust std library.61pub(crate) const DEFAULT_TCP_BACKLOG: u32 = 128;6263/// Theoretical maximum byte size of a UDP datagram, the real limit is lower,64/// but we do not account for e.g. the transport layer here for simplicity.65/// In practice, datagrams are typically less than 1500 bytes.66pub(crate) const MAX_UDP_DATAGRAM_SIZE: usize = u16::MAX as usize;6768#[derive(Clone, Default)]69pub struct WasiSocketsCtx {70pub(crate) socket_addr_check: SocketAddrCheck,71pub(crate) allowed_network_uses: AllowedNetworkUses,72}7374pub struct WasiSocketsCtxView<'a> {75pub ctx: &'a mut WasiSocketsCtx,76pub table: &'a mut ResourceTable,77}7879pub trait WasiSocketsView: Send {80fn sockets(&mut self) -> WasiSocketsCtxView<'_>;81}8283#[derive(Copy, Clone)]84pub(crate) struct AllowedNetworkUses {85pub(crate) ip_name_lookup: bool,86pub(crate) udp: bool,87pub(crate) tcp: bool,88}8990impl Default for AllowedNetworkUses {91fn default() -> Self {92Self {93ip_name_lookup: false,94udp: true,95tcp: true,96}97}98}99100impl AllowedNetworkUses {101pub(crate) fn check_allowed_udp(&self) -> std::io::Result<()> {102if !self.udp {103return Err(std::io::Error::new(104std::io::ErrorKind::PermissionDenied,105"UDP is not allowed",106));107}108109Ok(())110}111112pub(crate) fn check_allowed_tcp(&self) -> std::io::Result<()> {113if !self.tcp {114return Err(std::io::Error::new(115std::io::ErrorKind::PermissionDenied,116"TCP is not allowed",117));118}119120Ok(())121}122}123124/// A check that will be called for each socket address that is used of whether the address is permitted.125#[derive(Clone)]126pub(crate) struct SocketAddrCheck(127Arc<128dyn Fn(SocketAddr, SocketAddrUse) -> Pin<Box<dyn Future<Output = bool> + Send + Sync>>129+ Send130+ Sync,131>,132);133134impl SocketAddrCheck {135/// A check that will be called for each socket address that is used.136///137/// Returning `true` will permit socket connections to the `SocketAddr`,138/// while returning `false` will reject the connection.139pub(crate) fn new(140f: impl Fn(SocketAddr, SocketAddrUse) -> Pin<Box<dyn Future<Output = bool> + Send + Sync>>141+ Send142+ Sync143+ 'static,144) -> Self {145Self(Arc::new(f))146}147148pub(crate) async fn check(149&self,150addr: SocketAddr,151reason: SocketAddrUse,152) -> std::io::Result<()> {153if (self.0)(addr, reason).await {154Ok(())155} else {156Err(std::io::Error::new(157std::io::ErrorKind::PermissionDenied,158"An address was not permitted by the socket address check.",159))160}161}162}163164impl Deref for SocketAddrCheck {165type Target = dyn Fn(SocketAddr, SocketAddrUse) -> Pin<Box<dyn Future<Output = bool> + Send + Sync>>166+ Send167+ Sync;168169fn deref(&self) -> &Self::Target {170self.0.as_ref()171}172}173174impl Default for SocketAddrCheck {175fn default() -> Self {176Self(Arc::new(|_, _| Box::pin(async { false })))177}178}179180/// The reason what a socket address is being used for.181#[derive(Clone, Copy, Debug)]182pub enum SocketAddrUse {183/// Binding TCP socket184TcpBind,185/// Connecting TCP socket186TcpConnect,187/// Binding UDP socket188UdpBind,189/// Connecting UDP socket190UdpConnect,191/// Sending datagram on non-connected UDP socket192UdpOutgoingDatagram,193}194195#[derive(Copy, Clone, Eq, PartialEq)]196pub(crate) enum SocketAddressFamily {197Ipv4,198Ipv6,199}200201202