From 8fa7fb7fc9e37b334178a00509c935c444a89a77 Mon Sep 17 00:00:00 2001 From: Eugene Crosser Date: Fri, 31 Oct 2025 23:53:29 +0100 Subject: [PATCH 1/2] Initial code --- .gitignore | 2 ++ Cargo.toml | 11 ++++++++ README.md | 16 ++++++++++++ ironfinger.rs | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 ironfinger.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b397ff1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +Cargo.lock +target/* diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..093e77c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "ironfinger" +default-run = "ironfinger" +edition = "2021" + +[[bin]] +name = "ironfinger" +path = "ironfinger.rs" + +[dependencies] +getopts = "0.2" diff --git a/README.md b/README.md new file mode 100644 index 0000000..2433124 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +Dependencies: + librust-getopts-dev + +Configure cargo this way: + +``` +$ cat ~/.cargo/config.toml +[net] +offline = true + +[source] +[source.debian-packages] +directory = "/usr/share/cargo/registry" +[source.crates-io] +replace-with = "debian-packages" +``` diff --git a/ironfinger.rs b/ironfinger.rs new file mode 100644 index 0000000..b22372b --- /dev/null +++ b/ironfinger.rs @@ -0,0 +1,69 @@ +use std::env; +use std::io::{Read, Write}; +use std::net::{Ipv6Addr, Shutdown, TcpListener, TcpStream}; +use std::time::Duration; + +extern crate getopts; +use getopts::Options; + +fn handle_client(mut stream: TcpStream) { + println!("Connection from {:?}", stream.peer_addr().unwrap()); + stream + .set_read_timeout(Some(Duration::from_secs(5))) + .expect("set_read_timeout failed"); + let mut buffer = [0; 128]; + match stream.read(&mut buffer) { + Ok(l) => { + let request = String::from_utf8_lossy(&buffer[..l]); + let name = request.trim_end(); + println!("Got {l:?} bytes request: \"{}\"", name); + stream + .write("Got this request\r\n".as_bytes()) + .expect("Write failed"); + stream.write(request.as_bytes()).expect("Write data failed"); + } + Err(e) => { + println!("Read error: {e:?}"); + } + } + stream.shutdown(Shutdown::Both).expect("Shutdown failed"); + println!("Finished processing client"); +} + +fn main() -> std::io::Result<()> { + let args: Vec = env::args().collect(); + let progname = args[0].clone(); + let mut opts = Options::new(); + opts.optopt("p", "port", "set port to listen", "79"); + opts.optflag("h", "help", "print this help menu"); + let mo = match opts.parse(&args[1..]) { + Ok(m) => m, + Err(e) => { + panic!("{}", e.to_string()) + } + }; + if mo.opt_present("h") { + println!("{}: there is no help!", progname); + return Ok(()); + } + let p = match mo.opt_get_default::("p", 79) { + Ok(p) => p, + Err(e) => { + panic!("Bad option for port {:?}", e) + } + }; + println!("Binding to port {:?}", p); + let listener = TcpListener::bind((Ipv6Addr::UNSPECIFIED, p)) + .expect("Could not bind to finger port"); + for stream in listener.incoming() { + match stream { + Ok(stream) => { + handle_client(stream); + } + Err(e) => { + println!("Unaccepted {e:?}"); + } + } + } + Ok(()) +} -- 2.43.0 From c7816fb34f227b6af9b56bd13a444732dfbb1e77 Mon Sep 17 00:00:00 2001 From: Eugene Crosser Date: Mon, 3 Nov 2025 23:29:12 +0100 Subject: [PATCH 2/2] Process requests in a separate process --- .cargo/config.toml | 8 +++++ Cargo.toml | 1 + ironfinger.rs | 76 ++++++++++++++++++++++++++++++++-------------- 3 files changed, 63 insertions(+), 22 deletions(-) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..94564f3 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,8 @@ +[net] +offline = true + +[source] +[source.debian-packages] +directory = "/usr/share/cargo/registry" +[source.crates-io] +replace-with = "debian-packages" diff --git a/Cargo.toml b/Cargo.toml index 093e77c..d3d0934 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,4 @@ path = "ironfinger.rs" [dependencies] getopts = "0.2" +libc = "0.2" diff --git a/ironfinger.rs b/ironfinger.rs index b22372b..0491334 100644 --- a/ironfinger.rs +++ b/ironfinger.rs @@ -1,36 +1,67 @@ use std::env; -use std::io::{Read, Write}; +use std::io::{Error, Read, Result, Write}; use std::net::{Ipv6Addr, Shutdown, TcpListener, TcpStream}; use std::time::Duration; extern crate getopts; +extern crate libc; use getopts::Options; +fn check_err(num: T) -> Result { + println!("check_err trying to convert {:?}", num); + if num < T::default() { + Err(Error::last_os_error()) + } else { + Ok(num) + } +} + +fn fork() -> Result { + check_err(unsafe { libc::fork() }).map(|pid| pid as u32) +} + +fn abandon_children() -> Result { + let res = check_err(unsafe { libc::signal(libc::SIGCHLD, libc::SIG_IGN) }); + println!("result from signal call with ({:?}, {:?}) is {:?} (FYI SIG_DFL={:?})", libc::SIGCHLD, libc::SIG_IGN, res, libc::SIG_DFL); + res +} + +fn exit() -> () { + unsafe { libc::exit(0) } +} + + fn handle_client(mut stream: TcpStream) { println!("Connection from {:?}", stream.peer_addr().unwrap()); - stream - .set_read_timeout(Some(Duration::from_secs(5))) - .expect("set_read_timeout failed"); - let mut buffer = [0; 128]; - match stream.read(&mut buffer) { - Ok(l) => { - let request = String::from_utf8_lossy(&buffer[..l]); - let name = request.trim_end(); - println!("Got {l:?} bytes request: \"{}\"", name); - stream - .write("Got this request\r\n".as_bytes()) - .expect("Write failed"); - stream.write(request.as_bytes()).expect("Write data failed"); - } - Err(e) => { - println!("Read error: {e:?}"); + let pid = fork().unwrap(); + if pid == 0 { + stream + .set_read_timeout(Some(Duration::from_secs(5))) + .expect("set_read_timeout failed"); + let mut buffer = [0; 128]; + match stream.read(&mut buffer) { + Ok(l) => { + let request = String::from_utf8_lossy(&buffer[..l]); + let name = request.trim_end(); + println!("Got {l:?} bytes request: \"{}\"", name); + stream + .write("Got this request\r\n".as_bytes()) + .expect("Write failed"); + stream.write(request.as_bytes()).expect("Write data failed"); + } + Err(e) => { + println!("Read error: {e:?}"); + } } + stream.shutdown(Shutdown::Both).expect("Shutdown failed"); + println!("Finished processing client"); + exit() + } else { + println!("parent returning, child pid was {:?}", pid); } - stream.shutdown(Shutdown::Both).expect("Shutdown failed"); - println!("Finished processing client"); } -fn main() -> std::io::Result<()> { +fn main() -> Result<()> { let args: Vec = env::args().collect(); let progname = args[0].clone(); let mut opts = Options::new(); @@ -52,9 +83,10 @@ fn main() -> std::io::Result<()> { panic!("Bad option for port {:?}", e) } }; + abandon_children().unwrap(); println!("Binding to port {:?}", p); - let listener = TcpListener::bind((Ipv6Addr::UNSPECIFIED, p)) - .expect("Could not bind to finger port"); + let listener = + TcpListener::bind((Ipv6Addr::UNSPECIFIED, p)).expect("Could not bind to finger port"); for stream in listener.incoming() { match stream { Ok(stream) => { -- 2.43.0