Skip to content

Commit

Permalink
Add ability to get selected candidate pair stats
Browse files Browse the repository at this point in the history
It is useful to have stats from just the selected pair as a lightweight
option where a lot of agents are running, for example, an SFU.

lint

Switch udp_mux_test to use sha256 instead of sha1 (#733)

Minor change to this test to stop using sha1 and remove the linter
exceptions.

Co-authored-by: Daniel Kessler <[email protected]>

Update module golang.org/x/net to v0.29.0

Generated by renovateBot

Update module github.com/pion/dtls/v3 to v3.0.3

Generated by renovateBot
  • Loading branch information
boks1971 committed Oct 7, 2024
1 parent 2d9be9b commit d47bfa6
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 21 deletions.
50 changes: 50 additions & 0 deletions agent_stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,56 @@ func (a *Agent) GetCandidatePairsStats() []CandidatePairStats {
return res
}

// GetSelectedCandidatePairStats returns a candidate pair stats for selected candidate pair.
// Returns false if there is no selected pair
func (a *Agent) GetSelectedCandidatePairStats() (CandidatePairStats, bool) {
isAvailable := false
var res CandidatePairStats
err := a.loop.Run(a.loop, func(_ context.Context) {
sp := a.getSelectedPair()
if sp == nil {
return

Check warning on line 65 in agent_stats.go

View check run for this annotation

Codecov / codecov/patch

agent_stats.go#L59-L65

Added lines #L59 - L65 were not covered by tests
}

isAvailable = true
res = CandidatePairStats{
Timestamp: time.Now(),
LocalCandidateID: sp.Local.ID(),
RemoteCandidateID: sp.Remote.ID(),
State: sp.state,
Nominated: sp.nominated,

Check warning on line 74 in agent_stats.go

View check run for this annotation

Codecov / codecov/patch

agent_stats.go#L68-L74

Added lines #L68 - L74 were not covered by tests
// PacketsSent uint32
// PacketsReceived uint32
// BytesSent uint64
// BytesReceived uint64
// LastPacketSentTimestamp time.Time
// LastPacketReceivedTimestamp time.Time
// FirstRequestTimestamp time.Time
// LastRequestTimestamp time.Time
// LastResponseTimestamp time.Time
TotalRoundTripTime: sp.TotalRoundTripTime(),
CurrentRoundTripTime: sp.CurrentRoundTripTime(),

Check warning on line 85 in agent_stats.go

View check run for this annotation

Codecov / codecov/patch

agent_stats.go#L84-L85

Added lines #L84 - L85 were not covered by tests
// AvailableOutgoingBitrate float64
// AvailableIncomingBitrate float64
// CircuitBreakerTriggerCount uint32
// RequestsReceived uint64
// RequestsSent uint64
ResponsesReceived: sp.ResponsesReceived(),

Check warning on line 91 in agent_stats.go

View check run for this annotation

Codecov / codecov/patch

agent_stats.go#L91

Added line #L91 was not covered by tests
// ResponsesSent uint64
// RetransmissionsReceived uint64
// RetransmissionsSent uint64
// ConsentRequestsSent uint64
// ConsentExpiredTimestamp time.Time
}
})
if err != nil {
a.log.Errorf("Failed to get selected candidate pair stats: %v", err)
return CandidatePairStats{}, false

Check warning on line 101 in agent_stats.go

View check run for this annotation

Codecov / codecov/patch

agent_stats.go#L99-L101

Added lines #L99 - L101 were not covered by tests
}

return res, isAvailable

Check warning on line 104 in agent_stats.go

View check run for this annotation

Codecov / codecov/patch

agent_stats.go#L104

Added line #L104 was not covered by tests
}

// GetLocalCandidatesStats returns a list of local candidates stats
func (a *Agent) GetLocalCandidatesStats() []CandidateStats {
var res []CandidateStats
Expand Down
85 changes: 84 additions & 1 deletion agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,7 @@ func TestInvalidGather(t *testing.T) {
})
}

