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