Skip to content

Commit

Permalink
Merge pull request #42 from quartiq/feature/tcp-updates
Browse files Browse the repository at this point in the history
Feature/tcp updates
  • Loading branch information
ryan-summers authored Jun 22, 2023
2 parents 7c9da38 + 14cedbd commit 0548673
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 104 deletions.
11 changes: 7 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

This document describes the changes to smoltcp-nal between releases.

# [Unreleased]
# [0.3.0]

## Added
* Implemented full UDP socket
* Updated to smoltcp 0.9
* [breaking] Updated to smoltcp 0.9

## Fixed
## Changed
* [breaking] embedded-nal updated to 0.7

# [0.2.1]
## Added
Expand Down Expand Up @@ -37,7 +39,8 @@ This document describes the changes to smoltcp-nal between releases.
# Version [0.1.0] - 2021-02-17
* Initial library release and publish to crates.io

[Unreleased]: https://github.com/quartiq/smoltcp-nal/compare/0.2.1...HEAD
[Unreleased]: https://github.com/quartiq/smoltcp-nal/compare/0.3.0...HEAD
[0.3.0]: https://github.com/quartiq/smoltcp-nal/tree/0.3.0
[0.2.1]: https://github.com/quartiq/smoltcp-nal/tree/0.2.1
[0.2.0]: https://github.com/quartiq/smoltcp-nal/tree/0.2.0
[0.1.0]: https://github.com/quartiq/smoltcp-nal/tree/0.1.0
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "smoltcp-nal"
version = "0.2.1"
version = "0.3.0"
authors = ["Ryan Summers <[email protected]>"]
edition = "2018"
license = "MIT"
Expand All @@ -11,7 +11,7 @@ repository = "https://github.com/quartiq/smoltcp-nal.git"

[dependencies]
heapless = "0.7"
embedded-nal = "0.6"
embedded-nal = "0.7"
embedded-time = "0.12"

[dependencies.nanorand]
Expand Down
141 changes: 44 additions & 97 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,26 @@ pub enum SmoltcpError {
#[derive(Debug, Copy, Clone)]
pub enum NetworkError {
NoSocket,
ConnectionFailure,
ReadFailure,
WriteFailure,
UdpConnectionFailure(smoltcp::socket::udp::BindError),
TcpConnectionFailure(smoltcp::socket::tcp::ConnectError),
TcpReadFailure(smoltcp::socket::tcp::RecvError),
TcpWriteFailure(smoltcp::socket::tcp::SendError),
UdpReadFailure(smoltcp::socket::udp::RecvError),
UdpWriteFailure(smoltcp::socket::udp::SendError),
Unsupported,
NoIpAddress,
NotConnected,
}

impl embedded_nal::TcpError for NetworkError {
fn kind(&self) -> embedded_nal::TcpErrorKind {
match self {
NetworkError::TcpReadFailure(_) => embedded_nal::TcpErrorKind::PipeClosed,
NetworkError::TcpWriteFailure(_) => embedded_nal::TcpErrorKind::PipeClosed,
_ => embedded_nal::TcpErrorKind::Other,
}
}
}

impl From<smoltcp::iface::RouteTableFull> for SmoltcpError {
fn from(_: smoltcp::iface::RouteTableFull) -> SmoltcpError {
SmoltcpError::RouteTableFull
Expand Down Expand Up @@ -375,14 +387,6 @@ where
}
}
}

fn is_ip_unspecified(&self) -> bool {
// Note(unwrap): This stack only supports Ipv4.
self.network_interface
.ipv4_addr()
.map(|ip| ip.is_unspecified())
.unwrap_or(true)
}
}

impl<'a, Device, Clock> TcpClientStack for NetworkStack<'a, Device, Clock>
Expand All @@ -395,11 +399,6 @@ where
type TcpSocket = SocketHandle;

