@@ -35,7 +35,10 @@ import (
3535 "github.com/pkg/errors"
3636)
3737
38- const shimBinaryFormat = "containerd-shim-%s-%s"
38+ const (
39+ shimBinaryFormat = "containerd-shim-%s-%s"
40+ socketPathLimit = 106
41+ )
3942
4043func getSysProcAttr () * syscall.SysProcAttr {
4144 return & syscall.SysProcAttr {
@@ -63,20 +66,21 @@ func AdjustOOMScore(pid int) error {
6366 return nil
6467}
6568
66- // SocketAddress returns an abstract socket address
67- func SocketAddress (ctx context.Context , id string ) (string , error ) {
69+ const socketRoot = "/run/containerd"
70+
71+ // SocketAddress returns a socket address
72+ func SocketAddress (ctx context.Context , socketPath , id string ) (string , error ) {
6873 ns , err := namespaces .NamespaceRequired (ctx )
6974 if err != nil {
7075 return "" , err
7176 }
72- d := sha256 .Sum256 ([]byte (filepath .Join (ns , id )))
73- return filepath . Join ( string ( filepath . Separator ), "containerd-shim " , fmt . Sprintf ( "%x.sock" , d ) ), nil
77+ d := sha256 .Sum256 ([]byte (filepath .Join (socketPath , ns , id )))
78+ return fmt . Sprintf ( "unix://%s/%x " , filepath . Join ( socketRoot , "s" ) , d ), nil
7479}
7580
76- // AnonDialer returns a dialer for an abstract socket
81+ // AnonDialer returns a dialer for a socket
7782func AnonDialer (address string , timeout time.Duration ) (net.Conn , error ) {
78- address = strings .TrimPrefix (address , "unix://" )
79- return dialer .Dialer ("\x00 " + address , timeout )
83+ return dialer .Dialer (socket (address ).path (), timeout )
8084}
8185
8286func AnonReconnectDialer (address string , timeout time.Duration ) (net.Conn , error ) {
@@ -85,12 +89,82 @@ func AnonReconnectDialer(address string, timeout time.Duration) (net.Conn, error
8589
8690// NewSocket returns a new socket
8791func NewSocket (address string ) (* net.UnixListener , error ) {
88- if len (address ) > 106 {
89- return nil , errors .Errorf ("%q: unix socket path too long (> 106)" , address )
92+ var (
93+ sock = socket (address )
94+ path = sock .path ()
95+ )
96+ if ! sock .isAbstract () {
97+ if err := os .MkdirAll (filepath .Dir (path ), 0600 ); err != nil {
98+ return nil , errors .Wrapf (err , "%s" , path )
99+ }
90100 }
91- l , err := net .Listen ("unix" , " \x00 " + address )
101+ l , err := net .Listen ("unix" , path )
92102 if err != nil {
93- return nil , errors .Wrapf (err , "failed to listen to abstract unix socket %q" , address )
103+ return nil , err
104+ }
105+ if err := os .Chmod (path , 0600 ); err != nil {
106+ os .Remove (sock .path ())
107+ l .Close ()
108+ return nil , err
94109 }
95110 return l .(* net.UnixListener ), nil
96111}
112+
113+ const abstractSocketPrefix = "\x00 "
114+
115+ type socket string
116+
117+ func (s socket ) isAbstract () bool {
118+ return ! strings .HasPrefix (string (s ), "unix://" )
119+ }
120+
121+ func (s socket ) path () string {
122+ path := strings .TrimPrefix (string (s ), "unix://" )
123+ // if there was no trim performed, we assume an abstract socket
124+ if len (path ) == len (s ) {
125+ path = abstractSocketPrefix + path
126+ }
127+ return path
128+ }
129+
130+ // RemoveSocket removes the socket at the specified address if
131+ // it exists on the filesystem
132+ func RemoveSocket (address string ) error {
133+ sock := socket (address )
134+ if ! sock .isAbstract () {
135+ return os .Remove (sock .path ())
136+ }
137+ return nil
138+ }
139+
140+ // SocketEaddrinuse returns true if the provided error is caused by the
141+ // EADDRINUSE error number
142+ func SocketEaddrinuse (err error ) bool {
143+ netErr , ok := err .(* net.OpError )
144+ if ! ok {
145+ return false
146+ }
147+ if netErr .Op != "listen" {
148+ return false
149+ }
150+ syscallErr , ok := netErr .Err .(* os.SyscallError )
151+ if ! ok {
152+ return false
153+ }
154+ errno , ok := syscallErr .Err .(syscall.Errno )
155+ if ! ok {
156+ return false
157+ }
158+ return errno == syscall .EADDRINUSE
159+ }
160+
161+ // CanConnect returns true if the socket provided at the address
162+ // is accepting new connections
163+ func CanConnect (address string ) bool {
164+ conn , err := AnonDialer (address , 100 * time .Millisecond )
165+ if err != nil {
166+ return false
167+ }
168+ conn .Close ()
169+ return true
170+ }
0 commit comments