dns_over_https/
windows.rs

1#![cfg(windows)]
2
3windows_service::define_windows_service!(ffi_service_main, my_service_main);
4
5pub fn start_service() -> Result<(), windows_service::Error> {
6    // Register generated `ffi_service_main` with the system and start the service,
7    // blocking this thread until the service is stopped.
8    windows_service::service_dispatcher::start("dns-over-https", ffi_service_main)?;
9    Ok(())
10}
11
12fn my_service_main(arguments: Vec<std::ffi::OsString>) {
13    // The entry point where execution will start on a background thread after a call to
14    // `service_dispatcher::start` from `main`.
15
16    if let Err(_e) = run_service(arguments) {
17        // Handle errors in some way.
18    }
19}
20
21fn run_service(_arguments: Vec<std::ffi::OsString>) -> Result<(), crate::BoxError> {
22    use windows_service::service::ServiceControl;
23    use windows_service::service_control_handler::{self, ServiceControlHandlerResult};
24
25    let event_handler = move |control_event| -> ServiceControlHandlerResult {
26        match control_event {
27            ServiceControl::Stop => {
28                // Handle stop event and return control back to the system.
29                unsafe { crate::dns_over_https_stop() };
30                ServiceControlHandlerResult::NoError
31            }
32            // All services must accept Interrogate even if it's a no-op.
33            ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,
34            _ => ServiceControlHandlerResult::NotImplemented,
35        }
36    };
37
38    // Register system service event handler
39    let status_handle = service_control_handler::register("dns-over-https", event_handler)?;
40
41    let mut next_status = windows_service::service::ServiceStatus {
42        // Should match the one from system service registry
43        service_type: windows_service::service::ServiceType::OWN_PROCESS,
44        // The new state
45        current_state: windows_service::service::ServiceState::Running,
46        // Accept stop events when running
47        controls_accepted: windows_service::service::ServiceControlAccept::STOP,
48        // Used to report an error when starting or stopping only, otherwise must be zero
49        exit_code: windows_service::service::ServiceExitCode::Win32(0),
50        // Only used for pending states, otherwise must be zero
51        checkpoint: 0,
52        // Only used for pending states, otherwise must be zero
53        wait_hint: std::time::Duration::default(),
54        // Unused for setting status
55        process_id: None,
56    };
57
58    // Tell the system that the service is running now
59    status_handle.set_service_status(next_status.clone())?;
60
61    let args = crate::Args::parse();
62
63    let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build()?;
64    rt.block_on(async {
65        crate::main_loop(&args).await?;
66        Ok::<(), crate::Error>(())
67    })?;
68
69    // Tell the system that the service is stopped now
70    next_status.current_state = windows_service::service::ServiceState::Stopped;
71    status_handle.set_service_status(next_status)?;
72
73    Ok(())
74}