Skip to main content

tcp_echo/
tcp_echo.rs

1/// TCP echo server using F-Stack.
2///
3/// Run with:
4///   cargo run --example tcp_echo
5///
6/// Test from inside the container:
7///   nc -w3 10.0.0.1 8080
8///   (type a message, press Enter, see it echoed back)
9
10use teto_dpdk::config::{FStackConfig, TcpSocketOptions};
11use teto_dpdk::fstack::ffi::{
12    init_fstack, create_tcp_listener, run_fstack_tcp, TcpMessage, FStackTcpListener,
13};
14use cxx::UniquePtr;
15
16static mut GLOBAL_LISTENER: Option<*const FStackTcpListener> = None;
17
18fn on_connect(fd: i32, ip: &String, port: u16) {
19    println!("[TCP] New connection fd={} from {}:{}", fd, ip, port);
20}
21
22fn on_data(fd: i32, msg: &TcpMessage) {
23    println!(
24        "[TCP] Received {} bytes from {}:{} on fd={}",
25        msg.payload.len(), msg.src_ip, msg.src_port, fd
26    );
27    unsafe {
28        if let Some(ptr) = GLOBAL_LISTENER {
29            (*ptr).send_to(fd, &msg.payload);
30        }
31    }
32}
33
34fn on_disconnect(fd: i32) {
35    println!("[TCP] Connection closed fd={}", fd);
36}
37
38fn main() {
39    // Docker/TAP configuration — swap for FStackConfig::for_bare_metal() on bare metal.
40    let cfg = FStackConfig::for_docker();
41
42    println!("Initializing F-Stack...");
43    init_fstack(&cfg.config_args(), &cfg.eal_args());
44
45    let bind_ip   = "0.0.0.0".to_string();
46    let bind_port = 8080u16;
47
48    let tcp_opts = TcpSocketOptions::default()
49        .nodelay(true)
50        .quickack(true);
51
52    println!("Creating TCP listener on {}:{}...", bind_ip, bind_port);
53    let listener: UniquePtr<FStackTcpListener> =
54        create_tcp_listener(&bind_ip, bind_port, &tcp_opts.to_ffi(), on_connect, on_data, on_disconnect);
55
56    unsafe {
57        GLOBAL_LISTENER = Some(&*listener as *const FStackTcpListener);
58    }
59
60    println!("Starting F-Stack TCP event loop...");
61    run_fstack_tcp(&listener);
62}