From f3c3bd215731f55cf042e0d1c9eae4aa880f6257 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Thu, 28 Feb 2019 07:19:06 +0100 Subject: service: track tunnel service status --- service/tunneltracker.go | 117 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 service/tunneltracker.go (limited to 'service/tunneltracker.go') diff --git a/service/tunneltracker.go b/service/tunneltracker.go new file mode 100644 index 00000000..2545930d --- /dev/null +++ b/service/tunneltracker.go @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package service + +import ( + "golang.org/x/sys/windows" + "golang.org/x/sys/windows/svc/mgr" + "golang.zx2c4.com/wireguard/windows/conf" + "runtime" + "unsafe" +) + +//sys notifyServiceStatusChange(service windows.Handle, notifyMask uint32, notifyBuffer uintptr) (err error) [failretval!=0] = advapi32.NotifyServiceStatusChangeW +//sys sleepEx(milliseconds uint32, alertable bool) (ret uint32, err error) = kernel32.SleepEx + +const ( + serviceNotify_CREATED uint32 = 0x00000080 + serviceNotify_CONTINUE_PENDING = 0x00000010 + serviceNotify_DELETE_PENDING = 0x00000200 + serviceNotify_DELETED = 0x00000100 + serviceNotify_PAUSE_PENDING = 0x00000020 + serviceNotify_PAUSED = 0x00000040 + serviceNotify_RUNNING = 0x00000008 + serviceNotify_START_PENDING = 0x00000002 + serviceNotify_STOP_PENDING = 0x00000004 + serviceNotify_STOPPED = 0x00000001 +) +const serviceNotify_STATUS_CHANGE uint32 = 2 +const errorServiceMARKED_FOR_DELETE uint32 = 1072 + +type serviceNotify struct { + version uint32 + notifyCallback uintptr + context uintptr + notificationStatus uint32 + serviceType uint32 + currentState uint32 + controlsAccepted uint32 + win32ExitCode uint32 + serviceSpecificExitCode uint32 + checkPoint uint32 + waitHint uint32 + processId uint32 + serviceFlags uint32 + notificationTriggered uint32 + serviceNames *uint16 +} + +func serviceTrackerCallback(notifier *serviceNotify) uintptr { + return 0 +} + +var serviceTrackerCallbackPtr uintptr + +func init() { + serviceTrackerCallbackPtr = windows.NewCallback(serviceTrackerCallback) +} + +func trackExistingTunnels() error { + m, err := serviceManager() + if err != nil { + return err + } + names, err := conf.ListConfigNames() + if err != nil { + return err + } + for _, name := range names { + serviceName := "WireGuard Tunnel: " + name + service, err := m.OpenService(serviceName) + if err != nil { + continue + } + go trackTunnelService(name, service) + } + return nil +} + +func trackTunnelService(tunnelName string, svc *mgr.Service) { + runtime.LockOSThread() + const serviceNotifications = serviceNotify_RUNNING | serviceNotify_START_PENDING | serviceNotify_STOP_PENDING | serviceNotify_STOPPED | serviceNotify_DELETE_PENDING + notifier := &serviceNotify{ + version: serviceNotify_STATUS_CHANGE, + notifyCallback: serviceTrackerCallbackPtr, + } + defer svc.Close() + for { + notifier.context = 0 + err := notifyServiceStatusChange(svc.Handle, serviceNotifications, uintptr(unsafe.Pointer(notifier))) + if err != nil { + return + } + sleepEx(windows.INFINITE, true) + if notifier.notificationStatus != 0 { + return + } + state := TunnelUnknown + if notifier.notificationTriggered&serviceNotify_DELETE_PENDING != 0 { + state = TunnelDeleting + } else if notifier.notificationTriggered&serviceNotify_STOPPED != 0 { + state = TunnelStopped + } else if notifier.notificationTriggered&serviceNotify_STOP_PENDING != 0 { + state = TunnelStopping + } else if notifier.notificationTriggered&serviceNotify_RUNNING != 0 { + state = TunnelStarted + } else if notifier.notificationTriggered&serviceNotify_START_PENDING != 0 { + state = TunnelStarting + } + IPCServerNotifyTunnelChange(tunnelName, state) + if state == TunnelDeleting { + return + } + } +} -- cgit v1.2.3-59-g8ed1b