proxy: prepare to encapsulate UDP datagrams over a vsock connection

A net.UDPListener is the datagram equivalent of a net.Conn. This patch
accepts at most one connection from vsock and attempts to read and write
UDP datagrams along it.

Signed-off-by: David Scott <dave.scott@docker.com>
This commit is contained in:
David Scott 2016-04-21 16:26:28 +01:00
parent abbafd82f1
commit 3870705eaf
3 changed files with 105 additions and 17 deletions

View File

@ -28,22 +28,16 @@ type Proxy interface {
// NewProxy creates a Proxy according to the specified frontendAddr and backendAddr.
func NewProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) {
switch frontendAddr.(type) {
func NewProxy(frontendAddr *vsock.VsockAddr, backendAddr net.Addr) (Proxy, error) {
switch backendAddr.(type) {
case *net.UDPAddr:
listener, err := net.ListenUDP("udp", frontendAddr.(*net.UDPAddr))
listener, err := vsock.Listen(frontendAddr.Port)
if err != nil {
return nil, err
}
return NewUDPProxy(frontendAddr, listener, backendAddr.(*net.UDPAddr))
return NewUDPProxy(frontendAddr, NewUDPListener(listener), backendAddr.(*net.UDPAddr))
case *net.TCPAddr:
listener, err := net.Listen("tcp", frontendAddr.String())
if err != nil {
return nil, err
}
return NewTCPProxy(listener, backendAddr.(*net.TCPAddr))
case *vsock.VsockAddr:
listener, err := vsock.Listen(frontendAddr.(*vsock.VsockAddr).Port)
listener, err := vsock.Listen(frontendAddr.Port)
if err != nil {
return nil, err
}

View File

@ -0,0 +1,100 @@
package libproxy
import (
//"encoding/binary"
"errors"
"net"
//"strings"
"sync"
//"syscall"
"github.com/Sirupsen/logrus"
)
type udpListener interface {
ReadFromUDP(b []byte) (int, *net.UDPAddr, error)
WriteToUDP(b []byte, addr *net.UDPAddr) (int, error)
Close() error
}
type udpEncapsulator struct {
conn *net.Conn
listener net.Listener
m *sync.Mutex
r *sync.Mutex
w *sync.Mutex
}
func (u *udpEncapsulator) getConn() (net.Conn, error) {
u.m.Lock()
defer u.m.Unlock()
if u.conn != nil {
return *u.conn, nil
}
conn, err := u.listener.Accept()
if err != nil {
logrus.Printf("Failed to accept connection: %#v", err)
return nil, err
}
u.conn = &conn
return conn, nil
}
func (u *udpEncapsulator) ReadFromUDP(b []byte) (int, *net.UDPAddr, error) {
conn, err := u.getConn()
if err != nil {
return 0, nil, err
}
u.r.Lock()
defer u.r.Unlock()
datagram := &udpDatagram{payload: b}
err = datagram.Unmarshal(conn)
if err != nil {
return 0, nil, err
}
return len(datagram.payload), &net.UDPAddr{IP: *datagram.IP, Port: datagram.Port, Zone: datagram.Zone}, nil
}
func (u *udpEncapsulator) WriteToUDP(b []byte, addr *net.UDPAddr) (int, error) {
conn, err := u.getConn()
if err != nil {
return 0, err
}
u.w.Lock()
defer u.w.Unlock()
datagram := &udpDatagram{payload: b, IP: &addr.IP, Port: addr.Port, Zone: addr.Zone}
return len(b), datagram.Marshal(conn)
}
func (u *udpEncapsulator) Close() error {
if u.conn != nil {
conn := *u.conn
conn.Close()
}
u.listener.Close()
return nil
}
func NewUDPListener(listener net.Listener) udpListener {
var m sync.Mutex;
return &udpEncapsulator{
conn: nil,
listener: listener,
m: &m,
}
}
type udpDatagram struct {
payload []byte
IP *net.IP
Port int
Zone string
}
func (u *udpDatagram) Marshal(conn net.Conn) error {
return errors.New("Marshal unimplemented")
}
func (u *udpDatagram) Unmarshal(conn net.Conn) error {
return errors.New("Unmarshal unimplemented")
}

View File

@ -18,12 +18,6 @@ const (
UDPBufSize = 65507
)
type udpListener interface {
ReadFromUDP(b []byte) (int, *net.UDPAddr, error)
WriteToUDP(b []byte, addr *net.UDPAddr) (int, error)
Close() error
}
// A net.Addr where the IP is split into two fields so you can use it as a key
// in a map:
type connTrackKey struct {