1 #![cfg_attr(not(feature = "std"), no_std)]
2 #![allow(unused_mut)]
3 #![allow(clippy::collapsible_if)]
4
5 #[cfg(feature = "std")]
6 #[allow(dead_code)]
7 mod utils;
8
9 use core::str;
10 use log::{debug, error, info};
11
12 use smoltcp::iface::{Config, Interface, SocketSet};
13 use smoltcp::phy::{Loopback, Medium};
14 use smoltcp::socket::tcp;
15 use smoltcp::time::{Duration, Instant};
16 use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
17
18 #[cfg(not(feature = "std"))]
19 mod mock {
20 use core::cell::Cell;
21 use smoltcp::time::{Duration, Instant};
22
23 #[derive(Debug)]
24 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
25 pub struct Clock(Cell<Instant>);
26
27 impl Clock {
new() -> Clock28 pub fn new() -> Clock {
29 Clock(Cell::new(Instant::from_millis(0)))
30 }
31
advance(&self, duration: Duration)32 pub fn advance(&self, duration: Duration) {
33 self.0.set(self.0.get() + duration)
34 }
35
elapsed(&self) -> Instant36 pub fn elapsed(&self) -> Instant {
37 self.0.get()
38 }
39 }
40 }
41
42 #[cfg(feature = "std")]
43 mod mock {
44 use smoltcp::time::{Duration, Instant};
45 use std::sync::atomic::{AtomicUsize, Ordering};
46 use std::sync::Arc;
47
48 // should be AtomicU64 but that's unstable
49 #[derive(Debug, Clone)]
50 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
51 pub struct Clock(Arc<AtomicUsize>);
52
53 impl Clock {
new() -> Clock54 pub fn new() -> Clock {
55 Clock(Arc::new(AtomicUsize::new(0)))
56 }
57
advance(&self, duration: Duration)58 pub fn advance(&self, duration: Duration) {
59 self.0
60 .fetch_add(duration.total_millis() as usize, Ordering::SeqCst);
61 }
62
elapsed(&self) -> Instant63 pub fn elapsed(&self) -> Instant {
64 Instant::from_millis(self.0.load(Ordering::SeqCst) as i64)
65 }
66 }
67 }
68
main()69 fn main() {
70 let clock = mock::Clock::new();
71 let device = Loopback::new(Medium::Ethernet);
72
73 #[cfg(feature = "std")]
74 let mut device = {
75 let clock = clock.clone();
76 utils::setup_logging_with_clock("", move || clock.elapsed());
77
78 let (mut opts, mut free) = utils::create_options();
79 utils::add_middleware_options(&mut opts, &mut free);
80
81 let mut matches = utils::parse_options(&opts, free);
82 utils::parse_middleware_options(&mut matches, device, /*loopback=*/ true)
83 };
84
85 // Create interface
86 let mut config = Config::new();
87 config.hardware_addr = Some(EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]).into());
88
89 let mut iface = Interface::new(config, &mut device);
90 iface.update_ip_addrs(|ip_addrs| {
91 ip_addrs
92 .push(IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8))
93 .unwrap();
94 });
95
96 // Create sockets
97 let server_socket = {
98 // It is not strictly necessary to use a `static mut` and unsafe code here, but
99 // on embedded systems that smoltcp targets it is far better to allocate the data
100 // statically to verify that it fits into RAM rather than get undefined behavior
101 // when stack overflows.
102 static mut TCP_SERVER_RX_DATA: [u8; 1024] = [0; 1024];
103 static mut TCP_SERVER_TX_DATA: [u8; 1024] = [0; 1024];
104 let tcp_rx_buffer = tcp::SocketBuffer::new(unsafe { &mut TCP_SERVER_RX_DATA[..] });
105 let tcp_tx_buffer = tcp::SocketBuffer::new(unsafe { &mut TCP_SERVER_TX_DATA[..] });
106 tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer)
107 };
108
109 let client_socket = {
110 static mut TCP_CLIENT_RX_DATA: [u8; 1024] = [0; 1024];
111 static mut TCP_CLIENT_TX_DATA: [u8; 1024] = [0; 1024];
112 let tcp_rx_buffer = tcp::SocketBuffer::new(unsafe { &mut TCP_CLIENT_RX_DATA[..] });
113 let tcp_tx_buffer = tcp::SocketBuffer::new(unsafe { &mut TCP_CLIENT_TX_DATA[..] });
114 tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer)
115 };
116
117 let mut sockets: [_; 2] = Default::default();
118 let mut sockets = SocketSet::new(&mut sockets[..]);
119 let server_handle = sockets.add(server_socket);
120 let client_handle = sockets.add(client_socket);
121
122 let mut did_listen = false;
123 let mut did_connect = false;
124 let mut done = false;
125 while !done && clock.elapsed() < Instant::from_millis(10_000) {
126 iface.poll(clock.elapsed(), &mut device, &mut sockets);
127
128 let mut socket = sockets.get_mut::<tcp::Socket>(server_handle);
129 if !socket.is_active() && !socket.is_listening() {
130 if !did_listen {
131 debug!("listening");
132 socket.listen(1234).unwrap();
133 did_listen = true;
134 }
135 }
136
137 if socket.can_recv() {
138 debug!(
139 "got {:?}",
140 socket.recv(|buffer| { (buffer.len(), str::from_utf8(buffer).unwrap()) })
141 );
142 socket.close();
143 done = true;
144 }
145
146 let mut socket = sockets.get_mut::<tcp::Socket>(client_handle);
147 let cx = iface.context();
148 if !socket.is_open() {
149 if !did_connect {
150 debug!("connecting");
151 socket
152 .connect(cx, (IpAddress::v4(127, 0, 0, 1), 1234), 65000)
153 .unwrap();
154 did_connect = true;
155 }
156 }
157
158 if socket.can_send() {
159 debug!("sending");
160 socket.send_slice(b"0123456789abcdef").unwrap();
161 socket.close();
162 }
163
164 match iface.poll_delay(clock.elapsed(), &sockets) {
165 Some(Duration::ZERO) => debug!("resuming"),
166 Some(delay) => {
167 debug!("sleeping for {} ms", delay);
168 clock.advance(delay)
169 }
170 None => clock.advance(Duration::from_millis(1)),
171 }
172 }
173
174 if done {
175 info!("done")
176 } else {
177 error!("this is taking too long, bailing out")
178 }
179 }
180