use embedded_nal::TcpClientStack;
use embedded_nal::TcpFullStack;
use super::ClientSocketOp;
use super::Handle;
use super::StackError;
use super::WincClient;
use super::Xfer;
use crate::manager::SocketError;
use crate::net_ops::op::OpImpl;
use crate::net_ops::tcp_accept::TcpAcceptOp;
use crate::net_ops::tcp_connect::TcpConnectOp;
use crate::net_ops::tcp_receive::TcpReceiveOp;
use crate::net_ops::tcp_send::TcpSendOp;
use crate::{debug, info};
use embedded_nal::nb;
use crate::stack::sock_holder::SocketStore;
#[cfg(test)]
use crate::stack::constants::MAX_SEND_LENGTH_TEST;
impl<X: Xfer> WincClient<'_, X> {
fn poll_op<O: OpImpl<X, Error = StackError>>(
&mut self,
op: &mut O,
) -> nb::Result<O::Output, StackError> {
self.dispatch_events()?;
match op.poll_impl(&mut self.manager, &mut self.callbacks) {
Ok(Some(r)) => Ok(r),
Ok(None) => Err(nb::Error::WouldBlock),
Err(e) => Err(nb::Error::Other(e)),
}
}
}
impl<X: Xfer> embedded_nal::TcpClientStack for WincClient<'_, X> {
type TcpSocket = Handle;
type Error = StackError;
fn socket(
&mut self,
) -> Result<<Self as TcpClientStack>::TcpSocket, <Self as TcpClientStack>::Error> {
self.dispatch_events()?;
let s = self.get_next_session_id();
let handle = self
.callbacks
.tcp_sockets
.add(s)
.ok_or(StackError::OutOfSockets)?;
Ok(handle)
}
fn connect(
&mut self,
socket: &mut Self::TcpSocket,
remote: core::net::SocketAddr,
) -> nb::Result<(), Self::Error> {
let addr = match remote {
core::net::SocketAddr::V4(addr) => addr,
core::net::SocketAddr::V6(_) => unimplemented!("IPv6 not supported"),
};
let mut op = TcpConnectOp::new(*socket, addr);
let res = self.poll_op(&mut op);
self.test_hook();
res
}
fn send(
&mut self,
socket: &mut <Self as TcpClientStack>::TcpSocket,
data: &[u8],
) -> Result<usize, nb::Error<<Self as TcpClientStack>::Error>> {
let mut op = TcpSendOp::new(*socket, data);
let res = self.poll_op(&mut op);
self.test_hook();
res
}
fn receive(
&mut self,
socket: &mut <Self as TcpClientStack>::TcpSocket,
data: &mut [u8],
) -> Result<usize, nb::Error<<Self as TcpClientStack>::Error>> {
let mut op = TcpReceiveOp::new(*socket, data);
let res = self.poll_op(&mut op);
self.test_hook();
res
}
fn close(&mut self, socket: <Self as TcpClientStack>::TcpSocket) -> Result<(), Self::Error> {
debug!("Closing socket {:?}", socket);
self.dispatch_events()?;
let (sock, _op) = self.callbacks.tcp_sockets.get(socket).unwrap();
let socket_id = sock.v as usize;
self.callbacks.listening_sockets[socket_id] = false;
self.callbacks.accept_backlog[socket_id] = None;
self.manager
.send_close(*sock)
.map_err(StackError::SendCloseFailed)?;
self.callbacks
.tcp_sockets
.get(socket)
.ok_or(StackError::CloseFailed)?;
self.callbacks.tcp_sockets.remove(socket);
Ok(())
}
}
impl<X: Xfer> TcpFullStack for WincClient<'_, X> {
fn bind(&mut self, socket: &mut Self::TcpSocket, local_port: u16) -> Result<(), Self::Error> {
let server_addr =
core::net::SocketAddrV4::new(core::net::Ipv4Addr::new(0, 0, 0, 0), local_port);
let (sock, op) = self.callbacks.tcp_sockets.get(*socket).unwrap();
*op = ClientSocketOp::Bind(None);
debug!("<> Sending TCP socket bind to {:?}", sock);
self.manager
.send_bind(*sock, server_addr)
.map_err(StackError::BindFailed)?;
self.wait_with_timeout(Self::BIND_TIMEOUT, |client, _| {
let (_, op) = client.callbacks.tcp_sockets.get(*socket).unwrap();
let res = match op {
ClientSocketOp::Bind(Some(bind_result)) => match bind_result.error {
SocketError::NoError => Some(Ok(())),
_ => Some(Err(StackError::OpFailed(bind_result.error))),
},
_ => None,
};
if res.is_some() {
*op = ClientSocketOp::None;
}
res
})
}
fn listen(&mut self, socket: &mut Self::TcpSocket) -> Result<(), Self::Error> {
let (sock, op) = self.callbacks.tcp_sockets.get(*socket).unwrap();
let sock_index = sock.v as usize;
*op = ClientSocketOp::Listen(None);
debug!("<> Sending TCP socket listen to {:?}", sock);
self.manager.send_listen(*sock, Self::TCP_SOCKET_BACKLOG)?;
let res = self.wait_with_timeout(Self::LISTEN_TIMEOUT, |client, _| {
let (_, op) = client.callbacks.tcp_sockets.get(*socket).unwrap();
let res = match op {
ClientSocketOp::Listen(Some(listen_result)) => match listen_result.error {
SocketError::NoError => Some(Ok(())),
_ => Some(Err(StackError::OpFailed(listen_result.error))),
},
_ => None,
};
if res.is_some() {
*op = ClientSocketOp::None;
}
res
});
if res.is_ok() {
self.callbacks.listening_sockets[sock_index] = true;
}
res
}
fn accept(
&mut self,
socket: &mut Handle,
) -> nb::Result<(Handle, core::net::SocketAddr), StackError> {
for backlog in self.callbacks.accept_backlog.iter_mut() {
if let Some((accepted_socket, addr)) = backlog.take() {
info!("Accepting backlogged socket {:?}", accepted_socket);
return Ok((Handle(accepted_socket.v), core::net::SocketAddr::V4(addr)));
}
}
let mut op = TcpAcceptOp::new(*socket);
let res = self.poll_op(&mut op);
self.test_hook();
match res {
Ok((raw_socket, addr)) => {
let handle = self
.callbacks
.tcp_sockets
.put(Handle(raw_socket.v), raw_socket.s)
.ok_or(StackError::SocketAlreadyInUse)?;
Ok((handle, core::net::SocketAddr::V4(addr)))
}
Err(err) => Err(err),
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::client::test_shared::*;
use crate::stack::socket_callbacks::AsyncOp;
use crate::{client::SocketCallbacks, manager::EventListener, socket::Socket};
use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4};
use embedded_nal::{TcpClientStack, TcpFullStack};
#[test]
fn test_tcp_socket_open() {
let mut client = make_test_client();
let tcp_socket = client.socket();
assert!(tcp_socket.is_ok());
}
#[test]
fn test_tcp_connect() {
let mut client = make_test_client();
let mut tcp_socket = client.socket().unwrap();
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_connect(Socket::new(0, 0), SocketError::NoError);
};
client.debug_callback = Some(&mut my_debug);
let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 80);
let result = nb::block!(client.connect(&mut tcp_socket, socket_addr));
assert!(result.is_ok());
}
#[test]
fn test_tcp_connect_check_blocking() {
let mut client = make_test_client();
let mut tcp_socket = client.socket().unwrap();
let mut counter: u8 = 0;
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_connect(Socket::new(0, 0), SocketError::NoError);
};
let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 80);
while counter != 5 {
let result = client.connect(&mut tcp_socket, socket_addr);
assert!(matches!(result, Err(nb::Error::WouldBlock)));
counter += 1;
}
client.debug_callback = Some(&mut my_debug);
let result = nb::block!(client.connect(&mut tcp_socket, socket_addr));
assert_eq!(result, Ok(()));
}
#[test]
fn test_tcp_send() {
let mut client = make_test_client();
let mut tcp_socket = client.socket().unwrap();
let packet = "Hello, World";
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_send(Socket::new(0, 0), MAX_SEND_LENGTH_TEST as i16);
};
client.debug_callback = Some(&mut my_debug);
let result = nb::block!(client.send(&mut tcp_socket, packet.as_bytes()));
assert_eq!(result.ok(), Some(packet.len()));
}
#[test]
fn test_tcp_receive() {
let mut client = make_test_client();
let mut tcp_socket = client.socket().unwrap();
let socket_addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 80);
let mut recv_buff = [0u8; 32];
let test_data = "Hello, World";
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_recv(
Socket::new(0, 0),
socket_addr,
test_data.as_bytes(),
SocketError::NoError,
);
};
client.debug_callback = Some(&mut my_debug);
let result = nb::block!(client.receive(&mut tcp_socket, &mut recv_buff));
assert_eq!(result.ok(), Some(test_data.len()));
assert_eq!(&recv_buff[..test_data.len()], test_data.as_bytes());
}
#[test]
fn test_tcp_close() {
let mut client = make_test_client();
let tcp_socket = client.socket().unwrap();
let result = client.close(tcp_socket);
assert!(result.is_ok());
}
#[test]
fn test_tcp_bind() {
let mut client = make_test_client();
let mut tcp_socket = client.socket().unwrap();
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_bind(Socket::new(0, 0), SocketError::NoError);
};
client.debug_callback = Some(&mut my_debug);
let result = client.bind(&mut tcp_socket, 8080);
assert!(result.is_ok());
}
#[test]
fn test_tcp_listen() {
let mut client = make_test_client();
let mut tcp_socket = client.socket().unwrap();
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_listen(Socket::new(0, 0), SocketError::NoError);
};
client.debug_callback = Some(&mut my_debug);
let result = client.listen(&mut tcp_socket);
assert!(result.is_ok());
}
#[test]
fn test_tcp_accept() {
let mut client = make_test_client();
let mut tcp_socket = client.socket().unwrap();
let socket_addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 80);
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_accept(socket_addr, Socket::new(0, 0), Socket::new(1, 0), 0);
};
client.debug_callback = Some(&mut my_debug);
let result = nb::block!(client.accept(&mut tcp_socket));
assert!(result.is_ok());
}
#[test]
fn test_tcp_check_max_send_buffer() {
let mut client = make_test_client();
let mut tcp_socket = client.socket().unwrap();
let packet = "Hello, World";
let socket = Socket::new(0, 0);
let valid_len: i16 = MAX_SEND_LENGTH_TEST as i16;
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_send(socket, valid_len);
};
client.debug_callback = Some(&mut my_debug);
let result = client.send(&mut tcp_socket, packet.as_bytes());
assert_eq!(result, Err(nb::Error::WouldBlock));
if let Some((_, ClientSocketOp::AsyncOp(AsyncOp::Send(req, _), _))) =
client.callbacks.resolve(socket)
{
assert!(req.total_sent == valid_len);
} else {
assert!(false, "Expected Some value, but it returned None");
}
}
#[test]
fn test_tcp_check_receive_timeout() {
let mut client = make_test_client();
let mut tcp_socket = client.socket().unwrap();
let socket_addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 80);
let mut recv_buff = [0u8; 32];
let mut counter = 5;
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_recv(Socket::new(0, 0), socket_addr, &[], SocketError::Timeout);
};
client.debug_callback = Some(&mut my_debug);
while counter != 0 {
let result = client.receive(&mut tcp_socket, &mut recv_buff);
assert_eq!(result.err(), Some(nb::Error::WouldBlock));
counter -= 1;
}
}
#[test]
fn test_tcp_check_receive_err() {
let mut client = make_test_client();
let mut tcp_socket = client.socket().unwrap();
let socket_addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 80);
let mut recv_buff = [0u8; 32];
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_recv(
Socket::new(0, 0),
socket_addr,
&[],
SocketError::ConnAborted,
);
};
client.debug_callback = Some(&mut my_debug);
let result = nb::block!(client.receive(&mut tcp_socket, &mut recv_buff));
assert_eq!(
result.err(),
Some(StackError::OpFailed(SocketError::ConnAborted))
);
}
#[test]
fn test_tcp_check_bind_error() {
let mut client = make_test_client();
let mut tcp_socket = client.socket().unwrap();
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_bind(Socket::new(0, 0), SocketError::InvalidAddress);
};
client.debug_callback = Some(&mut my_debug);
let result = client.bind(&mut tcp_socket, 8080);
assert_eq!(
result.err(),
Some(StackError::OpFailed(SocketError::InvalidAddress))
);
}
#[test]
fn test_tcp_check_accept_backlog() {
let mut client = make_test_client();
let mut tcp_socket = client.socket().unwrap();
let socket_addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 80);
let socket = Socket::new(0, 0);
client.callbacks.accept_backlog[0] = Some((socket, socket_addr));
let result = nb::block!(client.accept(&mut tcp_socket));
assert_eq!(
result.ok(),
Some((Handle(0), core::net::SocketAddr::V4(socket_addr)))
);
}
#[test]
fn test_tcp_check_listen_error() {
let mut client = make_test_client();
let mut tcp_socket = client.socket().unwrap();
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_listen(Socket::new(0, 0), SocketError::ConnAborted);
};
client.debug_callback = Some(&mut my_debug);
let result = client.listen(&mut tcp_socket);
assert!(result.is_err());
}
#[test]
fn test_tcp_connect_error() {
let mut client = make_test_client();
let mut tcp_socket = client.socket().unwrap();
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_connect(Socket::new(0, 0), SocketError::ConnAborted);
};
client.debug_callback = Some(&mut my_debug);
let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 80);
let result = nb::block!(client.connect(&mut tcp_socket, socket_addr));
assert_eq!(
result.err(),
Some(StackError::OpFailed(SocketError::ConnAborted))
);
}
#[test]
#[should_panic]
fn test_tcp_connect_ipv6() {
let mut client = make_test_client();
let mut tcp_socket = client.socket().unwrap();
let socket_addr = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), 80);
let _ = client.connect(&mut tcp_socket, socket_addr);
}
#[test]
fn test_tcp_large_payload_receive() {
let mut client = make_test_client();
let mut tcp_socket = client.socket().unwrap();
let socket_addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 80);
let mut recv_buffer = [0u8; 350];
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_recv(
Socket::new(0, 0),
socket_addr,
&[0xAA; 1400], SocketError::NoError,
);
};
client.debug_callback = Some(&mut my_debug);
let first_read = nb::block!(client.receive(&mut tcp_socket, &mut recv_buffer)).unwrap();
assert_eq!(first_read, 350);
assert!(recv_buffer.iter().all(|&x| x == 0xAA));
let second_read = nb::block!(client.receive(&mut tcp_socket, &mut recv_buffer)).unwrap();
assert_eq!(second_read, 350);
assert!(recv_buffer.iter().all(|&x| x == 0xAA));
let third_read = nb::block!(client.receive(&mut tcp_socket, &mut recv_buffer)).unwrap();
assert_eq!(third_read, 350);
assert!(recv_buffer.iter().all(|&x| x == 0xAA));
let fourth_read = nb::block!(client.receive(&mut tcp_socket, &mut recv_buffer)).unwrap();
assert_eq!(fourth_read, 350);
assert!(recv_buffer.iter().all(|&x| x == 0xAA));
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_recv(
Socket::new(0, 0),
socket_addr,
&[0x55; 700], SocketError::NoError,
);
};
client.debug_callback = Some(&mut my_debug);
let fifth_read = nb::block!(client.receive(&mut tcp_socket, &mut recv_buffer)).unwrap();
assert_eq!(fifth_read, 350);
assert!(recv_buffer.iter().all(|&x| x == 0x55));
let sixth_read = nb::block!(client.receive(&mut tcp_socket, &mut recv_buffer)).unwrap();
assert_eq!(sixth_read, 350);
assert!(recv_buffer.iter().all(|&x| x == 0x55));
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_recv(Socket::new(0, 0), socket_addr, &[], SocketError::NoError);
};
client.debug_callback = Some(&mut my_debug);
let seventh_read = nb::block!(client.receive(&mut tcp_socket, &mut recv_buffer)).unwrap();
assert_eq!(seventh_read, 0);
}
#[test]
fn partial_receive_full_test() {
run_partial_read_test(10240, 31, 2048);
run_partial_read_test(10240, 100, 100);
run_partial_read_test(10240, 64, 64);
run_partial_read_test(10240, 1024, 31);
run_partial_read_test(10240, 1024, 100);
run_partial_read_test(10240, 1024, 1024);
run_partial_read_test(10240, 1400, 1400);
run_partial_read_test(64, 1024, 1400);
run_partial_read_test(9996, 97, 131); }
fn run_partial_read_test(total_size: usize, spi_chunk_size: usize, receive_buffer_size: usize) {
let mut client = make_test_client();
let mut socket_handle = client.socket().unwrap();
let socket_addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 80);
let mut source_data = [0u8; 10240];
assert!(total_size <= source_data.len());
let source_slice = &mut source_data[0..total_size];
crate::client::tests::generate_test_pattern(source_slice);
let expected_checksum = crate::client::tests::compute_crc16(source_slice);
let mut received_data = [0u8; 10240];
let mut app_receive_buffer = [0u8; 2048];
assert!(receive_buffer_size <= app_receive_buffer.len());
let initial_result = client.receive(
&mut socket_handle,
&mut app_receive_buffer[0..receive_buffer_size],
);
assert_eq!(initial_result, Err(nb::Error::WouldBlock));
let mut total_bytes_received = 0;
let mut spi_offset = 0;
while spi_offset < total_size {
let chunk_end = (spi_offset + spi_chunk_size).min(total_size);
let chunk = &source_slice[spi_offset..chunk_end];
client.callbacks.recv_buffer[..chunk.len()].copy_from_slice(chunk);
client
.callbacks
.on_recv(Socket::new(0, 0), socket_addr, chunk, SocketError::NoError);
spi_offset = chunk_end;
loop {
let receive_slice = &mut app_receive_buffer[0..receive_buffer_size];
let read_result = client.receive(&mut socket_handle, receive_slice);
match read_result {
Ok(bytes_read) => {
if bytes_read == 0 {
break; }
received_data[total_bytes_received..total_bytes_received + bytes_read]
.copy_from_slice(&receive_slice[0..bytes_read]);
total_bytes_received += bytes_read;
}
Err(nb::Error::WouldBlock) => {
break; }
Err(e) => {
panic!("Unexpected error: {:?}", e);
}
}
}
}
assert_eq!(
total_bytes_received, total_size,
"Total bytes received {} != expected {} (SPI: {}, RX: {})",
total_bytes_received, total_size, spi_chunk_size, receive_buffer_size
);
let received_slice = &received_data[0..total_size];
let actual_checksum = crate::client::tests::compute_crc16(received_slice);
assert_eq!(
actual_checksum, expected_checksum,
"Checksum mismatch! (SPI: {}, RX: {})",
spi_chunk_size, receive_buffer_size
);
assert_eq!(
received_slice, source_slice,
"Data content mismatch! (SPI: {}, RX: {})",
spi_chunk_size, receive_buffer_size
);
}
#[test]
fn test_tcp_send_failed() {
let mut client = make_test_client();
let mut tcp_socket = client.socket().unwrap();
let packet = "Hello, World";
let mut my_debug = |callbacks: &mut SocketCallbacks| {
callbacks.on_send(Socket::new(0, 0), -7);
};
client.debug_callback = Some(&mut my_debug);
let result = nb::block!(client.send(&mut tcp_socket, packet.as_bytes()));
assert_eq!(
result.err(),
Some(StackError::OpFailed(SocketError::MaxListenSock))
);
}
}