Fix all lint errors, move SDP code to proper package

This commit is contained in:
Sean DuBois
2018-08-10 22:07:52 -07:00
parent bf062e38b7
commit 938e490c39
9 changed files with 101 additions and 86 deletions

View File

@@ -65,9 +65,9 @@ func NewManager(bufferTransportGenerator BufferTransportGenerator, dataChannelEv
m.IceAgent = ice.NewAgent(m.iceOutboundHandler) m.IceAgent = ice.NewAgent(m.iceOutboundHandler)
for _, i := range localInterfaces() { for _, i := range localInterfaces() {
p, err := newPort(i+":0", m) p, portErr := newPort(i+":0", m)
if err != nil { if portErr != nil {
return nil, err return nil, portErr
} }
m.ports = append(m.ports, p) m.ports = append(m.ports, p)

View File

@@ -135,33 +135,31 @@ func (p *port) networkLoop() {
}() }()
for { for {
select { in, socketOpen := <-incomingPackets
case in, socketOpen := <-incomingPackets: if !socketOpen {
if !socketOpen { // incomingPackets channel has closed, this port is finished processing
// incomingPackets channel has closed, this port is finished processing dtls.RemoveListener(p.listeningAddr.String())
dtls.RemoveListener(p.listeningAddr.String()) return
return
}
if len(in.buffer) == 0 {
fmt.Println("Inbound buffer is not long enough to demux")
continue
}
// https://tools.ietf.org/html/rfc5764#page-14
if 127 < in.buffer[0] && in.buffer[0] < 192 {
p.handleSRTP(in.buffer)
} else if 19 < in.buffer[0] && in.buffer[0] < 64 {
p.handleDTLS(in.buffer, in.srcAddr.String())
} else if in.buffer[0] < 2 {
p.m.IceAgent.HandleInbound(in.buffer, p.listeningAddr, in.srcAddr)
}
p.m.certPairLock.RLock()
if p.m.isOffer == false && p.m.certPair == nil {
p.m.dtlsState.DoHandshake(p.listeningAddr.String(), in.srcAddr.String())
}
p.m.certPairLock.RUnlock()
} }
if len(in.buffer) == 0 {
fmt.Println("Inbound buffer is not long enough to demux")
continue
}
// https://tools.ietf.org/html/rfc5764#page-14
if 127 < in.buffer[0] && in.buffer[0] < 192 {
p.handleSRTP(in.buffer)
} else if 19 < in.buffer[0] && in.buffer[0] < 64 {
p.handleDTLS(in.buffer, in.srcAddr.String())
} else if in.buffer[0] < 2 {
p.m.IceAgent.HandleInbound(in.buffer, p.listeningAddr, in.srcAddr)
}
p.m.certPairLock.RLock()
if !p.m.isOffer && p.m.certPair == nil {
p.m.dtlsState.DoHandshake(p.listeningAddr.String(), in.srcAddr.String())
}
p.m.certPairLock.RUnlock()
} }
} }

View File

