Skip to content

Commit

Permalink
Kill monero-wallet-rpc child process when receiving SIGINT, SIGTERM o…
Browse files Browse the repository at this point in the history
…r SIGHUP

When the CLI is terminated via a signal, the child process monero-wallet-rpc is not automatically terminated. This discrepancy arises from the behavior of terminal-initiated interrupts (e.g., STRG-C), which send the termination signal to all processes in the process group, effectively killing the child process.

To address this, we implement a signal handler that explicitly terminates the monero-wallet-rpc child process upon receiving a termination signal for the parent process. This ensures that the child process does not continue running in the background, detached from the parent. Failing to terminate the child process would lock the wallet, preventing future instances of the CLI from starting.
  • Loading branch information
binarybaron committed Aug 30, 2023
1 parent a57c534 commit b3cea64
Showing 1 changed file with 62 additions and 14 deletions.
76 changes: 62 additions & 14 deletions swap/src/monero/wallet_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ use reqwest::Url;
use std::io::ErrorKind;
use std::path::{Path, PathBuf};
use std::process::Stdio;
use std::sync::Arc;
use tokio::fs::{remove_file, OpenOptions};
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::process::{Child, Command};
use tokio::signal::unix::{signal, SignalKind};
use tokio::sync::Mutex;
use tokio::task::JoinHandle;
use tokio_util::codec::{BytesCodec, FramedRead};
use tokio_util::io::StreamReader;

Expand Down Expand Up @@ -46,8 +50,8 @@ const WALLET_RPC_VERSION: &str = "v0.18.1.2";
pub struct ExecutableNotFoundInArchive;

pub struct WalletRpcProcess {
_child: Child,
port: u16,
_child: Arc<Mutex<Child>>,
}

impl WalletRpcProcess {
Expand Down Expand Up @@ -176,25 +180,69 @@ impl WalletRpc {
}
};

let mut child = Command::new(self.exec_path())
.env("LANG", "en_AU.UTF-8")
.stdout(Stdio::piped())
.kill_on_drop(true)
.args(network_flag)
.arg("--daemon-address")
.arg(daemon_address)
.arg("--rpc-bind-port")
.arg(format!("{}", port))
.arg("--disable-rpc-login")
.arg("--wallet-dir")
.arg(self.working_dir.join("monero-data"))
.spawn()?;
let child = Arc::new(Mutex::new(
Command::new(self.exec_path())
.env("LANG", "en_AU.UTF-8")
.stdout(Stdio::piped())
.kill_on_drop(true)
.args(network_flag)
.arg("--daemon-address")
.arg(daemon_address)
.arg("--rpc-bind-port")
.arg(format!("{}", port))
.arg("--disable-rpc-login")
.arg("--wallet-dir")
.arg(self.working_dir.join("monero-data"))
.spawn()?,
));

let stdout = child
.lock()
.await
.stdout
.take()
.expect("monero wallet rpc stdout was not piped parent process");

/*
When the CLI is terminated via a signal, the child process monero-wallet-rpc is not automatically terminated. This discrepancy arises from the behavior of terminal-initiated interrupts (e.g., STRG-C), which send the termination signal to all processes in the process group, effectively killing the child process.
To address this, we implement a signal handler that explicitly terminates the monero-wallet-rpc child process upon receiving a termination signal for the parent process. This ensures that the child process does not continue running in the background, detached from the parent. Failing to terminate the child process would lock the wallet, preventing future instances of the CLI from starting.
*/
let child_clone = child.clone(); // Clone the Arc for the signal handler

tokio::spawn(async move {
let sigint_stream = signal(SignalKind::interrupt());
let sigterm_stream = signal(SignalKind::terminate());
let sighup_stream = signal(SignalKind::hangup());

match (sigint_stream, sigterm_stream, sighup_stream) {
(Ok(mut sigint), Ok(mut sigterm), Ok(mut sighup)) => {
tokio::select! {
_ = sigint.recv() => {},
_ = sigterm.recv() => {},
_ = sighup.recv() => {},
}
match child_clone.lock().await.kill().await {
Ok(_) => {
tracing::debug!("Successfully terminated monero-wallet-rpc process");
}
Err(err) => {
tracing::warn!(
"Failed to terminate monero-wallet-rpc process: {}",
err
);
}
}
}
(Err(err), _, _) | (_, Err(err), _) | (_, _, Err(err)) => {
tracing::warn!(
"Failed to create kill signal listener for monero-wallet-rpc process: {}.",
err
);
}
}
});

let mut reader = BufReader::new(stdout).lines();

#[cfg(not(target_os = "windows"))]
Expand Down

0 comments on commit b3cea64

Please sign in to comment.