Update dependencies
This commit is contained in:
114
vendor/tailscale.com/net/memnet/conn.go
generated
vendored
Normal file
114
vendor/tailscale.com/net/memnet/conn.go
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package memnet
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NetworkName is the network name returned by [net.Addr.Network]
|
||||
// for [net.Conn.LocalAddr] and [net.Conn.RemoteAddr] from the [Conn] type.
|
||||
const NetworkName = "mem"
|
||||
|
||||
// Conn is a net.Conn that can additionally have its reads and writes blocked and unblocked.
|
||||
type Conn interface {
|
||||
net.Conn
|
||||
|
||||
// SetReadBlock blocks or unblocks the Read method of this Conn.
|
||||
// It reports an error if the existing value matches the new value,
|
||||
// or if the Conn has been Closed.
|
||||
SetReadBlock(bool) error
|
||||
|
||||
// SetWriteBlock blocks or unblocks the Write method of this Conn.
|
||||
// It reports an error if the existing value matches the new value,
|
||||
// or if the Conn has been Closed.
|
||||
SetWriteBlock(bool) error
|
||||
}
|
||||
|
||||
// NewConn creates a pair of Conns that are wired together by pipes.
|
||||
func NewConn(name string, maxBuf int) (Conn, Conn) {
|
||||
r := NewPipe(name+"|0", maxBuf)
|
||||
w := NewPipe(name+"|1", maxBuf)
|
||||
|
||||
return &connHalf{r: r, w: w}, &connHalf{r: w, w: r}
|
||||
}
|
||||
|
||||
// NewTCPConn creates a pair of Conns that are wired together by pipes.
|
||||
func NewTCPConn(src, dst netip.AddrPort, maxBuf int) (local Conn, remote Conn) {
|
||||
r := NewPipe(src.String(), maxBuf)
|
||||
w := NewPipe(dst.String(), maxBuf)
|
||||
|
||||
lAddr := net.TCPAddrFromAddrPort(src)
|
||||
rAddr := net.TCPAddrFromAddrPort(dst)
|
||||
|
||||
return &connHalf{r: r, w: w, remote: rAddr, local: lAddr}, &connHalf{r: w, w: r, remote: lAddr, local: rAddr}
|
||||
}
|
||||
|
||||
type connAddr string
|
||||
|
||||
func (a connAddr) Network() string { return NetworkName }
|
||||
func (a connAddr) String() string { return string(a) }
|
||||
|
||||
type connHalf struct {
|
||||
local, remote net.Addr
|
||||
r, w *Pipe
|
||||
}
|
||||
|
||||
func (c *connHalf) LocalAddr() net.Addr {
|
||||
if c.local != nil {
|
||||
return c.local
|
||||
}
|
||||
return connAddr(c.r.name)
|
||||
}
|
||||
|
||||
func (c *connHalf) RemoteAddr() net.Addr {
|
||||
if c.remote != nil {
|
||||
return c.remote
|
||||
}
|
||||
return connAddr(c.w.name)
|
||||
}
|
||||
|
||||
func (c *connHalf) Read(b []byte) (n int, err error) {
|
||||
return c.r.Read(b)
|
||||
}
|
||||
func (c *connHalf) Write(b []byte) (n int, err error) {
|
||||
return c.w.Write(b)
|
||||
}
|
||||
|
||||
func (c *connHalf) Close() error {
|
||||
if err := c.w.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.r.Close()
|
||||
}
|
||||
|
||||
func (c *connHalf) SetDeadline(t time.Time) error {
|
||||
err1 := c.SetReadDeadline(t)
|
||||
err2 := c.SetWriteDeadline(t)
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
return err2
|
||||
}
|
||||
func (c *connHalf) SetReadDeadline(t time.Time) error {
|
||||
return c.r.SetReadDeadline(t)
|
||||
}
|
||||
func (c *connHalf) SetWriteDeadline(t time.Time) error {
|
||||
return c.w.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
func (c *connHalf) SetReadBlock(b bool) error {
|
||||
if b {
|
||||
return c.r.Block()
|
||||
}
|
||||
return c.r.Unblock()
|
||||
}
|
||||
func (c *connHalf) SetWriteBlock(b bool) error {
|
||||
if b {
|
||||
return c.w.Block()
|
||||
}
|
||||
return c.w.Unblock()
|
||||
}
|
||||
100
vendor/tailscale.com/net/memnet/listener.go
generated
vendored
Normal file
100
vendor/tailscale.com/net/memnet/listener.go
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package memnet
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
bufferSize = 256 * 1024
|
||||
)
|
||||
|
||||
// Listener is a net.Listener using NewConn to create pairs of network
|
||||
// connections connected in memory using a buffered pipe. It also provides a
|
||||
// Dial method to establish new connections.
|
||||
type Listener struct {
|
||||
addr connAddr
|
||||
ch chan Conn
|
||||
closeOnce sync.Once
|
||||
closed chan struct{}
|
||||
|
||||
// NewConn, if non-nil, is called to create a new pair of connections
|
||||
// when dialing. If nil, NewConn is used.
|
||||
NewConn func(network, addr string, maxBuf int) (Conn, Conn)
|
||||
}
|
||||
|
||||
// Listen returns a new Listener for the provided address.
|
||||
func Listen(addr string) *Listener {
|
||||
return &Listener{
|
||||
addr: connAddr(addr),
|
||||
ch: make(chan Conn),
|
||||
closed: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// Addr implements net.Listener.Addr.
|
||||
func (l *Listener) Addr() net.Addr {
|
||||
return l.addr
|
||||
}
|
||||
|
||||
// Close closes the pipe listener.
|
||||
func (l *Listener) Close() error {
|
||||
l.closeOnce.Do(func() {
|
||||
close(l.closed)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// Accept blocks until a new connection is available or the listener is closed.
|
||||
func (l *Listener) Accept() (net.Conn, error) {
|
||||
select {
|
||||
case c := <-l.ch:
|
||||
return c, nil
|
||||
case <-l.closed:
|
||||
return nil, net.ErrClosed
|
||||
}
|
||||
}
|
||||
|
||||
// Dial connects to the listener using the provided context.
|
||||
// The provided Context must be non-nil. If the context expires before the
|
||||
// connection is complete, an error is returned. Once successfully connected
|
||||
// any expiration of the context will not affect the connection.
|
||||
func (l *Listener) Dial(ctx context.Context, network, addr string) (_ net.Conn, err error) {
|
||||
if !strings.HasSuffix(network, "tcp") {
|
||||
return nil, net.UnknownNetworkError(network)
|
||||
}
|
||||
if connAddr(addr) != l.addr {
|
||||
return nil, &net.AddrError{
|
||||
Err: "invalid address",
|
||||
Addr: addr,
|
||||
}
|
||||
}
|
||||
|
||||
newConn := l.NewConn
|
||||
if newConn == nil {
|
||||
newConn = func(network, addr string, maxBuf int) (Conn, Conn) {
|
||||
return NewConn(addr, maxBuf)
|
||||
}
|
||||
}
|
||||
c, s := newConn(network, addr, bufferSize)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
c.Close()
|
||||
s.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case <-l.closed:
|
||||
return nil, net.ErrClosed
|
||||
case l.ch <- s:
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
8
vendor/tailscale.com/net/memnet/memnet.go
generated
vendored
Normal file
8
vendor/tailscale.com/net/memnet/memnet.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Package memnet implements an in-memory network implementation.
|
||||
// It is useful for dialing and listening on in-memory addresses
|
||||
// in tests and other situations where you don't want to use the
|
||||
// network.
|
||||
package memnet
|
||||
244
vendor/tailscale.com/net/memnet/pipe.go
generated
vendored
Normal file
244
vendor/tailscale.com/net/memnet/pipe.go
generated
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package memnet
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const debugPipe = false
|
||||
|
||||
// Pipe implements an in-memory FIFO with timeouts.
|
||||
type Pipe struct {
|
||||
name string
|
||||
maxBuf int
|
||||
mu sync.Mutex
|
||||
cnd *sync.Cond
|
||||
|
||||
blocked bool
|
||||
closed bool
|
||||
buf bytes.Buffer
|
||||
readTimeout time.Time
|
||||
writeTimeout time.Time
|
||||
cancelReadTimer func()
|
||||
cancelWriteTimer func()
|
||||
}
|
||||
|
||||
// NewPipe creates a Pipe with a buffer size fixed at maxBuf.
|
||||
func NewPipe(name string, maxBuf int) *Pipe {
|
||||
p := &Pipe{
|
||||
name: name,
|
||||
maxBuf: maxBuf,
|
||||
}
|
||||
p.cnd = sync.NewCond(&p.mu)
|
||||
return p
|
||||
}
|
||||
|
||||
// readOrBlock attempts to read from the buffer, if the buffer is empty and
|
||||
// the connection hasn't been closed it will block until there is a change.
|
||||
func (p *Pipe) readOrBlock(b []byte) (int, error) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
if !p.readTimeout.IsZero() && !time.Now().Before(p.readTimeout) {
|
||||
return 0, os.ErrDeadlineExceeded
|
||||
}
|
||||
if p.blocked {
|
||||
p.cnd.Wait()
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
n, err := p.buf.Read(b)
|
||||
// err will either be nil or io.EOF.
|
||||
if err == io.EOF {
|
||||
if p.closed {
|
||||
return n, err
|
||||
}
|
||||
// Wait for something to change.
|
||||
p.cnd.Wait()
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Read implements io.Reader.
|
||||
// Once the buffer is drained (i.e. after Close), subsequent calls will
|
||||
// return io.EOF.
|
||||
func (p *Pipe) Read(b []byte) (n int, err error) {
|
||||
if debugPipe {
|
||||
orig := b
|
||||
defer func() {
|
||||
log.Printf("Pipe(%q).Read(%q) n=%d, err=%v", p.name, string(orig[:n]), n, err)
|
||||
}()
|
||||
}
|
||||
for n == 0 {
|
||||
n2, err := p.readOrBlock(b)
|
||||
if err != nil {
|
||||
return n2, err
|
||||
}
|
||||
n += n2
|
||||
}
|
||||
p.cnd.Signal()
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// writeOrBlock attempts to write to the buffer, if the buffer is full it will
|
||||
// block until there is a change.
|
||||
func (p *Pipe) writeOrBlock(b []byte) (int, error) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
if p.closed {
|
||||
return 0, net.ErrClosed
|
||||
}
|
||||
if !p.writeTimeout.IsZero() && !time.Now().Before(p.writeTimeout) {
|
||||
return 0, os.ErrDeadlineExceeded
|
||||
}
|
||||
if p.blocked {
|
||||
p.cnd.Wait()
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Optimistically we want to write the entire slice.
|
||||
n := len(b)
|
||||
if limit := p.maxBuf - p.buf.Len(); limit < n {
|
||||
// However, we don't have enough capacity to write everything.
|
||||
n = limit
|
||||
}
|
||||
if n == 0 {
|
||||
// Wait for something to change.
|
||||
p.cnd.Wait()
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
p.buf.Write(b[:n])
|
||||
p.cnd.Signal()
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Write implements io.Writer.
|
||||
func (p *Pipe) Write(b []byte) (n int, err error) {
|
||||
if debugPipe {
|
||||
orig := b
|
||||
defer func() {
|
||||
log.Printf("Pipe(%q).Write(%q) n=%d, err=%v", p.name, string(orig), n, err)
|
||||
}()
|
||||
}
|
||||
for len(b) > 0 {
|
||||
n2, err := p.writeOrBlock(b)
|
||||
if err != nil {
|
||||
return n + n2, err
|
||||
}
|
||||
n += n2
|
||||
b = b[n2:]
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Close closes the pipe.
|
||||
func (p *Pipe) Close() error {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
p.closed = true
|
||||
p.blocked = false
|
||||
if p.cancelWriteTimer != nil {
|
||||
p.cancelWriteTimer()
|
||||
p.cancelWriteTimer = nil
|
||||
}
|
||||
if p.cancelReadTimer != nil {
|
||||
p.cancelReadTimer()
|
||||
p.cancelReadTimer = nil
|
||||
}
|
||||
p.cnd.Broadcast()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Pipe) deadlineTimer(t time.Time) func() {
|
||||
if t.IsZero() {
|
||||
return nil
|
||||
}
|
||||
if t.Before(time.Now()) {
|
||||
p.cnd.Broadcast()
|
||||
return nil
|
||||
}
|
||||
ctx, cancel := context.WithDeadline(context.Background(), t)
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
if ctx.Err() == context.DeadlineExceeded {
|
||||
p.cnd.Broadcast()
|
||||
}
|
||||
}()
|
||||
return cancel
|
||||
}
|
||||
|
||||
// SetReadDeadline sets the deadline for future Read calls.
|
||||
func (p *Pipe) SetReadDeadline(t time.Time) error {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
p.readTimeout = t
|
||||
// If we already have a deadline, cancel it and create a new one.
|
||||
if p.cancelReadTimer != nil {
|
||||
p.cancelReadTimer()
|
||||
p.cancelReadTimer = nil
|
||||
}
|
||||
p.cancelReadTimer = p.deadlineTimer(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetWriteDeadline sets the deadline for future Write calls.
|
||||
func (p *Pipe) SetWriteDeadline(t time.Time) error {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
p.writeTimeout = t
|
||||
// If we already have a deadline, cancel it and create a new one.
|
||||
if p.cancelWriteTimer != nil {
|
||||
p.cancelWriteTimer()
|
||||
p.cancelWriteTimer = nil
|
||||
}
|
||||
p.cancelWriteTimer = p.deadlineTimer(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Block will cause all calls to Read and Write to block until they either
|
||||
// timeout, are unblocked or the pipe is closed.
|
||||
func (p *Pipe) Block() error {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
closed := p.closed
|
||||
blocked := p.blocked
|
||||
p.blocked = true
|
||||
|
||||
if closed {
|
||||
return fmt.Errorf("memnet.Pipe(%q).Block: closed", p.name)
|
||||
}
|
||||
if blocked {
|
||||
return fmt.Errorf("memnet.Pipe(%q).Block: already blocked", p.name)
|
||||
}
|
||||
p.cnd.Broadcast()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unblock will cause all blocked Read/Write calls to continue execution.
|
||||
func (p *Pipe) Unblock() error {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
closed := p.closed
|
||||
blocked := p.blocked
|
||||
p.blocked = false
|
||||
|
||||
if closed {
|
||||
return fmt.Errorf("memnet.Pipe(%q).Block: closed", p.name)
|
||||
}
|
||||
if !blocked {
|
||||
return fmt.Errorf("memnet.Pipe(%q).Block: already unblocked", p.name)
|
||||
}
|
||||
p.cnd.Broadcast()
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user