net_other.go

 1//go:build !windows
 2
 3package server
 4
 5import (
 6	"errors"
 7	"io/fs"
 8	"net"
 9	"os"
10	"time"
11)
12
13// staleSocketDialTimeout bounds the probe used to detect whether a Unix
14// socket file on disk is backed by a live listener.
15const staleSocketDialTimeout = 200 * time.Millisecond
16
17// listen binds a net.Listener on the given network and address.
18//
19// For unix sockets it self-heals from stale socket files: if the path
20// already exists on disk, it first probes with a short net.DialTimeout.
21// A successful dial means a live server owns the socket, so we proceed
22// to net.Listen (which surfaces the usual "address already in use"
23// error). A failed dial that isStaleSocketErr classifies as stale
24// triggers an os.Remove of the path (ignoring fs.ErrNotExist) before
25// the bind.
26//
27// The returned removedStale bool reports whether a stale socket file
28// was removed prior to binding so callers can log it. The operation
29// is idempotent: removing an absent file is a no-op, and a live
30// socket is never removed.
31func listen(network, address string) (net.Listener, bool, error) {
32	var removedStale bool
33	if network == "unix" && address != "" {
34		if _, err := os.Stat(address); err == nil {
35			conn, dialErr := net.DialTimeout(network, address, staleSocketDialTimeout) //nolint:noctx
36			if dialErr == nil {
37				// A live server owns the socket. Fall through to
38				// net.Listen so the caller sees the standard
39				// "address already in use" error.
40				conn.Close()
41			} else if isStaleSocketErr(dialErr) {
42				rmErr := os.Remove(address)
43				switch {
44				case rmErr == nil:
45					removedStale = true
46				case errors.Is(rmErr, fs.ErrNotExist):
47					// Another process removed it between our
48					// stat and remove; treat as a no-op.
49				default:
50					return nil, false, rmErr
51				}
52			}
53		}
54	}
55	//nolint:noctx
56	ln, err := net.Listen(network, address)
57	if err != nil {
58		return nil, removedStale, err
59	}
60	return ln, removedStale, nil
61}