Compare commits

...
1 Commits
Author SHA1 Message Date
Nikolay Edigaryev d7699e95a9 Support graceful termination via SIGINT (#23)
* Support graceful termination via SIGINT

* $ cargo fmt

* Explain why we need to ignore the SIGINT
2023-03-16 18:38:03 +04:00
5 changed files with 405 additions and 309 deletions
Generated
+362 -304
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -14,7 +14,7 @@ debug = true
[dependencies] [dependencies]
smoltcp = "0.8.1" smoltcp = "0.8.1"
libc = "0.2.126" libc = "0.2.126"
polling = "2.2.0" polling = { git = "https://github.com/smol-rs/polling.git" }
dhcproto = "0.7.0" dhcproto = "0.7.0"
vmnet = "0.1.1" vmnet = "0.1.1"
clap = { version = "3.1.18", features = ["derive"] } clap = { version = "3.1.18", features = ["derive"] }
@@ -27,3 +27,4 @@ system-configuration = "0.5.0"
num_enum = "0.5.7" num_enum = "0.5.7"
sentry = { version = "0.29.1", features = ["debug-images"] } sentry = { version = "0.29.1", features = ["debug-images"] }
sentry-anyhow = { version = "0.29.1", features = ["backtrace"] } sentry-anyhow = { version = "0.29.1", features = ["backtrace"] }
nix = "0.26.2"
+25 -2
View File
@@ -1,5 +1,7 @@
use anyhow::Result; use anyhow::Result;
use num_enum::IntoPrimitive; use num_enum::IntoPrimitive;
use polling::os::kqueue::PollerKqueueExt;
use polling::PollMode;
use std::os::unix::io::RawFd; use std::os::unix::io::RawFd;
use std::time::Duration; use std::time::Duration;
@@ -15,6 +17,7 @@ pub struct Poller {
enum EventKey { enum EventKey {
VM, VM,
Host, Host,
Interrupt,
} }
impl Poller { impl Poller {
@@ -34,6 +37,15 @@ impl Poller {
self.poller self.poller
.add(self.host_fd as RawFd, self.host_interest())?; .add(self.host_fd as RawFd, self.host_interest())?;
let interrupt_signal = polling::os::kqueue::Signal(libc::SIGINT);
self.poller
.add_filter(
interrupt_signal,
EventKey::Interrupt.into(),
PollMode::Oneshot,
)
.unwrap();
Ok(()) Ok(())
} }
@@ -45,10 +57,17 @@ impl Poller {
self.poller self.poller
.modify(self.host_fd as RawFd, self.host_interest())?; .modify(self.host_fd as RawFd, self.host_interest())?;
let interrupt_signal = polling::os::kqueue::Signal(libc::SIGINT);
self.poller.modify_filter(
interrupt_signal,
EventKey::Interrupt.into(),
PollMode::Oneshot,
)?;
Ok(()) Ok(())
} }
pub fn wait(&mut self) -> Result<(bool, bool)> { pub fn wait(&mut self) -> Result<(bool, bool, bool)> {
self.poller self.poller
.wait(&mut self.events, Some(Duration::from_millis(100)))?; .wait(&mut self.events, Some(Duration::from_millis(100)))?;
@@ -60,8 +79,12 @@ impl Poller {
.events .events
.iter() .iter()
.any(|ev| ev.key == Into::<usize>::into(EventKey::Host)); .any(|ev| ev.key == Into::<usize>::into(EventKey::Host));
let interrupt = self
.events
.iter()
.any(|ev| ev.key == Into::<usize>::into(EventKey::Interrupt));
Ok((vm_readable, host_readable)) Ok((vm_readable, host_readable, interrupt))
} }
fn vm_interest(&self) -> polling::Event { fn vm_interest(&self) -> polling::Event {
+6 -1
View File
@@ -43,7 +43,7 @@ impl Proxy {
self.poller.arm()?; self.poller.arm()?;
loop { loop {
let (vm_readable, host_readable) = self.poller.wait()?; let (vm_readable, host_readable, interrupt) = self.poller.wait()?;
if vm_readable { if vm_readable {
self.read_from_vm(buf.as_mut_slice())?; self.read_from_vm(buf.as_mut_slice())?;
@@ -53,6 +53,11 @@ impl Proxy {
self.read_from_host(buf.as_mut_slice())?; self.read_from_host(buf.as_mut_slice())?;
} }
// Graceful termination
if interrupt {
return Ok(());
}
self.poller.rearm()?; self.poller.rearm()?;
} }
} }
+10 -1
View File
@@ -1,5 +1,6 @@
use anyhow::{anyhow, Context}; use anyhow::{anyhow, Context};
use clap::Parser; use clap::Parser;
use nix::sys::signal::{signal, SigHandler, Signal};
use privdrop::PrivDrop; use privdrop::PrivDrop;
use softnet::proxy::Proxy; use softnet::proxy::Proxy;
use std::borrow::Cow; use std::borrow::Cow;
@@ -55,7 +56,7 @@ fn main() -> ExitCode {
// Initialize Sentry // Initialize Sentry
let _sentry = sentry::init(sentry::ClientOptions { let _sentry = sentry::init(sentry::ClientOptions {
release: option_env!("CIRRUS_TAG").map(|tag| { Cow::from(format!("softnet@{tag}")) }), release: option_env!("CIRRUS_TAG").map(|tag| Cow::from(format!("softnet@{tag}"))),
..Default::default() ..Default::default()
}); });
@@ -84,6 +85,14 @@ fn main() -> ExitCode {
} }
fn try_main() -> anyhow::Result<()> { fn try_main() -> anyhow::Result<()> {
// The default signal(3)[1] action for SIGINT is to interrupt program,
// but we want to handle SIGINT ourselves, so we ignore it. The kqueue(2)'s[2]
// EVFILT_SIGNAL will receive it anyways, because it has lower precedence.
//
// [1]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/signal.3.html
// [2]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/kqueue.2.html
unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }?;
let args: Args = Args::parse(); let args: Args = Args::parse();
// No need to run anything, just return // No need to run anything, just return