diff options
| author | Matt Johnston <[email protected]> | 2023-05-25 19:36:45 +0800 |
|---|---|---|
| committer | Matt Johnston <[email protected]> | 2023-05-25 20:43:36 +0800 |
| commit | 373eb973574ac9390f8b4b19c2de486b1b38101a (patch) | |
| tree | f2894e807cd34687bfd1f1f16611edae33e63e2a /examples/std/src | |
| parent | b20427b2ec7ec5bf2e4553cca24eba20e7373da4 (diff) | |
Add std example of a TCP listener
This also demonstrates calling .abort() on a TCP socket and ensuring
that the reset packet is sent out.
Diffstat (limited to 'examples/std/src')
| -rw-r--r-- | examples/std/src/bin/tcp_accept.rs | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/examples/std/src/bin/tcp_accept.rs b/examples/std/src/bin/tcp_accept.rs new file mode 100644 index 000000000..97ce77f42 --- /dev/null +++ b/examples/std/src/bin/tcp_accept.rs | |||
| @@ -0,0 +1,133 @@ | |||
| 1 | #![feature(type_alias_impl_trait)] | ||
| 2 | |||
| 3 | use core::fmt::Write as _; | ||
| 4 | use std::default::Default; | ||
| 5 | |||
| 6 | use clap::Parser; | ||
| 7 | use embassy_executor::{Executor, Spawner}; | ||
| 8 | use embassy_net::tcp::TcpSocket; | ||
| 9 | use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; | ||
| 10 | use embassy_time::{Duration, Timer}; | ||
| 11 | use embedded_io::asynch::Write as _; | ||
| 12 | use heapless::Vec; | ||
| 13 | use log::*; | ||
| 14 | use rand_core::{OsRng, RngCore}; | ||
| 15 | use static_cell::StaticCell; | ||
| 16 | |||
| 17 | #[path = "../tuntap.rs"] | ||
| 18 | mod tuntap; | ||
| 19 | |||
| 20 | use crate::tuntap::TunTapDevice; | ||
| 21 | |||
| 22 | macro_rules! singleton { | ||
| 23 | ($val:expr) => {{ | ||
| 24 | type T = impl Sized; | ||
| 25 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 26 | STATIC_CELL.init_with(move || $val) | ||
| 27 | }}; | ||
| 28 | } | ||
| 29 | |||
| 30 | #[derive(Parser)] | ||
| 31 | #[clap(version = "1.0")] | ||
| 32 | struct Opts { | ||
| 33 | /// TAP device name | ||
| 34 | #[clap(long, default_value = "tap0")] | ||
| 35 | tap: String, | ||
| 36 | /// use a static IP instead of DHCP | ||
| 37 | #[clap(long)] | ||
| 38 | static_ip: bool, | ||
| 39 | } | ||
| 40 | |||
| 41 | #[embassy_executor::task] | ||
| 42 | async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! { | ||
| 43 | stack.run().await | ||
| 44 | } | ||
| 45 | |||
| 46 | #[derive(Default)] | ||
| 47 | struct StrWrite(pub heapless::Vec<u8, 30>); | ||
| 48 | |||
| 49 | impl core::fmt::Write for StrWrite { | ||
| 50 | fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { | ||
| 51 | self.0.extend_from_slice(s.as_bytes()).unwrap(); | ||
| 52 | Ok(()) | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | #[embassy_executor::task] | ||
| 57 | async fn main_task(spawner: Spawner) { | ||
| 58 | let opts: Opts = Opts::parse(); | ||
| 59 | |||
| 60 | // Init network device | ||
| 61 | let device = TunTapDevice::new(&opts.tap).unwrap(); | ||
| 62 | |||
| 63 | // Choose between dhcp or static ip | ||
| 64 | let config = if opts.static_ip { | ||
| 65 | Config::Static(embassy_net::StaticConfig { | ||
| 66 | address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), | ||
| 67 | dns_servers: Vec::new(), | ||
| 68 | gateway: Some(Ipv4Address::new(192, 168, 69, 1)), | ||
| 69 | }) | ||
| 70 | } else { | ||
| 71 | Config::Dhcp(Default::default()) | ||
| 72 | }; | ||
| 73 | |||
| 74 | // Generate random seed | ||
| 75 | let mut seed = [0; 8]; | ||
| 76 | OsRng.fill_bytes(&mut seed); | ||
| 77 | let seed = u64::from_le_bytes(seed); | ||
| 78 | |||
| 79 | // Init network stack | ||
| 80 | let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<3>::new()), seed)); | ||
| 81 | |||
| 82 | // Launch network task | ||
| 83 | spawner.spawn(net_task(stack)).unwrap(); | ||
| 84 | |||
| 85 | // Then we can use it! | ||
| 86 | let mut rx_buffer = [0; 4096]; | ||
| 87 | let mut tx_buffer = [0; 4096]; | ||
| 88 | |||
| 89 | loop { | ||
| 90 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 91 | socket.set_timeout(Some(Duration::from_secs(10))); | ||
| 92 | info!("Listening on TCP:9999..."); | ||
| 93 | if let Err(_) = socket.accept(9999).await { | ||
| 94 | warn!("accept error"); | ||
| 95 | continue; | ||
| 96 | } | ||
| 97 | |||
| 98 | info!("Accepted a connection"); | ||
| 99 | |||
| 100 | // Write some quick output | ||
| 101 | for i in 1..=5 { | ||
| 102 | let mut w = StrWrite::default(); | ||
| 103 | write!(w, "{}! ", i).unwrap(); | ||
| 104 | let r = socket.write_all(&w.0).await; | ||
| 105 | if let Err(e) = r { | ||
| 106 | warn!("write error: {:?}", e); | ||
| 107 | return; | ||
| 108 | } | ||
| 109 | |||
| 110 | Timer::after(Duration::from_millis(500)).await; | ||
| 111 | } | ||
| 112 | info!("Closing the connection"); | ||
| 113 | socket.abort(); | ||
| 114 | info!("Flushing the RST out..."); | ||
| 115 | socket.flush().await; | ||
| 116 | info!("Finished with the socket"); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | static EXECUTOR: StaticCell<Executor> = StaticCell::new(); | ||
| 121 | |||
| 122 | fn main() { | ||
| 123 | env_logger::builder() | ||
| 124 | .filter_level(log::LevelFilter::Debug) | ||
| 125 | .filter_module("async_io", log::LevelFilter::Info) | ||
| 126 | .format_timestamp_nanos() | ||
| 127 | .init(); | ||
| 128 | |||
| 129 | let executor = EXECUTOR.init(Executor::new()); | ||
| 130 | executor.run(|spawner| { | ||
| 131 | spawner.spawn(main_task(spawner)).unwrap(); | ||
| 132 | }); | ||
| 133 | } | ||
