mirror of
https://github.com/tailscale/tailscale.git
synced 2025-01-09 17:43:40 +00:00
bb94561c96
I introduced a bug in 8fe503057da26 when unifying oneConnListener implementations. The NewOneConnListenerFrom API was easy to misuse (its Close method closes the underlying Listener), and we did (via http.Serve, which closes the listener after use, which meant we were close the peerapi's listener, even though we only wanted its Addr) Instead, combine those two constructors into one and pass in the Addr explicitly, without delegating through to any Listener. Change-Id: I061d7e5f842e0cada416e7b2dd62100d4f987125 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
66 lines
1.5 KiB
Go
66 lines
1.5 KiB
Go
// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Package netutil contains misc shared networking code & types.
|
|
package netutil
|
|
|
|
import (
|
|
"io"
|
|
"net"
|
|
"sync"
|
|
)
|
|
|
|
// NewOneConnListener returns a net.Listener that returns c on its
|
|
// first Accept and EOF thereafter.
|
|
//
|
|
// The returned Listener's Addr method returns addr if non-nil. If nil,
|
|
// Addr returns a non-nil dummy address instead.
|
|
func NewOneConnListener(c net.Conn, addr net.Addr) net.Listener {
|
|
if addr == nil {
|
|
addr = dummyAddr("one-conn-listener")
|
|
}
|
|
return &oneConnListener{
|
|
addr: addr,
|
|
conn: c,
|
|
}
|
|
}
|
|
|
|
type oneConnListener struct {
|
|
addr net.Addr
|
|
|
|
mu sync.Mutex
|
|
conn net.Conn
|
|
}
|
|
|
|
func (ln *oneConnListener) Accept() (c net.Conn, err error) {
|
|
ln.mu.Lock()
|
|
defer ln.mu.Unlock()
|
|
c = ln.conn
|
|
if c == nil {
|
|
err = io.EOF
|
|
return
|
|
}
|
|
err = nil
|
|
ln.conn = nil
|
|
return
|
|
}
|
|
|
|
func (ln *oneConnListener) Addr() net.Addr { return ln.addr }
|
|
|
|
func (ln *oneConnListener) Close() error {
|
|
ln.Accept() // guarantee future call returns io.EOF
|
|
return nil
|
|
}
|
|
|
|
type dummyListener struct{}
|
|
|
|
func (dummyListener) Close() error { return nil }
|
|
func (dummyListener) Addr() net.Addr { return dummyAddr("unused-address") }
|
|
func (dummyListener) Accept() (c net.Conn, err error) { return nil, io.EOF }
|
|
|
|
type dummyAddr string
|
|
|
|
func (a dummyAddr) Network() string { return string(a) }
|
|
func (a dummyAddr) String() string { return string(a) }
|