Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions crates/test-programs/src/bin/p2_tcp_listen.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use test_programs::sockets::supports_ipv6;
use test_programs::wasi::sockets::network::{ErrorCode, IpAddressFamily};
use test_programs::wasi::sockets::tcp::TcpSocket;

/// Socket must be explicitly bound before listening.
fn test_tcp_listen_without_bind(family: IpAddressFamily) {
let sock = TcpSocket::new(family).unwrap();

assert!(matches!(
sock.blocking_listen(),
Err(ErrorCode::InvalidState)
));
}

fn main() {
test_tcp_listen_without_bind(IpAddressFamily::Ipv4);

if supports_ipv6() {
test_tcp_listen_without_bind(IpAddressFamily::Ipv6);
}
}
15 changes: 15 additions & 0 deletions crates/test-programs/src/bin/p2_udp_connect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,18 @@ fn test_udp_connect_wrong_family(net: &Network, family: IpAddressFamily) {
));
}

/// Socket must be explicitly bound before connecting.
fn test_udp_connect_without_bind(family: IpAddressFamily) {
let remote_addr = IpSocketAddress::new(IpAddress::new_loopback(family), SOME_PORT);

let sock = UdpSocket::new(family).unwrap();

assert!(matches!(
sock.stream(Some(remote_addr)),
Err(ErrorCode::InvalidState)
));
}

