diff --git a/cmd/limactl/usernet.go b/cmd/limactl/usernet.go index 37777de65d7..9c11ce39a89 100644 --- a/cmd/limactl/usernet.go +++ b/cmd/limactl/usernet.go @@ -7,7 +7,9 @@ import ( "errors" "fmt" "os" + "os/signal" "strconv" + "syscall" "github.com/spf13/cobra" @@ -77,10 +79,13 @@ func usernetAction(cmd *cobra.Command, _ []string) error { os.RemoveAll(qemuSocket) os.RemoveAll(fdSocket) + ctx, cancel := signal.NotifyContext(cmd.Context(), os.Interrupt, syscall.SIGTERM) + defer cancel() + // Environment Variables // LIMA_USERNET_RESOLVE_IP_ADDRESS_TIMEOUT: Specifies the timeout duration for resolving IP addresses in minutes. Default is 2 minutes. - return usernet.StartGVisorNetstack(cmd.Context(), &usernet.GVisorNetstackOpts{ + return usernet.StartGVisorNetstack(ctx, &usernet.GVisorNetstackOpts{ MTU: mtu, Endpoint: endpoint, QemuSocket: qemuSocket, diff --git a/pkg/networks/usernet/gvproxy.go b/pkg/networks/usernet/gvproxy.go index 4df2c62d655..363ac996600 100644 --- a/pkg/networks/usernet/gvproxy.go +++ b/pkg/networks/usernet/gvproxy.go @@ -6,6 +6,7 @@ package usernet import ( "bufio" "context" + "errors" "fmt" "net" "net/http" @@ -128,9 +129,16 @@ func listenQEMU(ctx context.Context, vn *virtualnetwork.VirtualNetwork) error { go func() { defer listener.Close() + <-ctx.Done() + }() + + go func() { for { conn, err := listener.Accept() if err != nil { + if errors.Is(err, net.ErrClosed) { + return + } logrus.Error("QEMU accept failed", err) } @@ -162,10 +170,18 @@ func listenFD(ctx context.Context, vn *virtualnetwork.VirtualNetwork) error { go func() { defer listener.Close() + <-ctx.Done() + }() + + go func() { for { conn, err := listener.Accept() if err != nil { + if errors.Is(err, net.ErrClosed) { + return + } logrus.Error("FD accept failed", err) + continue // since conn is nil } files, err := fd.Get(conn.(*net.UnixConn), 1, []string{"client"}) @@ -202,20 +218,20 @@ func listenFD(ctx context.Context, vn *virtualnetwork.VirtualNetwork) error { } func httpServe(ctx context.Context, g *errgroup.Group, ln net.Listener, mux http.Handler) { + s := &http.Server{ + Handler: mux, + ReadTimeout: 10 * time.Second, + WriteTimeout: 10 * time.Second, + } g.Go(func() error { <-ctx.Done() - return ln.Close() + return s.Close() }) g.Go(func() error { - s := &http.Server{ - Handler: mux, - ReadTimeout: 10 * time.Second, - WriteTimeout: 10 * time.Second, - } err := s.Serve(ln) if err != nil { - if err != http.ErrServerClosed { - return err + if err == http.ErrServerClosed { + return nil } return err } diff --git a/pkg/networks/usernet/udpfileconn.go b/pkg/networks/usernet/udpfileconn.go index ef04b841e5d..ea8696c0fbc 100644 --- a/pkg/networks/usernet/udpfileconn.go +++ b/pkg/networks/usernet/udpfileconn.go @@ -16,8 +16,7 @@ type UDPFileConn struct { func (conn *UDPFileConn) Read(b []byte) (n int, err error) { // Check if the connection has been closed if err := conn.SetReadDeadline(time.Time{}); err != nil { - var opErr *net.OpError - if errors.As(err, &opErr) && opErr.Err.Error() == "use of closed network connection" { + if errors.Is(err, net.ErrClosed) { return 0, errors.New("UDPFileConn connection closed") } }