Compare commits

..
Author SHA1 Message Date
ian-at-strix caed7b374f Log the Windows service's connection failures at warn 2026-10-22 17:35:12 -04:00
ian-at-strix 8d781f3f98 Show a popup when pausing or resuming screening fails (#54)
The service now answers Pause and Continue only after rewriting the hosts
file, returning the write's error so the tray's ControlService call fails
and shows it. The tray's popup includes the error's source, which
windows-service's own message hides.
2026-10-22 17:33:56 -04:00
ian-at-strix e521cbdefa Show a popup when a package is blocked (#18) 2026-10-22 16:58:13 -04:00
2 changed files with 28 additions and 9 deletions

No files matched your search

+23 -8
View File
@@ -26,6 +26,7 @@ use std::net::{IpAddr, Ipv4Addr};
use std::sync::Arc;
use std::time::Duration;
use tracing_appender::rolling::{RollingFileAppender, Rotation};
use windows::Win32::Foundation::ERROR_GEN_FAILURE;
use windows_service::service::*;
use windows_service::service_control_handler::{
self, ServiceControlHandlerResult, ServiceStatusHandle,
@@ -73,8 +74,12 @@ fn run_until_stopped() -> Result<(), BoxError> {
| ServiceControl::Shutdown
| ServiceControl::Pause
| ServiceControl::Continue => {
let _ = control_sender.send(control);
ServiceControlHandlerResult::NoError
// Answered once handled, so a failed pause fails the caller's ControlService.
let (reply, handled) = tokio::sync::oneshot::channel();
let _ = control_sender.send((control, reply));
handled
.blocking_recv()
.unwrap_or(ServiceControlHandlerResult::NoError)
}
ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,
_ => ServiceControlHandlerResult::NotImplemented,
@@ -89,16 +94,26 @@ fn run_until_stopped() -> Result<(), BoxError> {
}
};
// Only pausing removes our hosts entries; a stop or crash keeps them, failing closed.
while let Some(control) = control_receiver.recv().await {
while let Some((control, reply)) = control_receiver.recv().await {
let (hosts, state) = match control {
ServiceControl::Pause => (&[][..], ServiceState::Paused),
ServiceControl::Continue => (&hosts[..], ServiceState::Running),
_ => break,
};
match write_hosts_entries(hosts) {
Ok(()) => set_status(&status, state, false)?,
Err(error) => tracing::error!(%error, "could not rewrite the hosts file"),
}
let result = match write_hosts_entries(hosts) {
Ok(()) => {
set_status(&status, state, false)?;
ServiceControlHandlerResult::NoError
}
Err(error) => {
tracing::error!(%error, "could not rewrite the hosts file");
let code = error
.raw_os_error()
.map_or(ERROR_GEN_FAILURE.0, |code| code as u32);
ServiceControlHandlerResult::Other(code)
}
};
let _ = reply.send(result);
}
Ok::<_, BoxError>(())
});
@@ -147,7 +162,7 @@ async fn start_screening(status: &ServiceStatusHandle) -> Result<Vec<&'static st
resolver: resolver.clone(),
service: service.clone(),
};
let upstream = ConsumeErrLayer::trace_as_debug().into_layer(upstream);
let upstream = ConsumeErrLayer::trace_as_warning().into_layer(upstream);
tokio::spawn(listen_on(address, port, &exec)?.serve(upstream));
}
}
+5 -1
View File
@@ -144,7 +144,11 @@ impl Tray {
}
fn show_error(error: BoxError) {
let text = HSTRING::from(error.to_string());
let text = match error.source() {
Some(source) => format!("{error}: {source}"),
None => error.to_string(),
};
let text = HSTRING::from(text);
unsafe { MessageBoxW(None, &text, w!("Strix Firewall"), MB_ICONERROR) };
}