func (c *UDPConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
	for {
		select {
		case ibData := <-c.readCh:
			n := copy(p, ibData.data)
			if n < len(ibData.data) {
				return 0, nil, io.ErrShortBuffer
			}
			return n, ibData.from, nil
		case <-c.readTimer.C:
			return 0, nil, &net.OpError{
				Op:   "read",
				Net:  c.LocalAddr().Network(),
				Addr: c.LocalAddr(),
				Err:  newTimeoutError("i/o timeout"),
			}
		case <-c.closeCh:
			return 0, nil, &net.OpError{
				Op:   "read",
				Net:  c.LocalAddr().Network(),
				Addr: c.LocalAddr(),
				Err:  errClosed,
			}
		}
	}
}
ReadFrom reads a packet from the connection,
copying the payload into p. It returns the number of
bytes copied into p and the return address that
was on the packet.
It returns the number of bytes read (0 <= n <= len(p))
and any error encountered. Callers should always process
the n > 0 bytes returned before considering the error err.
ReadFrom can be made to time out and return
an Error with Timeout() == true after a fixed time limit;
see SetDeadline and SetReadDeadline.
package client
import (
	"errors"
	"fmt"
	"io"
	"math"
	"net"
	"sync"
	"time"
	"github.com/pion/logging"
	"github.com/pion/stun"
	"github.com/pion/turn/v2/internal/proto"
)
const (
	maxReadQueueSize    = 1024
	permRefreshInterval = 120 * time.Second
	maxRetryAttempts    = 3
)
const (
	timerIDRefreshAlloc int = iota
	timerIDRefreshPerms
)
func noDeadline() time.Time {
	return time.Time{}
}
type inboundData struct {
	data []byte
	from net.Addr
}
type UDPConnObserver interface {
	TURNServerAddr() net.Addr
	Username() stun.Username
	Realm() stun.Realm
	WriteTo(data []byte, to net.Addr) (int, error)
	PerformTransaction(msg *stun.Message, to net.Addr, dontWait bool) (TransactionResult, error)
	OnDeallocated(relayedAddr net.Addr)
}
type UDPConnConfig struct {
	Observer    UDPConnObserver
	RelayedAddr net.Addr
	Integrity   stun.MessageIntegrity
	Nonce       stun.Nonce
	Lifetime    time.Duration
	Log         logging.LeveledLogger
}
type UDPConn struct {
	obs               UDPConnObserver        
	relayedAddr       net.Addr               
	permMap           *permissionMap         
	bindingMgr        *bindingManager        
	integrity         stun.MessageIntegrity  
	_nonce            stun.Nonce             
	_lifetime         time.Duration          
	readCh            chan *inboundData      
	closeCh           chan struct{}          
	readTimer         *time.Timer            
	refreshAllocTimer *PeriodicTimer         
	refreshPermsTimer *PeriodicTimer         
	mutex             sync.RWMutex           
	log               logging.LeveledLogger  
}
func NewUDPConn(config *UDPConnConfig) *UDPConn {
	c := &UDPConn{
		obs:         config.Observer,
		relayedAddr: config.RelayedAddr,
		permMap:     newPermissionMap(),
		bindingMgr:  newBindingManager(),
		integrity:   config.Integrity,
		_nonce:      config.Nonce,
		_lifetime:   config.Lifetime,
		readCh:      make(chan *inboundData, maxReadQueueSize),
		closeCh:     make(chan struct{}),
		readTimer:   time.NewTimer(time.Duration(math.MaxInt64)),
		log:         config.Log,
	}
	c.log.Debugf("initial lifetime: %d seconds", int(c.lifetime().Seconds()))
	c.refreshAllocTimer = NewPeriodicTimer(
		timerIDRefreshAlloc,
		c.onRefreshTimers,
		c.lifetime()/2,
	)
	c.refreshPermsTimer = NewPeriodicTimer(
		timerIDRefreshPerms,
		c.onRefreshTimers,
		permRefreshInterval,
	)
	if c.refreshAllocTimer.Start() {
		c.log.Debugf("refreshAllocTimer started")
	}
	if c.refreshPermsTimer.Start() {
		c.log.Debugf("refreshPermsTimer started")
	}
	return c
}