-
Notifications
You must be signed in to change notification settings - Fork 2.1k
cli-plugins: don't use abstract sockets on macOS #4783
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| package socket | ||
|
|
||
| import ( | ||
| "errors" | ||
| "io" | ||
| "net" | ||
| "os" | ||
|
|
||
| "github.com/docker/distribution/uuid" | ||
| ) | ||
|
|
||
| // EnvKey represents the well-known environment variable used to pass the plugin being | ||
| // executed the socket name it should listen on to coordinate with the host CLI. | ||
| const EnvKey = "DOCKER_CLI_PLUGIN_SOCKET" | ||
|
|
||
| // SetupConn sets up a Unix socket listener, establishes a goroutine to handle connections | ||
| // and update the conn pointer, and returns the environment variable to pass to the plugin. | ||
| func SetupConn(conn **net.UnixConn) (string, error) { | ||
| listener, err := listen("docker_cli_" + uuid.Generate().String()) | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
|
|
||
| accept(listener, conn) | ||
|
|
||
| return EnvKey + "=" + listener.Addr().String(), nil | ||
| } | ||
|
|
||
| func accept(listener *net.UnixListener, conn **net.UnixConn) { | ||
| defer listener.Close() | ||
|
|
||
| go func() { | ||
| for { | ||
| // ignore error here, if we failed to accept a connection, | ||
| // conn is nil and we fallback to previous behavior | ||
| *conn, _ = listener.AcceptUnix() | ||
| // perform any platform-specific actions on accept (e.g. unlink non-abstract sockets) | ||
| onAccept(*conn, listener) | ||
| } | ||
| }() | ||
| } | ||
|
|
||
| // ConnectAndWait connects to the socket passed via well-known env var, | ||
| // if present, and attempts to read from it until it receives an EOF, at which | ||
| // point cb is called. | ||
| func ConnectAndWait(cb func()) { | ||
| socketAddr, ok := os.LookupEnv(EnvKey) | ||
| if !ok { | ||
| // if a plugin compiled against a more recent version of docker/cli | ||
| // is executed by an older CLI binary, ignore missing environment | ||
| // variable and behave as usual | ||
| return | ||
| } | ||
| addr, err := net.ResolveUnixAddr("unix", socketAddr) | ||
| if err != nil { | ||
| return | ||
| } | ||
| conn, err := net.DialUnix("unix", nil, addr) | ||
| if err != nil { | ||
| return | ||
| } | ||
|
|
||
| go func() { | ||
| b := make([]byte, 1) | ||
| for { | ||
| _, err := conn.Read(b) | ||
| if errors.Is(err, io.EOF) { | ||
| cb() | ||
| } | ||
| } | ||
| }() | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package socket | ||
|
|
||
| import ( | ||
| "net" | ||
| "os" | ||
| "path/filepath" | ||
| "syscall" | ||
| ) | ||
|
|
||
| func listen(socketname string) (*net.UnixListener, error) { | ||
| return net.ListenUnix("unix", &net.UnixAddr{ | ||
| Name: filepath.Join(os.TempDir(), socketname), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was changed from LOL, also don't look at the windows implementation of
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that is one difference from @laurazard's original version; I didn't see any reason to not just use the TMPDIR after verifying length should not be an issue. |
||
| Net: "unix", | ||
| }) | ||
| } | ||
|
|
||
| func onAccept(conn *net.UnixConn, listener *net.UnixListener) { | ||
| syscall.Unlink(listener.Addr().String()) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| //go:build !darwin | ||
|
|
||
| package socket | ||
|
|
||
| import ( | ||
| "net" | ||
| ) | ||
|
|
||
| func listen(socketname string) (*net.UnixListener, error) { | ||
| return net.ListenUnix("unix", &net.UnixAddr{ | ||
| Name: "@" + socketname, | ||
| Net: "unix", | ||
| }) | ||
| } | ||
|
|
||
| func onAccept(conn *net.UnixConn, listener *net.UnixListener) { | ||
| // do nothing | ||
neersighted marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // while on darwin we would unlink here; on non-darwin the socket is abstract and not present on the filesystem | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @milas @glours FYI this const was moved; in case code changes are needed when updating the module in compose