• Stars
    star
    501
  • Rank 88,002 (Top 2 %)
  • Language
    Rust
  • License
    Apache License 2.0
  • Created over 6 years ago
  • Updated 5 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Windows services in Rust

windows-service

A crate that provides facilities for management and implementation of windows services.

Implementing windows service

This section describes the steps of implementing a program that runs as a windows service, for complete source code of such program take a look at examples folder.

Basics

Each windows service has to implement a service entry function fn(argc: u32, argv: *mut *mut u16) and register it with the system from the application's main.

This crate provides a handy [define_windows_service!] macro to generate a low level boilerplate for the service entry function that parses input from the system and delegates handling to user defined higher level function fn(arguments: Vec<OsString>).

This guide references the low level entry function as ffi_service_main and higher level function as my_service_main but it's up to developer how to call them.

#[macro_use]
extern crate windows_service;

use std::ffi::OsString;
use windows_service::service_dispatcher;

define_windows_service!(ffi_service_main, my_service_main);

fn my_service_main(arguments: Vec<OsString>) {
    // The entry point where execution will start on a background thread after a call to
    // `service_dispatcher::start` from `main`.
}

fn main() -> Result<(), windows_service::Error> {
    // Register generated `ffi_service_main` with the system and start the service, blocking
    // this thread until the service is stopped.
    service_dispatcher::start("myservice", ffi_service_main)?;
    Ok(())
}

Handling service events

The first thing that a windows service should do early in its lifecycle is to subscribe for service events such as stop or pause and many other.

extern crate windows_service;

use std::ffi::OsString;
use windows_service::service::ServiceControl;
use windows_service::service_control_handler::{self, ServiceControlHandlerResult};

fn my_service_main(arguments: Vec<OsString>) {
    if let Err(_e) = run_service(arguments) {
        // Handle errors in some way.
    }
}

fn run_service(arguments: Vec<OsString>) -> Result<(), windows_service::Error> {
    let event_handler = move |control_event| -> ServiceControlHandlerResult {
        match control_event {
            ServiceControl::Stop => {
                // Handle stop event and return control back to the system.
                ServiceControlHandlerResult::NoError
            }
            // All services must accept Interrogate even if it's a no-op.
            ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,
            _ => ServiceControlHandlerResult::NotImplemented,
        }
    };

    // Register system service event handler
    let status_handle = service_control_handler::register("myservice", event_handler)?;
    Ok(())
}

Please see the corresponding MSDN article that describes how event handler works internally:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms685149(v=vs.85).aspx

Updating service status

When application that implements a windows service is launched by the system, it's automatically put in the StartPending state.

The application needs to complete the initialization, obtain ServiceStatusHandle (see [service_control_handler::register]) and transition to Running state.

If service has a lengthy initialization, it should immediately tell the system how much time it needs to complete it, by sending the StartPending state, time estimate using ServiceStatus::wait_hint and increment ServiceStatus::checkpoint each time the service completes a step in initialization.

The system will attempt to kill a service that is not able to transition to Running state before the proposed ServiceStatus::wait_hint expired.

The same concept applies when transitioning between other pending states and their corresponding target states.

Note that it's safe to clone ServiceStatusHandle and use it from any thread.

extern crate windows_service;

use std::ffi::OsString;
use std::time::Duration;
use windows_service::service::{
    ServiceControl, ServiceControlAccept, ServiceExitCode, ServiceState, ServiceStatus,
    ServiceType,
};
use windows_service::service_control_handler::{self, ServiceControlHandlerResult};

fn my_service_main(arguments: Vec<OsString>) {
    if let Err(_e) = run_service(arguments) {
        // Handle error in some way.
    }
}

fn run_service(arguments: Vec<OsString>) -> windows_service::Result<()> {
    let event_handler = move |control_event| -> ServiceControlHandlerResult {
        match control_event {
            ServiceControl::Stop | ServiceControl::Interrogate => {
                ServiceControlHandlerResult::NoError
            }
            _ => ServiceControlHandlerResult::NotImplemented,
        }
    };

    // Register system service event handler
    let status_handle = service_control_handler::register("my_service_name", event_handler)?;

    let next_status = ServiceStatus {
        // Should match the one from system service registry
        service_type: ServiceType::OWN_PROCESS,
        // The new state
        current_state: ServiceState::Running,
        // Accept stop events when running
        controls_accepted: ServiceControlAccept::STOP,
        // Used to report an error when starting or stopping only, otherwise must be zero
        exit_code: ServiceExitCode::Win32(0),
        // Only used for pending states, otherwise must be zero
        checkpoint: 0,
        // Only used for pending states, otherwise must be zero
        wait_hint: Duration::default(),
    };

    // Tell the system that the service is running now
    status_handle.set_service_status(next_status)?;

    // Do some work

    Ok(())
}

