diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig index 4f90f8d6935188..fe923ef2ab93ba 100644 --- a/samples/rust/Kconfig +++ b/samples/rust/Kconfig @@ -130,6 +130,16 @@ config SAMPLE_RUST_NETFILTER If unsure, say N. +config SAMPLE_RUST_ECHO_SERVER + tristate "Echo server module" + help + This option builds the Rust echo server module sample. + + To compile this as a module, choose M here: + the module will be called rust_echo_server. + + If unsure, say N. + config SAMPLE_RUST_HOSTPROGS bool "Host programs" help diff --git a/samples/rust/Makefile b/samples/rust/Makefile index fb5a205ebb8cf8..636cf1e73d23cc 100644 --- a/samples/rust/Makefile +++ b/samples/rust/Makefile @@ -12,5 +12,6 @@ obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE_C) += rust_semaphore_c.o obj-$(CONFIG_SAMPLE_RUST_RANDOM) += rust_random.o obj-$(CONFIG_SAMPLE_RUST_PLATFORM) += rust_platform.o obj-$(CONFIG_SAMPLE_RUST_NETFILTER) += rust_netfilter.o +obj-$(CONFIG_SAMPLE_RUST_ECHO_SERVER) += rust_echo_server.o subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS) += hostprogs diff --git a/samples/rust/rust_echo_server.rs b/samples/rust/rust_echo_server.rs new file mode 100644 index 00000000000000..5fc802f4dc33c2 --- /dev/null +++ b/samples/rust/rust_echo_server.rs @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Rust echo server sample. + +use kernel::{ + kasync::executor::{workqueue::Executor as WqExecutor, AutoStopHandle, Executor}, + kasync::net::{TcpListener, TcpStream}, + net::{self, Ipv4Addr, SocketAddr, SocketAddrV4}, + prelude::*, + spawn_task, + sync::{Ref, RefBorrow}, +}; + +async fn echo_server(stream: TcpStream) -> Result { + let mut buf = [0u8; 1024]; + loop { + let n = stream.read(&mut buf).await?; + if n == 0 { + return Ok(()); + } + stream.write_all(&buf[..n]).await?; + } +} + +async fn accept_loop(listener: TcpListener, executor: Ref) { + loop { + if let Ok(stream) = listener.accept().await { + let _ = spawn_task!(executor.as_ref_borrow(), echo_server(stream)); + } + } +} + +fn start_listener(ex: RefBorrow<'_, impl Executor + Send + Sync + 'static>) -> Result { + let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::ANY, 8080)); + let listener = TcpListener::try_new(net::init_ns(), &addr)?; + spawn_task!(ex, accept_loop(listener, ex.into()))?; + Ok(()) +} + +struct RustEchoServer { + _handle: AutoStopHandle, +} + +impl kernel::Module for RustEchoServer { + fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result { + let handle = WqExecutor::try_new(kernel::workqueue::system())?; + start_listener(handle.executor())?; + Ok(Self { + _handle: handle.into(), + }) + } +} + +module! { + type: RustEchoServer, + name: b"rust_echo_server", + author: b"Rust for Linux Contributors", + description: b"Rust tcp echo sample", + license: b"GPL v2", +}