#![cfg(windows)]
const SERVICE_NAME: &str = "tun2proxy";
windows_service::define_windows_service!(ffi_service_main, my_service_main);
pub fn start_service() -> Result<(), windows_service::Error> {
windows_service::service_dispatcher::start(SERVICE_NAME, ffi_service_main)?;
Ok(())
}
fn my_service_main(arguments: Vec<std::ffi::OsString>) {
if let Err(_e) = run_service(arguments) {
log::error!("Error: {_e:?}");
}
}
fn run_service(_arguments: Vec<std::ffi::OsString>) -> Result<(), crate::BoxError> {
use windows_service::service::ServiceControl;
use windows_service::service_control_handler::{self, ServiceControlHandlerResult};
let shutdown_token = crate::CancellationToken::new();
let shutdown_token_clone = shutdown_token.clone();
let event_handler = move |control_event| -> ServiceControlHandlerResult {
match control_event {
ServiceControl::Stop => {
shutdown_token_clone.cancel();
ServiceControlHandlerResult::NoError
}
ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,
_ => ServiceControlHandlerResult::NotImplemented,
}
};
let status_handle = service_control_handler::register(SERVICE_NAME, event_handler)?;
let mut next_status = windows_service::service::ServiceStatus {
service_type: windows_service::service::ServiceType::OWN_PROCESS,
current_state: windows_service::service::ServiceState::Running,
controls_accepted: windows_service::service::ServiceControlAccept::STOP,
exit_code: windows_service::service::ServiceExitCode::Win32(0),
checkpoint: 0,
wait_hint: std::time::Duration::default(),
process_id: None,
};
status_handle.set_service_status(next_status.clone())?;
{
let args = crate::Args::parse_args();
let default = format!("{:?},trust_dns_proto=warn", args.verbosity);
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or(default)).init();
let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build()?;
rt.block_on(async {
unsafe extern "C" fn traffic_cb(status: *const crate::TrafficStatus, _: *mut std::ffi::c_void) {
let status = unsafe { &*status };
log::debug!("Traffic: ▲ {} : ▼ {}", status.tx, status.rx);
}
unsafe { crate::tun2proxy_set_traffic_status_callback(1, Some(traffic_cb), std::ptr::null_mut()) };
let ret = crate::general_run_async(args.clone(), tun::DEFAULT_MTU, false, shutdown_token).await;
match &ret {
Ok(sessions) => log::debug!("tun2proxy exited normally, current session count: {sessions}"),
Err(e) => log::error!("failed to run tun2proxy with error: {e:?}"),
}
let _h = std::thread::spawn(move || {
std::thread::sleep(crate::FORCE_EXIT_TIMEOUT);
log::info!("Forcing exit now.");
std::process::exit(-1);
});
tokio::time::sleep(std::time::Duration::from_micros(100)).await;
Ok::<(), crate::Error>(())
})?;
}
next_status.current_state = windows_service::service::ServiceState::Stopped;
status_handle.set_service_status(next_status)?;
Ok(())
}