Please refer to the "Service State Transitions" article on MSDN for more info:
https://msdn.microsoft.com/en-us/library/windows/desktop/ee126211(v=vs.85).aspx

License: MIT/Apache-2.0

More Repositories

1

mullvadvpn-app

The Mullvad VPN client app for desktop and mobile
Rust
4,976
star
2

mullvad-browser

Privacy-focused browser for Linux, macOS and Windows. Made in collaboration between @torproject and @mullvad
1,259
star
3

dns-blocklists

Lists and configuration for our DNS blocking service
Shell
976
star
4

udp-over-tcp

Proxy UDP traffic over a TCP stream
Rust
343
star
5

encrypted-dns-profiles

macOS and iOS profiles to configure our DNS over TLS and DNS over HTTPS service. Can be applied with human interaction, or via MDM.
242
star
6

browser-extension

Mullvad Browser Extension improves your browsing experience while using Mullvad VPN.
TypeScript
191
star
7

libwfp

C++ library for interacting with the Windows Filtering Platform (WFP)
C++
82
star
8

nftnl-rs

Rust bindings and abstraction for libnftnl, low-level userspace access to the in-kernel nf_tables subsystem
Rust
71
star
9

pfctl-rs

Library and CLI for interfacing with the PF firewall on macOS
Rust
64
star
10

jsonrpc-client-rs

A JSON-RPC 2.0 client in and for Rust
Rust
53
star
11

jnix

Procedural macros for automatically generating conversion code between Rust and Java
Rust
47
star
12

message-queue

A redis pubsub -> websocket message queue
Go
37
star
13

mullvadvpn-app-binaries

Extra binaries to bundle with Mullvad VPN app
C
36
star
14

win-split-tunnel

Mullvad split tunnel driver for Windows
C++
36
star
15

system-configuration-rs

Bindings to System Configuration framework for macOS
Rust
35
star
16

oqs-rs

Rust bindings and key exchange for liboqs (Open Quantum Safe), a library for quantum-resistant cryptographic algorithms
Rust
35
star
17

system-transparency

Shell
33
star
18

coding-guidelines

Guides and texts about how we develop, format and work with code at Mullvad
32
star
19

windows-libraries

C++ libraries for Windows
C++
23
star
20

mullvad-wg.sh

Configuration script for using Mullvad with WireGuard on linux
Shell
19
star
21

openvpn-plugin-rs

A crate allowing easy creation of OpenVPN plugins in Rust
Rust
18
star
22

NSEventMonitor

Node.js module for monitoring NSEvents
Objective-C++
17
star
23

windows-security

Node add-on to access security features on Windows
C++
15
star
24

apisocks5

Censorship circumvention. Reroute and optionally obfuscate traffic destined for the Mullvad API.
Go
14
star
25

mnl-rs

Rust bindings and abstraction for libmnl. A minimalistic user-space library oriented to Netlink developers
Rust
8
star
26

wgephemeralpeer

Mullvad Post-Quantum-secure WireGuard tunnels for vanilla WireGuard and custom integrations.
Go
8
star
27

mullvadvpn-app-tests

Rust
3
star
28

infrastructure-ansible-packages

Ansible installation packages used by the Infrastructure Team
Shell
3
star
29

globe-mesh-builder

Parses SHP (shapefiles) and produce OpenGL compatible vertex and index buffers for drawing a spherical world map (globe). Used by the Mullvad VPN app to generate map data
Rust
2
star
30

hyper-dnscache

An implementation of the hyper Resolve trait that can cache in memory
Rust
2
star
31

grpc-sandbox

App team playing around with gRPC
Rust
2
star
32

mullvadvpn-app-assets

This repository contains the graphical assets used in mullvadvpn-app
Shell
1
star
33

heathrow_wifi

DIGITAL Command Language
1
star
34

wireguard-go

Go
1
star
35

client-binaries

Binaries that are bundled with the Mullvad VPN client.
Shell
1
star
36

supply-chain

Shared third party code audits
1
star
37

mullvadvpn-app-screenshots

Screenshots for CI purposes
1
star