Skip to content

Commit 05f37da

Browse files
samples: net: add basic echo server sample using UDP
Add an echo server sample to test UDP networking functionality.
1 parent 4e532f0 commit 05f37da

File tree

8 files changed

+124
-0
lines changed

8 files changed

+124
-0
lines changed

dt-rust.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
- "nordic,nrf52-flash-controller"
4646
- "nordic,nrf51-flash-controller"
4747
- "raspberrypi,pico-flash-controller"
48+
- "st,stm32-flash-controller"
4849
level: 0
4950
actions:
5051
- type: instance
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# SPDX-License-Identifier: Apache-2.0 OR MIT
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
5+
project(echo_server)
6+
7+
rust_cargo_application()

samples/net/echo_server/Cargo.toml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright (c) 2025 Witekio
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
[package]
5+
# This must be rustapp for now.
6+
name = "rustapp"
7+
version = "0.1.0"
8+
edition = "2021"
9+
description = "Echo's back any data received from a UDP network socket to the sender"
10+
license = "Apache-2.0 OR MIT"
11+
12+
[lib]
13+
crate-type = ["staticlib"]
14+
15+
[dependencies]
16+
zephyr = "0.1.0"
17+
log = "0.4.22"
18+
static_cell = "2.1.0"
19+
20+
[build-dependencies]
21+
zephyr-build = "0.1.0"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CONFIG_TEST_RANDOM_GENERATOR=y

samples/net/echo_server/build.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
fn main() {
2+
// This call will make make config entries available in the code for every device tree node, to
3+
// allow conditional compilation based on whether it is present in the device tree.
4+
// For example, it will be possible to have:
5+
// ```rust
6+
// #[cfg(dt = "aliases::led0")]
7+
// ```
8+
zephyr_build::dt_cfgs();
9+
}

samples/net/echo_server/prj.conf

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
CONFIG_RUST=y
2+
CONFIG_MAIN_STACK_SIZE=2048
3+
4+
# Networking config
5+
CONFIG_NETWORKING=y
6+
CONFIG_NET_IPV4=y
7+
CONFIG_NET_IPV6=y
8+
CONFIG_NET_UDP=y
9+
CONFIG_NET_SOCKETS=y
10+
11+
# Net config settings for sample
12+
CONFIG_NET_CONFIG_SETTINGS=y
13+
CONFIG_NET_CONFIG_NEED_IPV6=y
14+
CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1"
15+
CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2"
16+
CONFIG_NET_CONFIG_NEED_IPV4=y
17+
CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1"
18+
CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2"
19+
20+
CONFIG_SHELL=y
21+
CONFIG_NET_SHELL=y

samples/net/echo_server/sample.yaml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# See doc/develop/test/twister.rst for what is here.
2+
sample:
3+
name: Echo Server Sample
4+
common:
5+
filter: CONFIG_RUST_SUPPORTED
6+
platform_allow:
7+
- qemu_cortex_m3
8+
tests:
9+
sample.rust.net.echo_server:
10+
tags:
11+
- net
12+
depends_on: netif
13+
harness: net
14+
integration_platforms:
15+
- qemu_cortex_m3

samples/net/echo_server/src/lib.rs

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright (c) 2025 Witekio
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#![no_std]
5+
#![allow(unexpected_cfgs)]
6+
7+
use log::{error, info, warn};
8+
use static_cell::ConstStaticCell;
9+
use zephyr::error::Result;
10+
use zephyr::net::udp::UdpSocket;
11+
12+
#[no_mangle]
13+
extern "C" fn rust_main() {
14+
unsafe {
15+
zephyr::set_logger().unwrap();
16+
}
17+
18+
let res = run_echo();
19+
20+
if let Err(e) = res {
21+
error!("Echo server terminated with error {}", e);
22+
}
23+
}
24+
25+
fn run_echo() -> Result<()> {
26+
// Don't allocate the large RX buffer on the stack
27+
static RX_BUF: ConstStaticCell<[u8; 2048]> = ConstStaticCell::new([0; 2048]);
28+
let rx_buf = RX_BUF.take();
29+
30+
let sockaddr = "0.0.0.0:4242".parse().unwrap();
31+
let sock = UdpSocket::bind(&sockaddr)?;
32+
33+
info!("Waiting for UDP packets on port 4242");
34+
35+
loop {
36+
let (n, peer) = sock.recv_from(rx_buf)?;
37+
38+
// Note that being able to set the MSG_TRUNC sockopt is not implemented yet so it should
39+
// not be possible to get n > rx_buf.len(), but it's probably still worth including the
40+
// check for when this sockopt is implemented.
41+
let n_trunc = n.min(rx_buf.len());
42+
if n != n_trunc {
43+
warn!("Data truncated, got {} / {} bytes", n_trunc, n);
44+
}
45+
46+
info!("Echoing {} bytes back to peer address {:?}", n_trunc, peer);
47+
let _ = sock.send_to(&rx_buf[0..n_trunc], &peer)?;
48+
}
49+
}

0 commit comments

Comments
 (0)