github.com/cloudfoundry-attic/garden-linux@v0.333.2-candidate/container_daemon/unix_socket/listener.go (about) 1 package unix_socket 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "net" 8 "os" 9 "syscall" 10 11 "github.com/cloudfoundry-incubator/garden-linux/container_daemon" 12 ) 13 14 type Listener struct { 15 listener net.Listener 16 socketFile *os.File 17 } 18 19 type Response struct { 20 ErrMessage string 21 Pid int 22 } 23 24 // This function should be called from the host namespace, to open the socket file in the right file system. 25 func NewListenerFromPath(socketPath string) (*Listener, error) { 26 l := &Listener{} 27 var err error 28 29 l.listener, err = net.Listen("unix", socketPath) 30 if err != nil { 31 return nil, fmt.Errorf("unix_socket: error creating socket: %v", err) 32 } 33 34 return l, nil 35 } 36 37 func NewListenerFromFile(socketFile *os.File) (*Listener, error) { 38 l := &Listener{} 39 40 var err error 41 l.listener, err = net.FileListener(socketFile) 42 if err != nil { 43 return nil, fmt.Errorf("unix_socket: error creating listener: %v", err) 44 } 45 46 return l, nil 47 } 48 49 func (l *Listener) Listen(ch container_daemon.ConnectionHandler) error { 50 if l.listener == nil { 51 return errors.New("unix_socket: listener is not initialized") 52 } 53 54 var conn net.Conn 55 var err error 56 for { 57 conn, err = l.listener.Accept() 58 if err != nil { 59 return fmt.Errorf("container_daemon: Failure while accepting: %v", err) 60 } 61 62 go func(conn *net.UnixConn, ch container_daemon.ConnectionHandler) { 63 defer conn.Close() // Ignore error 64 65 decoder := json.NewDecoder(conn) 66 67 response, err := ch.Handle(decoder) 68 if err != nil { 69 response = &container_daemon.ResponseMessage{ErrMessage: err.Error()} 70 } 71 writeData(conn, response) 72 }(conn.(*net.UnixConn), ch) 73 } 74 } 75 76 func writeData(conn *net.UnixConn, response *container_daemon.ResponseMessage) { 77 data, _ := json.Marshal(response) // Ignore error 78 79 args := make([]int, len(response.Files)) 80 for i, f := range response.Files { 81 args[i] = int(f.Fd()) 82 } 83 oobData := syscall.UnixRights(args...) 84 85 conn.WriteMsgUnix(data, oobData, nil) // Ignore error 86 87 // Close the files whose descriptors have been sent to the host to ensure that 88 // a close on the host takes effect in a timely fashion. 89 for _, file := range response.Files { 90 file.Close() // Ignore error 91 } 92 } 93 94 func (l *Listener) File() (*os.File, error) { 95 unixListener, ok := l.listener.(*net.UnixListener) 96 if !ok { 97 return nil, fmt.Errorf("unix_socket: incorrect listener type: %v", l.listener) 98 } 99 return unixListener.File() 100 } 101 102 func (l *Listener) Close() error { 103 return l.listener.Close() 104 }