Last active
June 20, 2023 09:12
-
-
Save leiless/e4af121675eead74f59d4506aefa5110 to your computer and use it in GitHub Desktop.
UDP ping service: windows_service + tokio async runtime
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use windows_service::service::{ | |
ServiceType, | |
ServiceControl, | |
ServiceStatus, | |
ServiceState, | |
ServiceControlAccept, | |
ServiceExitCode, | |
}; | |
use windows_service::service_control_handler::ServiceControlHandlerResult; | |
const SERVICE_NAME: &str = "ping_service"; | |
const SERVICE_TYPE: ServiceType = ServiceType::OWN_PROCESS; | |
pub fn run() -> anyhow::Result<()> { | |
// Register generated `ffi_service_main` with the system and start the service | |
// blocking this thread until the service is stopped. | |
windows_service::service_dispatcher::start(SERVICE_NAME, ffi_service_main)?; | |
Ok(()) | |
} | |
windows_service::define_windows_service!(ffi_service_main, ping_service_main); | |
fn ping_service_main(args: Vec<std::ffi::OsString>) { | |
if let Err(err) = run_service(args) { | |
eprintln!("service error: {}", err); | |
} | |
} | |
fn run_service(_args: Vec<std::ffi::OsString>) -> anyhow::Result<()> { | |
let (shutdown_tx, shutdown_rx) = std::sync::mpsc::channel(); | |
let event_handler = move |control_event| -> ServiceControlHandlerResult { | |
match control_event { | |
// Notifies a service to report its current status information to the service | |
// control manager. Always return NoError even if not implemented. | |
ServiceControl::Interrogate => ServiceControlHandlerResult::NoError, | |
// Handle stop | |
ServiceControl::Stop => { | |
shutdown_tx.send(()).unwrap(); | |
ServiceControlHandlerResult::NoError | |
} | |
_ => ServiceControlHandlerResult::NotImplemented, | |
} | |
}; | |
// Register system service event handler. | |
// The returned status handle should be used to report service status changes to the system. | |
let status_handle = windows_service::service_control_handler::register(SERVICE_NAME, event_handler)?; | |
// Tell the system that service is running | |
status_handle.set_service_status(ServiceStatus { | |
service_type: SERVICE_TYPE, | |
current_state: ServiceState::Running, | |
controls_accepted: ServiceControlAccept::STOP, | |
exit_code: ServiceExitCode::Win32(0), | |
checkpoint: 0, | |
wait_hint: std::time::Duration::default(), | |
process_id: None, | |
})?; | |
let result = app_main(shutdown_rx); | |
// Tell the system that service has stopped. | |
status_handle.set_service_status(ServiceStatus { | |
service_type: SERVICE_TYPE, | |
current_state: ServiceState::Stopped, | |
controls_accepted: ServiceControlAccept::empty(), | |
exit_code: ServiceExitCode::Win32(0), | |
checkpoint: 0, | |
wait_hint: std::time::Duration::default(), | |
process_id: None, | |
})?; | |
result | |
} | |
fn app_main(shutdown_rx: std::sync::mpsc::Receiver<()>) -> anyhow::Result<()> { | |
let rt = tokio::runtime::Runtime::new()?; | |
rt.block_on(async move { | |
// 0 means bind to any available port | |
let bind_addr = "127.0.0.1:0"; | |
let receiver_addr = "127.0.0.1:1235"; | |
let ping_msg = "ping\n"; | |
let socket = tokio::net::UdpSocket::bind(bind_addr).await?; | |
loop { | |
let len = socket.send_to(ping_msg.as_bytes(), receiver_addr).await?; | |
assert_eq!(len, ping_msg.len()); | |
match shutdown_rx.try_recv() { | |
Ok(_) => break, | |
Err(_) => {} | |
} | |
tokio::time::sleep(std::time::Duration::from_secs(1)).await; | |
} | |
Ok::<(), anyhow::Error>(()) | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://github.com/mullvad/windows-service-rs/blob/main/examples/ping_service.rs