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 use crate::net::tcp::{Error, TcpConnection, TcpSocket};
184 use embedded_io_async::{Read, Write};
185 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
186
187 pub async fn test_connect(
188 mut client: impl TcpSocket,
189 mut server: impl TcpSocket,
190 ip_address: &str,
191 ) {
192 let ip_address = ip_address.parse().unwrap();
193 let server_addr = SocketAddr::new(ip_address, 59001);
194
195 let server_task = async {
196 let (connection, remote_addr) = server.accept(server_addr).await.unwrap();
197
198 assert!(remote_addr.ip().is_loopback() || remote_addr.ip() == ip_address);
201 assert_ne!(remote_addr.port(), server_addr.port());
202 assert_ne!(remote_addr.port(), 0);
203
204 connection.close().await;
205 };
206
207 let client_task = async {
208 let connection = loop {
209 if let Ok(connection) = client.connect(server_addr).await {
210 break connection;
211 }
212 };
213
214 connection.close().await;
215 };
216
217 futures::join!(server_task, client_task);
218 }
219
220 pub async fn test_send_recv(
221 mut client: impl TcpSocket,
222 mut server: impl TcpSocket,
223 ip_address: &str,
224 ) {
225 let ip_address = ip_address.parse().unwrap();
226 let server_addr = SocketAddr::new(ip_address, 59003);
227
228 let server_task = async {
229 let (mut connection, _) = server.accept(server_addr).await.unwrap();
230
231 let mut buffer = [0u8; 256];
232 let read = connection.read(&mut buffer).await.unwrap();
233 assert_eq!(&buffer[..read], b"Test message from client");
234
235 connection.write_all(&buffer[..read]).await.unwrap();
236 connection.flush().await.unwrap();
237
238 let read = connection.read(&mut buffer).await.unwrap();
239 assert_eq!(&buffer[..read], b"Second message");
240
241 connection.write_all(b"Acknowledged").await.unwrap();
242 connection.flush().await.unwrap();
243
244 connection.close().await;
245 };
246
247 let client_task = async {
248 let mut connection = loop {
249 if let Ok(connection) = client.connect(server_addr).await {
250 break connection;
251 }
252 };
253
254 connection
255 .write_all(b"Test message from client")
256 .await
257 .unwrap();
258 connection.flush().await.unwrap();
259
260 let mut buffer = [0u8; 256];
261 let read = connection.read(&mut buffer).await.unwrap();
262 assert_eq!(&buffer[..read], b"Test message from client");
263
264 connection.write_all(b"Second message").await.unwrap();
265 connection.flush().await.unwrap();
266
267 let read = connection.read(&mut buffer).await.unwrap();
268 assert_eq!(&buffer[..read], b"Acknowledged");
269
270 connection.close().await;
271 };
272
273 futures::join!(server_task, client_task);
274 }
275
276 pub async fn test_connect_refused(mut client: impl TcpSocket, ip_address: &str) {
277 let ip_address = ip_address.parse().unwrap();
278 let server_addr = SocketAddr::new(ip_address, 59900);
279
280 assert_eq!(
281 client.connect(server_addr).await.unwrap_err(),
282 Error::ConnectionReset
283 );
284 }
285
286 pub async fn test_accept_with_zero_port(mut server: impl TcpSocket, ip_address: &str) {
287 let ip_address = ip_address.parse().unwrap();
288 let server_addr = SocketAddr::new(ip_address, 0);
289
290 assert_eq!(
291 server.accept(server_addr).await.unwrap_err(),
292 Error::InvalidPort
293 );
294 }
295
296 pub async fn test_accept_all_zero_ip(
297 mut client: impl TcpSocket,
298 mut server: impl TcpSocket,
299 ip_address: &str,
300 ) {
301 let port = 59910;
302 let ip_address: IpAddr = ip_address.parse().unwrap();
303 let ip_address = SocketAddr::new(ip_address, port);
304 let all_zero_address = if ip_address.is_ipv4() {
305 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), port)
306 } else {
307 SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), port)
308 };
309
310 let server_task = async {
311 let (mut connection, _) = server.accept(all_zero_address).await.unwrap();
312
313 let mut buffer = [0u8; 256];
314 let read = connection.read(&mut buffer).await.unwrap();
315 assert_eq!(&buffer[..read], b"Test message from client");
316
317 connection.write_all(&buffer[..read]).await.unwrap();
318 connection.flush().await.unwrap();
319 };
320
321 let client_task = async {
322 let mut connection = loop {
323 if let Ok(connection) = client.connect(ip_address).await {
324 break connection;
325 }
326 };
327
328 connection
329 .write_all(b"Test message from client")
330 .await
331 .unwrap();
332 connection.flush().await.unwrap();
333
334 connection.close().await;
335 };
336
337 futures::join!(server_task, client_task);
338 }
339
340 pub async fn test_close_connection(
341 mut client: impl TcpSocket,
342 mut server: impl TcpSocket,
343 ip_address: &str,
344 ) {
345 let ip_address = ip_address.parse().unwrap();
346 let server_addr = SocketAddr::new(ip_address, 59004);
347
348 let server_task = async {
349 let (mut connection, _) = server.accept(server_addr).await.unwrap();
350
351 connection.write_all(b"Hello").await.unwrap();
352 connection.flush().await.unwrap();
353
354 connection.close().await;
355 };
356
357 let client_task = async {
358 let mut connection = loop {
359 if let Ok(connection) = client.connect(server_addr).await {
360 break connection;
361 }
362 };
363
364 let mut buffer = [0u8; 32];
365 let read = connection.read(&mut buffer).await.unwrap();
366 assert_eq!(&buffer[..read], b"Hello");
367
368 let read = connection.read(&mut buffer).await.unwrap();
369 assert_eq!(
370 read, 0,
371 "Expected EOF (0 bytes) after server closed connection"
372 );
373
374 connection.close().await;
375 };
376
377 futures::join!(server_task, client_task);
378 }
379}