1use core::fmt::Display;
6use core::fmt::Formatter;
7use core::net::SocketAddr;
8use embedded_io_async::ErrorKind;
9
10#[expect(async_fn_in_trait)]
32pub trait TcpSocket {
33 async fn connect(&mut self, address: SocketAddr) -> Result<impl TcpConnection, Error>;
35
36 async fn accept(
50 &mut self,
51 address: SocketAddr,
52 ) -> Result<(impl TcpConnection, SocketAddr), Error>;
53}
54
55#[expect(async_fn_in_trait)]
82pub trait TcpConnection:
83 core::fmt::Debug
84 + embedded_io_async::Read
85 + embedded_io_async::Write
86 + embedded_io_async::ErrorType<Error = Error>
87{
88 async fn close(self);
90}
91
92#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Copy, Clone, Hash)]
94pub enum Error {
95 ConnectionReset,
97 InvalidState,
99 InvalidPort,
101 InvalidAddress,
105 TimedOut,
107 NoRoute,
109 PermissionDenied,
111 NetworkDown,
113 Other,
116}
117
118impl Display for Error {
119 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
120 match self {
121 Error::ConnectionReset => {
122 write!(f, "The connection was reset by timeout of RST packet.")
123 }
124 Error::InvalidState => {
125 write!(f, "The socket is in an invalid state.")
126 }
127 Error::InvalidPort => {
128 write!(f, "The provided port is invalid.")
129 }
130 Error::TimedOut => {
131 write!(f, "The connection timed out.")
132 }
133 Error::NoRoute => {
134 write!(f, "No route to host.")
135 }
136 Error::Other => {
137 write!(
138 f,
139 "Unspecified error, please open a bug report if you encounter this error."
140 )
141 }
142 Error::InvalidAddress => {
143 write!(f, "The provided address is invalid.")
144 }
145 Error::PermissionDenied => {
146 write!(f, "No permission to access the resource.")
147 }
148 Error::NetworkDown => {
149 write!(f, "The network stack is down.")
150 }
151 }
152 }
153}
154
155impl core::error::Error for Error {}
156
157impl embedded_io_async::ErrorType for Error {
158 type Error = Error;
159}
160
161impl embedded_io_async::Error for Error {
162 fn kind(&self) -> ErrorKind {
163 match self {
164 Error::ConnectionReset => ErrorKind::ConnectionReset,
165 Error::InvalidState => ErrorKind::InvalidInput,
166 Error::InvalidPort => ErrorKind::InvalidInput,
167 Error::InvalidAddress => ErrorKind::InvalidInput,
168 Error::TimedOut => ErrorKind::TimedOut,
169 Error::NoRoute => ErrorKind::Other,
170 Error::PermissionDenied => ErrorKind::PermissionDenied,
171 Error::NetworkDown => ErrorKind::NotConnected,
172 Error::Other => ErrorKind::Other,
173 }
174 }
175}
176
177#[doc(hidden)]
178#[cfg(feature = "test-suites")]
179#[cfg_attr(coverage_nightly, coverage(off))]
180pub mod test_suite {
181 #![expect(missing_docs, reason = "tests")]
182 use crate::net::tcp::{Error, TcpConnection, TcpSocket};
185 use embedded_io_async::{Read, Write};
186 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
187
188 pub async fn test_connect(
189 mut client: impl TcpSocket,
190 mut server: impl TcpSocket,
191 ip_address: &str,
192 ) {
193 let ip_address = ip_address.parse().unwrap();
194 let server_addr = SocketAddr::new(ip_address, 59001);
195
196 let server_task = async {
197 let (connection, remote_addr) = server.accept(server_addr).await.unwrap();
198
199 assert!(remote_addr.ip().is_loopback() || remote_addr.ip() == ip_address);
202 assert_ne!(remote_addr.port(), server_addr.port());
203 assert_ne!(remote_addr.port(), 0);
204
205 connection.close().await;
206 };
207
208 let client_task = async {
209 let connection = loop {
210 if let Ok(connection) = client.connect(server_addr).await {
211 break connection;
212 }
213 };
214
215 connection.close().await;
216 };
217
218 futures::join!(server_task, client_task);
219 }
220
221 pub async fn test_send_recv(
222 mut client: impl TcpSocket,
223 mut server: impl TcpSocket,
224 ip_address: &str,
225 ) {
226 let ip_address = ip_address.parse().unwrap();
227 let server_addr = SocketAddr::new(ip_address, 59003);
228
229 let server_task = async {
230 let (mut connection, _) = server.accept(server_addr).await.unwrap();
231
232 let mut buffer = [0u8; 256];
233 let read = connection.read(&mut buffer).await.unwrap();
234 assert_eq!(&buffer[..read], b"Test message from client");
235
236 connection.write_all(&buffer[..read]).await.unwrap();
237 connection.flush().await.unwrap();
238
239 let read = connection.read(&mut buffer).await.unwrap();
240 assert_eq!(&buffer[..read], b"Second message");
241
242 connection.write_all(b"Acknowledged").await.unwrap();
243 connection.flush().await.unwrap();
244
245 connection.close().await;
246 };
247
248 let client_task = async {
249 let mut connection = loop {
250 if let Ok(connection) = client.connect(server_addr).await {
251 break connection;
252 }
253 };
254
255 connection
256 .write_all(b"Test message from client")
257 .await
258 .unwrap();
259 connection.flush().await.unwrap();
260
261 let mut buffer = [0u8; 256];
262 let read = connection.read(&mut buffer).await.unwrap();
263 assert_eq!(&buffer[..read], b"Test message from client");
264
265 connection.write_all(b"Second message").await.unwrap();
266 connection.flush().await.unwrap();
267
268 let read = connection.read(&mut buffer).await.unwrap();
269 assert_eq!(&buffer[..read], b"Acknowledged");
270
271 connection.close().await;
272 };
273
274 futures::join!(server_task, client_task);
275 }
276
277 pub async fn test_connect_refused(mut client: impl TcpSocket, ip_address: &str) {
278 let ip_address = ip_address.parse().unwrap();
279 let server_addr = SocketAddr::new(ip_address, 59900);
280
281 assert_eq!(
282 client.connect(server_addr).await.unwrap_err(),
283 Error::ConnectionReset
284 );
285 }
286
287 pub async fn test_accept_with_zero_port(mut server: impl TcpSocket, ip_address: &str) {
288 let ip_address = ip_address.parse().unwrap();
289 let server_addr = SocketAddr::new(ip_address, 0);
290
291 assert_eq!(
292 server.accept(server_addr).await.unwrap_err(),
293 Error::InvalidPort
294 );
295 }
296
297 pub async fn test_accept_all_zero_ip(
298 mut client: impl TcpSocket,
299 mut server: impl TcpSocket,
300 ip_address: &str,
301 ) {
302 let port = 59910;
303 let ip_address: IpAddr = ip_address.parse().unwrap();
304 let ip_address = SocketAddr::new(ip_address, port);
305 let all_zero_address = if ip_address.is_ipv4() {
306 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), port)
307 } else {
308 SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), port)
309 };
310
311 let server_task = async {
312 let (mut connection, _) = server.accept(all_zero_address).await.unwrap();
313
314 let mut buffer = [0u8; 256];
315 let read = connection.read(&mut buffer).await.unwrap();
316 assert_eq!(&buffer[..read], b"Test message from client");
317
318 connection.write_all(&buffer[..read]).await.unwrap();
319 connection.flush().await.unwrap();
320 };
321
322 let client_task = async {
323 let mut connection = loop {
324 if let Ok(connection) = client.connect(ip_address).await {
325 break connection;
326 }
327 };
328
329 connection
330 .write_all(b"Test message from client")
331 .await
332 .unwrap();
333 connection.flush().await.unwrap();
334
335 connection.close().await;
336 };
337
338 futures::join!(server_task, client_task);
339 }
340
341 pub async fn test_close_connection(
342 mut client: impl TcpSocket,
343 mut server: impl TcpSocket,
344 ip_address: &str,
345 ) {
346 let ip_address = ip_address.parse().unwrap();
347 let server_addr = SocketAddr::new(ip_address, 59004);
348
349 let server_task = async {
350 let (mut connection, _) = server.accept(server_addr).await.unwrap();
351
352 connection.write_all(b"Hello").await.unwrap();
353 connection.flush().await.unwrap();
354
355 connection.close().await;
356 };
357
358 let client_task = async {
359 let mut connection = loop {
360 if let Ok(connection) = client.connect(server_addr).await {
361 break connection;
362 }
363 };
364
365 let mut buffer = [0u8; 32];
366 let read = connection.read(&mut buffer).await.unwrap();
367 assert_eq!(&buffer[..read], b"Hello");
368
369 let read = connection.read(&mut buffer).await.unwrap();
370 assert_eq!(
371 read, 0,
372 "Expected EOF (0 bytes) after server closed connection"
373 );
374
375 connection.close().await;
376 };
377
378 futures::join!(server_task, client_task);
379 }
380}