proxy: fix up the vsock interface

- don't try to create a `FileConn` because the Go library sees through
  the scam and rejects it
- explicitly keep a reference to the `ctl` file just in case the GC
  decides its dead and should be closed.

Signed-off-by: David Scott <dave.scott@docker.com>
This commit is contained in:
David Scott 2016-04-15 11:03:47 +01:00
parent 1d3b8b566e
commit 586d9c0598
3 changed files with 43 additions and 18 deletions

View File

@ -8,53 +8,57 @@ import (
"os" "os"
"libproxy" "libproxy"
"strings" "strings"
"vsock"
) )
func main() { func main() {
host, port, container := parseHostContainerAddrs() host, port, container := parseHostContainerAddrs()
err := exposePort(host, port) ctl, err := exposePort(host, port)
if err != nil { if err != nil {
sendError(err) sendError(err)
} }
p, err := libproxy.NewProxy(host, container)
p, err := libproxy.NewProxy(&vsock.VsockAddr{Port: uint(port)}, container)
if err != nil { if err != nil {
sendError(err) sendError(err)
} }
go handleStopSignals(p) go handleStopSignals(p)
sendOK() sendOK()
p.Run() p.Run()
ctl.Close() // ensure ctl remains alive and un-GCed until here
os.Exit(0) os.Exit(0)
} }
func exposePort(host net.Addr, port int) error { func exposePort(host net.Addr, port int) (*os.File, error) {
name := host.String() name := host.String()
log.Printf("exposePort %s\n", name) log.Printf("exposePort %s\n", name)
err := os.Mkdir("/port/"+name, 0) err := os.Mkdir("/port/"+name, 0)
if err != nil { if err != nil {
log.Printf("Failed to mkdir /port/%s: %#v\n", name, err) log.Printf("Failed to mkdir /port/%s: %#v\n", name, err)
return err return nil, err
} }
ctl, err := os.OpenFile("/port/"+name+"/ctl", os.O_RDWR, 0) ctl, err := os.OpenFile("/port/"+name+"/ctl", os.O_RDWR, 0)
if err != nil { if err != nil {
log.Printf("Failed to open /port/%s/ctl: %#v\n", name, err) log.Printf("Failed to open /port/%s/ctl: %#v\n", name, err)
return err return nil, err
} }
_, err = ctl.WriteString(fmt.Sprintf("%s:%08x", name, port)) _, err = ctl.WriteString(fmt.Sprintf("%s:%08x", name, port))
if err != nil { if err != nil {
log.Printf("Failed to open /port/%s/ctl: %#v\n", name, err) log.Printf("Failed to open /port/%s/ctl: %#v\n", name, err)
return err return nil, err
} }
_, err = ctl.Seek(0, 0) _, err = ctl.Seek(0, 0)
if err != nil { if err != nil {
log.Printf("Failed to seek on /port/%s/ctl: %#v\n", name, err) log.Printf("Failed to seek on /port/%s/ctl: %#v\n", name, err)
return err return nil, err
} }
results := make([]byte, 100) results := make([]byte, 100)
count, err := ctl.Read(results) count, err := ctl.Read(results)
if err != nil { if err != nil {
log.Printf("Failed to read from /port/%s/ctl: %#v\n", name, err) log.Printf("Failed to read from /port/%s/ctl: %#v\n", name, err)
return err return nil, err
} }
// We deliberately keep the control file open since 9P clunk // We deliberately keep the control file open since 9P clunk
// will trigger a shutdown on the host side. // will trigger a shutdown on the host side.
@ -63,8 +67,8 @@ func exposePort(host net.Addr, port int) error {
if strings.HasPrefix(response, "ERROR ") { if strings.HasPrefix(response, "ERROR ") {
os.Remove("/port/" + name + "/ctl") os.Remove("/port/" + name + "/ctl")
response = strings.Trim(response[6:], " \t\r\n") response = strings.Trim(response[6:], " \t\r\n")
return errors.New(response) return nil, errors.New(response)
} }
// Hold on to a reference to prevent premature GC and close
return nil return ctl, nil
} }

View File

@ -39,7 +39,7 @@ func NewProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) {
} }
return NewTCPProxy(listener, backendAddr.(*net.TCPAddr)) return NewTCPProxy(listener, backendAddr.(*net.TCPAddr))
case *vsock.VsockAddr: case *vsock.VsockAddr:
listener, err := vsock.Listen(frontendAddr.(vsock.VsockAddr).Port) listener, err := vsock.Listen(frontendAddr.(*vsock.VsockAddr).Port)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -6,6 +6,7 @@ import (
"net" "net"
"os" "os"
"syscall" "syscall"
"time"
) )
/* No way to teach net or syscall about vsock sockaddr, so go right to C */ /* No way to teach net or syscall about vsock sockaddr, so go right to C */
@ -101,7 +102,7 @@ func (v *vsockListener) Addr() net.Addr {
// a wrapper around FileConn which supports CloseRead and CloseWrite // a wrapper around FileConn which supports CloseRead and CloseWrite
type vsockConn struct { type vsockConn struct {
net.Conn vsock *os.File
fd uintptr fd uintptr
local VsockAddr local VsockAddr
remote VsockAddr remote VsockAddr
@ -113,13 +114,9 @@ type VsockConn struct {
func newVsockConn(fd uintptr, localPort uint) (*VsockConn, error) { func newVsockConn(fd uintptr, localPort uint) (*VsockConn, error) {
vsock := os.NewFile(fd, fmt.Sprintf("vsock:%d", fd)) vsock := os.NewFile(fd, fmt.Sprintf("vsock:%d", fd))
conn, err := net.FileConn(vsock)
if err != nil {
return nil, err
}
local := VsockAddr{Port: localPort} local := VsockAddr{Port: localPort}
remote := VsockAddr{Port: uint(0)} // FIXME remote := VsockAddr{Port: uint(0)} // FIXME
return &VsockConn{vsockConn{Conn: conn, fd: fd, local: local, remote: remote}}, nil return &VsockConn{vsockConn{vsock: vsock, fd: fd, local: local, remote: remote}}, nil
} }
func (v *VsockConn) LocalAddr() net.Addr { func (v *VsockConn) LocalAddr() net.Addr {
@ -137,3 +134,27 @@ func (v *VsockConn) CloseRead() error {
func (v *VsockConn) CloseWrite() error { func (v *VsockConn) CloseWrite() error {
return syscall.Shutdown(int(v.fd), syscall.SHUT_WR) return syscall.Shutdown(int(v.fd), syscall.SHUT_WR)
} }
func (v *VsockConn) Close() error {
return v.vsock.Close()
}
func (v *VsockConn) Read(buf []byte) (int, error) {
return v.vsock.Read(buf)
}
func (v *VsockConn) Write(buf []byte) (int, error) {
return v.vsock.Write(buf)
}
func (v *VsockConn) SetDeadline(t time.Time) error {
return nil // FIXME
}
func (v *VsockConn) SetReadDeadline(t time.Time) error {
return nil // FIXME
}
func (v *VsockConn) SetWriteDeadline(t time.Time) error {
return nil // FIXME
}