func (c *UDPConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
	dstAddr, ok := addr.(*net.UDPAddr)
	if !ok {
		return 0, fmt.Errorf("addr is not a net.UDPAddr")
	}
	srcIP := c.obs.determineSourceIP(c.locAddr.IP, dstAddr.IP)
	if srcIP == nil {
		return 0, fmt.Errorf("something went wrong with locAddr")
	}
	srcAddr := &net.UDPAddr{
		IP:   srcIP,
		Port: c.locAddr.Port,
	}
	chunk := newChunkUDP(srcAddr, dstAddr)
	chunk.userData = make([]byte, len(p))
	copy(chunk.userData, p)
	if err := c.obs.write(chunk); err != nil {
		return 0, err
	}
	return len(p), nil
}
WriteTo writes a packet with payload p to addr.
WriteTo can be made to time out and return
an Error with Timeout() == true after a fixed time limit;
see SetDeadline and SetWriteDeadline.
On packet-oriented connections, write timeouts are rare.
package vnet
import (
	"fmt"
	"io"
	"math"
	"net"
	"sync"
	"time"
)
const (
	maxReadQueueSize = 1024
)
var noDeadline time.Time
type UDPPacketConn interface {
	net.PacketConn
	Read(b []byte) (int, error)
	RemoteAddr() net.Addr
	Write(b []byte) (int, error)
}
type connObserver interface {
	write(c Chunk) error
	onClosed(addr net.Addr)
	determineSourceIP(locIP, dstIP net.IP) net.IP
}
type UDPConn struct {
	locAddr   *net.UDPAddr  
	remAddr   *net.UDPAddr  
	obs       connObserver  
	readCh    chan Chunk    
	muReadCh  sync.Mutex    
	readTimer *time.Timer   
}
func newUDPConn(locAddr, remAddr *net.UDPAddr, obs connObserver) (*UDPConn, error) {
	if obs == nil {
		return nil, fmt.Errorf("obs cannot be nil")
	}
	return &UDPConn{
		locAddr:   locAddr,
		remAddr:   remAddr,
		obs:       obs,
		readCh:    make(chan Chunk, maxReadQueueSize),
		readTimer: time.NewTimer(time.Duration(math.MaxInt64)),
	}, nil
}
func (c *UDPConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
loop:
	for {
		select {
		case chunk, ok := <-c.readCh:
			if !ok {
				break loop
			}
			var err error
			n := copy(p, chunk.UserData())
			addr := chunk.SourceAddr()
			if n < len(chunk.UserData()) {
				err = io.ErrShortBuffer
			}
			if c.remAddr != nil {
				if addr.String() != c.remAddr.String() {
					break  
				}
			}
			return n, addr, err
		case <-c.readTimer.C:
			return 0, nil, &net.OpError{
				Op:   "read",
				Net:  c.locAddr.Network(),
				Addr: c.locAddr,
				Err:  newTimeoutError("i/o timeout"),
			}
		}
	}
	return 0, nil, &net.OpError{
		Op:   "read",
		Net:  c.locAddr.Network(),
		Addr: c.locAddr,
		Err:  fmt.Errorf("use of closed network connection"),
	}
}