diff options
Diffstat (limited to 'ipc')
-rw-r--r-- | ipc/namedpipe/file.go (renamed from ipc/winpipe/file.go) | 39 | ||||
-rw-r--r-- | ipc/namedpipe/namedpipe.go (renamed from ipc/winpipe/winpipe.go) | 91 | ||||
-rw-r--r-- | ipc/namedpipe/namedpipe_test.go (renamed from ipc/winpipe/winpipe_test.go) | 124 | ||||
-rw-r--r-- | ipc/uapi_bsd.go | 5 | ||||
-rw-r--r-- | ipc/uapi_linux.go | 7 | ||||
-rw-r--r-- | ipc/uapi_unix.go | 6 | ||||
-rw-r--r-- | ipc/uapi_wasm.go | 15 | ||||
-rw-r--r-- | ipc/uapi_windows.go | 10 |
8 files changed, 167 insertions, 130 deletions
diff --git a/ipc/winpipe/file.go b/ipc/namedpipe/file.go index 319565f..ab1e13d 100644 --- a/ipc/winpipe/file.go +++ b/ipc/namedpipe/file.go @@ -1,12 +1,11 @@ -//go:build windows +// Copyright 2021 The Go Authors. All rights reserved. +// Copyright 2015 Microsoft +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2005 Microsoft - * Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved. - */ +//go:build windows -package winpipe +package namedpipe import ( "io" @@ -22,8 +21,10 @@ import ( type timeoutChan chan struct{} -var ioInitOnce sync.Once -var ioCompletionPort windows.Handle +var ( + ioInitOnce sync.Once + ioCompletionPort windows.Handle +) // ioResult contains the result of an asynchronous IO operation type ioResult struct { @@ -52,7 +53,7 @@ type file struct { handle windows.Handle wg sync.WaitGroup wgLock sync.RWMutex - closing uint32 // used as atomic boolean + closing atomic.Bool socket bool readDeadline deadlineHandler writeDeadline deadlineHandler @@ -63,7 +64,7 @@ type deadlineHandler struct { channel timeoutChan channelLock sync.RWMutex timer *time.Timer - timedout uint32 // used as atomic boolean + timedout atomic.Bool } // makeFile makes a new file from an existing file handle @@ -87,7 +88,7 @@ func makeFile(h windows.Handle) (*file, error) { func (f *file) closeHandle() { f.wgLock.Lock() // Atomically set that we are closing, releasing the resources only once. - if atomic.SwapUint32(&f.closing, 1) == 0 { + if f.closing.Swap(true) == false { f.wgLock.Unlock() // cancel all IO and wait for it to complete windows.CancelIoEx(f.handle, nil) @@ -110,7 +111,7 @@ func (f *file) Close() error { // The caller must call f.wg.Done() when the IO is finished, prior to Close() returning. func (f *file) prepareIo() (*ioOperation, error) { f.wgLock.RLock() - if atomic.LoadUint32(&f.closing) == 1 { + if f.closing.Load() { f.wgLock.RUnlock() return nil, os.ErrClosed } @@ -142,7 +143,7 @@ func (f *file) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, err err return int(bytes), err } - if atomic.LoadUint32(&f.closing) == 1 { + if f.closing.Load() { windows.CancelIoEx(f.handle, &c.o) } @@ -158,7 +159,7 @@ func (f *file) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, err err case r = <-c.ch: err = r.err if err == windows.ERROR_OPERATION_ABORTED { - if atomic.LoadUint32(&f.closing) == 1 { + if f.closing.Load() { err = os.ErrClosed } } else if err != nil && f.socket { @@ -190,7 +191,7 @@ func (f *file) Read(b []byte) (int, error) { } defer f.wg.Done() - if atomic.LoadUint32(&f.readDeadline.timedout) == 1 { + if f.readDeadline.timedout.Load() { return 0, os.ErrDeadlineExceeded } @@ -217,7 +218,7 @@ func (f *file) Write(b []byte) (int, error) { } defer f.wg.Done() - if atomic.LoadUint32(&f.writeDeadline.timedout) == 1 { + if f.writeDeadline.timedout.Load() { return 0, os.ErrDeadlineExceeded } @@ -254,7 +255,7 @@ func (d *deadlineHandler) set(deadline time.Time) error { } d.timer = nil } - atomic.StoreUint32(&d.timedout, 0) + d.timedout.Store(false) select { case <-d.channel: @@ -269,7 +270,7 @@ func (d *deadlineHandler) set(deadline time.Time) error { } timeoutIO := func() { - atomic.StoreUint32(&d.timedout, 1) + d.timedout.Store(true) close(d.channel) } diff --git a/ipc/winpipe/winpipe.go b/ipc/namedpipe/namedpipe.go index e3719d6..ef3dea1 100644 --- a/ipc/winpipe/winpipe.go +++ b/ipc/namedpipe/namedpipe.go @@ -1,13 +1,12 @@ -//go:build windows +// Copyright 2021 The Go Authors. All rights reserved. +// Copyright 2015 Microsoft +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2005 Microsoft - * Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved. - */ +//go:build windows -// Package winpipe implements a net.Conn and net.Listener around Windows named pipes. -package winpipe +// Package namedpipe implements a net.Conn and net.Listener around Windows named pipes. +package namedpipe import ( "context" @@ -15,6 +14,7 @@ import ( "net" "os" "runtime" + "sync/atomic" "time" "unsafe" @@ -28,7 +28,7 @@ type pipe struct { type messageBytePipe struct { pipe - writeClosed bool + writeClosed atomic.Bool readEOF bool } @@ -50,25 +50,26 @@ func (f *pipe) SetDeadline(t time.Time) error { // CloseWrite closes the write side of a message pipe in byte mode. func (f *messageBytePipe) CloseWrite() error { - if f.writeClosed { + if !f.writeClosed.CompareAndSwap(false, true) { return io.ErrClosedPipe } err := f.file.Flush() if err != nil { + f.writeClosed.Store(false) return err } _, err = f.file.Write(nil) if err != nil { + f.writeClosed.Store(false) return err } - f.writeClosed = true return nil } // Write writes bytes to a message pipe in byte mode. Zero-byte writes are ignored, since // they are used to implement CloseWrite. func (f *messageBytePipe) Write(b []byte) (int, error) { - if f.writeClosed { + if f.writeClosed.Load() { return 0, io.ErrClosedPipe } if len(b) == 0 { @@ -142,30 +143,24 @@ type DialConfig struct { ExpectedOwner *windows.SID // If non-nil, the pipe is verified to be owned by this SID. } -// Dial connects to the specified named pipe by path, timing out if the connection -// takes longer than the specified duration. If timeout is nil, then we use -// a default timeout of 2 seconds. -func Dial(path string, timeout *time.Duration, config *DialConfig) (net.Conn, error) { - var absTimeout time.Time - if timeout != nil { - absTimeout = time.Now().Add(*timeout) - } else { - absTimeout = time.Now().Add(2 * time.Second) +// DialTimeout connects to the specified named pipe by path, timing out if the +// connection takes longer than the specified duration. If timeout is zero, then +// we use a default timeout of 2 seconds. +func (config *DialConfig) DialTimeout(path string, timeout time.Duration) (net.Conn, error) { + if timeout == 0 { + timeout = time.Second * 2 } + absTimeout := time.Now().Add(timeout) ctx, _ := context.WithDeadline(context.Background(), absTimeout) - conn, err := DialContext(ctx, path, config) + conn, err := config.DialContext(ctx, path) if err == context.DeadlineExceeded { return nil, os.ErrDeadlineExceeded } return conn, err } -// DialContext attempts to connect to the specified named pipe by path -// cancellation or timeout. -func DialContext(ctx context.Context, path string, config *DialConfig) (net.Conn, error) { - if config == nil { - config = &DialConfig{} - } +// DialContext attempts to connect to the specified named pipe by path. +func (config *DialConfig) DialContext(ctx context.Context, path string) (net.Conn, error) { var err error var h windows.Handle h, err = tryDialPipe(ctx, &path) @@ -213,6 +208,18 @@ func DialContext(ctx context.Context, path string, config *DialConfig) (net.Conn return &pipe{file: f, path: path}, nil } +var defaultDialer DialConfig + +// DialTimeout calls DialConfig.DialTimeout using an empty configuration. +func DialTimeout(path string, timeout time.Duration) (net.Conn, error) { + return defaultDialer.DialTimeout(path, timeout) +} + +// DialContext calls DialConfig.DialContext using an empty configuration. +func DialContext(ctx context.Context, path string) (net.Conn, error) { + return defaultDialer.DialContext(ctx, path) +} + type acceptResponse struct { f *file err error @@ -222,12 +229,12 @@ type pipeListener struct { firstHandle windows.Handle path string config ListenConfig - acceptCh chan (chan acceptResponse) + acceptCh chan chan acceptResponse closeCh chan int doneCh chan int } -func makeServerPipeHandle(path string, sd *windows.SECURITY_DESCRIPTOR, c *ListenConfig, first bool) (windows.Handle, error) { +func makeServerPipeHandle(path string, sd *windows.SECURITY_DESCRIPTOR, c *ListenConfig, isFirstPipe bool) (windows.Handle, error) { path16, err := windows.UTF16PtrFromString(path) if err != nil { return 0, &os.PathError{Op: "open", Path: path, Err: err} @@ -247,7 +254,7 @@ func makeServerPipeHandle(path string, sd *windows.SECURITY_DESCRIPTOR, c *Liste oa.ObjectName = &ntPath // The security descriptor is only needed for the first pipe. - if first { + if isFirstPipe { if sd != nil { oa.SecurityDescriptor = sd } else { @@ -257,7 +264,7 @@ func makeServerPipeHandle(path string, sd *windows.SECURITY_DESCRIPTOR, c *Liste return 0, err } defer windows.LocalFree(windows.Handle(unsafe.Pointer(acl))) - sd, err := windows.NewSecurityDescriptor() + sd, err = windows.NewSecurityDescriptor() if err != nil { return 0, err } @@ -275,11 +282,11 @@ func makeServerPipeHandle(path string, sd *windows.SECURITY_DESCRIPTOR, c *Liste disposition := uint32(windows.FILE_OPEN) access := uint32(windows.GENERIC_READ | windows.GENERIC_WRITE | windows.SYNCHRONIZE) - if first { + if isFirstPipe { disposition = windows.FILE_CREATE // By not asking for read or write access, the named pipe file system // will put this pipe into an initially disconnected state, blocking - // client connections until the next call with first == false. + // client connections until the next call with isFirstPipe == false. access = windows.SYNCHRONIZE } @@ -395,10 +402,7 @@ type ListenConfig struct { // Listen creates a listener on a Windows named pipe path,such as \\.\pipe\mypipe. // The pipe must not already exist. -func Listen(path string, c *ListenConfig) (net.Listener, error) { - if c == nil { - c = &ListenConfig{} - } +func (c *ListenConfig) Listen(path string) (net.Listener, error) { h, err := makeServerPipeHandle(path, c.SecurityDescriptor, c, true) if err != nil { return nil, err @@ -407,12 +411,12 @@ func Listen(path string, c *ListenConfig) (net.Listener, error) { firstHandle: h, path: path, config: *c, - acceptCh: make(chan (chan acceptResponse)), + acceptCh: make(chan chan acceptResponse), closeCh: make(chan int), doneCh: make(chan int), } // The first connection is swallowed on Windows 7 & 8, so synthesize it. - if maj, _, _ := windows.RtlGetNtVersionNumbers(); maj <= 8 { + if maj, min, _ := windows.RtlGetNtVersionNumbers(); maj < 6 || (maj == 6 && min < 4) { path16, err := windows.UTF16PtrFromString(path) if err == nil { h, err = windows.CreateFile(path16, 0, 0, nil, windows.OPEN_EXISTING, windows.SECURITY_SQOS_PRESENT|windows.SECURITY_ANONYMOUS, 0) @@ -425,6 +429,13 @@ func Listen(path string, c *ListenConfig) (net.Listener, error) { return l, nil } +var defaultListener ListenConfig + +// Listen calls ListenConfig.Listen using an empty configuration. +func Listen(path string) (net.Listener, error) { + return defaultListener.Listen(path) +} + func connectPipe(p *file) error { c, err := p.prepareIo() if err != nil { diff --git a/ipc/winpipe/winpipe_test.go b/ipc/namedpipe/namedpipe_test.go index ea515e3..998453b 100644 --- a/ipc/winpipe/winpipe_test.go +++ b/ipc/namedpipe/namedpipe_test.go @@ -1,12 +1,11 @@ -//go:build windows +// Copyright 2021 The Go Authors. All rights reserved. +// Copyright 2015 Microsoft +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2005 Microsoft - * Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved. - */ +//go:build windows -package winpipe_test +package namedpipe_test import ( "bufio" @@ -22,7 +21,7 @@ import ( "time" "golang.org/x/sys/windows" - "golang.zx2c4.com/wireguard/ipc/winpipe" + "golang.zx2c4.com/wireguard/ipc/namedpipe" ) func randomPipePath() string { @@ -30,7 +29,7 @@ func randomPipePath() string { if err != nil { panic(err) } - return `\\.\PIPE\go-winpipe-test-` + guid.String() + return `\\.\PIPE\go-namedpipe-test-` + guid.String() } func TestPingPong(t *testing.T) { @@ -39,7 +38,7 @@ func TestPingPong(t *testing.T) { pong = 24 ) pipePath := randomPipePath() - listener, err := winpipe.Listen(pipePath, nil) + listener, err := namedpipe.Listen(pipePath) if err != nil { t.Fatalf("unable to listen on pipe: %v", err) } @@ -64,11 +63,12 @@ func TestPingPong(t *testing.T) { t.Fatalf("unable to write pong to pipe: %v", err) } }() - client, err := winpipe.Dial(pipePath, nil, nil) + client, err := namedpipe.DialTimeout(pipePath, time.Duration(0)) if err != nil { t.Fatalf("unable to dial pipe: %v", err) } defer client.Close() + client.SetDeadline(time.Now().Add(time.Second * 5)) var data [1]byte data[0] = ping _, err = client.Write(data[:]) @@ -85,7 +85,7 @@ func TestPingPong(t *testing.T) { } func TestDialUnknownFailsImmediately(t *testing.T) { - _, err := winpipe.Dial(randomPipePath(), nil, nil) + _, err := namedpipe.DialTimeout(randomPipePath(), time.Duration(0)) if !errors.Is(err, syscall.ENOENT) { t.Fatalf("expected ENOENT got %v", err) } @@ -93,13 +93,15 @@ func TestDialUnknownFailsImmediately(t *testing.T) { func TestDialListenerTimesOut(t *testing.T) { pipePath := randomPipePath() - l, err := winpipe.Listen(pipePath, nil) + l, err := namedpipe.Listen(pipePath) if err != nil { t.Fatal(err) } defer l.Close() - d := 10 * time.Millisecond - _, err = winpipe.Dial(pipePath, &d, nil) + pipe, err := namedpipe.DialTimeout(pipePath, 10*time.Millisecond) + if err == nil { + pipe.Close() + } if err != os.ErrDeadlineExceeded { t.Fatalf("expected os.ErrDeadlineExceeded, got %v", err) } @@ -107,14 +109,17 @@ func TestDialListenerTimesOut(t *testing.T) { func TestDialContextListenerTimesOut(t *testing.T) { pipePath := randomPipePath() - l, err := winpipe.Listen(pipePath, nil) + l, err := namedpipe.Listen(pipePath) if err != nil { t.Fatal(err) } defer l.Close() d := 10 * time.Millisecond ctx, _ := context.WithTimeout(context.Background(), d) - _, err = winpipe.DialContext(ctx, pipePath, nil) + pipe, err := namedpipe.DialContext(ctx, pipePath) + if err == nil { + pipe.Close() + } if err != context.DeadlineExceeded { t.Fatalf("expected context.DeadlineExceeded, got %v", err) } @@ -123,14 +128,14 @@ func TestDialContextListenerTimesOut(t *testing.T) { func TestDialListenerGetsCancelled(t *testing.T) { pipePath := randomPipePath() ctx, cancel := context.WithCancel(context.Background()) - l, err := winpipe.Listen(pipePath, nil) + l, err := namedpipe.Listen(pipePath) if err != nil { t.Fatal(err) } - ch := make(chan error) defer l.Close() + ch := make(chan error) go func(ctx context.Context, ch chan error) { - _, err := winpipe.DialContext(ctx, pipePath, nil) + _, err := namedpipe.DialContext(ctx, pipePath) ch <- err }(ctx, ch) time.Sleep(time.Millisecond * 30) @@ -147,23 +152,28 @@ func TestDialAccessDeniedWithRestrictedSD(t *testing.T) { } pipePath := randomPipePath() sd, _ := windows.SecurityDescriptorFromString("D:") - c := winpipe.ListenConfig{ + l, err := (&namedpipe.ListenConfig{ SecurityDescriptor: sd, - } - l, err := winpipe.Listen(pipePath, &c) + }).Listen(pipePath) if err != nil { t.Fatal(err) } defer l.Close() - _, err = winpipe.Dial(pipePath, nil, nil) + pipe, err := namedpipe.DialTimeout(pipePath, time.Duration(0)) + if err == nil { + pipe.Close() + } if !errors.Is(err, windows.ERROR_ACCESS_DENIED) { t.Fatalf("expected ERROR_ACCESS_DENIED, got %v", err) } } -func getConnection(cfg *winpipe.ListenConfig) (client net.Conn, server net.Conn, err error) { +func getConnection(cfg *namedpipe.ListenConfig) (client, server net.Conn, err error) { pipePath := randomPipePath() - l, err := winpipe.Listen(pipePath, cfg) + if cfg == nil { + cfg = &namedpipe.ListenConfig{} + } + l, err := cfg.Listen(pipePath) if err != nil { return } @@ -179,7 +189,7 @@ func getConnection(cfg *winpipe.ListenConfig) (client net.Conn, server net.Conn, ch <- response{c, err} }() - c, err := winpipe.Dial(pipePath, nil, nil) + c, err := namedpipe.DialTimeout(pipePath, time.Duration(0)) if err != nil { return } @@ -236,7 +246,7 @@ func server(l net.Listener, ch chan int) { func TestFullListenDialReadWrite(t *testing.T) { pipePath := randomPipePath() - l, err := winpipe.Listen(pipePath, nil) + l, err := namedpipe.Listen(pipePath) if err != nil { t.Fatal(err) } @@ -245,7 +255,7 @@ func TestFullListenDialReadWrite(t *testing.T) { ch := make(chan int) go server(l, ch) - c, err := winpipe.Dial(pipePath, nil, nil) + c, err := namedpipe.DialTimeout(pipePath, time.Duration(0)) if err != nil { t.Fatal(err) } @@ -275,7 +285,7 @@ func TestFullListenDialReadWrite(t *testing.T) { func TestCloseAbortsListen(t *testing.T) { pipePath := randomPipePath() - l, err := winpipe.Listen(pipePath, nil) + l, err := namedpipe.Listen(pipePath) if err != nil { t.Fatal(err) } @@ -328,7 +338,7 @@ func TestCloseServerEOFClient(t *testing.T) { } func TestCloseWriteEOF(t *testing.T) { - cfg := &winpipe.ListenConfig{ + cfg := &namedpipe.ListenConfig{ MessageMode: true, } c, s, err := getConnection(cfg) @@ -356,7 +366,7 @@ func TestCloseWriteEOF(t *testing.T) { func TestAcceptAfterCloseFails(t *testing.T) { pipePath := randomPipePath() - l, err := winpipe.Listen(pipePath, nil) + l, err := namedpipe.Listen(pipePath) if err != nil { t.Fatal(err) } @@ -369,12 +379,15 @@ func TestAcceptAfterCloseFails(t *testing.T) { func TestDialTimesOutByDefault(t *testing.T) { pipePath := randomPipePath() - l, err := winpipe.Listen(pipePath, nil) + l, err := namedpipe.Listen(pipePath) if err != nil { t.Fatal(err) } defer l.Close() - _, err = winpipe.Dial(pipePath, nil, nil) + pipe, err := namedpipe.DialTimeout(pipePath, time.Duration(0)) // Should timeout after 2 seconds. + if err == nil { + pipe.Close() + } if err != os.ErrDeadlineExceeded { t.Fatalf("expected os.ErrDeadlineExceeded, got %v", err) } @@ -382,7 +395,7 @@ func TestDialTimesOutByDefault(t *testing.T) { func TestTimeoutPendingRead(t *testing.T) { pipePath := randomPipePath() - l, err := winpipe.Listen(pipePath, nil) + l, err := namedpipe.Listen(pipePath) if err != nil { t.Fatal(err) } @@ -400,7 +413,7 @@ func TestTimeoutPendingRead(t *testing.T) { close(serverDone) }() - client, err := winpipe.Dial(pipePath, nil, nil) + client, err := namedpipe.DialTimeout(pipePath, time.Duration(0)) if err != nil { t.Fatal(err) } @@ -430,7 +443,7 @@ func TestTimeoutPendingRead(t *testing.T) { func TestTimeoutPendingWrite(t *testing.T) { pipePath := randomPipePath() - l, err := winpipe.Listen(pipePath, nil) + l, err := namedpipe.Listen(pipePath) if err != nil { t.Fatal(err) } @@ -448,7 +461,7 @@ func TestTimeoutPendingWrite(t *testing.T) { close(serverDone) }() - client, err := winpipe.Dial(pipePath, nil, nil) + client, err := namedpipe.DialTimeout(pipePath, time.Duration(0)) if err != nil { t.Fatal(err) } @@ -480,13 +493,12 @@ type CloseWriter interface { } func TestEchoWithMessaging(t *testing.T) { - c := winpipe.ListenConfig{ + pipePath := randomPipePath() + l, err := (&namedpipe.ListenConfig{ MessageMode: true, // Use message mode so that CloseWrite() is supported InputBufferSize: 65536, // Use 64KB buffers to improve performance OutputBufferSize: 65536, - } - pipePath := randomPipePath() - l, err := winpipe.Listen(pipePath, &c) + }).Listen(pipePath) if err != nil { t.Fatal(err) } @@ -496,19 +508,21 @@ func TestEchoWithMessaging(t *testing.T) { clientDone := make(chan bool) go func() { // server echo - conn, e := l.Accept() - if e != nil { - t.Fatal(e) + conn, err := l.Accept() + if err != nil { + t.Fatal(err) } defer conn.Close() time.Sleep(500 * time.Millisecond) // make *sure* we don't begin to read before eof signal is sent - io.Copy(conn, conn) + _, err = io.Copy(conn, conn) + if err != nil { + t.Fatal(err) + } conn.(CloseWriter).CloseWrite() close(listenerDone) }() - timeout := 1 * time.Second - client, err := winpipe.Dial(pipePath, &timeout, nil) + client, err := namedpipe.DialTimeout(pipePath, time.Second) if err != nil { t.Fatal(err) } @@ -521,7 +535,7 @@ func TestEchoWithMessaging(t *testing.T) { if e != nil { t.Fatal(e) } - if n != 2 { + if n != 2 || bytes[0] != 0 || bytes[1] != 1 { t.Fatalf("expected 2 bytes, got %v", n) } close(clientDone) @@ -545,7 +559,7 @@ func TestEchoWithMessaging(t *testing.T) { func TestConnectRace(t *testing.T) { pipePath := randomPipePath() - l, err := winpipe.Listen(pipePath, nil) + l, err := namedpipe.Listen(pipePath) if err != nil { t.Fatal(err) } @@ -565,7 +579,7 @@ func TestConnectRace(t *testing.T) { }() for i := 0; i < 1000; i++ { - c, err := winpipe.Dial(pipePath, nil, nil) + c, err := namedpipe.DialTimeout(pipePath, time.Duration(0)) if err != nil { t.Fatal(err) } @@ -580,7 +594,7 @@ func TestMessageReadMode(t *testing.T) { var wg sync.WaitGroup defer wg.Wait() pipePath := randomPipePath() - l, err := winpipe.Listen(pipePath, &winpipe.ListenConfig{MessageMode: true}) + l, err := (&namedpipe.ListenConfig{MessageMode: true}).Listen(pipePath) if err != nil { t.Fatal(err) } @@ -602,7 +616,7 @@ func TestMessageReadMode(t *testing.T) { s.Close() }() - c, err := winpipe.Dial(pipePath, nil, nil) + c, err := namedpipe.DialTimeout(pipePath, time.Duration(0)) if err != nil { t.Fatal(err) } @@ -643,13 +657,13 @@ func TestListenConnectRace(t *testing.T) { var wg sync.WaitGroup wg.Add(1) go func() { - c, err := winpipe.Dial(pipePath, nil, nil) + c, err := namedpipe.DialTimeout(pipePath, time.Duration(0)) if err == nil { c.Close() } wg.Done() }() - s, err := winpipe.Listen(pipePath, nil) + s, err := namedpipe.Listen(pipePath) if err != nil { t.Error(i, err) } else { diff --git a/ipc/uapi_bsd.go b/ipc/uapi_bsd.go index 6deaa87..ddcaf27 100644 --- a/ipc/uapi_bsd.go +++ b/ipc/uapi_bsd.go @@ -2,7 +2,7 @@ /* SPDX-License-Identifier: MIT * - * Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. */ package ipc @@ -54,7 +54,6 @@ func (l *UAPIListener) Addr() net.Addr { } func UAPIListen(name string, file *os.File) (net.Listener, error) { - // wrap file in listener listener, err := net.FileListener(file) @@ -104,7 +103,7 @@ func UAPIListen(name string, file *os.File) (net.Listener, error) { l.connErr <- err return } - if kerr != nil || n != 1 { + if (kerr != nil || n != 1) && kerr != unix.EINTR { if kerr != nil { l.connErr <- kerr } else { diff --git a/ipc/uapi_linux.go b/ipc/uapi_linux.go index e03a00b..1562a18 100644 --- a/ipc/uapi_linux.go +++ b/ipc/uapi_linux.go @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: MIT * - * Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. */ package ipc @@ -51,7 +51,6 @@ func (l *UAPIListener) Addr() net.Addr { } func UAPIListen(name string, file *os.File) (net.Listener, error) { - // wrap file in listener listener, err := net.FileListener(file) @@ -97,7 +96,7 @@ func UAPIListen(name string, file *os.File) (net.Listener, error) { } go func(l *UAPIListener) { - var buff [0]byte + var buf [0]byte for { defer uapi.inotifyRWCancel.Close() // start with lstat to avoid race condition @@ -105,7 +104,7 @@ func UAPIListen(name string, file *os.File) (net.Listener, error) { l.connErr <- err return } - _, err := uapi.inotifyRWCancel.Read(buff[:]) + _, err := uapi.inotifyRWCancel.Read(buf[:]) if err != nil { l.connErr <- err return diff --git a/ipc/uapi_unix.go b/ipc/uapi_unix.go index 57caf21..e67be26 100644 --- a/ipc/uapi_unix.go +++ b/ipc/uapi_unix.go @@ -2,7 +2,7 @@ /* SPDX-License-Identifier: MIT * - * Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. */ package ipc @@ -33,7 +33,7 @@ func sockPath(iface string) string { } func UAPIOpen(name string) (*os.File, error) { - if err := os.MkdirAll(socketDirectory, 0755); err != nil { + if err := os.MkdirAll(socketDirectory, 0o755); err != nil { return nil, err } @@ -43,7 +43,7 @@ func UAPIOpen(name string) (*os.File, error) { return nil, err } - oldUmask := unix.Umask(0077) + oldUmask := unix.Umask(0o077) defer unix.Umask(oldUmask) listener, err := net.ListenUnix("unix", addr) diff --git a/ipc/uapi_wasm.go b/ipc/uapi_wasm.go new file mode 100644 index 0000000..fa84684 --- /dev/null +++ b/ipc/uapi_wasm.go @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. + */ + +package ipc + +// Made up sentinel error codes for {js,wasip1}/wasm. +const ( + IpcErrorIO = 1 + IpcErrorInvalid = 2 + IpcErrorPortInUse = 3 + IpcErrorUnknown = 4 + IpcErrorProtocol = 5 +) diff --git a/ipc/uapi_windows.go b/ipc/uapi_windows.go index a4d68da..aa023c9 100644 --- a/ipc/uapi_windows.go +++ b/ipc/uapi_windows.go @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: MIT * - * Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. */ package ipc @@ -9,8 +9,7 @@ import ( "net" "golang.org/x/sys/windows" - - "golang.zx2c4.com/wireguard/ipc/winpipe" + "golang.zx2c4.com/wireguard/ipc/namedpipe" ) // TODO: replace these with actual standard windows error numbers from the win package @@ -61,10 +60,9 @@ func init() { } func UAPIListen(name string) (net.Listener, error) { - config := winpipe.ListenConfig{ + listener, err := (&namedpipe.ListenConfig{ SecurityDescriptor: UAPISecurityDescriptor, - } - listener, err := winpipe.Listen(`\\.\pipe\ProtectedPrefix\Administrators\WireGuard\`+name, &config) + }).Listen(`\\.\pipe\ProtectedPrefix\Administrators\WireGuard\` + name) if err != nil { return nil, err } |