aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/service
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-03-03 03:25:43 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2019-03-03 03:26:02 +0100
commite7f4071c4bea0406773cb6bfa6501ba4a3a94501 (patch)
tree1ed09d751f2e2f0b562cbfa54ab80a1155174a28 /service
parentcallbacks: use cb as receiver for unregister (diff)
downloadwireguard-windows-e7f4071c4bea0406773cb6bfa6501ba4a3a94501.tar.xz
wireguard-windows-e7f4071c4bea0406773cb6bfa6501ba4a3a94501.zip
tunnel: simplify shutdown
Diffstat (limited to 'service')
-rw-r--r--service/errors.go2
-rw-r--r--service/install.go9
-rw-r--r--service/service_tunnel.go84
3 files changed, 42 insertions, 53 deletions
diff --git a/service/errors.go b/service/errors.go
index 133617ea..04cedb45 100644
--- a/service/errors.go
+++ b/service/errors.go
@@ -18,6 +18,6 @@ const (
ERROR_NETWORK_BUSY uint32 = 0x00000036
ERROR_NO_TRACKING_SERVICE uint32 = 0x00000494
ERROR_OBJECT_ALREADY_EXISTS uint32 = 0x00001392
- ERROR_SERVICE_DOES_NOT_EXIST uint32 = 0x00000424
+ ERROR_SERVICE_DOES_NOT_EXIST uint32 = 0x00000424
ERROR_SERVICE_MARKED_FOR_DELETE uint32 = 0x00000430
)
diff --git a/service/install.go b/service/install.go
index 95a419de..bb2fb046 100644
--- a/service/install.go
+++ b/service/install.go
@@ -9,7 +9,6 @@ import (
"errors"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/svc"
- svcdbg "golang.org/x/sys/windows/svc/debug"
"golang.org/x/sys/windows/svc/mgr"
"golang.zx2c4.com/wireguard/windows/conf"
"os"
@@ -184,14 +183,10 @@ func UninstallTunnel(name string) error {
return err2
}
-func RunTunnel(confPath string, debug bool) error {
+func RunTunnel(confPath string) error {
name, err := conf.NameFromPath(confPath)
if err != nil {
return err
}
- if debug {
- return svcdbg.Run("WireGuard Tunnel: "+name, &tunnelService{confPath, true})
- } else {
- return svc.Run("WireGuard Tunnel: "+name, &tunnelService{confPath, false})
- }
+ return svc.Run("WireGuard Tunnel: "+name, &tunnelService{confPath})
}
diff --git a/service/service_tunnel.go b/service/service_tunnel.go
index 6eff6fa5..b97bea17 100644
--- a/service/service_tunnel.go
+++ b/service/service_tunnel.go
@@ -8,11 +8,13 @@ package service
import (
"bufio"
"fmt"
+ "golang.zx2c4.com/winipcfg"
"log"
+ "net"
+ "runtime/debug"
"strings"
"golang.org/x/sys/windows/svc"
- "golang.org/x/sys/windows/svc/debug"
"golang.org/x/sys/windows/svc/eventlog"
"golang.zx2c4.com/wireguard/windows/conf"
@@ -20,7 +22,7 @@ import (
)
type confElogger struct {
- elog debug.Log
+ elog *eventlog.Log
conf *conf.Config
level int
}
@@ -38,31 +40,44 @@ func (elog confElogger) Write(p []byte) (n int, err error) {
}
type tunnelService struct {
- path string
- debug bool
+ path string
}
func (service *tunnelService) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (svcSpecificEC bool, exitCode uint32) {
changes <- svc.Status{State: svc.StartPending}
- var elog debug.Log
- var err error
- if service.debug {
- elog = debug.New("WireGuard")
- } else {
- //TODO: remember to clean this up in the msi uninstaller
- eventlog.InstallAsEventCreate("WireGuard", eventlog.Info|eventlog.Warning|eventlog.Error)
- elog, err = eventlog.Open("WireGuard")
- if err != nil {
- changes <- svc.Status{State: svc.StopPending}
- exitCode = ERROR_LOG_CONTAINER_OPEN_FAILED
- return
+ var device *Device
+ var uapi net.Listener
+ var routeChangeCallback *winipcfg.RouteChangeCallback
+ var elog *eventlog.Log
+
+ defer func() {
+ changes <- svc.Status{State: svc.StopPending}
+ if routeChangeCallback != nil {
+ routeChangeCallback.Unregister()
+ }
+ if uapi != nil {
+ uapi.Close()
}
+ if device != nil {
+ device.Close()
+ }
+ if elog != nil {
+ elog.Info(1, "Shutting down")
+ }
+ }()
+
+ //TODO: remember to clean this up in the msi uninstaller
+ eventlog.InstallAsEventCreate("WireGuard", eventlog.Info|eventlog.Warning|eventlog.Error)
+ elog, err := eventlog.Open("WireGuard")
+ if err != nil {
+ exitCode = ERROR_LOG_CONTAINER_OPEN_FAILED
+ return
}
log.SetOutput(elogger{elog})
defer func() {
if x := recover(); x != nil {
- elog.Error(1, fmt.Sprint(x))
+ elog.Error(1, fmt.Sprintf("%v:\n%s", x, string(debug.Stack())))
panic(x)
}
}()
@@ -70,7 +85,6 @@ func (service *tunnelService) Execute(args []string, r <-chan svc.ChangeRequest,
conf, err := conf.LoadFromPath(service.path)
if err != nil {
elog.Error(1, "Unable to load configuration file from path "+service.path+": "+err.Error())
- changes <- svc.Status{State: svc.StopPending}
exitCode = ERROR_OPEN_FAILED
return
}
@@ -92,90 +106,70 @@ func (service *tunnelService) Execute(args []string, r <-chan svc.ChangeRequest,
}
} else {
logger.Error.Println("Failed to create TUN device:", err)
- changes <- svc.Status{State: svc.StopPending}
exitCode = ERROR_ADAP_HDW_ERR
return
}
- device := NewDevice(wintun, logger)
+ device = NewDevice(wintun, logger)
device.Up()
logger.Info.Println("Device started")
- uapi, err := UAPIListen(conf.Name)
+ uapi, err = UAPIListen(conf.Name)
if err != nil {
logger.Error.Println("Failed to listen on uapi socket:", err)
- changes <- svc.Status{State: svc.StopPending}
exitCode = ERROR_PIPE_LISTENING
- device.Close()
return
}
- errs := make(chan error)
go func() {
for {
conn, err := uapi.Accept()
if err != nil {
- errs <- err
- return
+ continue
}
go ipcHandle(device, conn)
}
}()
logger.Info.Println("UAPI listener started")
+
uapiConf, err := conf.ToUAPI()
if err != nil {
logger.Error.Println("Failed to convert to UAPI serialization:", err)
- changes <- svc.Status{State: svc.StopPending}
exitCode = ERROR_INVALID_PARAMETER
- device.Close()
return
}
ipcSetOperation(device, bufio.NewReader(strings.NewReader(uapiConf)))
guid := wintun.(*tun.NativeTun).GUID()
- routeMonitorCallback, err := monitorDefaultRoutes(device.net.bind.(*NativeBind), &guid)
+ routeChangeCallback, err = monitorDefaultRoutes(device.net.bind.(*NativeBind), &guid)
if err != nil {
logger.Error.Println("Unable to bind sockets to default route:", err)
- changes <- svc.Status{State: svc.StopPending}
exitCode = ERROR_NETWORK_BUSY
- device.Close()
return
}
err = configureInterface(conf, &guid)
if err != nil {
logger.Error.Println("Unable to set interface addresses, routes, DNS, or IP settings:", err)
- changes <- svc.Status{State: svc.StopPending}
exitCode = ERROR_NETWORK_BUSY
- device.Close()
return
}
changes <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop}
-loop:
for {
select {
case c := <-r:
switch c.Cmd {
case svc.Stop:
- break loop
+ return
case svc.Interrogate:
changes <- c.CurrentStatus
default:
logger.Error.Printf("Unexpected service control request #%d", c)
}
- case <-errs:
- break loop
case <-device.Wait():
- break loop
+ return
}
}
-
- changes <- svc.Status{State: svc.StopPending}
- logger.Info.Println("Shutting down")
- routeMonitorCallback.Unregister()
- uapi.Close()
- device.Close()
- return
}