diff --git a/CHANGELOG.md b/CHANGELOG.md index 57c24e4b..26f771f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Renamed debian.interfaces overlay to ifupdown +### Fixed + +- Fix "address already in use" in `wwclient` when `secure: true`. #2009 + ## v4.6.4, 2025-09-05 ### Added diff --git a/internal/app/wwclient/root.go b/internal/app/wwclient/root.go index ad9dae74..464927c5 100644 --- a/internal/app/wwclient/root.go +++ b/internal/app/wwclient/root.go @@ -115,6 +115,20 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) { LocalAddr: &localTCPAddr, Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, + Control: func(network, address string, c syscall.RawConn) error { + var sockoptErr error + err := c.Control(func(fd uintptr) { + // Set SO_REUSEADDR to allow immediate reuse of the local port + sockoptErr = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) + }) + if err != nil { + return err + } + if sockoptErr != nil { + return sockoptErr + } + return nil + }, }).DialContext, MaxIdleConns: 100, IdleConnTimeout: 2 * time.Duration(conf.Warewulf.UpdateInterval) * time.Second, @@ -271,6 +285,7 @@ func updateSystem(target string, ipaddr string, port int, wwid string, tag strin wwlog.Debug("making request: %s", getURL) resp, err = Webclient.Get(getURL.String()) if err == nil { + defer resp.Body.Close() break } else { if counter > 60 { @@ -510,6 +525,12 @@ func copyFile(src, dst string, srcInfo os.FileInfo) error { } func cleanUp() { + // Close idle connections to prevent "address already in use" errors + if Webclient != nil { + if transport, ok := Webclient.Transport.(*http.Transport); ok { + transport.CloseIdleConnections() + } + } err := pidfile.Remove(PIDFile) if err != nil { wwlog.Error("could not remove pidfile: %s", err)