socketpath.go RawHistoryFolder
1package swarm
2
3import (
4 "crypto/sha1"
5 "encoding/hex"
6 "fmt"
7 "os"
8 "path/filepath"
9 "runtime"
10)
11
12// maxUnixSocketPath is the conservative platform-portable path limit
13// for unix sockets. macOS allows 104, linux 108 (including the NUL
14// terminator). We pick 100 so the path itself plus a small filename
15// tail stays under both caps with a safety margin.
16const maxUnixSocketPath = 100
17
18// inboxSocketPath returns a per-agent unix-socket path that's short
19// enough to actually work (see maxUnixSocketPath) and unique per
20// swarm root so two zot instances on the same machine don't collide.
21//
22// Strategy:
23//
24// 1. Try <root>/agents/<id>/in.sock. This is the obvious place and
25// puts everything next to the durable state; on most setups it
26// fits.
27// 2. If that's too long, fall back to <tmp>/zot-swarm-<roothash>/<id>.sock.
28// We hash root rather than embedding it so the tmp directory name
29// stays short. SHA-1's first 8 hex chars is plenty: collisions
30// only matter within a single user's tmp dir and we already
31// create a dedicated subdir.
32// 3. If even /tmp is somehow too long (chroots, containers), give
33// up with a clear error so the caller surfaces it instead of
34// leaving the user wondering why follow-ups don't work.
35func inboxSocketPath(root, agentID string) (string, error) {
36 primary := filepath.Join(root, "agents", agentID, "in.sock")
37 if len(primary) <= maxUnixSocketPath {
38 return primary, nil
39 }
40 tmp := os.TempDir()
41 dir := filepath.Join(tmp, "zot-swarm-"+rootTag(root))
42 if err := os.MkdirAll(dir, 0o700); err != nil {
43 return "", fmt.Errorf("socket tmp dir: %w", err)
44 }
45 candidate := filepath.Join(dir, agentID+".sock")
46 if len(candidate) <= maxUnixSocketPath {
47 return candidate, nil
48 }
49 // Last-resort: use just the short hash of the id so even very long
50 // task slugs fit. We surface the original id in the meta.json /
51 // events log; the socket path is purely transport.
52 short := shortHash(agentID)
53 candidate = filepath.Join(dir, short+".sock")
54 if len(candidate) <= maxUnixSocketPath {
55 return candidate, nil
56 }
57 return "", fmt.Errorf("unix socket path too long even after shortening (%s, %d > %d, GOOS=%s)",
58 candidate, len(candidate), maxUnixSocketPath, runtime.GOOS)
59}
60
61// rootTag returns a stable 8-hex-char tag for the swarm root. Used
62// in the tmp-dir name so two parallel zot instances with different
63// roots don't share sockets.
64func rootTag(root string) string { return shortHash(root) }
65
66func shortHash(s string) string {
67 sum := sha1.Sum([]byte(s))
68 return hex.EncodeToString(sum[:4])
69}