Skip to content

Commit

Permalink
Catch signals a bit earlier
Browse files Browse the repository at this point in the history
Currently when Teliod is interrupted by a signal while waiting for an
identity or NC to start signal handlers are not registered yet, so
they kill Teliod brutaly and it doesn't make a proper cleanup (well, I'm
talking mainly about socket removal).
  • Loading branch information
stalowyjez committed Feb 13, 2025
1 parent 4370150 commit eb93dd5
Showing 1 changed file with 49 additions and 32 deletions.
81 changes: 49 additions & 32 deletions clis/teliod/src/daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ use telio::{
telio_utils::select,
telio_wg::AdapterType,
};
use tokio::sync::mpsc::Sender;
use tokio::{sync::mpsc, sync::oneshot, time::Duration};
use tracing::{debug, error, info, trace};
use tracing::{debug, error, info, trace, warn};

use crate::core_api::{get_meshmap as get_meshmap_from_server, init_with_api};
use crate::ClientCmd;
Expand Down Expand Up @@ -179,6 +180,32 @@ fn start_telio(
Ok(())
}

async fn daemon_init(
config: TeliodDaemonConfig,
telio_tx: Sender<TelioTaskCmd>,
token: Arc<String>,
) -> Result<Arc<DeviceIdentity>, TeliodError> {
// TODO: This if condition and ::default call is temporary to be removed later
// on when we have proper integration tests with core API.
// This is to not look for tokens in a test environment right now as the values
// are dummy and program will not run as it expects real tokens.
let identity = Arc::new(if !config.authentication_token.eq(EMPTY_TOKEN) {
init_with_api(&config.authentication_token).await?
} else {
DeviceIdentity::default()
});

let nc = NotificationCenter::new(&config, &identity.hw_identifier).await?;

let identity_clone = identity.clone();
nc.add_callback(Arc::new(move |_am| {
task_retrieve_meshmap(identity_clone.clone(), token.clone(), telio_tx.clone());
}))
.await;

Ok(identity)
}

pub async fn daemon_event_loop(config: TeliodDaemonConfig) -> Result<(), TeliodError> {
let (non_blocking_writer, _tracing_worker_guard) =
tracing_appender::non_blocking(fs::File::create(&config.log_file_path)?);
Expand All @@ -192,44 +219,34 @@ pub async fn daemon_event_loop(config: TeliodDaemonConfig) -> Result<(), TeliodE

debug!("started with config: {config:?}");

let socket = DaemonSocket::new(&DaemonSocket::get_ipc_socket_path()?)?;

// Tx is unused here, but this channel can be used to communicate with the
// telio task
let (tx, rx) = mpsc::channel(10);
let mut cmd_listener = CommandListener::new(socket, tx.clone());

// TODO: This if condition and ::default call is temporary to be removed later
// on when we have proper integration tests with core API.
// This is to not look for tokens in a test environment right now as the values
// are dummy and program will not run as it expects real tokens.
let mut identity = DeviceIdentity::default();
if !config.authentication_token.eq(EMPTY_TOKEN) {
identity = init_with_api(&config.authentication_token).await?;
}
let mut signals = Signals::new([SIGHUP, SIGTERM, SIGINT, SIGQUIT])?;

let nc = NotificationCenter::new(&config, &identity.hw_identifier).await?;
let (telio_tx, telio_rx) = mpsc::channel(10);

let tx_clone = tx.clone();
let socket = DaemonSocket::new(&DaemonSocket::get_ipc_socket_path()?)?;
let mut cmd_listener = CommandListener::new(socket, telio_tx.clone());

let token_ptr = Arc::new(config.authentication_token);
let token_clone = token_ptr.clone();
let token_ptr = Arc::new(config.authentication_token.clone());

let identity_ptr = Arc::new(identity);
let identity_clone = identity_ptr.clone();
let identity_ptr = select! {
init_values = daemon_init(config.clone(), telio_tx.clone(), token_ptr.clone()) => init_values?,
_ = signals.next() => {
warn!("Interrupted while obtaining identity - stopping");
return Ok(());
}
};

let tx_clone = telio_tx.clone();
let mut telio_task_handle = tokio::task::spawn_blocking(move || {
telio_task(identity_clone, token_clone, rx, tx_clone, &config.interface)
telio_task(
identity_ptr,
token_ptr,
telio_rx,
tx_clone,
&config.interface,
)
});

let tx_clone = tx.clone();
nc.add_callback(Arc::new(move |_am| {
task_retrieve_meshmap(identity_ptr.clone(), token_ptr.clone(), tx_clone.clone());
}))
.await;

let mut signals = Signals::new([SIGHUP, SIGTERM, SIGINT, SIGQUIT])?;

info!("Entering event loop");
eprintln!("Daemon started");

Expand Down Expand Up @@ -270,7 +287,7 @@ pub async fn daemon_event_loop(config: TeliodDaemonConfig) -> Result<(), TeliodE
match signal {
Some(s @ SIGHUP | s @ SIGTERM | s @ SIGINT | s @ SIGQUIT) => {
info!("Received signal {:?}, exiting", Signal::try_from(s));
if let Err(e) = tx.send_timeout(TelioTaskCmd::Quit, Duration::from_secs(2)).await {
if let Err(e) = telio_tx.send_timeout(TelioTaskCmd::Quit, Duration::from_secs(2)).await {
error!("Unable to send QUIT due to {e}");
};
break Ok(());
Expand Down

0 comments on commit eb93dd5

Please sign in to comment.