diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2021-01-25 21:11:31 +0100 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2021-02-01 16:55:02 +0100 |
commit | b95b36756ebfcdfaab6a403d93bc6514f3a3b2e2 (patch) | |
tree | e74ac26517b4c1eae2868d5351bee24746666f7b /manager | |
parent | version: adjust x/sys/windows type name (diff) | |
download | wireguard-windows-b95b36756ebfcdfaab6a403d93bc6514f3a3b2e2.tar.xz wireguard-windows-b95b36756ebfcdfaab6a403d93bc6514f3a3b2e2.zip |
manager: pipeline UAPI requests
This avoids the somewhat expensive pipe setup.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'manager')
-rw-r--r-- | manager/ipc_server.go | 35 | ||||
-rw-r--r-- | manager/ipc_uapi.go | 71 | ||||
-rw-r--r-- | manager/tunneltracker.go | 1 |
3 files changed, 88 insertions, 19 deletions
diff --git a/manager/ipc_server.go b/manager/ipc_server.go index 19298016..ccdfe85e 100644 --- a/manager/ipc_server.go +++ b/manager/ipc_server.go @@ -10,7 +10,6 @@ import ( "encoding/gob" "fmt" "io" - "io/ioutil" "log" "os" "sync" @@ -20,8 +19,6 @@ import ( "golang.org/x/sys/windows" "golang.org/x/sys/windows/svc" - "golang.zx2c4.com/wireguard/ipc/winpipe" - "golang.zx2c4.com/wireguard/windows/conf" "golang.zx2c4.com/wireguard/windows/services" "golang.zx2c4.com/wireguard/windows/updater" @@ -54,30 +51,30 @@ func (s *ManagerService) RuntimeConfig(tunnelName string) (*conf.Config, error) if err != nil { return nil, err } - pipePath, err := services.PipePathOfTunnel(storedConfig.Name) - if err != nil { - return nil, err - } - localSystem, err := windows.CreateWellKnownSid(windows.WinLocalSystemSid) + pipe, err := connectTunnelServicePipe(tunnelName) if err != nil { return nil, err } - pipe, err := winpipe.DialPipe(pipePath, nil, localSystem) - if err != nil { - return nil, err - } - defer pipe.Close() - pipe.SetWriteDeadline(time.Now().Add(time.Second * 2)) + pipe.SetDeadline(time.Now().Add(time.Second * 2)) _, err = pipe.Write([]byte("get=1\n\n")) - if err != nil { - return nil, err + if err == windows.ERROR_NO_DATA { + log.Println("IPC pipe closed unexpectedly, so reopening") + pipe.Unlock() + disconnectTunnelServicePipe(tunnelName) + pipe, err = connectTunnelServicePipe(tunnelName) + if err != nil { + return nil, err + } + pipe.SetDeadline(time.Now().Add(time.Second * 2)) + _, err = pipe.Write([]byte("get=1\n\n")) } - pipe.SetReadDeadline(time.Now().Add(time.Second * 2)) - resp, err := ioutil.ReadAll(pipe) if err != nil { + pipe.Unlock() + disconnectTunnelServicePipe(tunnelName) return nil, err } - conf, err := conf.FromUAPI(string(resp), storedConfig) + conf, err := conf.FromUAPI(pipe, storedConfig) + pipe.Unlock() if err != nil { return nil, err } diff --git a/manager/ipc_uapi.go b/manager/ipc_uapi.go new file mode 100644 index 00000000..b339e3ac --- /dev/null +++ b/manager/ipc_uapi.go @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019-2021 WireGuard LLC. All Rights Reserved. + */ + +package manager + +import ( + "net" + "sync" + + "golang.org/x/sys/windows" + "golang.zx2c4.com/wireguard/ipc/winpipe" + + "golang.zx2c4.com/wireguard/windows/services" +) + +type connectedTunnel struct { + net.Conn + sync.Mutex +} + +var connectedTunnelServicePipes = make(map[string]*connectedTunnel) +var connectedTunnelServicePipesLock sync.RWMutex + +func connectTunnelServicePipe(tunnelName string) (*connectedTunnel, error) { + connectedTunnelServicePipesLock.RLock() + pipe, ok := connectedTunnelServicePipes[tunnelName] + if ok { + pipe.Lock() + connectedTunnelServicePipesLock.RUnlock() + return pipe, nil + } + connectedTunnelServicePipesLock.RUnlock() + connectedTunnelServicePipesLock.Lock() + defer connectedTunnelServicePipesLock.Unlock() + pipe, ok = connectedTunnelServicePipes[tunnelName] + if ok { + pipe.Lock() + return pipe, nil + } + pipePath, err := services.PipePathOfTunnel(tunnelName) + if err != nil { + return nil, err + } + localSystem, err := windows.CreateWellKnownSid(windows.WinLocalSystemSid) + if err != nil { + return nil, err + } + pipe = &connectedTunnel{} + pipe.Conn, err = winpipe.DialPipe(pipePath, nil, localSystem) + if err != nil { + return nil, err + } + connectedTunnelServicePipes[tunnelName] = pipe + pipe.Lock() + return pipe, nil +} + +func disconnectTunnelServicePipe(tunnelName string) { + connectedTunnelServicePipesLock.Lock() + defer connectedTunnelServicePipesLock.Unlock() + pipe, ok := connectedTunnelServicePipes[tunnelName] + if !ok { + return + } + pipe.Lock() + pipe.Close() + delete(connectedTunnelServicePipes, tunnelName) + pipe.Unlock() +} diff --git a/manager/tunneltracker.go b/manager/tunneltracker.go index cfd28693..4625a8e8 100644 --- a/manager/tunneltracker.go +++ b/manager/tunneltracker.go @@ -273,4 +273,5 @@ func trackTunnelService(tunnelName string, service *mgr.Service) { IPCServerNotifyTunnelChange(tunnelName, TunnelStopped, fmt.Errorf("Unable to continue monitoring service, so stopping: %w", err)) service.Control(svc.Stop) } + disconnectTunnelServicePipe(tunnelName) } |