fn socket(&mut self) -> Result<SocketHandle, NetworkError> {
// If we do not have a valid IP address yet, do not open the socket.
if self.is_ip_unspecified() {
return Err(NetworkError::NoIpAddress);
}

match self.unused_tcp_handles.pop() {
Some(handle) => {
// Abort any active connections on the handle.
Expand All @@ -418,85 +417,57 @@ where
socket: &mut SocketHandle,
remote: embedded_nal::SocketAddr,
) -> embedded_nal::nb::Result<(), NetworkError> {
// If there is no longer an IP address assigned to the interface, do not allow usage of the
// socket.
if self.is_ip_unspecified() {
return Err(embedded_nal::nb::Error::Other(NetworkError::NoIpAddress));
}

{
let internal_socket = self.sockets.get::<smoltcp::socket::tcp::Socket>(*socket);

// If we're already in the process of connecting, ignore the request silently.
if internal_socket.is_open() {
return Ok(());
}
}

match remote.ip() {
let dest_addr = match remote.ip() {
embedded_nal::IpAddr::V4(addr) => {
let octets = addr.octets();
let address =
smoltcp::wire::Ipv4Address::new(octets[0], octets[1], octets[2], octets[3]);

let local_port = self.get_ephemeral_port();
let internal_socket = self
.sockets
.get_mut::<smoltcp::socket::tcp::Socket>(*socket);
let context = self.network_interface.context();
internal_socket
.connect(context, (address, remote.port()), local_port)
.map_err(|_| embedded_nal::nb::Error::Other(NetworkError::ConnectionFailure))
smoltcp::wire::Ipv4Address::new(octets[0], octets[1], octets[2], octets[3])
}

// We only support IPv4.
_ => Err(embedded_nal::nb::Error::Other(NetworkError::Unsupported)),
}
}
_ => return Err(embedded_nal::nb::Error::Other(NetworkError::Unsupported)),
};

fn is_connected(&mut self, socket: &SocketHandle) -> Result<bool, NetworkError> {
// If there is no longer an IP address assigned to the interface, do not allow usage of the
// socket.
if self.is_ip_unspecified() {
return Err(NetworkError::NoIpAddress);
let local_port = self.get_ephemeral_port();
let internal_socket = self
.sockets
.get_mut::<smoltcp::socket::tcp::Socket>(*socket);

if !internal_socket.is_open() {
let context = self.network_interface.context();
internal_socket
.connect(context, (dest_addr, remote.port()), local_port)
.map_err(|e| {
embedded_nal::nb::Error::Other(NetworkError::TcpConnectionFailure(e))
})?;
}

let socket: &mut smoltcp::socket::tcp::Socket = self.sockets.get_mut(*socket);
Ok(socket.may_send() && socket.may_recv())
if internal_socket.state() == smoltcp::socket::tcp::State::Established {
Ok(())
} else {
Err(embedded_nal::nb::Error::WouldBlock)
}
}

fn send(
&mut self,
socket: &mut SocketHandle,
buffer: &[u8],
) -> embedded_nal::nb::Result<usize, NetworkError> {
// If there is no longer an IP address assigned to the interface, do not allow usage of the
// socket.
if self.is_ip_unspecified() {
return Err(embedded_nal::nb::Error::Other(NetworkError::NoIpAddress));
}

let socket: &mut smoltcp::socket::tcp::Socket = self.sockets.get_mut(*socket);
socket
.send_slice(buffer)
.map_err(|_| embedded_nal::nb::Error::Other(NetworkError::WriteFailure))
.map_err(|e| embedded_nal::nb::Error::Other(NetworkError::TcpWriteFailure(e)))
}

fn receive(
&mut self,
socket: &mut SocketHandle,
buffer: &mut [u8],
) -> embedded_nal::nb::Result<usize, NetworkError> {
// If there is no longer an IP address assigned to the interface, do not allow usage of the
// socket.
if self.is_ip_unspecified() {
return Err(embedded_nal::nb::Error::Other(NetworkError::NoIpAddress));
}

let socket: &mut smoltcp::socket::tcp::Socket = self.sockets.get_mut(*socket);
socket
.recv_slice(buffer)
.map_err(|_| embedded_nal::nb::Error::Other(NetworkError::ReadFailure))
.map_err(|e| embedded_nal::nb::Error::Other(NetworkError::TcpReadFailure(e)))
}

fn close(&mut self, socket: SocketHandle) -> Result<(), NetworkError> {
Expand All @@ -518,11 +489,6 @@ where
type UdpSocket = UdpSocket;

fn socket(&mut self) -> Result<UdpSocket, NetworkError> {
// If we do not have a valid IP address yet, do not open the socket.
if self.is_ip_unspecified() {
return Err(NetworkError::NoIpAddress);
}

let handle = self
.unused_udp_handles
.pop()
Expand All @@ -543,9 +509,6 @@ where
socket: &mut UdpSocket,
remote: embedded_nal::SocketAddr,
) -> Result<(), NetworkError> {
if self.is_ip_unspecified() {
return Err(NetworkError::NoIpAddress);
}
// Store the route for this socket.
match remote {
embedded_nal::SocketAddr::V4(addr) => {
Expand Down Expand Up @@ -577,7 +540,7 @@ where
self.sockets.get_mut(socket.handle);
internal_socket
.bind(local_endpoint)
.map_err(|_| NetworkError::ConnectionFailure)?;
.map_err(NetworkError::UdpConnectionFailure)?;

Ok(())
}
Expand All @@ -587,32 +550,24 @@ where
socket: &mut UdpSocket,
buffer: &[u8],
) -> embedded_nal::nb::Result<(), NetworkError> {
if self.is_ip_unspecified() {
return Err(embedded_nal::nb::Error::Other(NetworkError::NoIpAddress));
}

let internal_socket: &mut smoltcp::socket::udp::Socket =
self.sockets.get_mut(socket.handle);
let destination = socket.destination.ok_or(NetworkError::NotConnected)?;
internal_socket
.send_slice(buffer, destination)
.map_err(|_| embedded_nal::nb::Error::Other(NetworkError::WriteFailure))
.map_err(|e| embedded_nal::nb::Error::Other(NetworkError::UdpWriteFailure(e)))
}

fn receive(
&mut self,
socket: &mut UdpSocket,
buffer: &mut [u8],
) -> embedded_nal::nb::Result<(usize, embedded_nal::SocketAddr), NetworkError> {
if self.is_ip_unspecified() {
return Err(embedded_nal::nb::Error::Other(NetworkError::NoIpAddress));
}

let internal_socket: &mut smoltcp::socket::udp::Socket =
self.sockets.get_mut(socket.handle);
let (size, source) = internal_socket
.recv_slice(buffer)
.map_err(|_| embedded_nal::nb::Error::Other(NetworkError::ReadFailure))?;
.map_err(|e| embedded_nal::nb::Error::Other(NetworkError::UdpReadFailure(e)))?;

let source = {
let octets = source.addr.as_bytes();
Expand Down Expand Up @@ -649,10 +604,6 @@ where
{
/// Bind a UDP socket to a specific port.
fn bind(&mut self, socket: &mut UdpSocket, local_port: u16) -> Result<(), NetworkError> {
if self.is_ip_unspecified() {
return Err(NetworkError::NoIpAddress);
}

let local_address = self
.network_interface
.ip_addrs()
Expand All @@ -667,7 +618,7 @@ where
self.sockets.get_mut(socket.handle);
internal_socket
.bind(local_endpoint)
.map_err(|_| NetworkError::ConnectionFailure)?;
.map_err(NetworkError::UdpConnectionFailure)?;

Ok(())
}
Expand All @@ -679,10 +630,6 @@ where
remote: embedded_nal::SocketAddr,
buffer: &[u8],
) -> embedded_nal::nb::Result<(), NetworkError> {
if self.is_ip_unspecified() {
return Err(embedded_nal::nb::Error::Other(NetworkError::NoIpAddress));
}

let destination = match remote {
embedded_nal::SocketAddr::V4(addr) => {
let octets = addr.ip().octets();
Expand All @@ -699,6 +646,6 @@ where
self.sockets.get_mut(socket.handle);
internal_socket
.send_slice(buffer, destination)
.map_err(|_| embedded_nal::nb::Error::Other(NetworkError::WriteFailure))
.map_err(|e| embedded_nal::nb::Error::Other(NetworkError::UdpWriteFailure(e)))
}
}
1 change: 0 additions & 1 deletion src/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ where

forward! {socket() -> Result<S::TcpSocket, S::Error>}
forward! {connect(socket: &mut S::TcpSocket, remote: embedded_nal::SocketAddr) -> embedded_nal::nb::Result<(), S::Error>}
forward! {is_connected(socket: &S::TcpSocket) -> Result<bool, S::Error>}
forward! {send(socket: &mut S::TcpSocket, buffer: &[u8]) -> embedded_nal::nb::Result<usize, S::Error>}
forward! {receive(socket: &mut S::TcpSocket, buffer: &mut [u8]) -> embedded_nal::nb::Result<usize, S::Error>}
forward! {close(socket: S::TcpSocket) -> Result<(), S::Error>}
Expand Down

0 comments on commit 0548673

Please sign in to comment.