Skip to content

Commit 1460da4

Browse files
Merge pull request #1 from netbirdio/feature/add-latency
Add latency calculation to binding requests
2 parents cb8a47a + 3be7f17 commit 1460da4

File tree

4 files changed

+59
-7
lines changed

4 files changed

+59
-7
lines changed

agent.go

+13-7
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ import (
1515
"sync/atomic"
1616
"time"
1717

18-
atomicx "github.com/pion/ice/v3/internal/atomic"
19-
stunx "github.com/pion/ice/v3/internal/stun"
2018
"github.com/pion/logging"
2119
"github.com/pion/mdns"
2220
"github.com/pion/stun/v2"
@@ -25,6 +23,9 @@ import (
2523
"github.com/pion/transport/v3/stdnet"
2624
"github.com/pion/transport/v3/vnet"
2725
"golang.org/x/net/proxy"
26+
27+
atomicx "github.com/pion/ice/v3/internal/atomic"
28+
stunx "github.com/pion/ice/v3/internal/stun"
2829
)
2930

3031
type bindingRequest struct {
@@ -40,9 +41,10 @@ type Agent struct {
4041
afterRunFn []func(ctx context.Context)
4142
muAfterRun sync.Mutex
4243

43-
onConnectionStateChangeHdlr atomic.Value // func(ConnectionState)
44-
onSelectedCandidatePairChangeHdlr atomic.Value // func(Candidate, Candidate)
45-
onCandidateHdlr atomic.Value // func(Candidate)
44+
onConnectionStateChangeHdlr atomic.Value // func(ConnectionState)
45+
onSelectedCandidatePairChangeHdlr atomic.Value // func(Candidate, Candidate)
46+
onCandidateHdlr atomic.Value // func(Candidate)
47+
onSuccessfulSelectedPairBindingResponseHdlr atomic.Value // func(*Candidate)
4648

4749
// State owned by the taskLoop
4850
onConnected chan struct{}
@@ -648,7 +650,8 @@ func (a *Agent) checkKeepalive() {
648650

649651
if (a.keepaliveInterval != 0) &&
650652
((time.Since(selectedPair.Local.LastSent()) > a.keepaliveInterval) ||
651-
(time.Since(selectedPair.Remote.LastReceived()) > a.keepaliveInterval)) {
653+
(time.Since(selectedPair.Remote.LastReceived()) > a.keepaliveInterval) ||
654+
(time.Since(selectedPair.lastBindingRequest) > a.keepaliveInterval)) {
652655
// We use binding request instead of indication to support refresh consent schemas
653656
// see https://tools.ietf.org/html/rfc7675
654657
a.selector.PingCandidate(selectedPair.Local, selectedPair.Remote)
@@ -991,6 +994,9 @@ func (a *Agent) sendBindingRequest(m *stun.Message, local, remote Candidate) {
991994
isUseCandidate: m.Contains(stun.AttrUseCandidate),
992995
})
993996

997+
p := a.findPair(local, remote)
998+
p.markBindingRequest(m.TransactionID)
999+
9941000
a.sendSTUN(m, local, remote)
9951001
}
9961002

@@ -1174,7 +1180,7 @@ func (a *Agent) GetSelectedCandidatePair() (*CandidatePair, error) {
11741180
return nil, err
11751181
}
11761182

1177-
return &CandidatePair{Local: local, Remote: remote}, nil
1183+
return &CandidatePair{Local: local, Remote: remote, latency: selectedPair.Latency()}, nil
11781184
}
11791185

11801186
func (a *Agent) getSelectedPair() *CandidatePair {

agent_handlers.go

+12
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ func (a *Agent) OnCandidate(f func(Candidate)) error {
2323
return nil
2424
}
2525

26+
// OnSuccessfulSelectedPairBindingResponse sets a handler that is fired when a successful binding response is received for the selected candidate pair
27+
func (a *Agent) OnSuccessfulSelectedPairBindingResponse(f func(*CandidatePair)) error {
28+
a.onSuccessfulSelectedPairBindingResponseHdlr.Store(f)
29+
return nil
30+
}
31+
2632
func (a *Agent) onSelectedCandidatePairChange(p *CandidatePair) {
2733
if h, ok := a.onSelectedCandidatePairChangeHdlr.Load().(func(Candidate, Candidate)); ok {
2834
h(p.Local, p.Remote)
@@ -41,6 +47,12 @@ func (a *Agent) onConnectionStateChange(s ConnectionState) {
4147
}
4248
}
4349

50+
func (a *Agent) onSuccessfulSelectedPairBindingResponse(p *CandidatePair) {
51+
if h, ok := a.onSuccessfulSelectedPairBindingResponseHdlr.Load().(func(*CandidatePair)); ok {
52+
h(p)
53+
}
54+
}
55+
4456
func (a *Agent) candidatePairRoutine() {
4557
for p := range a.chanCandidatePair {
4658
a.onSelectedCandidatePairChange(p)

candidatepair.go

+24
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package ice
55

66
import (
77
"fmt"
8+
"time"
89

910
"github.com/pion/stun/v2"
1011
)
@@ -18,12 +19,17 @@ func newCandidatePair(local, remote Candidate, controlling bool) *CandidatePair
1819
}
1920
}
2021

22+
type TransactionID [stun.TransactionIDSize]byte
23+
2124
// CandidatePair is a combination of a
2225
// local and remote candidate
2326
type CandidatePair struct {
2427
iceRoleControlling bool
2528
Remote Candidate
2629
Local Candidate
30+
latency time.Duration
31+
lastBindingRequest time.Time
32+
lastBindingTransactionID TransactionID
2733
bindingRequestCount uint16
2834
state CandidatePairState
2935
nominated bool
@@ -100,3 +106,21 @@ func (a *Agent) sendSTUN(msg *stun.Message, local, remote Candidate) {
100106
a.log.Tracef("Failed to send STUN message: %s", err)
101107
}
102108
}
109+
110+
func (p *CandidatePair) markBindingRequest(transactionID TransactionID) {
111+
p.lastBindingRequest = time.Now()
112+
p.lastBindingTransactionID = transactionID
113+
}
114+
115+
func (p *CandidatePair) markBindingResponse(transactionID TransactionID) bool {
116+
if p.lastBindingRequest.IsZero() || transactionID != p.lastBindingTransactionID {
117+
return false
118+
}
119+
120+
p.latency = time.Since(p.lastBindingRequest)
121+
return true
122+
}
123+
124+
func (p *CandidatePair) Latency() time.Duration {
125+
return p.latency
126+
}

selection.go

+10
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,11 @@ func (s *controllingSelector) HandleSuccessResponse(m *stun.Message, local, remo
144144
if pendingRequest.isUseCandidate && s.agent.getSelectedPair() == nil {
145145
s.agent.setSelectedPair(p)
146146
}
147+
148+
ok = p.markBindingResponse(m.TransactionID)
149+
if ok && s.agent.getSelectedPair() == p {
150+
s.agent.onSuccessfulSelectedPairBindingResponse(p)
151+
}
147152
}
148153

149154
func (s *controllingSelector) PingCandidate(local, remote Candidate) {
@@ -230,6 +235,11 @@ func (s *controlledSelector) HandleSuccessResponse(m *stun.Message, local, remot
230235
return
231236
}
232237

238+
ok = p.markBindingResponse(m.TransactionID)
239+
if ok {
240+
s.agent.onSuccessfulSelectedPairBindingResponse(p)
241+
}
242+
233243
p.state = CandidatePairStateSucceeded
234244
s.log.Tracef("Found valid candidate pair: %s", p)
235245
if p.nominateOnBindingSuccess {

0 commit comments

Comments
 (0)