refactor(tsconnect/wasm): drop the unreachable LocalAPI socket
jsIPN.localAPI serves localapi.Handler in-process through an httptest.ResponseRecorder, so nothing ever dialled the safesocket listener that run() opened. The other in-tree callers of safesocket.ConnectContext do not apply either: driveimpl's FileSystemForRemote is replaced by jsFileSystemForRemote in this build, and logpolicy's fallback is behind version.IsWindowsGUI. Remove the listener, and with it ipnserver, whose only remaining use was serving that listener. ipnserver.New builds a struct and SetLocalBackend stores a pointer, so dropping both leaves LocalBackend untouched. Two behaviours go with it: srv.Run's deferred lb.Shutdown, which made shutdown call lb.Shutdown twice, and its localapi.Shutdown bus subscription, which nothing in this build emits. safesocket's generated per-listener name existed so several IPNs could share one runtime. Each runtime has its own Go heap and its own memconn registry, so the fixed name never conflicted between runtimes, and there is now at most one IPN in each. Restoring the fixed name returns safesocket_js.go to its upstream contents. Co-Authored-By: claude-opus-5 <noreply@anthropic.com>
This commit is contained in:
@@ -44,7 +44,6 @@ import (
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/ipn/ipnauth"
|
||||
"tailscale.com/ipn/ipnlocal"
|
||||
"tailscale.com/ipn/ipnserver"
|
||||
"tailscale.com/ipn/localapi"
|
||||
"tailscale.com/ipn/store/mem"
|
||||
"tailscale.com/logpolicy"
|
||||
@@ -53,7 +52,6 @@ import (
|
||||
"tailscale.com/net/netns"
|
||||
"tailscale.com/net/tsaddr"
|
||||
"tailscale.com/net/tsdial"
|
||||
"tailscale.com/safesocket"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/tsd"
|
||||
"tailscale.com/types/logid"
|
||||
@@ -205,7 +203,6 @@ func newIPN(jsConfig js.Value, shutdownCh chan struct{}) (map[string]any, error)
|
||||
// initDriveForRemote must be called before NewLocalBackend (SubSystem is set-once).
|
||||
driveFS := initDriveForRemote(sys)
|
||||
|
||||
srv := ipnserver.New(logf, logid, sys.Bus.Get(), sys.NetMon.Get())
|
||||
lb, err := ipnlocal.NewLocalBackend(logf, logid, sys, controlclient.LoginEphemeral)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ipnlocal.NewLocalBackend: %w", err)
|
||||
@@ -214,11 +211,9 @@ func newIPN(jsConfig js.Value, shutdownCh chan struct{}) (map[string]any, error)
|
||||
return nil, fmt.Errorf("starting netstack: %w", err)
|
||||
}
|
||||
wireTaildropFileOps(lb, jsConfig.Get("fileOps"))
|
||||
srv.SetLocalBackend(lb)
|
||||
|
||||
jsIPN := &jsIPN{
|
||||
dialer: dialer,
|
||||
srv: srv,
|
||||
lb: lb,
|
||||
ns: ns,
|
||||
controlURL: controlURL,
|
||||
@@ -411,7 +406,6 @@ func newIPN(jsConfig js.Value, shutdownCh chan struct{}) (map[string]any, error)
|
||||
|
||||
type jsIPN struct {
|
||||
dialer *tsdial.Dialer
|
||||
srv *ipnserver.Server
|
||||
lb *ipnlocal.LocalBackend
|
||||
ns *netstack.Impl
|
||||
controlURL string
|
||||
@@ -422,9 +416,6 @@ type jsIPN struct {
|
||||
funnelMu sync.Mutex
|
||||
funnelPorts map[uint16]*funnelListenerEntry
|
||||
|
||||
// ln is the safesocket listener created by run(); stored here so shutdown
|
||||
// can close it and unblock srv.Run.
|
||||
ln net.Listener
|
||||
shutdownCh chan struct{} // closed by shutdown() to unblock main()
|
||||
shutdownOnce sync.Once
|
||||
}
|
||||
@@ -617,18 +608,6 @@ func (i *jsIPN) run(jsCallbacks js.Value) {
|
||||
}
|
||||
}()
|
||||
|
||||
ln, err := safesocket.Listen("")
|
||||
if err != nil {
|
||||
log.Fatalf("safesocket.Listen: %v", err)
|
||||
}
|
||||
i.ln = ln
|
||||
|
||||
go func() {
|
||||
err := i.srv.Run(context.Background(), ln)
|
||||
if err != nil && !errors.Is(err, net.ErrClosed) {
|
||||
log.Fatalf("ipnserver.Run exited: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (i *jsIPN) login() {
|
||||
@@ -652,9 +631,6 @@ func (i *jsIPN) shutdown() js.Value {
|
||||
if i.lb != nil {
|
||||
i.lb.Shutdown()
|
||||
}
|
||||
if i.ln != nil {
|
||||
i.ln.Close()
|
||||
}
|
||||
close(i.shutdownCh)
|
||||
})
|
||||
return nil, nil
|
||||
|
||||
@@ -5,22 +5,15 @@ package safesocket
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/akutz/memconn"
|
||||
)
|
||||
|
||||
const memName = "Tailscale-IPN"
|
||||
|
||||
// memSeq ensures each IPN instance in the same WASM process gets a distinct
|
||||
// memconn address, so concurrent instances do not conflict on the registry.
|
||||
var memSeq atomic.Int64
|
||||
|
||||
func listen(path string) (net.Listener, error) {
|
||||
name := fmt.Sprintf("%s-%d", memName, memSeq.Add(1))
|
||||
return memconn.Listen("memu", name)
|
||||
return memconn.Listen("memu", memName)
|
||||
}
|
||||
|
||||
func connect(ctx context.Context, _ string) (net.Conn, error) {
|
||||
|
||||
Reference in New Issue
Block a user