diff options
author | Mathias Hall-Andersen <mathias@hall-andersen.dk> | 2018-05-05 02:23:03 +0200 |
---|---|---|
committer | Mathias Hall-Andersen <mathias@hall-andersen.dk> | 2018-05-05 02:23:03 +0200 |
commit | edbce6b400250f764d3b9f38ecfc7bb29adbd967 (patch) | |
tree | 4b92b85cf66de6ddd7ec420c81c1c9f88805b183 /uapi_darwin.go | |
parent | 6db41d5a269c79bd04b18dbfa171cc241a6cdcc9 (diff) | |
parent | e1de0f229a8f2cbfc4bb56230de885386a775fd6 (diff) | |
download | wireguard-go-edbce6b400250f764d3b9f38ecfc7bb29adbd967.tar.gz wireguard-go-edbce6b400250f764d3b9f38ecfc7bb29adbd967.zip |
Merge branch 'master' of ssh://git.zx2c4.com/wireguard-go
Diffstat (limited to 'uapi_darwin.go')
-rw-r--r-- | uapi_darwin.go | 120 |
1 files changed, 103 insertions, 17 deletions
diff --git a/uapi_darwin.go b/uapi_darwin.go index 2850184..69b0e3d 100644 --- a/uapi_darwin.go +++ b/uapi_darwin.go @@ -1,12 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( + "errors" "fmt" "golang.org/x/sys/unix" "net" "os" "path" - "time" ) const ( @@ -22,6 +27,8 @@ type UAPIListener struct { listener net.Listener // unix socket listener connNew chan net.Conn connErr chan error + kqueueFd int + keventFd int } func (l *UAPIListener) Accept() (net.Conn, error) { @@ -37,48 +44,74 @@ func (l *UAPIListener) Accept() (net.Conn, error) { } func (l *UAPIListener) Close() error { - return l.listener.Close() + err1 := unix.Close(l.kqueueFd) + err2 := unix.Close(l.keventFd) + err3 := l.listener.Close() + if err1 != nil { + return err1 + } + if err2 != nil { + return err2 + } + return err3 } func (l *UAPIListener) Addr() net.Addr { return nil } -func NewUAPIListener(name string) (net.Listener, error) { +func UAPIListen(name string, file *os.File) (net.Listener, error) { - // check if path exist + // wrap file in listener - err := os.MkdirAll(socketDirectory, 077) - if err != nil && !os.IsExist(err) { + listener, err := net.FileListener(file) + if err != nil { return nil, err } - // open UNIX socket + uapi := &UAPIListener{ + listener: listener, + connNew: make(chan net.Conn, 1), + connErr: make(chan error, 1), + } socketPath := path.Join( socketDirectory, fmt.Sprintf(socketName, name), ) - listener, err := net.Listen("unix", socketPath) + // watch for deletion of socket + + uapi.kqueueFd, err = unix.Kqueue() if err != nil { return nil, err } - - uapi := &UAPIListener{ - listener: listener, - connNew: make(chan net.Conn, 1), - connErr: make(chan error, 1), + uapi.keventFd, err = unix.Open(socketDirectory, unix.O_EVTONLY, 0) + if err != nil { + unix.Close(uapi.kqueueFd) + return nil, err } - // watch for deletion of socket - go func(l *UAPIListener) { - for ; ; time.Sleep(time.Second) { - if _, err := os.Stat(socketPath); os.IsNotExist(err) { + event := unix.Kevent_t{ + Ident: uint64(uapi.keventFd), + Filter: unix.EVFILT_VNODE, + Flags: unix.EV_ADD | unix.EV_ENABLE | unix.EV_ONESHOT, + Fflags: unix.NOTE_WRITE, + } + events := make([]unix.Kevent_t, 1) + n := 1 + var kerr error + for { + // start with lstat to avoid race condition + if _, err := os.Lstat(socketPath); os.IsNotExist(err) { l.connErr <- err return } + if kerr != nil || n != 1 { + return + } + n, kerr = unix.Kevent(uapi.kqueueFd, []unix.Kevent_t{event}, events, nil) } }(uapi) @@ -97,3 +130,56 @@ func NewUAPIListener(name string) (net.Listener, error) { return uapi, nil } + +func UAPIOpen(name string) (*os.File, error) { + + // check if path exist + + err := os.MkdirAll(socketDirectory, 0600) + if err != nil && !os.IsExist(err) { + return nil, err + } + + // open UNIX socket + + socketPath := path.Join( + socketDirectory, + fmt.Sprintf(socketName, name), + ) + + addr, err := net.ResolveUnixAddr("unix", socketPath) + if err != nil { + return nil, err + } + + listener, err := func() (*net.UnixListener, error) { + + // initial connection attempt + + listener, err := net.ListenUnix("unix", addr) + if err == nil { + return listener, nil + } + + // check if socket already active + + _, err = net.Dial("unix", socketPath) + if err == nil { + return nil, errors.New("unix socket in use") + } + + // cleanup & attempt again + + err = os.Remove(socketPath) + if err != nil { + return nil, err + } + return net.ListenUnix("unix", addr) + }() + + if err != nil { + return nil, err + } + + return listener.File() +} |