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  }