func (m *Manager) CreateAllocation(fiveTuple *FiveTuple, turnSocket net.PacketConn, requestedPort int, lifetime time.Duration) (*Allocation, error) {
	switch {
	case fiveTuple == nil:
		return nil, errNilFiveTuple
	case fiveTuple.SrcAddr == nil:
		return nil, errNilFiveTupleSrcAddr
	case fiveTuple.DstAddr == nil:
		return nil, errNilFiveTupleDstAddr
	case turnSocket == nil:
		return nil, errNilTurnSocket
	case lifetime == 0:
		return nil, errLifetimeZero
	}
	if a := m.GetAllocation(fiveTuple); a != nil {
		return nil, fmt.Errorf("%w: %v", errDupeFiveTuple, fiveTuple)
	}
	a := NewAllocation(turnSocket, fiveTuple, m.log)
	conn, relayAddr, err := m.allocatePacketConn("udp4", requestedPort)
	if err != nil {
		return nil, err
	}
	a.RelaySocket = conn
	a.RelayAddr = relayAddr
	m.log.Debugf("listening on relay addr: %s", a.RelayAddr.String())
	a.lifetimeTimer = time.AfterFunc(lifetime, func() {
		m.DeleteAllocation(a.fiveTuple)
	})
	m.lock.Lock()
	m.allocations[fiveTuple.Fingerprint()] = a
	m.lock.Unlock()
	go a.packetHandler(m)
	return a, nil
}
CreateAllocation creates a new allocation and starts relaying
package allocation
import (
	"fmt"
	"net"
	"sync"
	"time"
	"github.com/pion/logging"
)
type ManagerConfig struct {
	LeveledLogger      logging.LeveledLogger
	AllocatePacketConn func(network string, requestedPort int) (net.PacketConn, net.Addr, error)
	AllocateConn       func(network string, requestedPort int) (net.Conn, net.Addr, error)
}
type reservation struct {
	token string
	port  int
}
type Manager struct {
	lock sync.RWMutex
	log  logging.LeveledLogger
	allocations  map[string]*Allocation
	reservations []*reservation
	allocatePacketConn func(network string, requestedPort int) (net.PacketConn, net.Addr, error)
	allocateConn       func(network string, requestedPort int) (net.Conn, net.Addr, error)
}
func NewManager(config ManagerConfig) (*Manager, error) {
	switch {
	case config.AllocatePacketConn == nil:
		return nil, errAllocatePacketConnMustBeSet
	case config.AllocateConn == nil:
		return nil, errAllocateConnMustBeSet
	case config.LeveledLogger == nil:
		return nil, errLeveledLoggerMustBeSet
	}
	return &Manager{
		log:                config.LeveledLogger,
		allocations:        make(map[string]*Allocation, 64),
		allocatePacketConn: config.AllocatePacketConn,
		allocateConn:       config.AllocateConn,
	}, nil
}
func (m *Manager) GetAllocation(fiveTuple *FiveTuple) *Allocation {
	m.lock.RLock()
	defer m.lock.RUnlock()
	return m.allocations[fiveTuple.Fingerprint()]
}
func (m *Manager) Close() error {
	m.lock.Lock()
	defer m.lock.Unlock()
	for _, a := range m.allocations {
		if err := a.Close(); err != nil {
			return err
		}
	}
	return nil
}