fn test_udp_connect_dual_stack(net: &Network) {
// Set-up:
let v4_server = UdpSocket::new(IpAddressFamily::Ipv4).unwrap();
Expand Down Expand Up @@ -120,5 +132,8 @@ fn main() {
test_udp_connect_wrong_family(&net, IpAddressFamily::Ipv4);
test_udp_connect_wrong_family(&net, IpAddressFamily::Ipv6);

test_udp_connect_without_bind(IpAddressFamily::Ipv4);
test_udp_connect_without_bind(IpAddressFamily::Ipv6);

test_udp_connect_dual_stack(&net);
}
45 changes: 45 additions & 0 deletions crates/test-programs/src/bin/p3_sockets_tcp_listen.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use test_programs::p3::wasi::sockets::types::{
IpAddress, IpAddressFamily, IpSocketAddress, TcpSocket,
};
use test_programs::sockets::supports_ipv6;

struct Component;

test_programs::p3::export!(Component);

/// Listen should perform implicit bind.
fn test_tcp_listen_without_bind(family: IpAddressFamily) {
let sock = TcpSocket::create(family).unwrap();

assert!(matches!(sock.get_local_address(), Err(_)));
assert!(matches!(sock.listen(), Ok(_)));
assert!(matches!(sock.get_local_address(), Ok(_)));
}

/// Listen should work in combination with an explicit bind.
fn test_tcp_listen_with_bind(family: IpAddressFamily) {
let bind_addr = IpSocketAddress::new(IpAddress::new_unspecified(family), 0);
let sock = TcpSocket::create(family).unwrap();

sock.bind(bind_addr).unwrap();
let local_addr = sock.get_local_address().unwrap();

assert!(matches!(sock.listen(), Ok(_)));
assert_eq!(sock.get_local_address(), Ok(local_addr));
}

impl test_programs::p3::exports::wasi::cli::run::Guest for Component {
async fn run() -> Result<(), ()> {
test_tcp_listen_without_bind(IpAddressFamily::Ipv4);
test_tcp_listen_with_bind(IpAddressFamily::Ipv4);

if supports_ipv6() {
test_tcp_listen_without_bind(IpAddressFamily::Ipv6);
test_tcp_listen_with_bind(IpAddressFamily::Ipv6);
}

Ok(())
}
}

fn main() {}
35 changes: 30 additions & 5 deletions crates/test-programs/src/bin/p3_sockets_udp_connect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ test_programs::p3::export!(Component);
const SOME_PORT: u16 = 47; // If the tests pass, this will never actually be connected to.

fn test_udp_connect_disconnect_reconnect(family: IpAddressFamily) {
let unspecified_addr = IpSocketAddress::new(IpAddress::new_unspecified(family), 0);
let remote1 = IpSocketAddress::new(IpAddress::new_loopback(family), 4321);
let remote2 = IpSocketAddress::new(IpAddress::new_loopback(family), 4320);

let client = UdpSocket::create(family).unwrap();
client.bind(unspecified_addr).unwrap();

assert_eq!(client.disconnect(), Err(ErrorCode::InvalidState));
assert_eq!(client.get_remote_address(), Err(ErrorCode::InvalidState));
Expand Down Expand Up @@ -43,7 +41,6 @@ fn test_udp_connect_unspec(family: IpAddressFamily) {
let ip = IpAddress::new_unspecified(family);
let addr = IpSocketAddress::new(ip, SOME_PORT);
let sock = UdpSocket::create(family).unwrap();
sock.bind_unspecified().unwrap();

assert!(matches!(
sock.connect(addr),
Expand All @@ -55,7 +52,6 @@ fn test_udp_connect_unspec(family: IpAddressFamily) {
fn test_udp_connect_port_0(family: IpAddressFamily) {
let addr = IpSocketAddress::new(IpAddress::new_loopback(family), 0);
let sock = UdpSocket::create(family).unwrap();
sock.bind_unspecified().unwrap();

assert!(matches!(
sock.connect(addr),
Expand All @@ -72,14 +68,37 @@ fn test_udp_connect_wrong_family(family: IpAddressFamily) {
let remote_addr = IpSocketAddress::new(wrong_ip, SOME_PORT);

let sock = UdpSocket::create(family).unwrap();
sock.bind_unspecified().unwrap();

assert!(matches!(
sock.connect(remote_addr),
Err(ErrorCode::InvalidArgument)
));
}

/// Connect should perform implicit bind.
fn test_udp_connect_without_bind(family: IpAddressFamily) {
let remote_addr = IpSocketAddress::new(IpAddress::new_loopback(family), SOME_PORT);

let sock = UdpSocket::create(family).unwrap();

assert!(matches!(sock.get_local_address(), Err(_)));
assert!(matches!(sock.connect(remote_addr), Ok(_)));
assert!(matches!(sock.get_local_address(), Ok(_)));
}

/// Connect should work in combination with an explicit bind.
fn test_udp_connect_with_bind(family: IpAddressFamily) {
let remote_addr = IpSocketAddress::new(IpAddress::new_loopback(family), SOME_PORT);

let sock = UdpSocket::create(family).unwrap();

sock.bind_unspecified().unwrap();

assert!(matches!(sock.get_local_address(), Ok(_)));
assert!(matches!(sock.connect(remote_addr), Ok(_)));
assert!(matches!(sock.get_local_address(), Ok(_)));
}

fn test_udp_connect_dual_stack() {
// Set-up:
let v4_server = UdpSocket::create(IpAddressFamily::Ipv4).unwrap();
Expand Down Expand Up @@ -123,6 +142,12 @@ impl test_programs::p3::exports::wasi::cli::run::Guest for Component {
test_udp_connect_wrong_family(IpAddressFamily::Ipv4);
test_udp_connect_wrong_family(IpAddressFamily::Ipv6);

test_udp_connect_without_bind(IpAddressFamily::Ipv4);
test_udp_connect_without_bind(IpAddressFamily::Ipv6);

test_udp_connect_with_bind(IpAddressFamily::Ipv4);
test_udp_connect_with_bind(IpAddressFamily::Ipv6);

test_udp_connect_dual_stack();
Ok(())
}
Expand Down
28 changes: 28 additions & 0 deletions crates/test-programs/src/bin/p3_sockets_udp_receive.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use test_programs::p3::wasi::sockets::types::{ErrorCode, IpAddressFamily, UdpSocket};

struct Component;

test_programs::p3::export!(Component);

// Receive requires the socket to be bound.
async fn test_udp_receive_without_bind_or_connect(family: IpAddressFamily) {
let sock = UdpSocket::create(family).unwrap();

assert!(matches!(sock.get_local_address(), Err(_)));

assert!(matches!(sock.receive().await, Err(ErrorCode::InvalidState)));

assert!(matches!(sock.get_local_address(), Err(_)));
assert!(matches!(sock.get_remote_address(), Err(_)));
}

impl test_programs::p3::exports::wasi::cli::run::Guest for Component {
async fn run() -> Result<(), ()> {
test_udp_receive_without_bind_or_connect(IpAddressFamily::Ipv4).await;
test_udp_receive_without_bind_or_connect(IpAddressFamily::Ipv6).await;

Ok(())
}
}

fn main() {}
36 changes: 36 additions & 0 deletions crates/test-programs/src/bin/p3_sockets_udp_send.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use test_programs::p3::wasi::sockets::types::{
IpAddress, IpAddressFamily, IpSocketAddress, UdpSocket,
};

struct Component;

test_programs::p3::export!(Component);

// Send without prior `bind` or `connect` performs an implicit bind.
async fn test_udp_send_without_bind_or_connect(family: IpAddressFamily) {
let message = b"Hello, world!";
let remote_addr = IpSocketAddress::new(IpAddress::new_loopback(family), 42);

let sock = UdpSocket::create(family).unwrap();

assert!(matches!(sock.get_local_address(), Err(_)));

assert!(matches!(
sock.send(message.to_vec(), Some(remote_addr)).await,
Ok(_)
));

assert!(matches!(sock.get_local_address(), Ok(_)));
assert!(matches!(sock.get_remote_address(), Err(_)));
}

impl test_programs::p3::exports::wasi::cli::run::Guest for Component {
async fn run() -> Result<(), ()> {
test_udp_send_without_bind_or_connect(IpAddressFamily::Ipv4).await;
test_udp_send_without_bind_or_connect(IpAddressFamily::Ipv6).await;

Ok(())
}
}

fn main() {}
7 changes: 3 additions & 4 deletions crates/test-programs/src/bin/p3_sockets_udp_states.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ test_programs::p3::export!(Component);
async fn test_udp_unbound_state_invariants(family: IpAddressFamily) {
let sock = UdpSocket::create(family).unwrap();

// Skipping: udp::start_bind
// Skipping: udp::bind

assert_eq!(
sock.send(b"test".into(), None).await,
Expand Down Expand Up @@ -38,7 +38,7 @@ fn test_udp_bound_state_invariants(family: IpAddressFamily) {
sock.bind(bind_address),
Err(ErrorCode::InvalidState)
));
// Skipping: udp::stream
// Skipping: udp::connect

assert!(matches!(sock.get_local_address(), Ok(_)));
assert!(matches!(
Expand All @@ -59,14 +59,13 @@ fn test_udp_connected_state_invariants(family: IpAddressFamily) {
let bind_address = IpSocketAddress::new(IpAddress::new_loopback(family), 0);
let connect_address = IpSocketAddress::new(IpAddress::new_loopback(family), 54321);
let sock = UdpSocket::create(family).unwrap();
sock.bind(bind_address).unwrap();
sock.connect(connect_address).unwrap();

assert!(matches!(
sock.bind(bind_address),
Err(ErrorCode::InvalidState)
));
// Skipping: udp::stream
// Skipping: udp::connect

assert!(matches!(sock.get_local_address(), Ok(_)));
assert!(matches!(sock.get_remote_address(), Ok(_)));
Expand Down
4 changes: 2 additions & 2 deletions crates/wasi/src/p2/host/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,13 @@ impl crate::p2::host::tcp::tcp::HostTcpSocket for WasiSocketsCtxView<'_> {
fn start_listen(&mut self, this: Resource<TcpSocket>) -> SocketResult<()> {
let socket = self.table.get_mut(&this)?;

socket.start_listen()?;
socket.start_listen_p2()?;
Ok(())
}

fn finish_listen(&mut self, this: Resource<TcpSocket>) -> SocketResult<()> {
let socket = self.table.get_mut(&this)?;
socket.finish_listen()?;
socket.finish_listen_p2()?;
Ok(())
}

Expand Down
2 changes: 1 addition & 1 deletion crates/wasi/src/p2/host/udp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ impl udp::HostUdpSocket for WasiSocketsCtxView<'_> {
return Err(ErrorCode::InvalidState.into());
};
check.check(connect_addr, SocketAddrUse::UdpConnect).await?;
socket.connect(connect_addr)?;
socket.connect_p2(connect_addr)?;
}

let incoming_stream = IncomingDatagramStream {
Expand Down
3 changes: 1 addition & 2 deletions crates/wasi/src/p3/sockets/host/types/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,7 @@ impl HostTcpSocketWithStore for WasiSockets {
) -> SocketResult<StreamReader<Resource<TcpSocket>>> {
let getter = store.getter();
let socket = get_socket_mut(store.get().table, &socket)?;
socket.start_listen()?;
socket.finish_listen()?;
socket.listen_p3()?;
let listener = socket.tcp_listener_arc().unwrap().clone();
let family = socket.address_family();
let options = socket.non_inherited_options().clone();
Expand Down
24 changes: 10 additions & 14 deletions crates/wasi/src/p3/sockets/host/types/udp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,31 +39,27 @@ impl HostUdpSocketWithStore for WasiSockets {
if data.len() > MAX_UDP_DATAGRAM_SIZE {
return Err(ErrorCode::DatagramTooLarge.into());
}
let remote_address = remote_address.map(SocketAddr::from);

if let Some(addr) = remote_address {
let addr = SocketAddr::from(addr);
if !is_addr_allowed(store, addr, SocketAddrUse::UdpOutgoingDatagram).await {
return Err(ErrorCode::AccessDenied.into());
}
let fut = store.with(|mut view| {
get_socket(view.get().table, &socket).map(|sock| sock.send_to(data, addr))
})?;
fut.await?;
Ok(())
} else {
let fut = store.with(|mut view| {
get_socket(view.get().table, &socket).map(|sock| sock.send(data))
})?;
fut.await?;
Ok(())
}

let fut = store.with(|mut view| {
get_socket_mut(view.get().table, &socket).map(|sock| sock.send_p3(data, remote_address))
})?;
fut.await?;
Ok(())
}

async fn receive<T>(
store: &Accessor<T, Self>,
socket: Resource<UdpSocket>,
) -> SocketResult<(Vec<u8>, IpSocketAddress)> {
let fut = store
.with(|mut view| get_socket(view.get().table, &socket).map(|sock| sock.receive()))?;
.with(|mut view| get_socket(view.get().table, &socket).map(|sock| sock.receive_p3()))?;
let (result, addr) = fut.await?;
Ok((result, addr.into()))
}
Expand Down Expand Up @@ -95,7 +91,7 @@ impl HostUdpSocket for WasiSocketsCtxView<'_> {
return Err(ErrorCode::AccessDenied.into());
}
let socket = get_socket_mut(self.table, &socket)?;
socket.connect(remote_address)?;
socket.connect_p3(remote_address)?;
Ok(())
}

Expand Down
Loading