mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-21 14:11:56 +00:00
ipn/ipnserver: close a small race in ipnserver, ~simplify code
There was a small window in ipnserver after we assigned a LocalBackend to the ipnserver's atomic but before we Start'ed it where our initalization Start could conflict with API calls from the LocalAPI. Simplify that a bit and lay out the rules in the docs. Updates #12028 Change-Id: Ic5f5e4861e26340599184e20e308e709edec68b1 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
32bc596062
commit
727c0d6cfd
@ -35,6 +35,7 @@ import (
|
|||||||
"tailscale.com/control/controlclient"
|
"tailscale.com/control/controlclient"
|
||||||
"tailscale.com/drive/driveimpl"
|
"tailscale.com/drive/driveimpl"
|
||||||
"tailscale.com/envknob"
|
"tailscale.com/envknob"
|
||||||
|
"tailscale.com/ipn"
|
||||||
"tailscale.com/ipn/conffile"
|
"tailscale.com/ipn/conffile"
|
||||||
"tailscale.com/ipn/ipnlocal"
|
"tailscale.com/ipn/ipnlocal"
|
||||||
"tailscale.com/ipn/ipnserver"
|
"tailscale.com/ipn/ipnserver"
|
||||||
@ -480,6 +481,15 @@ func startIPNServer(ctx context.Context, logf logger.Logf, logID logid.PublicID,
|
|||||||
lb, err := getLocalBackend(ctx, logf, logID, sys)
|
lb, err := getLocalBackend(ctx, logf, logID, sys)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
logf("got LocalBackend in %v", time.Since(t0).Round(time.Millisecond))
|
logf("got LocalBackend in %v", time.Since(t0).Round(time.Millisecond))
|
||||||
|
if lb.Prefs().Valid() {
|
||||||
|
if err := lb.Start(ipn.Options{}); err != nil {
|
||||||
|
logf("LocalBackend.Start: %v", err)
|
||||||
|
lb.Shutdown()
|
||||||
|
lbErr.Store(err)
|
||||||
|
cancel()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
srv.SetLocalBackend(lb)
|
srv.SetLocalBackend(lb)
|
||||||
close(wgEngineCreated)
|
close(wgEngineCreated)
|
||||||
return
|
return
|
||||||
|
@ -46,9 +46,6 @@ type Server struct {
|
|||||||
// is true, the ForceDaemon pref can override this.
|
// is true, the ForceDaemon pref can override this.
|
||||||
resetOnZero bool
|
resetOnZero bool
|
||||||
|
|
||||||
startBackendOnce sync.Once
|
|
||||||
runCalled atomic.Bool
|
|
||||||
|
|
||||||
// mu guards the fields that follow.
|
// mu guards the fields that follow.
|
||||||
// lock order: mu, then LocalBackend.mu
|
// lock order: mu, then LocalBackend.mu
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
@ -471,16 +468,15 @@ func New(logf logger.Logf, logID logid.PublicID, netMon *netmon.Monitor) *Server
|
|||||||
|
|
||||||
// SetLocalBackend sets the server's LocalBackend.
|
// SetLocalBackend sets the server's LocalBackend.
|
||||||
//
|
//
|
||||||
// If b.Run has already been called, then lb.Start will be called.
|
// It should only call be called after calling lb.Start.
|
||||||
// Otherwise Start will be called once Run is called.
|
|
||||||
func (s *Server) SetLocalBackend(lb *ipnlocal.LocalBackend) {
|
func (s *Server) SetLocalBackend(lb *ipnlocal.LocalBackend) {
|
||||||
if lb == nil {
|
if lb == nil {
|
||||||
panic("nil LocalBackend")
|
panic("nil LocalBackend")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !s.lb.CompareAndSwap(nil, lb) {
|
if !s.lb.CompareAndSwap(nil, lb) {
|
||||||
panic("already set")
|
panic("already set")
|
||||||
}
|
}
|
||||||
s.startBackendIfNeeded()
|
|
||||||
|
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
s.backendWaiter.wakeAll()
|
s.backendWaiter.wakeAll()
|
||||||
@ -490,21 +486,6 @@ func (s *Server) SetLocalBackend(lb *ipnlocal.LocalBackend) {
|
|||||||
// https://github.com/tailscale/tailscale/issues/6522
|
// https://github.com/tailscale/tailscale/issues/6522
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Server) startBackendIfNeeded() {
|
|
||||||
if !b.runCalled.Load() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
lb := b.lb.Load()
|
|
||||||
if lb == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if lb.Prefs().Valid() {
|
|
||||||
b.startBackendOnce.Do(func() {
|
|
||||||
lb.Start(ipn.Options{})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// connIdentityContextKey is the http.Request.Context's context.Value key for either an
|
// connIdentityContextKey is the http.Request.Context's context.Value key for either an
|
||||||
// *ipnauth.ConnIdentity or an error.
|
// *ipnauth.ConnIdentity or an error.
|
||||||
type connIdentityContextKey struct{}
|
type connIdentityContextKey struct{}
|
||||||
@ -517,7 +498,6 @@ type connIdentityContextKey struct{}
|
|||||||
// If the Server's LocalBackend has already been set, Run starts it.
|
// If the Server's LocalBackend has already been set, Run starts it.
|
||||||
// Otherwise, the next call to SetLocalBackend will start it.
|
// Otherwise, the next call to SetLocalBackend will start it.
|
||||||
func (s *Server) Run(ctx context.Context, ln net.Listener) error {
|
func (s *Server) Run(ctx context.Context, ln net.Listener) error {
|
||||||
s.runCalled.Store(true)
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if lb := s.lb.Load(); lb != nil {
|
if lb := s.lb.Load(); lb != nil {
|
||||||
lb.Shutdown()
|
lb.Shutdown()
|
||||||
@ -537,7 +517,6 @@ func (s *Server) Run(ctx context.Context, ln net.Listener) error {
|
|||||||
ln.Close()
|
ln.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
s.startBackendIfNeeded()
|
|
||||||
systemd.Ready()
|
systemd.Ready()
|
||||||
|
|
||||||
hs := &http.Server{
|
hs := &http.Server{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user