Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

main: run aardvark as a daemon via forking and maintain its partial daemon like nature. #148

Merged
merged 1 commit into from
Jul 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ signal-hook = "0.3.13"
tokio = { version = "1.19.2", features = ["tokio-macros", "full"] }
async-broadcast = "0.4.0"
resolv-conf = "0.7.0"
nix = "0.23.0"
libc = "0.2"

[build-dependencies]
chrono = "0.4.7"
74 changes: 63 additions & 11 deletions src/commands/run.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
//! Runs the aardvark dns server with provided config
use crate::server::serve;
use clap::Parser;
use log::debug;
use nix::unistd;
use nix::unistd::{dup2, fork, ForkResult};
use std::fs::File;
use std::fs::OpenOptions;
use std::io::Error;
use std::io::Write;
use std::os::unix::io::AsRawFd;
use std::os::unix::io::FromRawFd;

#[derive(Parser, Debug)]
pub struct Run {}
Expand All @@ -19,18 +25,64 @@ impl Run {
port: u32,
filter_search_domain: String,
) -> Result<(), Error> {
debug!(
"Setting up aardvark server with input directory as {:?}",
input_dir
);
// create a temporary path for unix socket
// so parent can communicate with child and
// only exit when child is ready to serve.
let (ready_pipe_read, ready_pipe_write) = nix::unistd::pipe()?;

if let Err(er) = serve::serve(&input_dir, port, &filter_search_domain) {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("Error starting server {}", er),
));
// fork and verify if server is running
// and exit parent
// setsid() ensures that there is no controlling terminal on the child process
match unsafe { fork() } {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this unsafe?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nix's fork is returns unsafe most likely because it invokes fork( directly in such cases rust compiler will bark however our use-case is okay here so all such functions can be invoked under unsafe. See https://docs.rs/nix/latest/nix/unistd/fn.fork.html and this https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html

But invocation is fine for our use-case.

Ok(ForkResult::Parent { child, .. }) => {
log::debug!("starting aardvark on a child with pid {}", child);
// verify aardvark here and block till will start
unistd::read(ready_pipe_read, &mut [0_u8; 1])?;
unistd::close(ready_pipe_read)?;
unistd::close(ready_pipe_write)?;
Ok(())
}
Ok(ForkResult::Child) => {
// remove any controlling terminals
flouthoc marked this conversation as resolved.
Show resolved Hide resolved
// but don't hardstop if this fails
let _ = unsafe { libc::setsid() }; // check https://docs.rs/libc
// close fds -> stdout, stdin and stderr
let dev_null = OpenOptions::new()
.read(true)
.write(true)
.open("/dev/null")
.map_err(|e| std::io::Error::new(e.kind(), format!("/dev/null: {}", e)));
// redirect stdout, stdin and stderr to /dev/null
if let Ok(dev_null) = dev_null {
let fd = dev_null.as_raw_fd();
let _ = dup2(fd, 0);
let _ = dup2(fd, 1);
let _ = dup2(fd, 2);
if fd < 2 {
std::mem::forget(dev_null);
}
}

let mut f = unsafe { File::from_raw_fd(ready_pipe_write) };
write!(&mut f, "ready")?;
unistd::close(ready_pipe_read)?;
unistd::close(ready_pipe_write)?;
if let Err(er) = serve::serve(&input_dir, port, &filter_search_domain) {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("Error starting server {}", er),
));
}
Ok(())
}
Err(err) => {
log::debug!("fork failed with error {}", err);
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("fork failed with error: {}", err),
));
}
}
Ok(())
}
}

Expand Down