mirror of
https://github.com/shadowsocks/shadowsocks-rust.git
synced 2026-11-06 08:14:07 +00:00
feat(sswinservice): Running ssservice as a Windows Service
ref #1292 https://learn.microsoft.com/en-us/windows/win32/services/about-services
This commit is contained in:
Generated
+110
-32
@@ -126,7 +126,7 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -136,7 +136,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -379,7 +379,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
"windows-targets",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -633,7 +633,7 @@ dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -715,7 +715,7 @@ checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -752,7 +752,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.3.5",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1179,7 +1179,7 @@ checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1196,7 +1196,7 @@ checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
|
||||
dependencies = [
|
||||
"socket2 0.5.3",
|
||||
"widestring",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
@@ -1223,7 +1223,7 @@ checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"rustix 0.38.13",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1458,7 +1458,7 @@ dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1506,7 +1506,7 @@ dependencies = [
|
||||
"log",
|
||||
"mio",
|
||||
"walkdir",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1658,7 +1658,7 @@ dependencies = [
|
||||
"libc",
|
||||
"redox_syscall 0.3.5",
|
||||
"smallvec",
|
||||
"windows-targets",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2088,7 +2088,7 @@ dependencies = [
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
"linux-raw-sys 0.3.8",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2101,7 +2101,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.7",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2168,7 +2168,7 @@ version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2361,7 +2361,7 @@ dependencies = [
|
||||
"tokio-tfo",
|
||||
"trust-dns-resolver",
|
||||
"url",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2421,6 +2421,7 @@ dependencies = [
|
||||
"tcmalloc",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"windows-service",
|
||||
"xdg",
|
||||
]
|
||||
|
||||
@@ -2465,7 +2466,7 @@ dependencies = [
|
||||
"trust-dns-resolver",
|
||||
"tun",
|
||||
"webpki-roots",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2557,7 +2558,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2656,7 +2657,7 @@ dependencies = [
|
||||
"fastrand",
|
||||
"redox_syscall 0.3.5",
|
||||
"rustix 0.38.13",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2675,7 +2676,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237"
|
||||
dependencies = [
|
||||
"rustix 0.37.23",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2740,7 +2741,7 @@ dependencies = [
|
||||
"signal-hook-registry",
|
||||
"socket2 0.5.3",
|
||||
"tokio-macros",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2788,7 +2789,7 @@ dependencies = [
|
||||
"pin-project",
|
||||
"socket2 0.5.3",
|
||||
"tokio",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3206,7 +3207,27 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-service"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd9db37ecb5b13762d95468a2fc6009d4b2c62801243223aabd44fca13ad13c8"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"widestring",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||
dependencies = [
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3215,7 +3236,22 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.42.2",
|
||||
"windows_aarch64_msvc 0.42.2",
|
||||
"windows_i686_gnu 0.42.2",
|
||||
"windows_i686_msvc 0.42.2",
|
||||
"windows_x86_64_gnu 0.42.2",
|
||||
"windows_x86_64_gnullvm 0.42.2",
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3224,51 +3260,93 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
"windows_aarch64_gnullvm 0.48.5",
|
||||
"windows_aarch64_msvc 0.48.5",
|
||||
"windows_i686_gnu 0.48.5",
|
||||
"windows_i686_msvc 0.48.5",
|
||||
"windows_x86_64_gnu 0.48.5",
|
||||
"windows_x86_64_gnullvm 0.48.5",
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
@@ -3282,7 +3360,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -39,6 +39,11 @@ name = "ssservice"
|
||||
path = "bin/ssservice.rs"
|
||||
required-features = ["service"]
|
||||
|
||||
[[bin]]
|
||||
name = "sswinservice"
|
||||
path = "bin/sswinservice.rs"
|
||||
required-features = ["winservice"]
|
||||
|
||||
[workspace]
|
||||
members = ["crates/shadowsocks", "crates/shadowsocks-service"]
|
||||
|
||||
@@ -75,6 +80,8 @@ manager = ["shadowsocks-service/manager"]
|
||||
utility = ["qrcode"]
|
||||
# Enable service
|
||||
service = ["local", "server", "manager"]
|
||||
# Enable Windows Service
|
||||
winservice = ["service", "windows-service"]
|
||||
|
||||
# Enables trust-dns for replacing tokio's builtin DNS resolver
|
||||
trust-dns = ["shadowsocks-service/trust-dns"]
|
||||
@@ -184,6 +191,8 @@ rpmalloc = { version = "0.2", optional = true }
|
||||
|
||||
shadowsocks-service = { version = "1.16.1", path = "./crates/shadowsocks-service" }
|
||||
|
||||
windows-service = { version = "0.6", optional = true }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
daemonize = "0.5"
|
||||
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
use std::{
|
||||
ffi::OsString,
|
||||
future::Future,
|
||||
process::ExitCode,
|
||||
sync::atomic::{AtomicU32, Ordering},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use clap::Command;
|
||||
use log::{error, info};
|
||||
use shadowsocks_rust::service::{local, manager, server};
|
||||
use tokio::{runtime::Runtime, sync::oneshot};
|
||||
use windows_service::{
|
||||
define_windows_service,
|
||||
service::{ServiceControl, ServiceControlAccept, ServiceExitCode, ServiceState, ServiceStatus, ServiceType},
|
||||
service_control_handler::{self, ServiceControlHandlerResult, ServiceStatusHandle},
|
||||
service_dispatcher,
|
||||
};
|
||||
|
||||
const SERVICE_NAME: &str = "ssservice";
|
||||
const SERVICE_EXIT_CODE_ARGUMENT_ERROR: u32 = 100;
|
||||
const SERVICE_EXIT_CODE_EXITED_UNEXPECTLY: u32 = 101;
|
||||
const SERVICE_EXIT_CODE_CREATE_FAILED: u32 = 102;
|
||||
|
||||
#[inline]
|
||||
fn set_service_status(
|
||||
handle: &ServiceStatusHandle,
|
||||
current_state: ServiceState,
|
||||
exit_code: ServiceExitCode,
|
||||
wait_hint: Duration,
|
||||
) -> Result<(), windows_service::Error> {
|
||||
static SERVICE_STATE_CHECKPOINT: AtomicU32 = AtomicU32::new(0);
|
||||
|
||||
let next_status = ServiceStatus {
|
||||
service_type: ServiceType::OWN_PROCESS,
|
||||
current_state,
|
||||
controls_accepted: if current_state == ServiceState::StartPending {
|
||||
ServiceControlAccept::empty()
|
||||
} else {
|
||||
ServiceControlAccept::STOP
|
||||
},
|
||||
exit_code,
|
||||
checkpoint: if matches!(current_state, ServiceState::Running | ServiceState::Stopped) {
|
||||
SERVICE_STATE_CHECKPOINT.fetch_add(1, Ordering::AcqRel)
|
||||
} else {
|
||||
0
|
||||
},
|
||||
wait_hint,
|
||||
process_id: None,
|
||||
};
|
||||
handle.set_service_status(next_status)
|
||||
}
|
||||
|
||||
fn handle_create_service_result<F>(
|
||||
status_handle: ServiceStatusHandle,
|
||||
create_service_result: Result<(Runtime, F), ExitCode>,
|
||||
stop_receiver: oneshot::Receiver<()>,
|
||||
) -> Result<(), windows_service::Error>
|
||||
where
|
||||
F: Future<Output = ExitCode>,
|
||||
{
|
||||
match create_service_result {
|
||||
Ok((runtime, main_fut)) => {
|
||||
// Successfully create runtime and future
|
||||
|
||||
// Report running state
|
||||
set_service_status(
|
||||
&status_handle,
|
||||
ServiceState::Running,
|
||||
ServiceExitCode::Win32(0),
|
||||
Duration::default(),
|
||||
)?;
|
||||
|
||||
// Run it right now.
|
||||
let exited_by_ctrl = runtime.block_on(async move {
|
||||
tokio::pin!(main_fut);
|
||||
tokio::pin!(stop_receiver);
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
_ = stop_receiver => {
|
||||
break true;
|
||||
}
|
||||
exit_code = main_fut => {
|
||||
info!("service exited unexpectly with code: {:?}", exit_code);
|
||||
break false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Report stopped state
|
||||
set_service_status(
|
||||
&status_handle,
|
||||
ServiceState::Stopped,
|
||||
if exited_by_ctrl {
|
||||
ServiceExitCode::Win32(0)
|
||||
} else {
|
||||
ServiceExitCode::ServiceSpecific(SERVICE_EXIT_CODE_EXITED_UNEXPECTLY)
|
||||
},
|
||||
Duration::default(),
|
||||
)?;
|
||||
}
|
||||
Err(exit_code) => {
|
||||
error!("failed to create service, exit code: {:?}", exit_code);
|
||||
|
||||
// Report running state
|
||||
set_service_status(
|
||||
&status_handle,
|
||||
ServiceState::Stopped,
|
||||
ServiceExitCode::ServiceSpecific(SERVICE_EXIT_CODE_CREATE_FAILED),
|
||||
Duration::default(),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn service_main(arguments: Vec<OsString>) -> Result<(), windows_service::Error> {
|
||||
// Create a Oneshot channel for receiving Stop event
|
||||
let (stop_sender, stop_receiver) = oneshot::channel();
|
||||
|
||||
let mut stop_sender_opt = Some(stop_sender);
|
||||
let event_handler = move |control_event| -> ServiceControlHandlerResult {
|
||||
match control_event {
|
||||
ServiceControl::Stop => {
|
||||
if let Some(stop_sender) = stop_sender_opt.take() {
|
||||
let _ = stop_sender.send(());
|
||||
}
|
||||
ServiceControlHandlerResult::NoError
|
||||
}
|
||||
ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,
|
||||
_ => ServiceControlHandlerResult::NotImplemented,
|
||||
}
|
||||
};
|
||||
|
||||
// Register system service event handler
|
||||
let status_handle = service_control_handler::register(SERVICE_NAME, event_handler)?;
|
||||
|
||||
// Report SERVICE_START_PENDING
|
||||
// https://learn.microsoft.com/en-us/windows/win32/services/writing-a-servicemain-function
|
||||
set_service_status(
|
||||
&status_handle,
|
||||
ServiceState::StartPending,
|
||||
ServiceExitCode::Win32(0),
|
||||
Duration::from_secs(30),
|
||||
)?;
|
||||
|
||||
let app = Command::new("shadowsocks service")
|
||||
.version(shadowsocks_rust::VERSION)
|
||||
.about("A fast tunnel proxy that helps you bypass firewalls. (https://shadowsocks.org)");
|
||||
|
||||
let app = app
|
||||
.subcommand_required(true)
|
||||
.subcommand(local::define_command_line_options(Command::new("local")).about("Shadowsocks Local service"))
|
||||
.subcommand(server::define_command_line_options(Command::new("server")).about("Shadowsocks Server service"))
|
||||
.subcommand(
|
||||
manager::define_command_line_options(Command::new("manager")).about("Shadowsocks Server Manager service"),
|
||||
);
|
||||
|
||||
let matches_result = if arguments.len() <= 1 {
|
||||
app.try_get_matches()
|
||||
} else {
|
||||
app.try_get_matches_from(arguments)
|
||||
};
|
||||
|
||||
let matches = match matches_result {
|
||||
Ok(m) => m,
|
||||
Err(err) => {
|
||||
error!("failed to parse command line arguments, error: {}", err);
|
||||
set_service_status(
|
||||
&status_handle,
|
||||
ServiceState::Stopped,
|
||||
ServiceExitCode::ServiceSpecific(SERVICE_EXIT_CODE_ARGUMENT_ERROR),
|
||||
Duration::default(),
|
||||
)?;
|
||||
return Err(windows_service::Error::LaunchArgumentsNotSupported);
|
||||
}
|
||||
};
|
||||
|
||||
match matches.subcommand() {
|
||||
Some(("local", matches)) => handle_create_service_result(status_handle, local::create(matches), stop_receiver),
|
||||
Some(("server", matches)) => {
|
||||
handle_create_service_result(status_handle, server::create(matches), stop_receiver)
|
||||
}
|
||||
Some(("manager", matches)) => {
|
||||
handle_create_service_result(status_handle, manager::create(matches), stop_receiver)
|
||||
}
|
||||
_ => Err(windows_service::Error::LaunchArgumentsNotSupported),
|
||||
}
|
||||
}
|
||||
|
||||
fn service_entry(arguments: Vec<OsString>) {
|
||||
if let Err(err) = service_main(arguments) {
|
||||
error!("service main exited with error: {}", err);
|
||||
}
|
||||
}
|
||||
|
||||
define_windows_service!(ffi_service_entry, service_entry);
|
||||
|
||||
fn main() -> Result<(), windows_service::Error> {
|
||||
service_dispatcher::start(SERVICE_NAME, ffi_service_entry)?;
|
||||
Ok(())
|
||||
}
|
||||
+25
-11
@@ -1,11 +1,14 @@
|
||||
//! Local server launchers
|
||||
|
||||
use std::{net::IpAddr, path::PathBuf, process::ExitCode, time::Duration};
|
||||
use std::{future::Future, net::IpAddr, path::PathBuf, process::ExitCode, time::Duration};
|
||||
|
||||
use clap::{builder::PossibleValuesParser, Arg, ArgAction, ArgGroup, ArgMatches, Command, ValueHint};
|
||||
use futures::future::{self, Either};
|
||||
use log::{info, trace};
|
||||
use tokio::{self, runtime::Builder};
|
||||
use tokio::{
|
||||
self,
|
||||
runtime::{Builder, Runtime},
|
||||
};
|
||||
|
||||
#[cfg(feature = "local-redir")]
|
||||
use shadowsocks_service::config::RedirType;
|
||||
@@ -496,8 +499,8 @@ pub fn define_command_line_options(mut app: Command) -> Command {
|
||||
app
|
||||
}
|
||||
|
||||
/// Program entrance `main`
|
||||
pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
/// Create `Runtime` and `main` entry
|
||||
pub fn create(matches: &ArgMatches) -> Result<(Runtime, impl Future<Output = ExitCode>), ExitCode> {
|
||||
let (config, runtime) = {
|
||||
let config_path_opt = matches.get_one::<PathBuf>("CONFIG").cloned().or_else(|| {
|
||||
if !matches.contains_id("SERVER_CONFIG") {
|
||||
@@ -518,7 +521,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
Ok(c) => c,
|
||||
Err(err) => {
|
||||
eprintln!("loading config {config_path:?}, {err}");
|
||||
return crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into();
|
||||
return Err(crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into());
|
||||
}
|
||||
},
|
||||
None => ServiceConfig::default(),
|
||||
@@ -542,7 +545,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
Ok(cfg) => cfg,
|
||||
Err(err) => {
|
||||
eprintln!("loading config {cpath:?}, {err}");
|
||||
return crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into();
|
||||
return Err(crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into());
|
||||
}
|
||||
},
|
||||
None => Config::new(ConfigType::Local),
|
||||
@@ -781,7 +784,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
Ok(acl) => acl,
|
||||
Err(err) => {
|
||||
eprintln!("loading ACL \"{acl_file}\", {err}");
|
||||
return crate::EXIT_CODE_LOAD_ACL_FAILURE.into();
|
||||
return Err(crate::EXIT_CODE_LOAD_ACL_FAILURE.into());
|
||||
}
|
||||
};
|
||||
config.acl = Some(acl);
|
||||
@@ -831,12 +834,12 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
"missing `local_address`, consider specifying it by --local-addr command line option, \
|
||||
or \"local_address\" and \"local_port\" in configuration file"
|
||||
);
|
||||
return crate::EXIT_CODE_INSUFFICIENT_PARAMS.into();
|
||||
return Err(crate::EXIT_CODE_INSUFFICIENT_PARAMS.into());
|
||||
}
|
||||
|
||||
if let Err(err) = config.check_integrity() {
|
||||
eprintln!("config integrity check failed, {err}");
|
||||
return crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into();
|
||||
return Err(crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into());
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -870,7 +873,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
(config, runtime)
|
||||
};
|
||||
|
||||
runtime.block_on(async move {
|
||||
let main_fut = async move {
|
||||
let config_path = config.config_path.clone();
|
||||
|
||||
let instance = Server::new(config).await.expect("create local");
|
||||
@@ -899,7 +902,18 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
// The abort signal future resolved. Means we should just exit.
|
||||
Either::Right(_) => ExitCode::SUCCESS,
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
Ok((runtime, main_fut))
|
||||
}
|
||||
|
||||
/// Program entrance `main`
|
||||
#[inline]
|
||||
pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
match create(matches) {
|
||||
Ok((runtime, main_fut)) => runtime.block_on(main_fut),
|
||||
Err(code) => code,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
|
||||
+25
-11
@@ -1,11 +1,14 @@
|
||||
//! Server Manager launchers
|
||||
|
||||
use std::{net::IpAddr, path::PathBuf, process::ExitCode, time::Duration};
|
||||
use std::{future::Future, net::IpAddr, path::PathBuf, process::ExitCode, time::Duration};
|
||||
|
||||
use clap::{builder::PossibleValuesParser, Arg, ArgAction, ArgGroup, ArgMatches, Command, ValueHint};
|
||||
use futures::future::{self, Either};
|
||||
use log::{info, trace};
|
||||
use tokio::{self, runtime::Builder};
|
||||
use tokio::{
|
||||
self,
|
||||
runtime::{Builder, Runtime},
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
use shadowsocks_service::config::ManagerServerMode;
|
||||
@@ -256,8 +259,8 @@ pub fn define_command_line_options(mut app: Command) -> Command {
|
||||
app
|
||||
}
|
||||
|
||||
/// Program entrance `main`
|
||||
pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
/// Create `Runtime` and `main` entry
|
||||
pub fn create(matches: &ArgMatches) -> Result<(Runtime, impl Future<Output = ExitCode>), ExitCode> {
|
||||
let (config, runtime) = {
|
||||
let config_path_opt = matches.get_one::<PathBuf>("CONFIG").cloned().or_else(|| {
|
||||
if !matches.contains_id("SERVER_CONFIG") {
|
||||
@@ -278,7 +281,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
Ok(c) => c,
|
||||
Err(err) => {
|
||||
eprintln!("loading config {config_path:?}, {err}");
|
||||
return crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into();
|
||||
return Err(crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into());
|
||||
}
|
||||
},
|
||||
None => ServiceConfig::default(),
|
||||
@@ -302,7 +305,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
Ok(cfg) => cfg,
|
||||
Err(err) => {
|
||||
eprintln!("loading config {cpath:?}, {err}");
|
||||
return crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into();
|
||||
return Err(crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into());
|
||||
}
|
||||
},
|
||||
None => Config::new(ConfigType::Manager),
|
||||
@@ -409,7 +412,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
Ok(acl) => acl,
|
||||
Err(err) => {
|
||||
eprintln!("loading ACL \"{acl_file}\", {err}");
|
||||
return crate::EXIT_CODE_LOAD_ACL_FAILURE.into();
|
||||
return Err(crate::EXIT_CODE_LOAD_ACL_FAILURE.into());
|
||||
}
|
||||
};
|
||||
config.acl = Some(acl);
|
||||
@@ -459,12 +462,12 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
"missing `manager_address`, consider specifying it by --manager-address command line option, \
|
||||
or \"manager_address\" and \"manager_port\" keys in configuration file"
|
||||
);
|
||||
return crate::EXIT_CODE_INSUFFICIENT_PARAMS.into();
|
||||
return Err(crate::EXIT_CODE_INSUFFICIENT_PARAMS.into());
|
||||
}
|
||||
|
||||
if let Err(err) = config.check_integrity() {
|
||||
eprintln!("config integrity check failed, {err}");
|
||||
return crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into();
|
||||
return Err(crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into());
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -503,7 +506,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
(config, runtime)
|
||||
};
|
||||
|
||||
runtime.block_on(async move {
|
||||
let main_fut = async move {
|
||||
let abort_signal = monitor::create_signal_monitor();
|
||||
let server = run_manager(config);
|
||||
|
||||
@@ -524,7 +527,18 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
// The abort signal future resolved. Means we should just exit.
|
||||
Either::Right(_) => ExitCode::SUCCESS,
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
Ok((runtime, main_fut))
|
||||
}
|
||||
|
||||
/// Program entrance `main`
|
||||
#[inline]
|
||||
pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
match create(matches) {
|
||||
Ok((runtime, main_fut)) => runtime.block_on(main_fut),
|
||||
Err(code) => code,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
+25
-11
@@ -1,11 +1,14 @@
|
||||
//! Server launchers
|
||||
|
||||
use std::{net::IpAddr, path::PathBuf, process::ExitCode, time::Duration};
|
||||
use std::{future::Future, net::IpAddr, path::PathBuf, process::ExitCode, time::Duration};
|
||||
|
||||
use clap::{builder::PossibleValuesParser, Arg, ArgAction, ArgGroup, ArgMatches, Command, ValueHint};
|
||||
use futures::future::{self, Either};
|
||||
use log::{info, trace};
|
||||
use tokio::{self, runtime::Builder};
|
||||
use tokio::{
|
||||
self,
|
||||
runtime::{Builder, Runtime},
|
||||
};
|
||||
|
||||
use shadowsocks_service::{
|
||||
acl::AccessControl,
|
||||
@@ -268,8 +271,8 @@ pub fn define_command_line_options(mut app: Command) -> Command {
|
||||
app
|
||||
}
|
||||
|
||||
/// Program entrance `main`
|
||||
pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
/// Create `Runtime` and `main` entry
|
||||
pub fn create(matches: &ArgMatches) -> Result<(Runtime, impl Future<Output = ExitCode>), ExitCode> {
|
||||
let (config, runtime) = {
|
||||
let config_path_opt = matches.get_one::<PathBuf>("CONFIG").cloned().or_else(|| {
|
||||
if !matches.contains_id("SERVER_CONFIG") {
|
||||
@@ -290,7 +293,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
Ok(c) => c,
|
||||
Err(err) => {
|
||||
eprintln!("loading config {config_path:?}, {err}");
|
||||
return crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into();
|
||||
return Err(crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into());
|
||||
}
|
||||
},
|
||||
None => ServiceConfig::default(),
|
||||
@@ -314,7 +317,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
Ok(cfg) => cfg,
|
||||
Err(err) => {
|
||||
eprintln!("loading config {cpath:?}, {err}");
|
||||
return crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into();
|
||||
return Err(crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into());
|
||||
}
|
||||
},
|
||||
None => Config::new(ConfigType::Server),
|
||||
@@ -428,7 +431,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
Ok(acl) => acl,
|
||||
Err(err) => {
|
||||
eprintln!("loading ACL \"{acl_file}\", {err}");
|
||||
return crate::EXIT_CODE_LOAD_ACL_FAILURE.into();
|
||||
return Err(crate::EXIT_CODE_LOAD_ACL_FAILURE.into());
|
||||
}
|
||||
};
|
||||
config.acl = Some(acl);
|
||||
@@ -479,12 +482,12 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
--server-addr, --encrypt-method, --password command line option, \
|
||||
or configuration file, check more details in https://shadowsocks.org/guide/configs.html"
|
||||
);
|
||||
return crate::EXIT_CODE_INSUFFICIENT_PARAMS.into();
|
||||
return Err(crate::EXIT_CODE_INSUFFICIENT_PARAMS.into());
|
||||
}
|
||||
|
||||
if let Err(err) = config.check_integrity() {
|
||||
eprintln!("config integrity check failed, {err}");
|
||||
return crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into();
|
||||
return Err(crate::EXIT_CODE_LOAD_CONFIG_FAILURE.into());
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -523,7 +526,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
(config, runtime)
|
||||
};
|
||||
|
||||
runtime.block_on(async move {
|
||||
let main_fut = async move {
|
||||
let abort_signal = monitor::create_signal_monitor();
|
||||
let server = run_server(config);
|
||||
|
||||
@@ -544,7 +547,18 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
// The abort signal future resolved. Means we should just exit.
|
||||
Either::Right(_) => ExitCode::SUCCESS,
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
Ok((runtime, main_fut))
|
||||
}
|
||||
|
||||
/// Program entrance `main`
|
||||
#[inline]
|
||||
pub fn main(matches: &ArgMatches) -> ExitCode {
|
||||
match create(matches) {
|
||||
Ok((runtime, main_fut)) => runtime.block_on(main_fut),
|
||||
Err(code) => code,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user