@@ -8,7 +8,7 @@ import (
"github.com/pions/webrtc/pkg/rtp" "github.com/pions/webrtc/pkg/rtp"
) )
func (p *port) sendRTP(packet *rtp.Packet, dst *net.UDPAddr) { func (p *port) sendRTP(packet *rtp.Packet, dst net.Addr) {
p.m.certPairLock.RLock() p.m.certPairLock.RLock()
defer p.m.certPairLock.RUnlock() defer p.m.certPairLock.RUnlock()
if p.m.certPair == nil { if p.m.certPair == nil {
@@ -44,13 +44,13 @@ func (p *port) sendRTP(packet *rtp.Packet, dst *net.UDPAddr) {
} }
} }
func (p *port) sendICE(buf []byte, dst *net.UDPAddr) { func (p *port) sendICE(buf []byte, dst net.Addr) {
if _, err := p.conn.WriteTo(buf, nil, dst); err != nil { if _, err := p.conn.WriteTo(buf, nil, dst); err != nil {
fmt.Printf("Failed to send packet: %s \n", err.Error()) fmt.Printf("Failed to send packet: %s \n", err.Error())
} }
} }
func (p *port) sendSCTP(buf []byte, dst *net.UDPAddr) { func (p *port) sendSCTP(buf []byte, dst fmt.Stringer) {
_, err := p.m.dtlsState.Send(buf, p.listeningAddr.String(), dst.String()) _, err := p.m.dtlsState.Send(buf, p.listeningAddr.String(), dst.String())
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)

View File

@@ -8,8 +8,8 @@ import (
"github.com/pions/webrtc/pkg/ice" "github.com/pions/webrtc/pkg/ice"
) )
// ICECandidateBuild takes a candidate strings and returns a ice.Candidate or nil if it fails to parse // ICECandidateUnmarshal takes a candidate strings and returns a ice.Candidate or nil if it fails to parse
func ICECandidateBuild(raw string) ice.Candidate { func ICECandidateUnmarshal(raw string) ice.Candidate {
split := strings.Fields(raw) split := strings.Fields(raw)
if len(split) < 8 { if len(split) < 8 {
fmt.Printf("Attribute not long enough to be ICE candidate (%d) %s \n", len(split), raw) fmt.Printf("Attribute not long enough to be ICE candidate (%d) %s \n", len(split), raw)
@@ -49,3 +49,29 @@ func ICECandidateBuild(raw string) ice.Candidate {
return nil return nil
} }
} }
func iceSrflxCandidateString(c *ice.CandidateSrflx, component int) string {
return fmt.Sprintf("udpcandidate %d udp %d %s %d typ srflx raddr %s rport %d generation 0",
component, c.CandidateBase.Priority(ice.SrflxCandidatePreference, uint16(component)), c.CandidateBase.Address, c.CandidateBase.Port, c.RemoteAddress, c.RemotePort)
}
func iceHostCandidateString(c *ice.CandidateHost, component int) string {
return fmt.Sprintf("udpcandidate %d udp %d %s %d typ host generation 0",
component, c.CandidateBase.Priority(ice.HostCandidatePreference, uint16(component)), c.CandidateBase.Address, c.CandidateBase.Port)
}
// ICECandidateMarshal takes a candidate and returns a string representation
func ICECandidateMarshal(c ice.Candidate) []string {
out := make([]string, 0)
switch c := c.(type) {
case *ice.CandidateSrflx:
out = append(out, iceSrflxCandidateString(c, 0))
out = append(out, iceSrflxCandidateString(c, 1))
case *ice.CandidateHost:
out = append(out, iceHostCandidateString(c, 0))
out = append(out, iceHostCandidateString(c, 1))
}
return out
}

View File

@@ -30,7 +30,7 @@ type Agent struct {
LocalUfrag string LocalUfrag string
LocalPwd string LocalPwd string
localCandidates []Candidate LocalCandidates []Candidate
remoteUfrag string remoteUfrag string
remotePwd string remotePwd string
@@ -50,16 +50,15 @@ const (
// NewAgent creates a new Agent // NewAgent creates a new Agent
func NewAgent(outboundCallback OutboundCallback) *Agent { func NewAgent(outboundCallback OutboundCallback) *Agent {
a := &Agent{ return &Agent{
tieBreaker: rand.Uint64(), tieBreaker: rand.Uint64(),
outboundCallback: outboundCallback, outboundCallback: outboundCallback,
gatheringState: GatheringStateComplete, // TODO trickle-ice
connectionState: ConnectionStateNew,
LocalUfrag: util.RandSeq(16), LocalUfrag: util.RandSeq(16),
LocalPwd: util.RandSeq(32), LocalPwd: util.RandSeq(32),
} }
if a.isControlling {
}
return a
} }
// Start starts the agent // Start starts the agent
@@ -89,7 +88,7 @@ func (a *Agent) pingCandidate(local, remote Candidate) {
&stun.Username{Username: a.remoteUfrag + ":" + a.LocalUfrag}, &stun.Username{Username: a.remoteUfrag + ":" + a.LocalUfrag},
&stun.UseCandidate{}, &stun.UseCandidate{},
&stun.IceControlling{TieBreaker: a.tieBreaker}, &stun.IceControlling{TieBreaker: a.tieBreaker},
&stun.Priority{Priority: uint32(local.GetBase().priority(hostCandidatePreference, 1))}, &stun.Priority{Priority: uint32(local.GetBase().Priority(HostCandidatePreference, 1))},
&stun.MessageIntegrity{ &stun.MessageIntegrity{
Key: []byte(a.remotePwd), Key: []byte(a.remotePwd),
}, },
@@ -111,19 +110,20 @@ func (a *Agent) pingCandidate(local, remote Candidate) {
func (a *Agent) agentControllingTaskLoop() { func (a *Agent) agentControllingTaskLoop() {
// TODO this should be dynamic, and grow when the connection is stable // TODO this should be dynamic, and grow when the connection is stable
t := time.NewTicker(agentTickerBaseInterval) t := time.NewTicker(agentTickerBaseInterval)
a.connectionState = ConnectionStateChecking
for { for {
select { select {
case <-t.C: case <-t.C:
a.Lock() a.Lock()
if a.selectedPair.remote == nil || a.selectedPair.local == nil { if a.selectedPair.remote == nil || a.selectedPair.local == nil {
for _, localCandidate := range a.localCandidates { for _, localCandidate := range a.LocalCandidates {
for _, remoteCandidate := range a.remoteCandidates { for _, remoteCandidate := range a.remoteCandidates {
a.pingCandidate(localCandidate, remoteCandidate) a.pingCandidate(localCandidate, remoteCandidate)
} }
} }
} else { } else {
if time.Now().Sub(a.selectedPair.remote.GetBase().LastSeen) > stunTimeout { if time.Since(a.selectedPair.remote.GetBase().LastSeen) > stunTimeout {
a.selectedPair.remote = nil a.selectedPair.remote = nil
a.selectedPair.local = nil a.selectedPair.local = nil
} else { } else {
@@ -149,7 +149,7 @@ func (a *Agent) AddRemoteCandidate(c Candidate) {
func (a *Agent) AddLocalCandidate(c Candidate) { func (a *Agent) AddLocalCandidate(c Candidate) {
a.Lock() a.Lock()
defer a.Unlock() defer a.Unlock()
a.localCandidates = append(a.localCandidates, c) a.LocalCandidates = append(a.LocalCandidates, c)
} }
// Close cleans up the Agent // Close cleans up the Agent
@@ -157,19 +157,6 @@ func (a *Agent) Close() {
close(a.taskLoopChan) close(a.taskLoopChan)
} }
// LocalCandidates generates the string representation of the
// local candidates that can be used in the SDP
func (a *Agent) LocalCandidates() (rtrn []string) {
a.Lock()
defer a.Unlock()
for _, c := range a.localCandidates {
rtrn = append(rtrn, c.String(1))
rtrn = append(rtrn, c.String(2))
}
return rtrn
}
func getTransportAddrCandidate(candidates []Candidate, addr *stun.TransportAddr) Candidate { func getTransportAddrCandidate(candidates []Candidate, addr *stun.TransportAddr) Candidate {
for _, c := range candidates { for _, c := range candidates {
if c.GetBase().Address == addr.IP.String() && c.GetBase().Port == addr.Port { if c.GetBase().Address == addr.IP.String() && c.GetBase().Port == addr.Port {
@@ -209,7 +196,7 @@ func (a *Agent) sendBindingSuccess(m *stun.Message, local *stun.TransportAddr, r
} }
func (a *Agent) handleInboundControlled(m *stun.Message, local *stun.TransportAddr, remote *net.UDPAddr, localCandidate, remoteCandidate Candidate) { func (a *Agent) handleInboundControlled(m *stun.Message, local *stun.TransportAddr, remote *net.UDPAddr, localCandidate, remoteCandidate Candidate) {
if _, isControlled := m.GetOneAttribute(stun.AttrIceControlled); isControlled && a.isControlling == false { if _, isControlled := m.GetOneAttribute(stun.AttrIceControlled); isControlled && !a.isControlling {
panic("inbound isControlled && a.isControlling == false") panic("inbound isControlled && a.isControlling == false")
} }
@@ -221,9 +208,9 @@ func (a *Agent) handleInboundControlled(m *stun.Message, local *stun.TransportAd
} }
func (a *Agent) handleInboundControlling(m *stun.Message, local *stun.TransportAddr, remote *net.UDPAddr, localCandidate, remoteCandidate Candidate) { func (a *Agent) handleInboundControlling(m *stun.Message, local *stun.TransportAddr, remote *net.UDPAddr, localCandidate, remoteCandidate Candidate) {
if _, isControlling := m.GetOneAttribute(stun.AttrIceControlling); isControlling && a.isControlling == true { if _, isControlling := m.GetOneAttribute(stun.AttrIceControlling); isControlling && a.isControlling {
panic("inbound isControlling && a.isControlling == true") panic("inbound isControlling && a.isControlling == true")
} else if _, useCandidate := m.GetOneAttribute(stun.AttrUseCandidate); useCandidate && a.isControlling == true { } else if _, useCandidate := m.GetOneAttribute(stun.AttrUseCandidate); useCandidate && a.isControlling {
panic("useCandidate && a.isControlling == true") panic("useCandidate && a.isControlling == true")
} }
@@ -243,7 +230,7 @@ func (a *Agent) HandleInbound(buf []byte, local *stun.TransportAddr, remote *net
a.Lock() a.Lock()
defer a.Unlock() defer a.Unlock()
localCandidate := getTransportAddrCandidate(a.localCandidates, local) localCandidate := getTransportAddrCandidate(a.LocalCandidates, local)
if localCandidate == nil { if localCandidate == nil {
// TODO debug // TODO debug
// fmt.Printf("Could not find local candidate for %s:%d ", local.IP.String(), local.Port) // fmt.Printf("Could not find local candidate for %s:%d ", local.IP.String(), local.Port)

View File

@@ -1,20 +1,19 @@
package ice package ice
import ( import (
"fmt"
"math/rand" "math/rand"
"time" "time"
) )
// Preference enums when generate Priority
const ( const (
hostCandidatePreference uint16 = 126 HostCandidatePreference uint16 = 126
srflxCandidatePreference uint16 = 100 SrflxCandidatePreference uint16 = 100
) )
// Candidate represents an ICE candidate // Candidate represents an ICE candidate
type Candidate interface { type Candidate interface {
GetBase() *CandidateBase GetBase() *CandidateBase
String(component int) string
} }
// CandidateBase represents an ICE candidate, a base with enough attributes // CandidateBase represents an ICE candidate, a base with enough attributes
@@ -26,7 +25,8 @@ type CandidateBase struct {
LastSeen time.Time LastSeen time.Time
} }
func (c *CandidateBase) priority(typePreference uint16, component uint16) uint16 { // Priority computes the priority for this ICE Candidate
func (c *CandidateBase) Priority(typePreference uint16, component uint16) uint16 {
localPreference := uint16(rand.Uint32() / 2) localPreference := uint16(rand.Uint32() / 2)
return (2^24)*typePreference + return (2^24)*typePreference +
(2^8)*localPreference + (2^8)*localPreference +
@@ -38,12 +38,6 @@ type CandidateHost struct {
CandidateBase CandidateBase
} }
// String for CandidateHost
func (c *CandidateHost) String(component int) string {
return fmt.Sprintf("udpcandidate %d udp %d %s %d typ host generation 0",
component, c.CandidateBase.priority(hostCandidatePreference, uint16(component)), c.CandidateBase.Address, c.CandidateBase.Port)
}
// GetBase returns the CandidateBase, attributes shared between all Candidates // GetBase returns the CandidateBase, attributes shared between all Candidates
func (c *CandidateHost) GetBase() *CandidateBase { func (c *CandidateHost) GetBase() *CandidateBase {
return &c.CandidateBase return &c.CandidateBase
@@ -66,12 +60,6 @@ type CandidateSrflx struct {
RemotePort int RemotePort int
} }
// String for CandidateSrflx
func (c *CandidateSrflx) String(component int) string {
return fmt.Sprintf("udpcandidate %d udp %d %s %d typ srflx raddr %s rport %d generation 0",
component, c.CandidateBase.priority(srflxCandidatePreference, uint16(component)), c.CandidateBase.Address, c.CandidateBase.Port, c.RemoteAddress, c.RemotePort)
}
// GetBase returns the CandidateBase, attributes shared between all Candidates // GetBase returns the CandidateBase, attributes shared between all Candidates
func (c *CandidateSrflx) GetBase() *CandidateBase { func (c *CandidateSrflx) GetBase() *CandidateBase {
return &c.CandidateBase return &c.CandidateBase

View File

@@ -1,6 +1,7 @@
package webrtc package webrtc
import ( import (
"fmt"
"time" "time"
"github.com/pions/webrtc/pkg/ice" "github.com/pions/webrtc/pkg/ice"
@@ -243,7 +244,10 @@ func (r *RTCPeerConnection) setICEServers(config RTCConfiguration) error {
if err != nil { if err != nil {
return err return err
} }
r.networkManager.AddURL(&url) err = r.networkManager.AddURL(&url)
if err != nil {
fmt.Println(err)
}
} }
} }
return nil return nil

View File

@@ -65,6 +65,7 @@ type RTCPeerConnection struct {
// ICE // ICE
OnICEConnectionStateChange func(iceConnectionState ice.ConnectionState) OnICEConnectionStateChange func(iceConnectionState ice.ConnectionState)
IceConnectionState ice.ConnectionState
config RTCConfiguration config RTCConfiguration
@@ -179,10 +180,10 @@ func (r *RTCPeerConnection) iceStateChange(newState ice.ConnectionState) {
r.Lock() r.Lock()
defer r.Unlock() defer r.Unlock()
// if r.OnICEConnectionStateChange != nil && r.iceState != newState { if r.OnICEConnectionStateChange != nil {
// r.OnICEConnectionStateChange(newState) r.OnICEConnectionStateChange(newState)
// } }
// r.iceState = newState r.IceConnectionState = newState
} }
func (r *RTCPeerConnection) dataChannelEventHandler(e network.DataChannelEvent) { func (r *RTCPeerConnection) dataChannelEventHandler(e network.DataChannelEvent) {

View File

@@ -123,7 +123,7 @@ func (r *RTCPeerConnection) SetRemoteDescription(desc RTCSessionDescription) err
for _, m := range r.remoteDescription.MediaDescriptions { for _, m := range r.remoteDescription.MediaDescriptions {
for _, a := range m.Attributes { for _, a := range m.Attributes {
if strings.HasPrefix(a, "candidate") { if strings.HasPrefix(a, "candidate") {
if c := sdp.ICECandidateBuild(a); c != nil { if c := sdp.ICECandidateUnmarshal(a); c != nil {
r.networkManager.IceAgent.AddRemoteCandidate(c) r.networkManager.IceAgent.AddRemoteCandidate(c)
} else { } else {
fmt.Printf("Tried to parse ICE candidate, but failed %s ", a) fmt.Printf("Tried to parse ICE candidate, but failed %s ", a)
@@ -140,6 +140,17 @@ func (r *RTCPeerConnection) SetRemoteDescription(desc RTCSessionDescription) err
return nil return nil
} }
func (r *RTCPeerConnection) generateLocalCandidates() []string {
r.networkManager.IceAgent.RLock()
defer r.networkManager.IceAgent.RUnlock()
candidates := make([]string, 0)
for _, c := range r.networkManager.IceAgent.LocalCandidates {
candidates = append(candidates, sdp.ICECandidateMarshal(c)...)
}
return candidates
}
// CreateOffer starts the RTCPeerConnection and generates the localDescription // CreateOffer starts the RTCPeerConnection and generates the localDescription
func (r *RTCPeerConnection) CreateOffer(options *RTCOfferOptions) (RTCSessionDescription, error) { func (r *RTCPeerConnection) CreateOffer(options *RTCOfferOptions) (RTCSessionDescription, error) {
useIdentity := r.idpLoginURL != nil useIdentity := r.idpLoginURL != nil
@@ -151,8 +162,8 @@ func (r *RTCPeerConnection) CreateOffer(options *RTCOfferOptions) (RTCSessionDes
return RTCSessionDescription{}, &InvalidStateError{Err: ErrConnectionClosed} return RTCSessionDescription{}, &InvalidStateError{Err: ErrConnectionClosed}
} }
candidates := r.networkManager.IceAgent.LocalCandidates()
d := sdp.NewJSEPSessionDescription(r.networkManager.DTLSFingerprint(), useIdentity) d := sdp.NewJSEPSessionDescription(r.networkManager.DTLSFingerprint(), useIdentity)
candidates := r.generateLocalCandidates()
r.addRTPMediaSections(d, []RTCRtpCodecType{RTCRtpCodecTypeAudio, RTCRtpCodecTypeVideo}, candidates) r.addRTPMediaSections(d, []RTCRtpCodecType{RTCRtpCodecTypeAudio, RTCRtpCodecTypeVideo}, candidates)
r.addDataMediaSection(d, candidates) r.addDataMediaSection(d, candidates)
@@ -195,7 +206,7 @@ func (r *RTCPeerConnection) CreateAnswer(options *RTCAnswerOptions) (RTCSessionD
} }
} }
candidates := r.networkManager.IceAgent.LocalCandidates() candidates := r.generateLocalCandidates()
d := sdp.NewJSEPSessionDescription(r.networkManager.DTLSFingerprint(), useIdentity) d := sdp.NewJSEPSessionDescription(r.networkManager.DTLSFingerprint(), useIdentity)
r.addRTPMediaSections(d, mediaSectionsToAdd, candidates) r.addRTPMediaSections(d, mediaSectionsToAdd, candidates)