net/netutil: unify two oneConnListeners into a new package

I was about to add a third copy, so unify them now instead.

Change-Id: I3b93896aa1249b1250a6b1df4829d57717f2311a
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2022-02-13 14:45:50 -08:00 committed by Brad Fitzpatrick
parent 5d9ab502f3
commit 8fe503057d
4 changed files with 55 additions and 43 deletions

View File

@ -203,6 +203,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/net/netknob from tailscale.com/logpolicy+
tailscale.com/net/netns from tailscale.com/cmd/tailscaled+
💣 tailscale.com/net/netstat from tailscale.com/ipn/ipnserver
tailscale.com/net/netutil from tailscale.com/ipn/ipnlocal+
tailscale.com/net/packet from tailscale.com/net/tstun+
tailscale.com/net/portmapper from tailscale.com/cmd/tailscaled+
tailscale.com/net/proxymux from tailscale.com/cmd/tailscaled

View File

@ -38,6 +38,7 @@
"tailscale.com/logtail/backoff"
"tailscale.com/net/dns/resolver"
"tailscale.com/net/interfaces"
"tailscale.com/net/netutil"
"tailscale.com/syncs"
"tailscale.com/tailcfg"
"tailscale.com/util/clientmetric"
@ -506,27 +507,9 @@ func (pln *peerAPIListener) ServeConn(src netaddr.IPPort, c net.Conn) {
if addH2C != nil {
addH2C(httpServer)
}
go httpServer.Serve(&oneConnListener{Listener: pln.ln, conn: c})
go httpServer.Serve(netutil.NewOneConnListenerFrom(c, pln.ln))
}
type oneConnListener struct {
net.Listener
conn net.Conn
}
func (l *oneConnListener) Accept() (c net.Conn, err error) {
c = l.conn
if c == nil {
err = io.EOF
return
}
err = nil
l.conn = nil
return
}
func (l *oneConnListener) Close() error { return nil }
// peerAPIHandler serves the Peer API for a source specific client.
type peerAPIHandler struct {
ps *peerAPIServer

View File

@ -39,6 +39,7 @@
"tailscale.com/ipn/store/aws"
"tailscale.com/logtail/backoff"
"tailscale.com/net/netstat"
"tailscale.com/net/netutil"
"tailscale.com/net/tsdial"
"tailscale.com/paths"
"tailscale.com/safesocket"
@ -308,7 +309,7 @@ func (s *Server) serveConn(ctx context.Context, c net.Conn, logf logger.Logf) {
ErrorLog: logger.StdLogger(logf),
Handler: s.localhostHandler(ci),
}
httpServer.Serve(&oneConnListener{&protoSwitchConn{s: s, br: br, Conn: c}})
httpServer.Serve(netutil.NewOneConnListener(&protoSwitchConn{s: s, br: br, Conn: c}))
return
}
@ -1061,29 +1062,6 @@ func getEngineUntilItWorksWrapper(getEngine func() (wgengine.Engine, error)) fun
}
}
type dummyAddr string
type oneConnListener struct {
conn net.Conn
}
func (l *oneConnListener) Accept() (c net.Conn, err error) {
c = l.conn
if c == nil {
err = io.EOF
return
}
err = nil
l.conn = nil
return
}
func (l *oneConnListener) Close() error { return nil }
func (l *oneConnListener) Addr() net.Addr { return dummyAddr("unused-address") }
func (a dummyAddr) Network() string { return string(a) }
func (a dummyAddr) String() string { return string(a) }
// protoSwitchConn is a net.Conn that's we want to speak HTTP to but
// it's already had a few bytes read from it to determine that it's
// HTTP. So we Read from its bufio.Reader. On Close, we we tell the

50
net/netutil/netutil.go Normal file
View File

@ -0,0 +1,50 @@
// 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"
)
// NewOneConnListener returns a net.Listener that returns c on its first
// Accept and EOF thereafter. The Listener's Addr is a dummy address.
func NewOneConnListener(c net.Conn) net.Listener {
return NewOneConnListenerFrom(c, dummyListener{})
}
// NewOneConnListenerFrom returns a net.Listener wrapping ln where
// its Accept returns c on the first call and io.EOF thereafter.
func NewOneConnListenerFrom(c net.Conn, ln net.Listener) net.Listener {
return &oneConnListener{c, ln}
}
type oneConnListener struct {
conn net.Conn
net.Listener
}
func (l *oneConnListener) Accept() (c net.Conn, err error) {
c = l.conn
if c == nil {
err = io.EOF
return
}
err = nil
l.conn = nil
return
}
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) }