func TestCandidatePairStats(t *testing.T) {
func TestCandidatePairsStats(t *testing.T) {
defer test.CheckRoutines(t)()

// Avoid deadlocks?
Expand Down Expand Up @@ -789,6 +789,89 @@ func TestCandidatePairStats(t *testing.T) {
}
}

func TestSelectedCandidatePairStats(t *testing.T) {
defer test.CheckRoutines(t)()

// Avoid deadlocks?
defer test.TimeOut(1 * time.Second).Stop()

a, err := NewAgent(&AgentConfig{})
if err != nil {
t.Fatalf("Failed to create agent: %s", err)
}
defer func() {
require.NoError(t, a.Close())
}()

hostConfig := &CandidateHostConfig{
Network: "udp",
Address: "192.168.1.1",
Port: 19216,
Component: 1,
}
hostLocal, err := NewCandidateHost(hostConfig)
if err != nil {
t.Fatalf("Failed to construct local host candidate: %s", err)
}

srflxConfig := &CandidateServerReflexiveConfig{
Network: "udp",
Address: "10.10.10.2",
Port: 19218,
Component: 1,
RelAddr: "4.3.2.1",
RelPort: 43212,
}
srflxRemote, err := NewCandidateServerReflexive(srflxConfig)
if err != nil {
t.Fatalf("Failed to construct remote srflx candidate: %s", err)
}

// no selected pair, should return not available
_, ok := a.GetSelectedCandidatePairStats()
require.False(t, ok)

// add pair and populate some RTT stats
p := a.findPair(hostLocal, srflxRemote)
if p == nil {
a.addPair(hostLocal, srflxRemote)
p = a.findPair(hostLocal, srflxRemote)
}
for i := 0; i < 10; i++ {
p.UpdateRoundTripTime(time.Duration(i+1) * time.Second)
}

// set the pair as selected
a.setSelectedPair(p)

stats, ok := a.GetSelectedCandidatePairStats()
require.True(t, ok)

if stats.LocalCandidateID != hostLocal.ID() {
t.Fatal("invalid local candidate id")
}
if stats.RemoteCandidateID != srflxRemote.ID() {
t.Fatal("invalid remote candidate id")
}

expectedCurrentRoundTripTime := time.Duration(10) * time.Second
if stats.CurrentRoundTripTime != expectedCurrentRoundTripTime.Seconds() {
t.Fatalf("expected current round trip time to be %f, it is %f instead",
expectedCurrentRoundTripTime.Seconds(), stats.CurrentRoundTripTime)
}

expectedTotalRoundTripTime := time.Duration(55) * time.Second
if stats.TotalRoundTripTime != expectedTotalRoundTripTime.Seconds() {
t.Fatalf("expected total round trip time to be %f, it is %f instead",
expectedTotalRoundTripTime.Seconds(), stats.TotalRoundTripTime)
}

if stats.ResponsesReceived != 10 {
t.Fatalf("expected responses received to be 10, it is %d instead",
stats.ResponsesReceived)
}
}

func TestLocalCandidateStats(t *testing.T) {
defer test.CheckRoutines(t)()

Expand Down
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,24 @@ go 1.20

require (
github.com/google/uuid v1.6.0
github.com/pion/dtls/v3 v3.0.2
github.com/pion/dtls/v3 v3.0.3
github.com/pion/logging v0.2.2
github.com/pion/mdns/v2 v2.0.7
github.com/pion/randutil v0.1.0
github.com/pion/stun/v3 v3.0.0
github.com/pion/transport/v3 v3.0.7
github.com/pion/turn/v4 v4.0.0
github.com/stretchr/testify v1.9.0
golang.org/x/net v0.28.0
golang.org/x/net v0.29.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/wlynxg/anet v0.0.3 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/crypto v0.27.0 // indirect
golang.org/x/sys v0.25.0 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pion/dtls/v3 v3.0.2 h1:425DEeJ/jfuTTghhUDW0GtYZYIwwMtnKKJNMcWccTX0=
github.com/pion/dtls/v3 v3.0.2/go.mod h1:dfIXcFkKoujDQ+jtd8M6RgqKK3DuaUilm3YatAbGp5k=
github.com/pion/dtls/v3 v3.0.3 h1:j5ajZbQwff7Z8k3pE3S+rQ4STvKvXUdKsi/07ka+OWM=
github.com/pion/dtls/v3 v3.0.3/go.mod h1:weOTUyIV4z0bQaVzKe8kpaP17+us3yAuiQsEAG1STMU=
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM=
Expand All @@ -27,12 +27,12 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/wlynxg/anet v0.0.3 h1:PvR53psxFXstc12jelG6f1Lv4MWqE0tI76/hHGjh9rg=
github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
16 changes: 8 additions & 8 deletions udp_mux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ package ice

import (
"crypto/rand"
"crypto/sha1" //nolint:gosec
"crypto/sha256"
"encoding/binary"
"net"
"sync"
Expand Down Expand Up @@ -216,12 +216,12 @@ func testMuxConnectionPair(t *testing.T, pktConn net.PacketConn, remoteConn *net
for written := 0; written < targetSize; {
buf := make([]byte, receiveMTU)
// Byte 0-4: sequence
// Bytes 4-24: sha1 checksum
// Bytes2 4-mtu: random data
_, err := rand.Read(buf[24:])
// Bytes 4-36: sha256 checksum
// Bytes2 36-mtu: random data
_, err := rand.Read(buf[36:])
require.NoError(t, err)
h := sha1.Sum(buf[24:]) //nolint:gosec
copy(buf[4:24], h[:])
h := sha256.Sum256(buf[36:])
copy(buf[4:36], h[:])
binary.LittleEndian.PutUint32(buf[0:4], uint32(sequence))

_, err = remoteConn.Write(buf)
Expand All @@ -240,8 +240,8 @@ func testMuxConnectionPair(t *testing.T, pktConn net.PacketConn, remoteConn *net
func verifyPacket(t *testing.T, b []byte, nextSeq uint32) {
readSeq := binary.LittleEndian.Uint32(b[0:4])
require.Equal(t, nextSeq, readSeq)
h := sha1.Sum(b[24:]) //nolint:gosec
require.Equal(t, h[:], b[4:24])
h := sha256.Sum256(b[36:])
require.Equal(t, h[:], b[4:36])
}

func TestUDPMux_Agent_Restart(t *testing.T) {
Expand Down

0 comments on commit d47bfa6

Please sign in to comment.