ping_service/
ping_service.rs1#[cfg(windows)]
16fn main() -> windows_service::Result<()> {
17 ping_service::run()
18}
19
20#[cfg(not(windows))]
21fn main() {
22 panic!("This program is only intended to run on Windows.");
23}
24
25#[cfg(windows)]
26mod ping_service {
27 use std::{
28 ffi::OsString,
29 net::{IpAddr, SocketAddr, UdpSocket},
30 sync::mpsc,
31 time::Duration,
32 };
33 use windows_service::{
34 define_windows_service,
35 service::{
36 ServiceControl, ServiceControlAccept, ServiceExitCode, ServiceState, ServiceStatus,
37 ServiceType,
38 },
39 service_control_handler::{self, ServiceControlHandlerResult},
40 service_dispatcher, Result,
41 };
42
43 const SERVICE_NAME: &str = "ping_service";
44 const SERVICE_TYPE: ServiceType = ServiceType::OWN_PROCESS;
45
46 const LOOPBACK_ADDR: [u8; 4] = [127, 0, 0, 1];
47 const RECEIVER_PORT: u16 = 1234;
48 const PING_MESSAGE: &str = "ping\n";
49
50 pub fn run() -> Result<()> {
51 service_dispatcher::start(SERVICE_NAME, ffi_service_main)
54 }
55
56 define_windows_service!(ffi_service_main, my_service_main);
61
62 pub fn my_service_main(_arguments: Vec<OsString>) {
66 if let Err(_e) = run_service() {
67 }
69 }
70
71 pub fn run_service() -> Result<()> {
72 let (shutdown_tx, shutdown_rx) = mpsc::channel();
74
75 let event_handler = move |control_event| -> ServiceControlHandlerResult {
77 match control_event {
78 ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,
81
82 ServiceControl::Stop => {
84 shutdown_tx.send(()).unwrap();
85 ServiceControlHandlerResult::NoError
86 }
87
88 ServiceControl::UserEvent(code) => {
90 if code.to_raw() == 130 {
91 shutdown_tx.send(()).unwrap();
92 }
93 ServiceControlHandlerResult::NoError
94 }
95
96 _ => ServiceControlHandlerResult::NotImplemented,
97 }
98 };
99
100 let status_handle = service_control_handler::register(SERVICE_NAME, event_handler)?;
103
104 status_handle.set_service_status(ServiceStatus {
106 service_type: SERVICE_TYPE,
107 current_state: ServiceState::Running,
108 controls_accepted: ServiceControlAccept::STOP,
109 exit_code: ServiceExitCode::Win32(0),
110 checkpoint: 0,
111 wait_hint: Duration::default(),
112 process_id: None,
113 })?;
114
115 let loopback_ip = IpAddr::from(LOOPBACK_ADDR);
117 let sender_addr = SocketAddr::new(loopback_ip, 0);
118 let receiver_addr = SocketAddr::new(loopback_ip, RECEIVER_PORT);
119 let msg = PING_MESSAGE.as_bytes();
120 let socket = UdpSocket::bind(sender_addr).unwrap();
121
122 loop {
123 let _ = socket.send_to(msg, receiver_addr);
124
125 match shutdown_rx.recv_timeout(Duration::from_secs(1)) {
127 Ok(_) | Err(mpsc::RecvTimeoutError::Disconnected) => break,
129
130 Err(mpsc::RecvTimeoutError::Timeout) => (),
132 };
133 }
134
135 status_handle.set_service_status(ServiceStatus {
137 service_type: SERVICE_TYPE,
138 current_state: ServiceState::Stopped,
139 controls_accepted: ServiceControlAccept::empty(),
140 exit_code: ServiceExitCode::Win32(0),
141 checkpoint: 0,
142 wait_hint: Duration::default(),
143 process_id: None,
144 })?;
145
146 Ok(())
147 }
148}