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