Bypass other host candidates with UDPMux

Separate candidate gathering when UDPMux is enabled.
Only a single UDP host candidate should be generated
that points to the mux.
This commit is contained in:
David Zhao
2021-04-25 14:07:45 -07:00
parent 894452d0c3
commit c4d5d1c670
3 changed files with 78 additions and 18 deletions
+2 -3
View File
@@ -109,9 +109,6 @@ var (
// ErrTCPRemoteAddrAlreadyExists indicates we already have the connection with same remote addr.
ErrTCPRemoteAddrAlreadyExists = errors.New("conn with same remote addr already exists")
// ErrMuxNotStarted indicates the Mux has not been started prior to use
ErrMuxNotStarted = errors.New("mux must be started first")
errSendPacket = errors.New("failed to send packet")
errAttributeTooShortICECandidate = errors.New("attribute not long enough to be ICE candidate")
errParseComponent = errors.New("could not parse component")
@@ -132,4 +129,6 @@ var (
errUnknownRole = errors.New("unknown role")
errMismatchUsername = errors.New("username mismatch")
errICEWriteSTUNMessage = errors.New("the ICE conn can't write STUN messages")
errUDPMuxDisabled = errors.New("UDPMux is not enabled")
errCandidateIPNotFound = errors.New("could not determine local IP for Mux candidate")
)
+72 -13
View File
@@ -134,6 +134,14 @@ func (a *Agent) gatherCandidatesLocal(ctx context.Context, networkTypes []Networ
}
}
// when UDPMux is enabled, skip other UDP candidates
if a.udpMux != nil {
if err := a.gatherCandidatesLocalUDPMux(ctx); err != nil {
a.log.Warnf("could not create host candidate for UDPMux")
}
delete(networks, udp)
}
localIPs, err := localInterfaces(a.net, a.interfaceFilter, networkTypes)
if err != nil {
a.log.Warnf("failed to iterate local interfaces, host candidates will not be gathered %s", err)
@@ -159,8 +167,8 @@ func (a *Agent) gatherCandidatesLocal(ctx context.Context, networkTypes []Networ
var port int
var conn net.PacketConn
var err error
var tcpType TCPType
switch network {
case tcp:
// Handle ICE TCP passive mode
@@ -177,18 +185,10 @@ func (a *Agent) gatherCandidatesLocal(ctx context.Context, networkTypes []Networ
// is there a way to verify that the listen address is even
// accessible from the current interface.
case udp:
if a.udpMux != nil {
conn, err = a.udpMux.GetConn(a.localUfrag)
if err != nil {
a.log.Warnf("could not get udp muxed connection: %v\n", err)
continue
}
} else {
conn, err = listenUDPInPortRange(a.net, a.log, int(a.portmax), int(a.portmin), network, &net.UDPAddr{IP: ip, Port: 0})
if err != nil {
a.log.Warnf("could not listen %s %s\n", network, ip)
continue
}
conn, err = listenUDPInPortRange(a.net, a.log, int(a.portmax), int(a.portmin), network, &net.UDPAddr{IP: ip, Port: 0})
if err != nil {
a.log.Warnf("could not listen %s %s\n", network, ip)
continue
}
port = conn.LocalAddr().(*net.UDPAddr).Port
@@ -224,6 +224,65 @@ func (a *Agent) gatherCandidatesLocal(ctx context.Context, networkTypes []Networ
}
}
func (a *Agent) gatherCandidatesLocalUDPMux(ctx context.Context) error {
if a.udpMux == nil {
return errUDPMuxDisabled
}
// find the IP address to advertise
localIPs, err := localInterfaces(a.net, a.interfaceFilter, []NetworkType{NetworkTypeUDP4})
if err != nil {
return err
}
var candidateIP net.IP
if a.extIPMapper != nil && a.extIPMapper.candidateType == CandidateTypeHost {
for _, ip := range localIPs {
if candidateIP, err = a.extIPMapper.findExternalIP(ip.String()); err == nil {
// ok with first mapped IP
break
} else {
a.log.Warnf("1:1 NAT mapping is enabled but no external IP is found for %s", ip.String())
}
}
}
if candidateIP == nil && len(localIPs) > 0 {
candidateIP = localIPs[0]
}
if candidateIP == nil {
return errCandidateIPNotFound
}
conn, err := a.udpMux.GetConn(a.localUfrag)
if err != nil {
return err
}
port := conn.LocalAddr().(*net.UDPAddr).Port
hostConfig := CandidateHostConfig{
Network: udp,
Address: candidateIP.String(),
Port: port,
Component: ComponentRTP,
}
c, err := NewCandidateHost(&hostConfig)
if err != nil {
closeConnAndLog(conn, a.log, fmt.Sprintf("Failed to create host mux candidate: %s %d: %v\n", candidateIP, port, err))
// already logged error
return nil
}
if err := a.addCandidate(ctx, c, conn); err != nil {
if closeErr := c.close(); closeErr != nil {
a.log.Warnf("Failed to close candidate: %v", closeErr)
}
return err
}
return nil
}
func (a *Agent) gatherCandidatesSrflxMapped(ctx context.Context, networkTypes []NetworkType) {
var wg sync.WaitGroup
defer wg.Wait()
+4 -2
View File
@@ -184,8 +184,9 @@ func (m *UDPMuxDefault) registerConnForAddress(conn *udpMuxedConn, addr string)
if ok {
existing.removeAddress(addr)
}
m.addressMap[addr] = conn
m.params.Logger.Debugf("Registered %s for %s", addr, conn.params.Key)
}
func (m *UDPMuxDefault) createMuxedConn(key string) *udpMuxedConn {
@@ -257,11 +258,12 @@ func (m *UDPMuxDefault) connWorker() {
}
if destinationConn == nil {
m.params.Logger.Tracef("dropping packet from %s, addr: %s", udpAddr.String(), addr.String())
continue
}
if err = destinationConn.writePacket(buf[:n], udpAddr); err != nil {
logger.Errorf("could not write packet: %v", err)
m.params.Logger.Errorf("could not write packet: %v", err)
}
}
}