Skip to content

Commit 1498212

Browse files
samples: net: add TCP to echo server sample
Spawn the UDP echo server in a thread, and run a TCP echo server in the main thread. Signed-off-by: Matt Rodgers <[email protected]>
1 parent fcdf2c9 commit 1498212

File tree

4 files changed

+80
-19
lines changed

4 files changed

+80
-19
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
CONFIG_NET_QEMU_ETHERNET=y
21
CONFIG_TEST_RANDOM_GENERATOR=y
2+
CONFIG_NET_QEMU_ETHERNET=y
3+
CONFIG_NET_L2_ETHERNET=y

samples/net/echo_server/prj.conf

+2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
CONFIG_RUST=y
2+
CONFIG_RUST_ALLOC=y # For threads
23
CONFIG_MAIN_STACK_SIZE=2048
34

45
# Networking config
56
CONFIG_NETWORKING=y
67
CONFIG_NET_IPV4=y
78
CONFIG_NET_IPV6=y
89
CONFIG_NET_UDP=y
10+
CONFIG_NET_TCP=y
911
CONFIG_NET_SOCKETS=y
1012

1113
# Net config settings for sample

samples/net/echo_server/src/lib.rs

+76-17
Original file line numberDiff line numberDiff line change
@@ -7,43 +7,102 @@
77
use log::{error, info, warn};
88
use static_cell::ConstStaticCell;
99
use zephyr::error::Result;
10-
use zephyr::net::UdpSocket;
10+
use zephyr::kobj_define;
11+
use zephyr::net::{TcpListener, TcpStream, UdpSocket};
1112

1213
#[no_mangle]
1314
extern "C" fn rust_main() {
1415
unsafe {
1516
zephyr::set_logger().unwrap();
1617
}
1718

18-
let res = run_echo();
19+
// Don't allocate the large RX buffers on the stack
20+
static UDP_RX_BUF: ConstStaticCell<[u8; 2048]> = ConstStaticCell::new([0; 2048]);
21+
static TCP_RX_BUF: ConstStaticCell<[u8; 2048]> = ConstStaticCell::new([0; 2048]);
22+
let udp_rx_buf = UDP_RX_BUF.take();
23+
let tcp_rx_buf = TCP_RX_BUF.take();
1924

20-
if let Err(e) = res {
21-
error!("Echo server terminated with error {}", e);
22-
}
23-
}
25+
// Create the sockets
26+
let sockaddr = "0.0.0.0:4242".parse().unwrap();
27+
let udp_sock = UdpSocket::bind(&sockaddr).expect("Failed to bind UdpSocket");
28+
let mut tcp_listener = TcpListener::bind(&sockaddr).expect("Failed to bind TcpListener");
2429

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();
30+
info!("Echo server bound to address {:?}", sockaddr);
2931

30-
let sockaddr = "0.0.0.0:4242".parse().unwrap();
31-
let sock = UdpSocket::bind(&sockaddr)?;
32+
// Spawn the UDP echo server in a thread
33+
let udp_thread = UDP_THREAD
34+
.init_once(UDP_STACK.init_once(()).unwrap())
35+
.unwrap();
36+
37+
udp_thread.spawn(move || {
38+
if let Err(e) = run_udp_echo(udp_sock, udp_rx_buf) {
39+
error!("UDP echo thread failed with error {:?}", e);
40+
}
41+
});
3242

33-
info!("Waiting for UDP packets on port 4242");
43+
// Run the TCP echo server in the main thread
44+
loop {
45+
match tcp_listener.accept() {
46+
Ok((sock, peer)) => {
47+
info!("Accepted connection from peer address {:?}", peer);
48+
let _ = run_tcp_echo(sock, tcp_rx_buf);
49+
}
50+
Err(e) => {
51+
error!("Failed to accept TCP connection with error {:?}", e);
52+
break;
53+
}
54+
}
55+
}
56+
57+
info!("TCP echo server exited");
58+
}
3459

60+
fn run_udp_echo(sock: UdpSocket, buf: &mut [u8]) -> Result<()> {
3561
loop {
36-
let (n, peer) = sock.recv_from(rx_buf)?;
62+
let (n, peer) = sock.recv_from(buf)?;
3763

3864
// Note that being able to set the MSG_TRUNC sockopt is not implemented yet so it should
3965
// not be possible to get n > rx_buf.len(), but it's probably still worth including the
4066
// check for when this sockopt is implemented.
41-
let n_trunc = n.min(rx_buf.len());
67+
let n_trunc = n.min(buf.len());
4268
if n != n_trunc {
4369
warn!("Data truncated, got {} / {} bytes", n_trunc, n);
4470
}
4571

46-
info!("Echoing {} bytes back to peer address {:?}", n_trunc, peer);
47-
let _ = sock.send_to(&rx_buf[0..n_trunc], &peer)?;
72+
info!(
73+
"Echoing {} bytes to peer address {:?} via UDP",
74+
n_trunc, peer
75+
);
76+
let _ = sock.send_to(&buf[0..n_trunc], &peer)?;
4877
}
4978
}
79+
80+
fn run_tcp_echo(mut sock: TcpStream, buf: &mut [u8]) -> Result<()> {
81+
loop {
82+
let n = sock.recv(buf)?;
83+
84+
if 0 == n {
85+
info!("TCP client disconected");
86+
return Ok(());
87+
}
88+
89+
info!("Echoing {} bytes via TCP", n);
90+
let mut remaining = &buf[0..n];
91+
while !remaining.is_empty() {
92+
match sock.send(remaining)? {
93+
0 => {
94+
info!("TCP client disconnected");
95+
return Ok(());
96+
}
97+
n => remaining = &remaining[n..],
98+
};
99+
}
100+
}
101+
}
102+
103+
const STACK_SIZE: usize = zephyr::kconfig::CONFIG_MAIN_STACK_SIZE as usize;
104+
105+
kobj_define! {
106+
static UDP_THREAD: StaticThread;
107+
static UDP_STACK: ThreadStack<STACK_SIZE>;
108+
}

zephyr/src/net/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ mod socket;
1010

1111
use crate::error::Result;
1212
use crate::net::socket::{Domain, Protocol, SockType, Socket};
13-
use core::ffi::c_int;
1413
use core::net::SocketAddr;
1514

1615
/// UDP socket.

0 commit comments

Comments
 (0)