func (c *Conn) LocalAddr() net.Addr {
	c.lock.Lock()
	l := c.listener
	c.lock.Unlock()
	if l == nil {
		return nil
	}
	return l.pConn.LocalAddr()
}
LocalAddr is a stub
package udp
import (
	"errors"
	"io"
	"net"
	"sync"
	"time"
)
const receiveMTU = 8192
const closeRetryInterval = 100 * time.Millisecond
var errClosedListener = errors.New("udp: listener closed")
type Listener struct {
	pConn *net.UDPConn
	lock      sync.RWMutex
	accepting bool
	acceptCh  chan *Conn
	doneCh    chan struct{}
	doneOnce  sync.Once
	conns map[string]*Conn
}
func (l *Listener) Accept() (*Conn, error) {
	select {
	case c := <-l.acceptCh:
		return c, nil
	case <-l.doneCh:
		return nil, errClosedListener
	}
}
func (l *Listener) Close(shutdownTimeout time.Duration) error {
	l.lock.Lock()
	defer l.lock.Unlock()
	var err error
	l.doneOnce.Do(func() {
		l.accepting = false
		close(l.doneCh)
		err = l.cleanupWithTimeout(shutdownTimeout)
	})
	return err
}
func (l *Listener) cleanupWithTimeout(shutdownTimeout time.Duration) error {
	timeoutTimer := time.NewTimer(shutdownTimeout)
	for {
		select {
		case <-time.After(closeRetryInterval):
			if len(l.conns) == 0 {
				return l.cleanup()
			}
		case <-timeoutTimer.C:
			return l.cleanup()
		}
	}
}
func (l *Listener) cleanup() error {
	if !l.accepting && len(l.conns) == 0 {
		return l.pConn.Close()
	}
	return nil
}
func (l *Listener) Addr() net.Addr {
	return l.pConn.LocalAddr()
}
func Listen(network string, laddr *net.UDPAddr) (*Listener, error) {
	conn, err := net.ListenUDP(network, laddr)
	if err != nil {
		return nil, err
	}
	l := &Listener{
		pConn:     conn,
		acceptCh:  make(chan *Conn),
		conns:     make(map[string]*Conn),
		accepting: true,
		doneCh:    make(chan struct{}),
	}
	go l.readLoop()
	return l, nil
}
func (l *Listener) readLoop() {
	buf := make([]byte, receiveMTU)
readLoop:
	for {
		n, raddr, err := l.pConn.ReadFrom(buf)
		if err != nil {
			return
		}
		conn, err := l.getConn(raddr)
		if err != nil {
			continue
		}
		select {
		case cBuf := <-conn.readCh:
			n = copy(cBuf, buf[:n])
			conn.sizeCh <- n
		case <-conn.doneCh:
			continue readLoop
		}
	}
}
func (l *Listener) getConn(raddr net.Addr) (*Conn, error) {
	l.lock.Lock()
	defer l.lock.Unlock()
	conn, ok := l.conns[raddr.String()]
	if !ok {
		if !l.accepting {
			return nil, errClosedListener
		}
		conn = l.newConn(raddr)
		l.conns[raddr.String()] = conn
		l.acceptCh <- conn
	}
	return conn, nil
}
type Conn struct {
	listener *Listener
	rAddr net.Addr
	readCh chan []byte
	sizeCh chan int
	lock     sync.RWMutex
	doneCh   chan struct{}
	doneOnce sync.Once
}
func (l *Listener) newConn(rAddr net.Addr) *Conn {
	return &Conn{
		listener: l,
		rAddr:    rAddr,
		readCh:   make(chan []byte),
		sizeCh:   make(chan int),
		doneCh:   make(chan struct{}),
	}
}
func (c *Conn) Read(p []byte) (int, error) {
	select {
	case c.readCh <- p:
		n := <-c.sizeCh
		return n, nil
	case <-c.doneCh:
		return 0, io.EOF
	}
}
func (c *Conn) Write(p []byte) (n int, err error) {
	c.lock.Lock()
	l := c.listener
	c.lock.Unlock()
	if l == nil {
		return 0, io.EOF
	}
	return l.pConn.WriteTo(p, c.rAddr)
}
func (c *Conn) Close() error {
	c.lock.Lock()
	defer c.lock.Unlock()
	var err error
	c.doneOnce.Do(func() {
		close(c.doneCh)
		c.listener.lock.Lock()
		delete(c.listener.conns, c.rAddr.String())
		err = c.listener.cleanup()
		c.listener.lock.Unlock()
		c.listener = nil
	})
	return err
}