-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/README.md b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/README.md
index cbb55fd8f..111ca7057 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/README.md
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/README.md
@@ -5,11 +5,11 @@
A Go implementation of ICE
-
+
-
-
+
+
@@ -20,48 +20,15 @@
The library is used as a part of our WebRTC implementation. Please refer to that [roadmap](https://github.com/pion/webrtc/issues/9) to track our major milestones.
### Community
-Pion has an active community on the [Golang Slack](https://invite.slack.golangbridge.org/). Sign up and join the **#pion** channel for discussions and support. You can also use [Pion mailing list](https://groups.google.com/forum/#!forum/pion).
+Pion has an active community on the [Slack](https://pion.ly/slack).
+
+Follow the [Pion Twitter](https://twitter.com/_pion) for project updates and important WebRTC news.
We are always looking to support **your projects**. Please reach out if you have something to build!
-
If you need commercial support or don't want to use public methods you can contact us at [team@pion.ly](mailto:team@pion.ly)
### Contributing
-Check out the **[contributing wiki](https://github.com/pion/webrtc/wiki/Contributing)** to join the group of amazing people making this project possible:
-
-* [John Bradley](https://github.com/kc5nra) - *Original Author*
-* [Sean DuBois](https://github.com/Sean-Der) - *Original Author*
-* [Michael MacDonald](https://github.com/mjmac) - *Original Author*
-* [Michiel De Backker](https://github.com/backkem) - *Original Author*
-* [Konstantin Itskov](https://github.com/trivigy) - *Original Author*
-* [Luke Curley](https://github.com/kixelated)
-* [Hugo Arregui](https://github.com/hugoArregui)
-* [Adam Kiss](https://github.com/masterada)
-* [Aleksandr Razumov](https://github.com/ernado)
-* [Yutaka Takeda](https://github.com/enobufs)
-* [Atsushi Watanabe](https://github.com/at-wat)
-* [Robert Eperjesi](https://github.com/epes)
-* [Sebastian Waisbrot](https://github.com/seppo0010)
-* [Zizheng Tai](https://github.com/ZizhengTai)
-* [Aaron France](https://github.com/AeroNotix)
-* [Chao Yuan](https://github.com/yuanchao0310)
-* [Jason Maldonis](https://github.com/jjmaldonis)
-* [Nevio Vesic](https://github.com/0x19)
-* [David Hamilton](https://github.com/dihamilton)
-* [adwpc](https://github.com/adwpc)
-* [Ori Bernstein](https://eigenstate.org)
-* [Sam Lancia](https://github.com/nerd2)
-* [Lander Noterman](https://github.com/LanderN)
-* [BUPTCZQ](https://github.com/buptczq)
-* [Henry](https://github.com/cryptix)
-* [Jerko Steiner](https://github.com/jeremija)
-* [Sidney San Martín](https://github.com/s4y)
-* [JooYoung Lim](https://github.com/DevRockstarZ)
-* [Kory Miller](https://github.com/korymiller1489)
-* [ZHENK](https://github.com/scorpionknifes)
-* [Assad Obaid](https://github.com/assadobaid)
-* [Antoine Baché](https://github.com/Antonito)
-* [Will Forcey](https://github.com/wawesomeNOGUI)
+Check out the [contributing wiki](https://github.com/pion/webrtc/wiki/Contributing) to join the group of amazing people making this project possible: [AUTHORS.txt](./AUTHORS.txt)
### License
MIT License - see [LICENSE](LICENSE) for full text
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/addr.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/addr.go
new file mode 100644
index 000000000..1d70025be
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/addr.go
@@ -0,0 +1,71 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package ice
+
+import (
+ "net"
+)
+
+func parseMulticastAnswerAddr(in net.Addr) (net.IP, bool) {
+ switch addr := in.(type) {
+ case *net.IPAddr:
+ return addr.IP, true
+ case *net.UDPAddr:
+ return addr.IP, true
+ case *net.TCPAddr:
+ return addr.IP, true
+ }
+ return nil, false
+}
+
+func parseAddr(in net.Addr) (net.IP, int, NetworkType, bool) {
+ switch addr := in.(type) {
+ case *net.UDPAddr:
+ return addr.IP, addr.Port, NetworkTypeUDP4, true
+ case *net.TCPAddr:
+ return addr.IP, addr.Port, NetworkTypeTCP4, true
+ }
+ return nil, 0, 0, false
+}
+
+func createAddr(network NetworkType, ip net.IP, port int) net.Addr {
+ switch {
+ case network.IsTCP():
+ return &net.TCPAddr{IP: ip, Port: port}
+ default:
+ return &net.UDPAddr{IP: ip, Port: port}
+ }
+}
+
+func addrEqual(a, b net.Addr) bool {
+ aIP, aPort, aType, aOk := parseAddr(a)
+ if !aOk {
+ return false
+ }
+
+ bIP, bPort, bType, bOk := parseAddr(b)
+ if !bOk {
+ return false
+ }
+
+ return aType == bType && aIP.Equal(bIP) && aPort == bPort
+}
+
+// AddrPort is an IP and a port number.
+type AddrPort [18]byte
+
+func toAddrPort(addr net.Addr) AddrPort {
+ var ap AddrPort
+ switch addr := addr.(type) {
+ case *net.UDPAddr:
+ copy(ap[:16], addr.IP.To16())
+ ap[16] = uint8(addr.Port >> 8)
+ ap[17] = uint8(addr.Port)
+ case *net.TCPAddr:
+ copy(ap[:16], addr.IP.To16())
+ ap[16] = uint8(addr.Port >> 8)
+ ap[17] = uint8(addr.Port)
+ }
+ return ap
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/agent.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/agent.go
index 9f1ac6ae8..5350330f6 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/agent.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/agent.go
@@ -1,20 +1,28 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
// Package ice implements the Interactive Connectivity Establishment (ICE)
// protocol defined in rfc5245.
package ice
import (
"context"
+ "fmt"
"net"
"strings"
"sync"
"sync/atomic"
"time"
+ atomicx "github.com/pion/ice/v2/internal/atomic"
+ stunx "github.com/pion/ice/v2/internal/stun"
"github.com/pion/logging"
"github.com/pion/mdns"
"github.com/pion/stun"
- "github.com/pion/transport/packetio"
- "github.com/pion/transport/vnet"
+ "github.com/pion/transport/v2"
+ "github.com/pion/transport/v2/packetio"
+ "github.com/pion/transport/v2/stdnet"
+ "github.com/pion/transport/v2/vnet"
"golang.org/x/net/proxy"
)
@@ -39,7 +47,7 @@ type Agent struct {
onConnected chan struct{}
onConnectedOnce sync.Once
- // force candidate to be contacted immediately (instead of waiting for task ticker)
+ // Force candidate to be contacted immediately (instead of waiting for task ticker)
forceCandidateContact chan bool
tieBreaker uint64
@@ -64,8 +72,8 @@ type Agent struct {
prflxAcceptanceMinWait time.Duration
relayAcceptanceMinWait time.Duration
- portmin uint16
- portmax uint16
+ portMin uint16
+ portMax uint16
candidateTypes []CandidateType
@@ -92,15 +100,15 @@ type Agent struct {
remotePwd string
remoteCandidates map[NetworkType][]Candidate
- checklist []*candidatePair
+ checklist []*CandidatePair
selector pairCandidateSelector
- selectedPair atomic.Value // *candidatePair
+ selectedPair atomic.Value // *CandidatePair
- urls []*URL
+ urls []*stun.URI
networkTypes []NetworkType
- buffer *packetio.Buffer
+ buf *packetio.Buffer
// LRU of outbound Binding request Transaction IDs
pendingBindingRequests []bindingRequest
@@ -109,22 +117,28 @@ type Agent struct {
extIPMapper *externalIPMapper
// State for closing
- done chan struct{}
- err atomicError
+ done chan struct{}
+ taskLoopDone chan struct{}
+ err atomicx.Error
gatherCandidateCancel func()
+ gatherCandidateDone chan struct{}
chanCandidate chan Candidate
- chanCandidatePair chan *candidatePair
+ chanCandidatePair chan *CandidatePair
chanState chan ConnectionState
loggerFactory logging.LoggerFactory
log logging.LeveledLogger
- net *vnet.Net
- tcpMux TCPMux
+ net transport.Net
+ tcpMux TCPMux
+ udpMux UDPMux
+ udpMuxSrflx UniversalUDPMux
interfaceFilter func(string) bool
+ ipFilter func(net.IP) bool
+ includeLoopback bool
insecureSkipVerify bool
@@ -200,8 +214,8 @@ func (a *Agent) taskLoop() {
a.deleteAllCandidates()
a.startedFn()
- if err := a.buffer.Close(); err != nil {
- a.log.Warnf("failed to close buffer: %v", err)
+ if err := a.buf.Close(); err != nil {
+ a.log.Warnf("Failed to close buffer: %v", err)
}
a.closeMulticastConn()
@@ -212,6 +226,7 @@ func (a *Agent) taskLoop() {
close(a.chanState)
close(a.chanCandidate)
close(a.chanCandidatePair)
+ close(a.taskLoopDone)
}()
for {
@@ -255,28 +270,13 @@ func NewAgent(config *AgentConfig) (*Agent, error) { //nolint:gocognit
}
log := loggerFactory.NewLogger("ice")
- var mDNSConn *mdns.Conn
- mDNSConn, mDNSMode, err = createMulticastDNS(mDNSMode, mDNSName, log)
- // Opportunistic mDNS: If we can't open the connection, that's ok: we
- // can continue without it.
- if err != nil {
- log.Warnf("Failed to initialize mDNS %s: %v", mDNSName, err)
- }
- closeMDNSConn := func() {
- if mDNSConn != nil {
- if mdnsCloseErr := mDNSConn.Close(); mdnsCloseErr != nil {
- log.Warnf("Failed to close mDNS: %v", mdnsCloseErr)
- }
- }
- }
-
startedCtx, startedFn := context.WithCancel(context.Background())
a := &Agent{
chanTask: make(chan task),
chanState: make(chan ConnectionState),
chanCandidate: make(chan Candidate),
- chanCandidatePair: make(chan *candidatePair),
+ chanCandidatePair: make(chan *CandidatePair),
tieBreaker: globalMathRandomGenerator.Uint64(),
lite: config.Lite,
gatheringState: GatheringStateNew,
@@ -286,20 +286,23 @@ func NewAgent(config *AgentConfig) (*Agent, error) { //nolint:gocognit
urls: config.Urls,
networkTypes: config.NetworkTypes,
onConnected: make(chan struct{}),
- buffer: packetio.NewBuffer(),
+ buf: packetio.NewBuffer(),
done: make(chan struct{}),
+ taskLoopDone: make(chan struct{}),
startedCh: startedCtx.Done(),
startedFn: startedFn,
- portmin: config.PortMin,
- portmax: config.PortMax,
+ portMin: config.PortMin,
+ portMax: config.PortMax,
loggerFactory: loggerFactory,
log: log,
net: config.Net,
proxyDialer: config.ProxyDialer,
+ tcpMux: config.TCPMux,
+ udpMux: config.UDPMux,
+ udpMuxSrflx: config.UDPMuxSrflx,
mDNSMode: mDNSMode,
mDNSName: mDNSName,
- mDNSConn: mDNSConn,
gatherCandidateCancel: func() {},
@@ -307,21 +310,29 @@ func NewAgent(config *AgentConfig) (*Agent, error) { //nolint:gocognit
interfaceFilter: config.InterfaceFilter,
- insecureSkipVerify: config.InsecureSkipVerify,
- }
+ ipFilter: config.IPFilter,
- a.tcpMux = config.TCPMux
- if a.tcpMux == nil {
- a.tcpMux = newInvalidTCPMux()
+ insecureSkipVerify: config.InsecureSkipVerify,
+
+ includeLoopback: config.IncludeLoopback,
}
if a.net == nil {
- a.net = vnet.NewNet(nil)
- } else if a.net.IsVirtual() {
- a.log.Warn("vnet is enabled")
- if a.mDNSMode != MulticastDNSModeDisabled {
- a.log.Warn("vnet does not support mDNS yet")
+ a.net, err = stdnet.NewNet()
+ if err != nil {
+ return nil, fmt.Errorf("failed to create network: %w", err)
}
+ } else if _, isVirtual := a.net.(*vnet.Net); isVirtual {
+ a.log.Warn("Virtual network is enabled")
+ if a.mDNSMode != MulticastDNSModeDisabled {
+ a.log.Warn("Virtual network does not support mDNS yet")
+ }
+ }
+
+ // Opportunistic mDNS: If we can't open the connection, that's ok: we
+ // can continue without it.
+ if a.mDNSConn, a.mDNSMode, err = createMulticastDNS(a.net, mDNSMode, mDNSName, log); err != nil {
+ log.Warnf("Failed to initialize mDNS %s: %v", mDNSName, err)
}
config.initWithDefaults(a)
@@ -329,29 +340,35 @@ func NewAgent(config *AgentConfig) (*Agent, error) { //nolint:gocognit
// Make sure the buffer doesn't grow indefinitely.
// NOTE: We actually won't get anywhere close to this limit.
// SRTP will constantly read from the endpoint and drop packets if it's full.
- a.buffer.SetLimitSize(maxBufferSize)
+ a.buf.SetLimitSize(maxBufferSize)
if a.lite && (len(a.candidateTypes) != 1 || a.candidateTypes[0] != CandidateTypeHost) {
- closeMDNSConn()
+ a.closeMulticastConn()
return nil, ErrLiteUsingNonHostCandidates
}
if config.Urls != nil && len(config.Urls) > 0 && !containsCandidateType(CandidateTypeServerReflexive, a.candidateTypes) && !containsCandidateType(CandidateTypeRelay, a.candidateTypes) {
- closeMDNSConn()
+ a.closeMulticastConn()
return nil, ErrUselessUrlsProvided
}
if err = config.initExtIPMapping(a); err != nil {
- closeMDNSConn()
+ a.closeMulticastConn()
return nil, err
}
go a.taskLoop()
- a.startOnConnectionStateChangeRoutine()
+
+ // CandidatePair and ConnectionState are usually changed at once.
+ // Blocking one by the other one causes deadlock.
+ // Hence, we call handlers from independent Goroutines.
+ go a.candidatePairRoutine()
+ go a.connectionStateRoutine()
+ go a.candidateRoutine()
// Restart is also used to initialize the agent for the first time
if err := a.Restart(config.LocalUfrag, config.LocalPwd); err != nil {
- closeMDNSConn()
+ a.closeMulticastConn()
_ = a.Close()
return nil, err
}
@@ -359,81 +376,6 @@ func NewAgent(config *AgentConfig) (*Agent, error) { //nolint:gocognit
return a, nil
}
-// OnConnectionStateChange sets a handler that is fired when the connection state changes
-func (a *Agent) OnConnectionStateChange(f func(ConnectionState)) error {
- a.onConnectionStateChangeHdlr.Store(f)
- return nil
-}
-
-// OnSelectedCandidatePairChange sets a handler that is fired when the final candidate
-// pair is selected
-func (a *Agent) OnSelectedCandidatePairChange(f func(Candidate, Candidate)) error {
- a.onSelectedCandidatePairChangeHdlr.Store(f)
- return nil
-}
-
-// OnCandidate sets a handler that is fired when new candidates gathered. When
-// the gathering process complete the last candidate is nil.
-func (a *Agent) OnCandidate(f func(Candidate)) error {
- a.onCandidateHdlr.Store(f)
- return nil
-}
-
-func (a *Agent) onSelectedCandidatePairChange(p *candidatePair) {
- if h, ok := a.onSelectedCandidatePairChangeHdlr.Load().(func(Candidate, Candidate)); ok {
- h(p.local, p.remote)
- }
-}
-
-func (a *Agent) onCandidate(c Candidate) {
- if onCandidateHdlr, ok := a.onCandidateHdlr.Load().(func(Candidate)); ok {
- onCandidateHdlr(c)
- }
-}
-
-func (a *Agent) onConnectionStateChange(s ConnectionState) {
- if hdlr, ok := a.onConnectionStateChangeHdlr.Load().(func(ConnectionState)); ok {
- hdlr(s)
- }
-}
-
-func (a *Agent) startOnConnectionStateChangeRoutine() {
- go func() {
- for {
- // CandidatePair and ConnectionState are usually changed at once.
- // Blocking one by the other one causes deadlock.
- p, isOpen := <-a.chanCandidatePair
- if !isOpen {
- return
- }
- a.onSelectedCandidatePairChange(p)
- }
- }()
- go func() {
- for {
- select {
- case s, isOpen := <-a.chanState:
- if !isOpen {
- for c := range a.chanCandidate {
- a.onCandidate(c)
- }
- return
- }
- a.onConnectionStateChange(s)
-
- case c, isOpen := <-a.chanCandidate:
- if !isOpen {
- for s := range a.chanState {
- a.onConnectionStateChange(s)
- }
- return
- }
- a.onCandidate(c)
- }
- }
- }()
-}
-
func (a *Agent) startConnectivityChecks(isControlling bool, remoteUfrag, remotePwd string) error {
a.muHaveStarted.Lock()
defer a.muHaveStarted.Unlock()
@@ -442,7 +384,7 @@ func (a *Agent) startConnectivityChecks(isControlling bool, remoteUfrag, remoteP
return ErrMultipleStart
default:
}
- if err := a.SetRemoteCredentials(remoteUfrag, remotePwd); err != nil {
+ if err := a.SetRemoteCredentials(remoteUfrag, remotePwd); err != nil { //nolint:contextcheck
return err
}
@@ -469,7 +411,7 @@ func (a *Agent) startConnectivityChecks(isControlling bool, remoteUfrag, remoteP
agent.updateConnectionState(ConnectionStateChecking)
a.requestConnectivityCheck()
- go a.connectivityChecks()
+ go a.connectivityChecks() //nolint:contextcheck
})
}
@@ -499,11 +441,12 @@ func (a *Agent) connectivityChecks() {
a.updateConnectionState(ConnectionStateFailed)
return
}
+ default:
}
a.selector.ContactCandidates()
}); err != nil {
- a.log.Warnf("taskLoop failed: %v", err)
+ a.log.Warnf("Failed to start connectivity checks: %v", err)
}
}
@@ -559,29 +502,27 @@ func (a *Agent) updateConnectionState(newState ConnectionState) {
}
}
-func (a *Agent) setSelectedPair(p *candidatePair) {
- a.log.Tracef("Set selected candidate pair: %s", p)
-
+func (a *Agent) setSelectedPair(p *CandidatePair) {
if p == nil {
- var nilPair *candidatePair
+ var nilPair *CandidatePair
a.selectedPair.Store(nilPair)
+ a.log.Tracef("Unset selected candidate pair")
return
}
p.nominated = true
a.selectedPair.Store(p)
+ a.log.Tracef("Set selected candidate pair: %s", p)
a.updateConnectionState(ConnectionStateConnected)
// Notify when the selected pair changes
- if p != nil {
- a.afterRun(func(ctx context.Context) {
- select {
- case a.chanCandidatePair <- p:
- case <-ctx.Done():
- }
- })
- }
+ a.afterRun(func(ctx context.Context) {
+ select {
+ case a.chanCandidatePair <- p:
+ case <-ctx.Done():
+ }
+ })
// Signal connected
a.onConnectedOnce.Do(func() { close(a.onConnected) })
@@ -591,7 +532,7 @@ func (a *Agent) pingAllCandidates() {
a.log.Trace("pinging all candidates")
if len(a.checklist) == 0 {
- a.log.Warn("pingAllCandidates called with no candidate pairs. Connection is not possible yet.")
+ a.log.Warn("Failed to ping without candidate pairs. Connection is not possible yet.")
}
for _, p := range a.checklist {
@@ -602,17 +543,17 @@ func (a *Agent) pingAllCandidates() {
}
if p.bindingRequestCount > a.maxBindingRequests {
- a.log.Tracef("max requests reached for pair %s, marking it as failed\n", p)
+ a.log.Tracef("max requests reached for pair %s, marking it as failed", p)
p.state = CandidatePairStateFailed
} else {
- a.selector.PingCandidate(p.local, p.remote)
+ a.selector.PingCandidate(p.Local, p.Remote)
p.bindingRequestCount++
}
}
}
-func (a *Agent) getBestAvailableCandidatePair() *candidatePair {
- var best *candidatePair
+func (a *Agent) getBestAvailableCandidatePair() *CandidatePair {
+ var best *CandidatePair
for _, p := range a.checklist {
if p.state == CandidatePairStateFailed {
continue
@@ -620,15 +561,15 @@ func (a *Agent) getBestAvailableCandidatePair() *candidatePair {
if best == nil {
best = p
- } else if best.Priority() < p.Priority() {
+ } else if best.priority() < p.priority() {
best = p
}
}
return best
}
-func (a *Agent) getBestValidCandidatePair() *candidatePair {
- var best *candidatePair
+func (a *Agent) getBestValidCandidatePair() *CandidatePair {
+ var best *CandidatePair
for _, p := range a.checklist {
if p.state != CandidatePairStateSucceeded {
continue
@@ -636,22 +577,22 @@ func (a *Agent) getBestValidCandidatePair() *candidatePair {
if best == nil {
best = p
- } else if best.Priority() < p.Priority() {
+ } else if best.priority() < p.priority() {
best = p
}
}
return best
}
-func (a *Agent) addPair(local, remote Candidate) *candidatePair {
+func (a *Agent) addPair(local, remote Candidate) *CandidatePair {
p := newCandidatePair(local, remote, a.isControlling)
a.checklist = append(a.checklist, p)
return p
}
-func (a *Agent) findPair(local, remote Candidate) *candidatePair {
+func (a *Agent) findPair(local, remote Candidate) *CandidatePair {
for _, p := range a.checklist {
- if p.local.Equal(local) && p.remote.Equal(remote) {
+ if p.Local.Equal(local) && p.Remote.Equal(remote) {
return p
}
}
@@ -666,7 +607,7 @@ func (a *Agent) validateSelectedPair() bool {
return false
}
- disconnectedTime := time.Since(selectedPair.remote.LastReceived())
+ disconnectedTime := time.Since(selectedPair.Remote.LastReceived())
// Only allow transitions to failed if a.failedTimeout is non-zero
totalTimeToFailure := a.failedTimeout
@@ -696,11 +637,11 @@ func (a *Agent) checkKeepalive() {
}
if (a.keepaliveInterval != 0) &&
- ((time.Since(selectedPair.local.LastSent()) > a.keepaliveInterval) ||
- (time.Since(selectedPair.remote.LastReceived()) > a.keepaliveInterval)) {
- // we use binding request instead of indication to support refresh consent schemas
+ ((time.Since(selectedPair.Local.LastSent()) > a.keepaliveInterval) ||
+ (time.Since(selectedPair.Remote.LastReceived()) > a.keepaliveInterval)) {
+ // We use binding request instead of indication to support refresh consent schemas
// see https://tools.ietf.org/html/rfc7675
- a.selector.PingCandidate(selectedPair.local, selectedPair.remote)
+ a.selector.PingCandidate(selectedPair.Local, selectedPair.Remote)
}
}
@@ -710,10 +651,10 @@ func (a *Agent) AddRemoteCandidate(c Candidate) error {
return nil
}
- // cannot check for network yet because it might not be applied
- // when mDNS hostame is used.
+ // Cannot check for network yet because it might not be applied
+ // when mDNS hostname is used.
if c.TCPType() == TCPTypeActive {
- // TCP Candidates with tcptype active will probe server passive ones, so
+ // TCP Candidates with TCP type active will probe server passive ones, so
// no need to do anything with them.
a.log.Infof("Ignoring remote candidate with tcpType active: %s", c)
return nil
@@ -722,7 +663,7 @@ func (a *Agent) AddRemoteCandidate(c Candidate) error {
// If we have a mDNS Candidate lets fully resolve it before adding it locally
if c.Type() == CandidateTypeHost && strings.HasSuffix(c.Address(), ".local") {
if a.mDNSMode == MulticastDNSModeDisabled {
- a.log.Warnf("remote mDNS candidate added, but mDNS is disabled: (%s)", c.Address())
+ a.log.Warnf("Remote mDNS candidate added, but mDNS is disabled: (%s)", c.Address())
return nil
}
@@ -756,8 +697,8 @@ func (a *Agent) resolveAndAddMulticastCandidate(c *CandidateHost) {
return
}
- ip, _, _, _ := parseAddr(src) //nolint:dogsled
- if ip == nil {
+ ip, ipOk := parseMulticastAnswerAddr(src)
+ if !ipOk {
a.log.Warnf("Failed to discover mDNS candidate %s: failed to parse IP", c.Address())
return
}
@@ -806,18 +747,22 @@ func (a *Agent) addRemoteCandidate(c Candidate) {
func (a *Agent) addCandidate(ctx context.Context, c Candidate, candidateConn net.PacketConn) error {
return a.run(ctx, func(ctx context.Context, agent *Agent) {
- c.start(a, candidateConn, a.startedCh)
-
set := a.localCandidates[c.NetworkType()]
for _, candidate := range set {
if candidate.Equal(c) {
+ a.log.Debugf("Ignore duplicate candidate: %s", c.String())
if err := c.close(); err != nil {
a.log.Warnf("Failed to close duplicate candidate: %v", err)
}
+ if err := candidateConn.Close(); err != nil {
+ a.log.Warnf("Failed to close duplicate candidate connection: %v", err)
+ }
return
}
}
+ c.start(a, candidateConn, a.startedCh)
+
set = append(set, c)
a.localCandidates[c.NetworkType()] = set
@@ -881,26 +826,36 @@ func (a *Agent) GetRemoteUserCredentials() (frag string, pwd string, err error)
return
}
+func (a *Agent) removeUfragFromMux() {
+ if a.tcpMux != nil {
+ a.tcpMux.RemoveConnByUfrag(a.localUfrag)
+ }
+ if a.udpMux != nil {
+ a.udpMux.RemoveConnByUfrag(a.localUfrag)
+ }
+ if a.udpMuxSrflx != nil {
+ a.udpMuxSrflx.RemoveConnByUfrag(a.localUfrag)
+ }
+}
+
// Close cleans up the Agent
func (a *Agent) Close() error {
if err := a.ok(); err != nil {
return err
}
- done := make(chan struct{})
-
a.afterRun(func(context.Context) {
- close(done)
+ a.gatherCandidateCancel()
+ if a.gatherCandidateDone != nil {
+ <-a.gatherCandidateDone
+ }
})
-
- a.gatherCandidateCancel()
a.err.Store(ErrClosed)
- a.tcpMux.RemoveConnByUfrag(a.localUfrag)
+ a.removeUfragFromMux()
close(a.done)
-
- <-done
+ <-a.taskLoopDone
return nil
}
@@ -930,7 +885,7 @@ func (a *Agent) deleteAllCandidates() {
func (a *Agent) findRemoteCandidate(networkType NetworkType, addr net.Addr) Candidate {
ip, port, _, ok := parseAddr(addr)
if !ok {
- a.log.Warnf("Error parsing addr: %s", addr)
+ a.log.Warnf("Failed to parse address: %s", addr)
return nil
}
@@ -944,7 +899,7 @@ func (a *Agent) findRemoteCandidate(networkType NetworkType, addr net.Addr) Cand
}
func (a *Agent) sendBindingRequest(m *stun.Message, local, remote Candidate) {
- a.log.Tracef("ping STUN from %s to %s\n", local.String(), remote.String())
+ a.log.Tracef("ping STUN from %s to %s", local.String(), remote.String())
a.invalidatePendingBindingRequests(time.Now())
a.pendingBindingRequests = append(a.pendingBindingRequests, bindingRequest{
@@ -962,7 +917,7 @@ func (a *Agent) sendBindingSuccess(m *stun.Message, local, remote Candidate) {
ip, port, _, ok := parseAddr(base.addr())
if !ok {
- a.log.Warnf("Error parsing addr: %s", base.addr())
+ a.log.Warnf("Failed to parse address: %s", base.addr())
return
}
@@ -980,12 +935,11 @@ func (a *Agent) sendBindingSuccess(m *stun.Message, local, remote Candidate) {
}
}
-/* Removes pending binding requests that are over maxBindingRequestTimeout old
-
- Let HTO be the transaction timeout, which SHOULD be 2*RTT if
- RTT is known or 500 ms otherwise.
- https://tools.ietf.org/html/rfc8445#appendix-B.1
-*/
+// Removes pending binding requests that are over maxBindingRequestTimeout old
+//
+// Let HTO be the transaction timeout, which SHOULD be 2*RTT if
+// RTT is known or 500 ms otherwise.
+// https://tools.ietf.org/html/rfc8445#appendix-B.1
func (a *Agent) invalidatePendingBindingRequests(filterTime time.Time) {
initialSize := len(a.pendingBindingRequests)
@@ -1033,38 +987,38 @@ func (a *Agent) handleInbound(m *stun.Message, local Candidate, remote net.Addr)
if a.isControlling {
if m.Contains(stun.AttrICEControlling) {
- a.log.Debug("inbound isControlling && a.isControlling == true")
+ a.log.Debug("Inbound STUN message: isControlling && a.isControlling == true")
return
} else if m.Contains(stun.AttrUseCandidate) {
- a.log.Debug("useCandidate && a.isControlling == true")
+ a.log.Debug("Inbound STUN message: useCandidate && a.isControlling == true")
return
}
} else {
if m.Contains(stun.AttrICEControlled) {
- a.log.Debug("inbound isControlled && a.isControlling == false")
+ a.log.Debug("Inbound STUN message: isControlled && a.isControlling == false")
return
}
}
remoteCandidate := a.findRemoteCandidate(local.NetworkType(), remote)
if m.Type.Class == stun.ClassSuccessResponse {
- if err = assertInboundMessageIntegrity(m, []byte(a.remotePwd)); err != nil {
- a.log.Warnf("discard message from (%s), %v", remote, err)
+ if err = stun.MessageIntegrity([]byte(a.remotePwd)).Check(m); err != nil {
+ a.log.Warnf("Discard message from (%s), %v", remote, err)
return
}
if remoteCandidate == nil {
- a.log.Warnf("discard success message from (%s), no such remote", remote)
+ a.log.Warnf("Discard success message from (%s), no such remote", remote)
return
}
a.selector.HandleSuccessResponse(m, local, remoteCandidate, remote)
} else if m.Type.Class == stun.ClassRequest {
- if err = assertInboundUsername(m, a.localUfrag+":"+a.remoteUfrag); err != nil {
- a.log.Warnf("discard message from (%s), %v", remote, err)
+ if err = stunx.AssertUsername(m, a.localUfrag+":"+a.remoteUfrag); err != nil {
+ a.log.Warnf("Discard message from (%s), %v", remote, err)
return
- } else if err = assertInboundMessageIntegrity(m, []byte(a.localPwd)); err != nil {
- a.log.Warnf("discard message from (%s), %v", remote, err)
+ } else if err = stun.MessageIntegrity([]byte(a.localPwd)).Check(m); err != nil {
+ a.log.Warnf("Discard message from (%s), %v", remote, err)
return
}
@@ -1091,7 +1045,7 @@ func (a *Agent) handleInbound(m *stun.Message, local Candidate, remote net.Addr)
}
remoteCandidate = prflxCandidate
- a.log.Debugf("adding a new peer-reflexive candidate: %s ", remote)
+ a.log.Debugf("Adding a new peer-reflexive candidate: %s ", remote)
a.addRemoteCandidate(remoteCandidate)
}
@@ -1107,35 +1061,52 @@ func (a *Agent) handleInbound(m *stun.Message, local Candidate, remote net.Addr)
// validateNonSTUNTraffic processes non STUN traffic from a remote candidate,
// and returns true if it is an actual remote candidate
-func (a *Agent) validateNonSTUNTraffic(local Candidate, remote net.Addr) bool {
- var isValidCandidate uint64
+func (a *Agent) validateNonSTUNTraffic(local Candidate, remote net.Addr) (Candidate, bool) {
+ var remoteCandidate Candidate
if err := a.run(local.context(), func(ctx context.Context, agent *Agent) {
- remoteCandidate := a.findRemoteCandidate(local.NetworkType(), remote)
+ remoteCandidate = a.findRemoteCandidate(local.NetworkType(), remote)
if remoteCandidate != nil {
remoteCandidate.seen(false)
- atomic.AddUint64(&isValidCandidate, 1)
}
}); err != nil {
- a.log.Warnf("failed to validate remote candidate: %v", err)
+ a.log.Warnf("Failed to validate remote candidate: %v", err)
}
- return atomic.LoadUint64(&isValidCandidate) == 1
+ return remoteCandidate, remoteCandidate != nil
}
-func (a *Agent) getSelectedPair() *candidatePair {
- selectedPair := a.selectedPair.Load()
-
+// GetSelectedCandidatePair returns the selected pair or nil if there is none
+func (a *Agent) GetSelectedCandidatePair() (*CandidatePair, error) {
+ selectedPair := a.getSelectedPair()
if selectedPair == nil {
- return nil
+ return nil, nil //nolint:nilnil
}
- return selectedPair.(*candidatePair)
+ local, err := selectedPair.Local.copy()
+ if err != nil {
+ return nil, err
+ }
+
+ remote, err := selectedPair.Remote.copy()
+ if err != nil {
+ return nil, err
+ }
+
+ return &CandidatePair{Local: local, Remote: remote}, nil
+}
+
+func (a *Agent) getSelectedPair() *CandidatePair {
+ if selectedPair, ok := a.selectedPair.Load().(*CandidatePair); ok {
+ return selectedPair
+ }
+
+ return nil
}
func (a *Agent) closeMulticastConn() {
if a.mDNSConn != nil {
if err := a.mDNSConn.Close(); err != nil {
- a.log.Warnf("failed to close mDNS Conn: %v", err)
+ a.log.Warnf("Failed to close mDNS Conn: %v", err)
}
}
}
@@ -1158,8 +1129,10 @@ func (a *Agent) SetRemoteCredentials(remoteUfrag, remotePwd string) error {
// Restart restarts the ICE Agent with the provided ufrag/pwd
// If no ufrag/pwd is provided the Agent will generate one itself
//
-// Restart must only be called when GatheringState is GatheringStateComplete
-// a user must then call GatherCandidates explicitly to start generating new ones
+// If there is a gatherer routine currently running, Restart will
+// cancel it.
+// After a Restart, the user must then call GatherCandidates explicitly
+// to start generating new ones.
func (a *Agent) Restart(ufrag, pwd string) error {
if ufrag == "" {
var err error
@@ -1186,17 +1159,17 @@ func (a *Agent) Restart(ufrag, pwd string) error {
var err error
if runErr := a.run(a.context(), func(ctx context.Context, agent *Agent) {
if agent.gatheringState == GatheringStateGathering {
- err = ErrRestartWhenGathering
- return
+ agent.gatherCandidateCancel()
}
// Clear all agent needed to take back to fresh state
+ a.removeUfragFromMux()
agent.localUfrag = ufrag
agent.localPwd = pwd
agent.remoteUfrag = ""
agent.remotePwd = ""
a.gatheringState = GatheringStateNew
- a.checklist = make([]*candidatePair, 0)
+ a.checklist = make([]*CandidatePair, 0)
a.pendingBindingRequests = make([]bindingRequest, 0)
a.setSelectedPair(nil)
a.deleteAllCandidates()
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/agent_config.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/agent_config.go
index e09ad76ff..f5897cd4a 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/agent_config.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/agent_config.go
@@ -1,10 +1,15 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
+ "net"
"time"
"github.com/pion/logging"
- "github.com/pion/transport/vnet"
+ "github.com/pion/stun"
+ "github.com/pion/transport/v2"
"golang.org/x/net/proxy"
)
@@ -21,25 +26,25 @@ const (
// defaultFailedTimeout is the default time till an Agent transitions to failed after disconnected
defaultFailedTimeout = 25 * time.Second
- // wait time before nominating a host candidate
+ // defaultHostAcceptanceMinWait is the wait time before nominating a host candidate
defaultHostAcceptanceMinWait = 0
- // wait time before nominating a srflx candidate
+ // defaultSrflxAcceptanceMinWait is the wait time before nominating a srflx candidate
defaultSrflxAcceptanceMinWait = 500 * time.Millisecond
- // wait time before nominating a prflx candidate
+ // defaultPrflxAcceptanceMinWait is the wait time before nominating a prflx candidate
defaultPrflxAcceptanceMinWait = 1000 * time.Millisecond
- // wait time before nominating a relay candidate
+ // defaultRelayAcceptanceMinWait is the wait time before nominating a relay candidate
defaultRelayAcceptanceMinWait = 2000 * time.Millisecond
- // max binding request before considering a pair failed
+ // defaultMaxBindingRequests is the maximum number of binding requests before considering a pair failed
defaultMaxBindingRequests = 7
- // the number of bytes that can be buffered before we start to error
+ // maxBufferSize is the number of bytes that can be buffered before we start to error
maxBufferSize = 1000 * 1000 // 1MB
- // wait time before binding requests can be deleted
+ // maxBindingRequestTimeout is the wait time before binding requests can be deleted
maxBindingRequestTimeout = 4000 * time.Millisecond
)
@@ -50,7 +55,7 @@ func defaultCandidateTypes() []CandidateType {
// AgentConfig collects the arguments to ice.Agent construction into
// a single structure, for future-proofness of the interface
type AgentConfig struct {
- Urls []*URL
+ Urls []*stun.URI
// PortMin and PortMax are optional. Leave them 0 for the default UDP port allocation strategy.
PortMin uint16
@@ -83,6 +88,10 @@ type AgentConfig struct {
// A keepalive interval of 0 means we never send keepalive packets
KeepaliveInterval *time.Duration
+ // CheckInterval controls how often our task loop runs when in the
+ // connecting state.
+ CheckInterval *time.Duration
+
// NetworkTypes is an optional configuration for disabling or enabling
// support for specific network types.
NetworkTypes []NetworkType
@@ -93,10 +102,6 @@ type AgentConfig struct {
LoggerFactory logging.LoggerFactory
- // checkInterval controls how often our internal task loop runs when
- // in the connecting state. Only useful for testing.
- checkInterval time.Duration
-
// MaxBindingRequests is the max amount of binding requests the agent will send
// over a candidate pair for validation or nomination, if after MaxBindingRequests
// the candidate is yet to answer a binding request or a nomination we set the pair as failed
@@ -108,14 +113,14 @@ type AgentConfig struct {
// NAT1To1IPCandidateType is used along with NAT1To1IPs to specify which candidate type
// the 1:1 NAT IP addresses should be mapped to.
// If unspecified or CandidateTypeHost, NAT1To1IPs are used to replace host candidate IPs.
- // If CandidateTypeServerReflexive, it will insert a srflx candidate (as if it was dervied
+ // If CandidateTypeServerReflexive, it will insert a srflx candidate (as if it was derived
// from a STUN server) with its port number being the one for the actual host candidate.
// Other values will result in an error.
NAT1To1IPCandidateType CandidateType
// NAT1To1IPs contains a list of public IP addresses that are to be used as a host
// candidate or srflx candidate. This is used typically for servers that are behind
- // 1:1 D-NAT (e.g. AWS EC2 instances) and to eliminate the need of server reflexisive
+ // 1:1 D-NAT (e.g. AWS EC2 instances) and to eliminate the need of server reflexive
// candidate gathering.
NAT1To1IPs []string
@@ -129,13 +134,17 @@ type AgentConfig struct {
RelayAcceptanceMinWait *time.Duration
// Net is the our abstracted network interface for internal development purpose only
- // (see github.com/pion/transport/vnet)
- Net *vnet.Net
+ // (see https://github.com/pion/transport)
+ Net transport.Net
- // InterfaceFilter is a function that you can use in order to whitelist or blacklist
+ // InterfaceFilter is a function that you can use in order to whitelist or blacklist
// the interfaces which are used to gather ICE candidates.
InterfaceFilter func(string) bool
+ // IPFilter is a function that you can use in order to whitelist or blacklist
+ // the ips which are used to gather ICE candidates.
+ IPFilter func(net.IP) bool
+
// InsecureSkipVerify controls if self-signed certificates are accepted when connecting
// to TURN servers via TLS or DTLS
InsecureSkipVerify bool
@@ -145,9 +154,26 @@ type AgentConfig struct {
// experimental and the API might change in the future.
TCPMux TCPMux
+ // UDPMux is used for multiplexing multiple incoming UDP connections on a single port
+ // when this is set, the agent ignores PortMin and PortMax configurations and will
+ // defer to UDPMux for incoming connections
+ UDPMux UDPMux
+
+ // UDPMuxSrflx is used for multiplexing multiple incoming UDP connections of server reflexive candidates
+ // on a single port when this is set, the agent ignores PortMin and PortMax configurations and will
+ // defer to UDPMuxSrflx for incoming connections
+ // It embeds UDPMux to do the actual connection multiplexing
+ UDPMuxSrflx UniversalUDPMux
+
// Proxy Dialer is a dialer that should be implemented by the user based on golang.org/x/net/proxy
// dial interface in order to support corporate proxies
ProxyDialer proxy.Dialer
+
+ // Deprecated: AcceptAggressiveNomination always enabled.
+ AcceptAggressiveNomination bool
+
+ // Include loopback addresses in the candidate list.
+ IncludeLoopback bool
}
// initWithDefaults populates an agent and falls back to defaults if fields are unset
@@ -200,10 +226,10 @@ func (config *AgentConfig) initWithDefaults(a *Agent) {
a.keepaliveInterval = *config.KeepaliveInterval
}
- if config.checkInterval == 0 {
+ if config.CheckInterval == nil {
a.checkInterval = defaultCheckInterval
} else {
- a.checkInterval = config.checkInterval
+ a.checkInterval = *config.CheckInterval
}
if config.CandidateTypes == nil || len(config.CandidateTypes) == 0 {
@@ -220,7 +246,7 @@ func (config *AgentConfig) initExtIPMapping(a *Agent) error {
return err
}
if a.extIPMapper == nil {
- return nil // this may happen when config.NAT1To1IPs is an empty array
+ return nil // This may happen when config.NAT1To1IPs is an empty array
}
if a.extIPMapper.candidateType == CandidateTypeHost {
if a.mDNSMode == MulticastDNSModeQueryAndGather {
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/agent_handlers.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/agent_handlers.go
new file mode 100644
index 000000000..c5a5ec03b
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/agent_handlers.go
@@ -0,0 +1,60 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package ice
+
+// OnConnectionStateChange sets a handler that is fired when the connection state changes
+func (a *Agent) OnConnectionStateChange(f func(ConnectionState)) error {
+ a.onConnectionStateChangeHdlr.Store(f)
+ return nil
+}
+
+// OnSelectedCandidatePairChange sets a handler that is fired when the final candidate
+// pair is selected
+func (a *Agent) OnSelectedCandidatePairChange(f func(Candidate, Candidate)) error {
+ a.onSelectedCandidatePairChangeHdlr.Store(f)
+ return nil
+}
+
+// OnCandidate sets a handler that is fired when new candidates gathered. When
+// the gathering process complete the last candidate is nil.
+func (a *Agent) OnCandidate(f func(Candidate)) error {
+ a.onCandidateHdlr.Store(f)
+ return nil
+}
+
+func (a *Agent) onSelectedCandidatePairChange(p *CandidatePair) {
+ if h, ok := a.onSelectedCandidatePairChangeHdlr.Load().(func(Candidate, Candidate)); ok {
+ h(p.Local, p.Remote)
+ }
+}
+
+func (a *Agent) onCandidate(c Candidate) {
+ if onCandidateHdlr, ok := a.onCandidateHdlr.Load().(func(Candidate)); ok {
+ onCandidateHdlr(c)
+ }
+}
+
+func (a *Agent) onConnectionStateChange(s ConnectionState) {
+ if hdlr, ok := a.onConnectionStateChangeHdlr.Load().(func(ConnectionState)); ok {
+ hdlr(s)
+ }
+}
+
+func (a *Agent) candidatePairRoutine() {
+ for p := range a.chanCandidatePair {
+ a.onSelectedCandidatePairChange(p)
+ }
+}
+
+func (a *Agent) connectionStateRoutine() {
+ for s := range a.chanState {
+ go a.onConnectionStateChange(s)
+ }
+}
+
+func (a *Agent) candidateRoutine() {
+ for c := range a.chanCandidate {
+ a.onCandidate(c)
+ }
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/agent_stats.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/agent_stats.go
index 18d9ed81f..b9ad7187e 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/agent_stats.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/agent_stats.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
@@ -13,8 +16,8 @@ func (a *Agent) GetCandidatePairsStats() []CandidatePairStats {
for _, cp := range agent.checklist {
stat := CandidatePairStats{
Timestamp: time.Now(),
- LocalCandidateID: cp.local.ID(),
- RemoteCandidateID: cp.remote.ID(),
+ LocalCandidateID: cp.Local.ID(),
+ RemoteCandidateID: cp.Remote.ID(),
State: cp.state,
Nominated: cp.nominated,
// PacketsSent uint32
@@ -45,7 +48,7 @@ func (a *Agent) GetCandidatePairsStats() []CandidatePairStats {
res = result
})
if err != nil {
- a.log.Errorf("error getting candidate pairs stats %v", err)
+ a.log.Errorf("Failed to get candidate pairs stats: %v", err)
return []CandidatePairStats{}
}
return res
@@ -58,6 +61,12 @@ func (a *Agent) GetLocalCandidatesStats() []CandidateStats {
result := make([]CandidateStats, 0, len(agent.localCandidates))
for networkType, localCandidates := range agent.localCandidates {
for _, c := range localCandidates {
+ relayProtocol := ""
+ if c.Type() == CandidateTypeRelay {
+ if cRelay, ok := c.(*CandidateRelay); ok {
+ relayProtocol = cRelay.RelayProtocol()
+ }
+ }
stat := CandidateStats{
Timestamp: time.Now(),
ID: c.ID(),
@@ -67,7 +76,7 @@ func (a *Agent) GetLocalCandidatesStats() []CandidateStats {
CandidateType: c.Type(),
Priority: c.Priority(),
// URL string
- RelayProtocol: "udp",
+ RelayProtocol: relayProtocol,
// Deleted bool
}
result = append(result, stat)
@@ -76,7 +85,7 @@ func (a *Agent) GetLocalCandidatesStats() []CandidateStats {
res = result
})
if err != nil {
- a.log.Errorf("error getting candidate pairs stats %v", err)
+ a.log.Errorf("Failed to get candidate pair stats: %v", err)
return []CandidateStats{}
}
return res
@@ -87,8 +96,8 @@ func (a *Agent) GetRemoteCandidatesStats() []CandidateStats {
var res []CandidateStats
err := a.run(a.context(), func(ctx context.Context, agent *Agent) {
result := make([]CandidateStats, 0, len(agent.remoteCandidates))
- for networkType, localCandidates := range agent.remoteCandidates {
- for _, c := range localCandidates {
+ for networkType, remoteCandidates := range agent.remoteCandidates {
+ for _, c := range remoteCandidates {
stat := CandidateStats{
Timestamp: time.Now(),
ID: c.ID(),
@@ -98,7 +107,7 @@ func (a *Agent) GetRemoteCandidatesStats() []CandidateStats {
CandidateType: c.Type(),
Priority: c.Priority(),
// URL string
- RelayProtocol: "udp",
+ RelayProtocol: "",
}
result = append(result, stat)
}
@@ -106,7 +115,7 @@ func (a *Agent) GetRemoteCandidatesStats() []CandidateStats {
res = result
})
if err != nil {
- a.log.Errorf("error getting candidate pairs stats %v", err)
+ a.log.Errorf("Failed to get candidate pair stats: %v", err)
return []CandidateStats{}
}
return res
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate.go
index 701f8f83c..92a007688 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
@@ -62,6 +65,7 @@ type Candidate interface {
context() context.Context
close() error
+ copy() (Candidate, error)
seen(outbound bool)
start(a *Agent, conn net.PacketConn, initializedCh <-chan struct{})
writeTo(raw []byte, dst Candidate) (int, error)
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_base.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_base.go
index 2f16a8a84..8e551d8f2 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_base.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_base.go
@@ -1,16 +1,20 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
"context"
+ "errors"
"fmt"
"hash/crc32"
+ "io"
"net"
"strconv"
"strings"
"sync/atomic"
"time"
- "github.com/pion/logging"
"github.com/pion/stun"
)
@@ -37,6 +41,8 @@ type candidateBase struct {
foundationOverride string
priorityOverride uint32
+
+ remoteCandidateCaches map[AddrPort]Candidate
}
// Done implements context.Context
@@ -60,7 +66,7 @@ func (c *candidateBase) Deadline() (deadline time.Time, ok bool) {
}
// Value implements context.Context
-func (c *candidateBase) Value(key interface{}) interface{} {
+func (c *candidateBase) Value(interface{}) interface{} {
return nil
}
@@ -206,9 +212,9 @@ func (c *candidateBase) start(a *Agent, conn net.PacketConn, initializedCh <-cha
}
func (c *candidateBase) recvLoop(initializedCh <-chan struct{}) {
- defer func() {
- close(c.closedCh)
- }()
+ a := c.agent()
+
+ defer close(c.closedCh)
select {
case <-initializedCh:
@@ -216,47 +222,73 @@ func (c *candidateBase) recvLoop(initializedCh <-chan struct{}) {
return
}
- log := c.agent().log
- buffer := make([]byte, receiveMTU)
+ buf := make([]byte, receiveMTU)
for {
- n, srcAddr, err := c.conn.ReadFrom(buffer)
+ n, srcAddr, err := c.conn.ReadFrom(buf)
if err != nil {
+ if !(errors.Is(err, io.EOF) || errors.Is(err, net.ErrClosed)) {
+ a.log.Warnf("Failed to read from candidate %s: %v", c, err)
+ }
return
}
- handleInboundCandidateMsg(c, c, buffer[:n], srcAddr, log)
+ c.handleInboundPacket(buf[:n], srcAddr)
}
}
-func handleInboundCandidateMsg(ctx context.Context, c Candidate, buffer []byte, srcAddr net.Addr, log logging.LeveledLogger) {
- if stun.IsMessage(buffer) {
+func (c *candidateBase) validateSTUNTrafficCache(addr net.Addr) bool {
+ if candidate, ok := c.remoteCandidateCaches[toAddrPort(addr)]; ok {
+ candidate.seen(false)
+ return true
+ }
+ return false
+}
+
+func (c *candidateBase) addRemoteCandidateCache(candidate Candidate, srcAddr net.Addr) {
+ if c.validateSTUNTrafficCache(srcAddr) {
+ return
+ }
+ c.remoteCandidateCaches[toAddrPort(srcAddr)] = candidate
+}
+
+func (c *candidateBase) handleInboundPacket(buf []byte, srcAddr net.Addr) {
+ a := c.agent()
+
+ if stun.IsMessage(buf) {
m := &stun.Message{
- Raw: make([]byte, len(buffer)),
+ Raw: make([]byte, len(buf)),
}
+
// Explicitly copy raw buffer so Message can own the memory.
- copy(m.Raw, buffer)
+ copy(m.Raw, buf)
+
if err := m.Decode(); err != nil {
- log.Warnf("Failed to handle decode ICE from %s to %s: %v", c.addr(), srcAddr, err)
+ a.log.Warnf("Failed to handle decode ICE from %s to %s: %v", c.addr(), srcAddr, err)
return
}
- err := c.agent().run(ctx, func(ctx context.Context, agent *Agent) {
- agent.handleInbound(m, c, srcAddr)
- })
- if err != nil {
- log.Warnf("Failed to handle message: %v", err)
+
+ if err := a.run(c, func(ctx context.Context, a *Agent) {
+ a.handleInbound(m, c, srcAddr)
+ }); err != nil {
+ a.log.Warnf("Failed to handle message: %v", err)
}
return
}
- if !c.agent().validateNonSTUNTraffic(c, srcAddr) {
- log.Warnf("Discarded message from %s, not a valid remote candidate", c.addr())
- return
+ if !c.validateSTUNTrafficCache(srcAddr) {
+ remoteCandidate, valid := a.validateNonSTUNTraffic(c, srcAddr) //nolint:contextcheck
+ if !valid {
+ a.log.Warnf("Discarded message from %s, not a valid remote candidate", c.addr())
+ return
+ }
+ c.addRemoteCandidateCache(remoteCandidate, srcAddr)
}
- // NOTE This will return packetio.ErrFull if the buffer ever manages to fill up.
- if _, err := c.agent().buffer.Write(buffer); err != nil {
- log.Warnf("failed to write packet")
+ // Note: This will return packetio.ErrFull if the buffer ever manages to fill up.
+ if _, err := a.buf.Write(buf); err != nil {
+ a.log.Warnf("Failed to write packet: %s", err)
+ return
}
}
@@ -300,7 +332,11 @@ func (c *candidateBase) close() error {
func (c *candidateBase) writeTo(raw []byte, dst Candidate) (int, error) {
n, err := c.conn.WriteTo(raw, dst.addr())
if err != nil {
- c.agent().log.Warnf("%s: %v", errSendPacket, err)
+ // If the connection is closed, we should return the error
+ if errors.Is(err, io.ErrClosedPipe) {
+ return n, err
+ }
+ c.agent().log.Infof("%s: %v", errSendPacket, err)
return n, nil
}
c.seen(true)
@@ -336,17 +372,16 @@ func (c *candidateBase) Equal(other Candidate) bool {
// String makes the candidateBase printable
func (c *candidateBase) String() string {
- return fmt.Sprintf("%s %s %s:%d%s", c.NetworkType(), c.Type(), c.Address(), c.Port(), c.relatedAddress)
+ return fmt.Sprintf("%s %s %s%s", c.NetworkType(), c.Type(), net.JoinHostPort(c.Address(), strconv.Itoa(c.Port())), c.relatedAddress)
}
// LastReceived returns a time.Time indicating the last time
// this candidate was received
func (c *candidateBase) LastReceived() time.Time {
- lastReceived := c.lastReceived.Load()
- if lastReceived == nil {
- return time.Time{}
+ if lastReceived, ok := c.lastReceived.Load().(time.Time); ok {
+ return lastReceived
}
- return lastReceived.(time.Time)
+ return time.Time{}
}
func (c *candidateBase) setLastReceived(t time.Time) {
@@ -356,11 +391,10 @@ func (c *candidateBase) setLastReceived(t time.Time) {
// LastSent returns a time.Time indicating the last time
// this candidate was sent
func (c *candidateBase) LastSent() time.Time {
- lastSent := c.lastSent.Load()
- if lastSent == nil {
- return time.Time{}
+ if lastSent, ok := c.lastSent.Load().(time.Time); ok {
+ return lastSent
}
- return lastSent.(time.Time)
+ return time.Time{}
}
func (c *candidateBase) setLastSent(t time.Time) {
@@ -387,10 +421,19 @@ func (c *candidateBase) context() context.Context {
return c
}
+func (c *candidateBase) copy() (Candidate, error) {
+ return UnmarshalCandidate(c.Marshal())
+}
+
// Marshal returns the string representation of the ICECandidate
func (c *candidateBase) Marshal() string {
- val := fmt.Sprintf("%s %d %s %d %s %d typ %s",
- c.Foundation(),
+ val := c.Foundation()
+ if val == " " {
+ val = ""
+ }
+
+ val = fmt.Sprintf("%s %d %s %d %s %d typ %s",
+ val,
c.Component(),
c.NetworkType().NetworkShort(),
c.Priority(),
@@ -402,11 +445,11 @@ func (c *candidateBase) Marshal() string {
val += fmt.Sprintf(" tcptype %s", c.tcpType.String())
}
- if c.RelatedAddress() != nil {
+ if r := c.RelatedAddress(); r != nil && r.Address != "" && r.Port != 0 {
val = fmt.Sprintf("%s raddr %s rport %d",
val,
- c.RelatedAddress().Address,
- c.RelatedAddress().Port)
+ r.Address,
+ r.Port)
}
return val
@@ -415,6 +458,10 @@ func (c *candidateBase) Marshal() string {
// UnmarshalCandidate creates a Candidate from its string representation
func UnmarshalCandidate(raw string) (Candidate, error) {
split := strings.Fields(raw)
+ // Foundation not specified: not RFC 8445 compliant but seen in the wild
+ if len(raw) != 0 && raw[0] == ' ' {
+ split = append([]string{" "}, split...)
+ }
if len(split) < 8 {
return nil, fmt.Errorf("%w (%d)", errAttributeTooShortICECandidate, len(split))
}
@@ -425,7 +472,7 @@ func UnmarshalCandidate(raw string) (Candidate, error) {
// Component
rawComponent, err := strconv.ParseUint(split[1], 10, 16)
if err != nil {
- return nil, fmt.Errorf("%w: %v", errParseComponent, err)
+ return nil, fmt.Errorf("%w: %v", errParseComponent, err) //nolint:errorlint
}
component := uint16(rawComponent)
@@ -435,7 +482,7 @@ func UnmarshalCandidate(raw string) (Candidate, error) {
// Priority
priorityRaw, err := strconv.ParseUint(split[3], 10, 32)
if err != nil {
- return nil, fmt.Errorf("%w: %v", errParsePriority, err)
+ return nil, fmt.Errorf("%w: %v", errParsePriority, err) //nolint:errorlint
}
priority := uint32(priorityRaw)
@@ -445,7 +492,7 @@ func UnmarshalCandidate(raw string) (Candidate, error) {
// Port
rawPort, err := strconv.ParseUint(split[5], 10, 16)
if err != nil {
- return nil, fmt.Errorf("%w: %v", errParsePort, err)
+ return nil, fmt.Errorf("%w: %v", errParsePort, err) //nolint:errorlint
}
port := int(rawPort)
typ := split[7]
@@ -468,12 +515,12 @@ func UnmarshalCandidate(raw string) (Candidate, error) {
// RelatedPort
rawRelatedPort, parseErr := strconv.ParseUint(split[3], 10, 16)
if parseErr != nil {
- return nil, fmt.Errorf("%w: %v", errParsePort, parseErr)
+ return nil, fmt.Errorf("%w: %v", errParsePort, parseErr) //nolint:errorlint
}
relatedPort = int(rawRelatedPort)
} else if split[0] == "tcptype" {
if len(split) < 2 {
- return nil, fmt.Errorf("%w: incorrect length", errParseTypType)
+ return nil, fmt.Errorf("%w: incorrect length", errParseTCPType)
}
tcpType = NewTCPType(split[1])
@@ -488,9 +535,9 @@ func UnmarshalCandidate(raw string) (Candidate, error) {
case "prflx":
return NewCandidatePeerReflexive(&CandidatePeerReflexiveConfig{"", protocol, address, port, component, priority, foundation, relatedAddress, relatedPort})
case "relay":
- return NewCandidateRelay(&CandidateRelayConfig{"", protocol, address, port, component, priority, foundation, relatedAddress, relatedPort, nil})
+ return NewCandidateRelay(&CandidateRelayConfig{"", protocol, address, port, component, priority, foundation, relatedAddress, relatedPort, "", nil})
default:
}
- return nil, fmt.Errorf("%w (%s)", errUnknownCandidateTyp, typ)
+ return nil, fmt.Errorf("%w (%s)", ErrUnknownCandidateTyp, typ)
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_host.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_host.go
index b03dbdb51..5d207dd91 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_host.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_host.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
@@ -34,14 +37,15 @@ func NewCandidateHost(config *CandidateHostConfig) (*CandidateHost, error) {
c := &CandidateHost{
candidateBase: candidateBase{
- id: candidateID,
- address: config.Address,
- candidateType: CandidateTypeHost,
- component: config.Component,
- port: config.Port,
- tcpType: config.TCPType,
- foundationOverride: config.Foundation,
- priorityOverride: config.Priority,
+ id: candidateID,
+ address: config.Address,
+ candidateType: CandidateTypeHost,
+ component: config.Component,
+ port: config.Port,
+ tcpType: config.TCPType,
+ foundationOverride: config.Foundation,
+ priorityOverride: config.Priority,
+ remoteCandidateCaches: map[AddrPort]Candidate{},
},
network: config.Network,
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_peer_reflexive.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_peer_reflexive.go
index 0b330d1c9..f019ec698 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_peer_reflexive.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_peer_reflexive.go
@@ -1,4 +1,8 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
// Package ice ...
+//
//nolint:dupl
package ice
@@ -55,6 +59,7 @@ func NewCandidatePeerReflexive(config *CandidatePeerReflexiveConfig) (*Candidate
Address: config.RelAddr,
Port: config.RelPort,
},
+ remoteCandidateCaches: map[AddrPort]Candidate{},
},
}, nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_relay.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_relay.go
index 44762f714..449d077a6 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_relay.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_relay.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
@@ -8,21 +11,23 @@ import (
type CandidateRelay struct {
candidateBase
- onClose func() error
+ relayProtocol string
+ onClose func() error
}
// CandidateRelayConfig is the config required to create a new CandidateRelay
type CandidateRelayConfig struct {
- CandidateID string
- Network string
- Address string
- Port int
- Component uint16
- Priority uint32
- Foundation string
- RelAddr string
- RelPort int
- OnClose func() error
+ CandidateID string
+ Network string
+ Address string
+ Port int
+ Component uint16
+ Priority uint32
+ Foundation string
+ RelAddr string
+ RelPort int
+ RelayProtocol string
+ OnClose func() error
}
// NewCandidateRelay creates a new relay candidate
@@ -58,11 +63,18 @@ func NewCandidateRelay(config *CandidateRelayConfig) (*CandidateRelay, error) {
Address: config.RelAddr,
Port: config.RelPort,
},
+ remoteCandidateCaches: map[AddrPort]Candidate{},
},
- onClose: config.OnClose,
+ relayProtocol: config.RelayProtocol,
+ onClose: config.OnClose,
}, nil
}
+// RelayProtocol returns the protocol used between the endpoint and the relay server.
+func (c *CandidateRelay) RelayProtocol() string {
+ return c.relayProtocol
+}
+
func (c *CandidateRelay) close() error {
err := c.candidateBase.close()
if c.onClose != nil {
@@ -71,3 +83,16 @@ func (c *CandidateRelay) close() error {
}
return err
}
+
+func (c *CandidateRelay) copy() (Candidate, error) {
+ cc, err := c.candidateBase.copy()
+ if err != nil {
+ return nil, err
+ }
+
+ if ccr, ok := cc.(*CandidateRelay); ok {
+ ccr.relayProtocol = c.relayProtocol
+ }
+
+ return cc, nil
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_server_reflexive.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_server_reflexive.go
index 125a53782..3a8ac0ff7 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_server_reflexive.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidate_server_reflexive.go
@@ -1,5 +1,6 @@
-// Package ice ...
-//nolint:dupl
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import "net"
@@ -54,6 +55,7 @@ func NewCandidateServerReflexive(config *CandidateServerReflexiveConfig) (*Candi
Address: config.RelAddr,
Port: config.RelPort,
},
+ remoteCandidateCaches: map[AddrPort]Candidate{},
},
}, nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidatepair.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidatepair.go
index 49dec373e..f33be539c 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidatepair.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidatepair.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
@@ -6,42 +9,44 @@ import (
"github.com/pion/stun"
)
-func newCandidatePair(local, remote Candidate, controlling bool) *candidatePair {
- return &candidatePair{
+func newCandidatePair(local, remote Candidate, controlling bool) *CandidatePair {
+ return &CandidatePair{
iceRoleControlling: controlling,
- remote: remote,
- local: local,
+ Remote: remote,
+ Local: local,
state: CandidatePairStateWaiting,
}
}
-// candidatePair represents a combination of a local and remote candidate
-type candidatePair struct {
- iceRoleControlling bool
- remote Candidate
- local Candidate
- bindingRequestCount uint16
- state CandidatePairState
- nominated bool
+// CandidatePair is a combination of a
+// local and remote candidate
+type CandidatePair struct {
+ iceRoleControlling bool
+ Remote Candidate
+ Local Candidate
+ bindingRequestCount uint16
+ state CandidatePairState
+ nominated bool
+ nominateOnBindingSuccess bool
}
-func (p *candidatePair) String() string {
+func (p *CandidatePair) String() string {
if p == nil {
return ""
}
return fmt.Sprintf("prio %d (local, prio %d) %s <-> %s (remote, prio %d)",
- p.Priority(), p.local.Priority(), p.local, p.remote, p.remote.Priority())
+ p.priority(), p.Local.Priority(), p.Local, p.Remote, p.Remote.Priority())
}
-func (p *candidatePair) Equal(other *candidatePair) bool {
+func (p *CandidatePair) equal(other *CandidatePair) bool {
if p == nil && other == nil {
return true
}
if p == nil || other == nil {
return false
}
- return p.local.Equal(other.local) && p.remote.Equal(other.remote)
+ return p.Local.Equal(other.Local) && p.Remote.Equal(other.Remote)
}
// RFC 5245 - 5.7.2. Computing Pair Priority and Ordering Pairs
@@ -49,15 +54,14 @@ func (p *candidatePair) Equal(other *candidatePair) bool {
// agent. Let D be the priority for the candidate provided by the
// controlled agent.
// pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0)
-func (p *candidatePair) Priority() uint64 {
- var g uint32
- var d uint32
+func (p *CandidatePair) priority() uint64 {
+ var g, d uint32
if p.iceRoleControlling {
- g = p.local.Priority()
- d = p.remote.Priority()
+ g = p.Local.Priority()
+ d = p.Remote.Priority()
} else {
- g = p.remote.Priority()
- d = p.local.Priority()
+ g = p.Remote.Priority()
+ d = p.Local.Priority()
}
// Just implement these here rather
@@ -86,8 +90,8 @@ func (p *candidatePair) Priority() uint64 {
return (1<<32-1)*min(g, d) + 2*max(g, d) + cmp(g, d)
}
-func (p *candidatePair) Write(b []byte) (int, error) {
- return p.local.writeTo(b, p.remote)
+func (p *CandidatePair) Write(b []byte) (int, error) {
+ return p.Local.writeTo(b, p.Remote)
}
func (a *Agent) sendSTUN(msg *stun.Message, local, remote Candidate) {
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidatepair_state.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidatepair_state.go
index 28c7187eb..1a1e827b0 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidatepair_state.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidatepair_state.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
// CandidatePairState represent the ICE candidate pair state
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidaterelatedaddress.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidaterelatedaddress.go
index 18cf31831..e87c70514 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidaterelatedaddress.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidaterelatedaddress.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import "fmt"
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidatetype.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidatetype.go
index 376c4089f..3972934cb 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidatetype.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/candidatetype.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
// CandidateType represents the type of candidate
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/codecov.yml b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/codecov.yml
index 085200a48..263e4d45c 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/codecov.yml
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/codecov.yml
@@ -3,6 +3,8 @@
#
# It is automatically copied from https://github.com/pion/.goassets repository.
#
+# SPDX-FileCopyrightText: 2023 The Pion community
+# SPDX-License-Identifier: MIT
coverage:
status:
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/context.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/context.go
index 627d81ef4..36454450c 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/context.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/context.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
@@ -32,6 +35,6 @@ func (a agentContext) Deadline() (deadline time.Time, ok bool) {
}
// Value implements context.Context
-func (a agentContext) Value(key interface{}) interface{} {
+func (a agentContext) Value(interface{}) interface{} {
return nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/errors.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/errors.go
index e7dd625d4..e05cce898 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/errors.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/errors.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import "errors"
@@ -10,7 +13,7 @@ var (
ErrSchemeType = errors.New("unknown scheme type")
// ErrSTUNQuery indicates query arguments are provided in a STUN URL.
- ErrSTUNQuery = errors.New("queries not supported in stun address")
+ ErrSTUNQuery = errors.New("queries not supported in STUN address")
// ErrInvalidQuery indicates an malformed query is provided.
ErrInvalidQuery = errors.New("invalid query")
@@ -25,7 +28,7 @@ var (
// Have to be at least 24 bits long
ErrLocalUfragInsufficientBits = errors.New("local username fragment is less than 24 bits long")
- // ErrLocalPwdInsufficientBits indicates local passoword insufficient bits are provided.
+ // ErrLocalPwdInsufficientBits indicates local password insufficient bits are provided.
// Have to be at least 128 bits long
ErrLocalPwdInsufficientBits = errors.New("local password is less than 128 bits long")
@@ -97,36 +100,43 @@ var (
// ErrInvalidMulticastDNSHostName indicates an invalid MulticastDNSHostName
ErrInvalidMulticastDNSHostName = errors.New("invalid mDNS HostName, must end with .local and can only contain a single '.'")
- // ErrRestartWhenGathering indicates Restart was called when Agent is in GatheringStateGathering
- ErrRestartWhenGathering = errors.New("ICE Agent can not be restarted when gathering")
-
// ErrRunCanceled indicates a run operation was canceled by its individual done
ErrRunCanceled = errors.New("run was canceled by done")
- // ErrTCPMuxNotInitialized indicates TCPMux is not initialized and that invalidTCPMux is used.
- ErrTCPMuxNotInitialized = errors.New("TCPMux is not initialized")
-
// ErrTCPRemoteAddrAlreadyExists indicates we already have the connection with same remote addr.
ErrTCPRemoteAddrAlreadyExists = errors.New("conn with same remote addr already exists")
+ // ErrUnknownCandidateTyp indicates that a candidate had a unknown type value.
+ ErrUnknownCandidateTyp = errors.New("unknown candidate typ")
+
+ // ErrDetermineNetworkType indicates that the NetworkType was not able to be parsed
+ ErrDetermineNetworkType = errors.New("unable to determine networkType")
+
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")
errParsePriority = errors.New("could not parse priority")
errParsePort = errors.New("could not parse port")
errParseRelatedAddr = errors.New("could not parse related addresses")
- errParseTypType = errors.New("could not parse typtype")
- errUnknownCandidateTyp = errors.New("unknown candidate typ")
+ errParseTCPType = errors.New("could not parse TCP type")
errGetXorMappedAddrResponse = errors.New("failed to get XOR-MAPPED-ADDRESS response")
errConnectionAddrAlreadyExist = errors.New("connection with same remote address already exists")
errReadingStreamingPacket = errors.New("error reading streaming packet")
errWriting = errors.New("error writing to")
errClosingConnection = errors.New("error closing connection")
- errDetermineNetworkType = errors.New("unable to determine networkType")
- errMissingProtocolScheme = errors.New("missing protocol scheme")
- errTooManyColonsAddr = errors.New("too many colons in address")
errRead = errors.New("unexpected error trying to read")
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")
+ errNoXorAddrMapping = errors.New("no address mapping")
+ errSendSTUNPacket = errors.New("failed to send STUN packet")
+ errXORMappedAddrTimeout = errors.New("timeout while waiting for XORMappedAddr")
+ errNotImplemented = errors.New("not implemented yet")
+ errNoUDPMuxAvailable = errors.New("no UDP mux is available")
+ errNoTCPMuxAvailable = errors.New("no TCP mux is available")
+ errInvalidAddress = errors.New("invalid address")
+
+ // UDPMuxDefault should not listen on unspecified address, but to keep backward compatibility, don't return error now.
+ // will be used in the future.
+ // errListenUnspecified = errors.New("can't listen on unspecified address")
)
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/external_ip_mapper.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/external_ip_mapper.go
index 5310cc0ae..3d542fb1a 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/external_ip_mapper.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/external_ip_mapper.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
@@ -15,8 +18,9 @@ func validateIPString(ipStr string) (net.IP, bool, error) {
// ipMapping holds the mapping of local and external IP address for a particular IP family
type ipMapping struct {
- ipSole net.IP // when non-nil, this is the sole external IP for one local IP assumed
- ipMap map[string]net.IP // local-to-external IP mapping (k: local, v: external)
+ ipSole net.IP // When non-nil, this is the sole external IP for one local IP assumed
+ ipMap map[string]net.IP // Local-to-external IP mapping (k: local, v: external)
+ valid bool // If not set any external IP, valid is false
}
func (m *ipMapping) setSoleIP(ip net.IP) error {
@@ -25,6 +29,7 @@ func (m *ipMapping) setSoleIP(ip net.IP) error {
}
m.ipSole = ip
+ m.valid = true
return nil
}
@@ -36,17 +41,22 @@ func (m *ipMapping) addIPMapping(locIP, extIP net.IP) error {
locIPStr := locIP.String()
- // check if dup of local IP
+ // Check if dup of local IP
if _, ok := m.ipMap[locIPStr]; ok {
return ErrInvalidNAT1To1IPMapping
}
m.ipMap[locIPStr] = extIP
+ m.valid = true
return nil
}
func (m *ipMapping) findExternalIP(locIP net.IP) (net.IP, error) {
+ if !m.valid {
+ return locIP, nil
+ }
+
if m.ipSole != nil {
return m.ipSole, nil
}
@@ -67,10 +77,10 @@ type externalIPMapper struct {
func newExternalIPMapper(candidateType CandidateType, ips []string) (*externalIPMapper, error) { //nolint:gocognit
if len(ips) == 0 {
- return nil, nil
+ return nil, nil //nolint:nilnil
}
if candidateType == CandidateTypeUnspecified {
- candidateType = CandidateTypeHost // defaults to host
+ candidateType = CandidateTypeHost // Defaults to host
} else if candidateType != CandidateTypeHost && candidateType != CandidateTypeServerReflexive {
return nil, ErrUnsupportedNAT1To1IPCandidateType
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/gather.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/gather.go
index 3bc3d7729..15e2da146 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/gather.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/gather.go
@@ -1,17 +1,23 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
"context"
"crypto/tls"
- "errors"
"fmt"
+ "io"
"net"
"reflect"
"sync"
"time"
"github.com/pion/dtls/v2"
+ "github.com/pion/ice/v2/internal/fakenet"
+ stunx "github.com/pion/ice/v2/internal/stun"
"github.com/pion/logging"
+ "github.com/pion/stun"
"github.com/pion/turn/v2"
)
@@ -19,42 +25,19 @@ const (
stunGatherTimeout = time.Second * 5
)
-type closeable interface {
- Close() error
-}
-
// Close a net.Conn and log if we have a failure
-func closeConnAndLog(c closeable, log logging.LeveledLogger, msg string) {
+func closeConnAndLog(c io.Closer, log logging.LeveledLogger, msg string, args ...interface{}) {
if c == nil || (reflect.ValueOf(c).Kind() == reflect.Ptr && reflect.ValueOf(c).IsNil()) {
- log.Warnf("Conn is not allocated (%s)", msg)
+ log.Warnf("Connection is not allocated: "+msg, args...)
return
}
log.Warnf(msg)
if err := c.Close(); err != nil {
- log.Warnf("Failed to close conn: %v", err)
+ log.Warnf("Failed to close connection: %v", err)
}
}
-// fakePacketConn wraps a net.Conn and emulates net.PacketConn
-type fakePacketConn struct {
- nextConn net.Conn
-}
-
-func (f *fakePacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
- n, err = f.nextConn.Read(p)
- addr = f.nextConn.RemoteAddr()
- return
-}
-func (f *fakePacketConn) Close() error { return f.nextConn.Close() }
-func (f *fakePacketConn) LocalAddr() net.Addr { return f.nextConn.LocalAddr() }
-func (f *fakePacketConn) SetDeadline(t time.Time) error { return f.nextConn.SetDeadline(t) }
-func (f *fakePacketConn) SetReadDeadline(t time.Time) error { return f.nextConn.SetReadDeadline(t) }
-func (f *fakePacketConn) SetWriteDeadline(t time.Time) error { return f.nextConn.SetWriteDeadline(t) }
-func (f *fakePacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
- return f.nextConn.Write(p)
-}
-
// GatherCandidates initiates the trickle based gathering process.
func (a *Agent) GatherCandidates() error {
var gatherErr error
@@ -71,17 +54,20 @@ func (a *Agent) GatherCandidates() error {
a.gatherCandidateCancel() // Cancel previous gathering routine
ctx, cancel := context.WithCancel(ctx)
a.gatherCandidateCancel = cancel
+ done := make(chan struct{})
+ a.gatherCandidateDone = done
- go a.gatherCandidates(ctx)
+ go a.gatherCandidates(ctx, done)
}); runErr != nil {
return runErr
}
return gatherErr
}
-func (a *Agent) gatherCandidates(ctx context.Context) {
- if err := a.setGatheringState(GatheringStateGathering); err != nil {
- a.log.Warnf("failed to set gatheringState to GatheringStateGathering: %v", err)
+func (a *Agent) gatherCandidates(ctx context.Context, done chan struct{}) {
+ defer close(done)
+ if err := a.setGatheringState(GatheringStateGathering); err != nil { //nolint:contextcheck
+ a.log.Warnf("Failed to set gatheringState to GatheringStateGathering: %v", err)
return
}
@@ -97,7 +83,11 @@ func (a *Agent) gatherCandidates(ctx context.Context) {
case CandidateTypeServerReflexive:
wg.Add(1)
go func() {
- a.gatherCandidatesSrflx(ctx, a.urls, a.networkTypes)
+ if a.udpMuxSrflx != nil {
+ a.gatherCandidatesSrflxUDPMux(ctx, a.urls, a.networkTypes)
+ } else {
+ a.gatherCandidatesSrflx(ctx, a.urls, a.networkTypes)
+ }
wg.Done()
}()
if a.extIPMapper != nil && a.extIPMapper.candidateType == CandidateTypeServerReflexive {
@@ -116,11 +106,12 @@ func (a *Agent) gatherCandidates(ctx context.Context) {
case CandidateTypePeerReflexive, CandidateTypeUnspecified:
}
}
+
// Block until all STUN and TURN URLs have been gathered (or timed out)
wg.Wait()
- if err := a.setGatheringState(GatheringStateComplete); err != nil {
- a.log.Warnf("failed to set gatheringState to GatheringStateComplete: %v", err)
+ if err := a.setGatheringState(GatheringStateComplete); err != nil { //nolint:contextcheck
+ a.log.Warnf("Failed to set gatheringState to GatheringStateComplete: %v", err)
}
}
@@ -134,19 +125,27 @@ func (a *Agent) gatherCandidatesLocal(ctx context.Context, networkTypes []Networ
}
}
- localIPs, err := localInterfaces(a.net, a.interfaceFilter, networkTypes)
+ // When UDPMux is enabled, skip other UDP candidates
+ if a.udpMux != nil {
+ if err := a.gatherCandidatesLocalUDPMux(ctx); err != nil {
+ a.log.Warnf("Failed to create host candidate for UDPMux: %s", err)
+ }
+ delete(networks, udp)
+ }
+
+ localIPs, err := localInterfaces(a.net, a.interfaceFilter, a.ipFilter, networkTypes, a.includeLoopback)
if err != nil {
- a.log.Warnf("failed to iterate local interfaces, host candidates will not be gathered %s", err)
+ a.log.Warnf("Failed to iterate local interfaces, host candidates will not be gathered %s", err)
return
}
for _, ip := range localIPs {
mappedIP := ip
if a.mDNSMode != MulticastDNSModeQueryAndGather && a.extIPMapper != nil && a.extIPMapper.candidateType == CandidateTypeHost {
- if _mappedIP, err := a.extIPMapper.findExternalIP(ip.String()); err == nil {
+ if _mappedIP, innerErr := a.extIPMapper.findExternalIP(ip.String()); innerErr == nil {
mappedIP = _mappedIP
} else {
- a.log.Warnf("1:1 NAT mapping is enabled but no external IP is found for %s\n", ip.String())
+ a.log.Warnf("1:1 NAT mapping is enabled but no external IP is found for %s", ip.String())
}
}
@@ -156,67 +155,168 @@ func (a *Agent) gatherCandidatesLocal(ctx context.Context, networkTypes []Networ
}
for network := range networks {
- var port int
- var conn net.PacketConn
- var err error
+ type connAndPort struct {
+ conn net.PacketConn
+ port int
+ }
+ var (
+ conns []connAndPort
+ tcpType TCPType
+ )
- var tcpType TCPType
switch network {
case tcp:
- // Handle ICE TCP passive mode
-
- a.log.Debugf("GetConn by ufrag: %s\n", a.localUfrag)
- conn, err = a.tcpMux.GetConnByUfrag(a.localUfrag)
- if err != nil {
- if !errors.Is(err, ErrTCPMuxNotInitialized) {
- a.log.Warnf("error getting tcp conn by ufrag: %s %s %s\n", network, ip, a.localUfrag)
- }
+ if a.tcpMux == nil {
+ continue
+ }
+
+ // Handle ICE TCP passive mode
+ var muxConns []net.PacketConn
+ if multi, ok := a.tcpMux.(AllConnsGetter); ok {
+ a.log.Debugf("GetAllConns by ufrag: %s", a.localUfrag)
+ muxConns, err = multi.GetAllConns(a.localUfrag, mappedIP.To4() == nil, ip)
+ if err != nil {
+ a.log.Warnf("Failed to get all TCP connections by ufrag: %s %s %s", network, ip, a.localUfrag)
+ continue
+ }
+ } else {
+ a.log.Debugf("GetConn by ufrag: %s", a.localUfrag)
+ conn, err := a.tcpMux.GetConnByUfrag(a.localUfrag, mappedIP.To4() == nil, ip)
+ if err != nil {
+ a.log.Warnf("Failed to get TCP connections by ufrag: %s %s %s", network, ip, a.localUfrag)
+ continue
+ }
+ muxConns = []net.PacketConn{conn}
+ }
+
+ // Extract the port for each PacketConn we got.
+ for _, conn := range muxConns {
+ if tcpConn, ok := conn.LocalAddr().(*net.TCPAddr); ok {
+ conns = append(conns, connAndPort{conn, tcpConn.Port})
+ } else {
+ a.log.Warnf("Failed to get port of connection from TCPMux: %s %s %s", network, ip, a.localUfrag)
+ }
+ }
+ if len(conns) == 0 {
+ // Didn't succeed with any, try the next network.
continue
}
- port = conn.LocalAddr().(*net.TCPAddr).Port
tcpType = TCPTypePassive
- // is there a way to verify that the listen address is even
+ // Is there a way to verify that the listen address is even
// accessible from the current interface.
case udp:
- conn, err = listenUDPInPortRange(a.net, a.log, int(a.portmax), int(a.portmin), network, &net.UDPAddr{IP: ip, Port: 0})
+ 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)
+ a.log.Warnf("Failed to listen %s %s", network, ip)
continue
}
- port = conn.LocalAddr().(*net.UDPAddr).Port
- }
- hostConfig := CandidateHostConfig{
- Network: network,
- Address: address,
- Port: port,
- Component: ComponentRTP,
- TCPType: tcpType,
- }
-
- c, err := NewCandidateHost(&hostConfig)
- if err != nil {
- closeConnAndLog(conn, a.log, fmt.Sprintf("Failed to create host candidate: %s %s %d: %v\n", network, mappedIP, port, err))
- continue
- }
-
- if a.mDNSMode == MulticastDNSModeQueryAndGather {
- if err = c.setIP(ip); err != nil {
- closeConnAndLog(conn, a.log, fmt.Sprintf("Failed to create host candidate: %s %s %d: %v\n", network, mappedIP, port, err))
+ if udpConn, ok := conn.LocalAddr().(*net.UDPAddr); ok {
+ conns = append(conns, connAndPort{conn, udpConn.Port})
+ } else {
+ a.log.Warnf("Failed to get port of UDPAddr from ListenUDPInPortRange: %s %s %s", network, ip, a.localUfrag)
continue
}
}
- if err := a.addCandidate(ctx, c, conn); err != nil {
- if closeErr := c.close(); closeErr != nil {
- a.log.Warnf("Failed to close candidate: %v", closeErr)
+ for _, connAndPort := range conns {
+ hostConfig := CandidateHostConfig{
+ Network: network,
+ Address: address,
+ Port: connAndPort.port,
+ Component: ComponentRTP,
+ TCPType: tcpType,
+ }
+
+ c, err := NewCandidateHost(&hostConfig)
+ if err != nil {
+ closeConnAndLog(connAndPort.conn, a.log, "failed to create host candidate: %s %s %d: %v", network, mappedIP, connAndPort.port, err)
+ continue
+ }
+
+ if a.mDNSMode == MulticastDNSModeQueryAndGather {
+ if err = c.setIP(ip); err != nil {
+ closeConnAndLog(connAndPort.conn, a.log, "failed to create host candidate: %s %s %d: %v", network, mappedIP, connAndPort.port, err)
+ continue
+ }
+ }
+
+ if err := a.addCandidate(ctx, c, connAndPort.conn); err != nil {
+ if closeErr := c.close(); closeErr != nil {
+ a.log.Warnf("Failed to close candidate: %v", closeErr)
+ }
+ a.log.Warnf("Failed to append to localCandidates and run onCandidateHdlr: %v", err)
}
- a.log.Warnf("Failed to append to localCandidates and run onCandidateHdlr: %v\n", err)
}
}
}
}
+func (a *Agent) gatherCandidatesLocalUDPMux(ctx context.Context) error { //nolint:gocognit
+ if a.udpMux == nil {
+ return errUDPMuxDisabled
+ }
+
+ localAddresses := a.udpMux.GetListenAddresses()
+ existingConfigs := make(map[CandidateHostConfig]struct{})
+
+ for _, addr := range localAddresses {
+ udpAddr, ok := addr.(*net.UDPAddr)
+ if !ok {
+ return errInvalidAddress
+ }
+ candidateIP := udpAddr.IP
+ if a.extIPMapper != nil && a.extIPMapper.candidateType == CandidateTypeHost {
+ mappedIP, err := a.extIPMapper.findExternalIP(candidateIP.String())
+ if err != nil {
+ a.log.Warnf("1:1 NAT mapping is enabled but no external IP is found for %s", candidateIP.String())
+ continue
+ }
+
+ candidateIP = mappedIP
+ }
+
+ hostConfig := CandidateHostConfig{
+ Network: udp,
+ Address: candidateIP.String(),
+ Port: udpAddr.Port,
+ Component: ComponentRTP,
+ }
+
+ // Detect a duplicate candidate before calling addCandidate().
+ // otherwise, addCandidate() detects the duplicate candidate
+ // and close its connection, invalidating all candidates
+ // that share the same connection.
+ if _, ok := existingConfigs[hostConfig]; ok {
+ continue
+ }
+
+ conn, err := a.udpMux.GetConn(a.localUfrag, udpAddr)
+ if err != nil {
+ return err
+ }
+
+ c, err := NewCandidateHost(&hostConfig)
+ if err != nil {
+ closeConnAndLog(conn, a.log, "failed to create host mux candidate: %s %d: %v", candidateIP, udpAddr.Port, err)
+ continue
+ }
+
+ if err := a.addCandidate(ctx, c, conn); err != nil {
+ if closeErr := c.close(); closeErr != nil {
+ a.log.Warnf("Failed to close candidate: %v", closeErr)
+ }
+
+ closeConnAndLog(conn, a.log, "failed to add candidate: %s %d: %v", candidateIP, udpAddr.Port, err)
+ continue
+ }
+
+ existingConfigs[hostConfig] = struct{}{}
+ }
+
+ return nil
+}
+
func (a *Agent) gatherCandidatesSrflxMapped(ctx context.Context, networkTypes []NetworkType) {
var wg sync.WaitGroup
defer wg.Wait()
@@ -230,34 +330,40 @@ func (a *Agent) gatherCandidatesSrflxMapped(ctx context.Context, networkTypes []
wg.Add(1)
go func() {
defer wg.Done()
- conn, err := listenUDPInPortRange(a.net, a.log, int(a.portmax), int(a.portmin), network, &net.UDPAddr{IP: nil, Port: 0})
+
+ conn, err := listenUDPInPortRange(a.net, a.log, int(a.portMax), int(a.portMin), network, &net.UDPAddr{IP: nil, Port: 0})
if err != nil {
- a.log.Warnf("Failed to listen %s: %v\n", network, err)
+ a.log.Warnf("Failed to listen %s: %v", network, err)
return
}
- laddr := conn.LocalAddr().(*net.UDPAddr)
- mappedIP, err := a.extIPMapper.findExternalIP(laddr.IP.String())
+ lAddr, ok := conn.LocalAddr().(*net.UDPAddr)
+ if !ok {
+ closeConnAndLog(conn, a.log, "1:1 NAT mapping is enabled but LocalAddr is not a UDPAddr")
+ return
+ }
+
+ mappedIP, err := a.extIPMapper.findExternalIP(lAddr.IP.String())
if err != nil {
- closeConnAndLog(conn, a.log, fmt.Sprintf("1:1 NAT mapping is enabled but no external IP is found for %s\n", laddr.IP.String()))
+ closeConnAndLog(conn, a.log, "1:1 NAT mapping is enabled but no external IP is found for %s", lAddr.IP.String())
return
}
srflxConfig := CandidateServerReflexiveConfig{
Network: network,
Address: mappedIP.String(),
- Port: laddr.Port,
+ Port: lAddr.Port,
Component: ComponentRTP,
- RelAddr: laddr.IP.String(),
- RelPort: laddr.Port,
+ RelAddr: lAddr.IP.String(),
+ RelPort: lAddr.Port,
}
c, err := NewCandidateServerReflexive(&srflxConfig)
if err != nil {
- closeConnAndLog(conn, a.log, fmt.Sprintf("Failed to create server reflexive candidate: %s %s %d: %v\n",
+ closeConnAndLog(conn, a.log, "failed to create server reflexive candidate: %s %s %d: %v",
network,
mappedIP.String(),
- laddr.Port,
- err))
+ lAddr.Port,
+ err)
return
}
@@ -265,13 +371,81 @@ func (a *Agent) gatherCandidatesSrflxMapped(ctx context.Context, networkTypes []
if closeErr := c.close(); closeErr != nil {
a.log.Warnf("Failed to close candidate: %v", closeErr)
}
- a.log.Warnf("Failed to append to localCandidates and run onCandidateHdlr: %v\n", err)
+ a.log.Warnf("Failed to append to localCandidates and run onCandidateHdlr: %v", err)
}
}()
}
}
-func (a *Agent) gatherCandidatesSrflx(ctx context.Context, urls []*URL, networkTypes []NetworkType) {
+func (a *Agent) gatherCandidatesSrflxUDPMux(ctx context.Context, urls []*stun.URI, networkTypes []NetworkType) { //nolint:gocognit
+ var wg sync.WaitGroup
+ defer wg.Wait()
+
+ for _, networkType := range networkTypes {
+ if networkType.IsTCP() {
+ continue
+ }
+
+ for i := range urls {
+ for _, listenAddr := range a.udpMuxSrflx.GetListenAddresses() {
+ udpAddr, ok := listenAddr.(*net.UDPAddr)
+ if !ok {
+ a.log.Warn("Failed to cast udpMuxSrflx listen address to UDPAddr")
+ continue
+ }
+ wg.Add(1)
+ go func(url stun.URI, network string, localAddr *net.UDPAddr) {
+ defer wg.Done()
+
+ hostPort := fmt.Sprintf("%s:%d", url.Host, url.Port)
+ serverAddr, err := a.net.ResolveUDPAddr(network, hostPort)
+ if err != nil {
+ a.log.Warnf("Failed to resolve STUN host: %s: %v", hostPort, err)
+ return
+ }
+
+ xorAddr, err := a.udpMuxSrflx.GetXORMappedAddr(serverAddr, stunGatherTimeout)
+ if err != nil {
+ a.log.Warnf("Failed get server reflexive address %s %s: %v", network, url, err)
+ return
+ }
+
+ conn, err := a.udpMuxSrflx.GetConnForURL(a.localUfrag, url.String(), localAddr)
+ if err != nil {
+ a.log.Warnf("Failed to find connection in UDPMuxSrflx %s %s: %v", network, url, err)
+ return
+ }
+
+ ip := xorAddr.IP
+ port := xorAddr.Port
+
+ srflxConfig := CandidateServerReflexiveConfig{
+ Network: network,
+ Address: ip.String(),
+ Port: port,
+ Component: ComponentRTP,
+ RelAddr: localAddr.IP.String(),
+ RelPort: localAddr.Port,
+ }
+ c, err := NewCandidateServerReflexive(&srflxConfig)
+ if err != nil {
+ closeConnAndLog(conn, a.log, "failed to create server reflexive candidate: %s %s %d: %v", network, ip, port, err)
+ return
+ }
+
+ if err := a.addCandidate(ctx, c, conn); err != nil {
+ if closeErr := c.close(); closeErr != nil {
+ a.log.Warnf("Failed to close candidate: %v", closeErr)
+ }
+ a.log.Warnf("Failed to append to localCandidates and run onCandidateHdlr: %v", err)
+ }
+ }(*urls[i], networkType.String(), udpAddr)
+ }
+ }
+ }
+}
+
+func (a *Agent) gatherCandidatesSrflx(ctx context.Context, urls []*stun.URI, networkTypes []NetworkType) { //nolint:gocognit
var wg sync.WaitGroup
defer wg.Wait()
@@ -282,42 +456,55 @@ func (a *Agent) gatherCandidatesSrflx(ctx context.Context, urls []*URL, networkT
for i := range urls {
wg.Add(1)
- go func(url URL, network string) {
+ go func(url stun.URI, network string) {
defer wg.Done()
+
hostPort := fmt.Sprintf("%s:%d", url.Host, url.Port)
serverAddr, err := a.net.ResolveUDPAddr(network, hostPort)
if err != nil {
- a.log.Warnf("failed to resolve stun host: %s: %v", hostPort, err)
+ a.log.Warnf("Failed to resolve STUN host: %s: %v", hostPort, err)
return
}
- conn, err := listenUDPInPortRange(a.net, a.log, int(a.portmax), int(a.portmin), network, &net.UDPAddr{IP: nil, Port: 0})
+ conn, err := listenUDPInPortRange(a.net, a.log, int(a.portMax), int(a.portMin), network, &net.UDPAddr{IP: nil, Port: 0})
if err != nil {
- closeConnAndLog(conn, a.log, fmt.Sprintf("Failed to listen for %s: %v\n", serverAddr.String(), err))
+ closeConnAndLog(conn, a.log, "failed to listen for %s: %v", serverAddr.String(), err)
return
}
+ // If the agent closes midway through the connection
+ // we end it early to prevent close delay.
+ cancelCtx, cancelFunc := context.WithCancel(ctx)
+ defer cancelFunc()
+ go func() {
+ select {
+ case <-cancelCtx.Done():
+ return
+ case <-a.done:
+ _ = conn.Close()
+ }
+ }()
- xoraddr, err := getXORMappedAddr(conn, serverAddr, stunGatherTimeout)
+ xorAddr, err := stunx.GetXORMappedAddr(conn, serverAddr, stunGatherTimeout)
if err != nil {
- closeConnAndLog(conn, a.log, fmt.Sprintf("could not get server reflexive address %s %s: %v\n", network, url, err))
+ closeConnAndLog(conn, a.log, "failed to get server reflexive address %s %s: %v", network, url, err)
return
}
- ip := xoraddr.IP
- port := xoraddr.Port
+ ip := xorAddr.IP
+ port := xorAddr.Port
- laddr := conn.LocalAddr().(*net.UDPAddr)
+ lAddr := conn.LocalAddr().(*net.UDPAddr) //nolint:forcetypeassert
srflxConfig := CandidateServerReflexiveConfig{
Network: network,
Address: ip.String(),
Port: port,
Component: ComponentRTP,
- RelAddr: laddr.IP.String(),
- RelPort: laddr.Port,
+ RelAddr: lAddr.IP.String(),
+ RelPort: lAddr.Port,
}
c, err := NewCandidateServerReflexive(&srflxConfig)
if err != nil {
- closeConnAndLog(conn, a.log, fmt.Sprintf("Failed to create server reflexive candidate: %s %s %d: %v\n", network, ip, port, err))
+ closeConnAndLog(conn, a.log, "failed to create server reflexive candidate: %s %s %d: %v", network, ip, port, err)
return
}
@@ -325,21 +512,21 @@ func (a *Agent) gatherCandidatesSrflx(ctx context.Context, urls []*URL, networkT
if closeErr := c.close(); closeErr != nil {
a.log.Warnf("Failed to close candidate: %v", closeErr)
}
- a.log.Warnf("Failed to append to localCandidates and run onCandidateHdlr: %v\n", err)
+ a.log.Warnf("Failed to append to localCandidates and run onCandidateHdlr: %v", err)
}
}(*urls[i], networkType.String())
}
}
}
-func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //nolint:gocognit
+func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*stun.URI) { //nolint:gocognit
var wg sync.WaitGroup
defer wg.Wait()
network := NetworkTypeUDP4.String()
for i := range urls {
switch {
- case urls[i].Scheme != SchemeTypeTURN && urls[i].Scheme != SchemeTypeTURNS:
+ case urls[i].Scheme != stun.SchemeTypeTURN && urls[i].Scheme != stun.SchemeTypeTURNS:
continue
case urls[i].Username == "":
a.log.Errorf("Failed to gather relay candidates: %v", ErrUsernameEmpty)
@@ -350,89 +537,124 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //noli
}
wg.Add(1)
- go func(url URL) {
+ go func(url stun.URI) {
defer wg.Done()
- TURNServerAddr := fmt.Sprintf("%s:%d", url.Host, url.Port)
+ turnServerAddr := fmt.Sprintf("%s:%d", url.Host, url.Port)
var (
- locConn net.PacketConn
- err error
- RelAddr string
- RelPort int
+ locConn net.PacketConn
+ err error
+ relAddr string
+ relPort int
+ relayProtocol string
)
switch {
- case url.Proto == ProtoTypeUDP && url.Scheme == SchemeTypeTURN:
+ case url.Proto == stun.ProtoTypeUDP && url.Scheme == stun.SchemeTypeTURN:
if locConn, err = a.net.ListenPacket(network, "0.0.0.0:0"); err != nil {
- a.log.Warnf("Failed to listen %s: %v\n", network, err)
+ a.log.Warnf("Failed to listen %s: %v", network, err)
return
}
- RelAddr = locConn.LocalAddr().(*net.UDPAddr).IP.String()
- RelPort = locConn.LocalAddr().(*net.UDPAddr).Port
- case a.proxyDialer != nil && url.Proto == ProtoTypeTCP &&
- (url.Scheme == SchemeTypeTURN || url.Scheme == SchemeTypeTURNS):
- conn, connectErr := a.proxyDialer.Dial(NetworkTypeTCP4.String(), TURNServerAddr)
+ relAddr = locConn.LocalAddr().(*net.UDPAddr).IP.String() //nolint:forcetypeassert
+ relPort = locConn.LocalAddr().(*net.UDPAddr).Port //nolint:forcetypeassert
+ relayProtocol = udp
+ case a.proxyDialer != nil && url.Proto == stun.ProtoTypeTCP &&
+ (url.Scheme == stun.SchemeTypeTURN || url.Scheme == stun.SchemeTypeTURNS):
+ conn, connectErr := a.proxyDialer.Dial(NetworkTypeTCP4.String(), turnServerAddr)
if connectErr != nil {
- a.log.Warnf("Failed to Dial TCP Addr %s via proxy dialer: %v\n", TURNServerAddr, connectErr)
+ a.log.Warnf("Failed to dial TCP address %s via proxy dialer: %v", turnServerAddr, connectErr)
return
}
- RelAddr = conn.LocalAddr().(*net.TCPAddr).IP.String()
- RelPort = conn.LocalAddr().(*net.TCPAddr).Port
+ relAddr = conn.LocalAddr().(*net.TCPAddr).IP.String() //nolint:forcetypeassert
+ relPort = conn.LocalAddr().(*net.TCPAddr).Port //nolint:forcetypeassert
+ if url.Scheme == stun.SchemeTypeTURN {
+ relayProtocol = tcp
+ } else if url.Scheme == stun.SchemeTypeTURNS {
+ relayProtocol = "tls"
+ }
locConn = turn.NewSTUNConn(conn)
- case url.Proto == ProtoTypeTCP && url.Scheme == SchemeTypeTURN:
- tcpAddr, connectErr := net.ResolveTCPAddr(NetworkTypeTCP4.String(), TURNServerAddr)
+ case url.Proto == stun.ProtoTypeTCP && url.Scheme == stun.SchemeTypeTURN:
+ tcpAddr, connectErr := a.net.ResolveTCPAddr(NetworkTypeTCP4.String(), turnServerAddr)
if connectErr != nil {
- a.log.Warnf("Failed to resolve TCP Addr %s: %v\n", TURNServerAddr, connectErr)
+ a.log.Warnf("Failed to resolve TCP address %s: %v", turnServerAddr, connectErr)
return
}
- conn, connectErr := net.DialTCP(NetworkTypeTCP4.String(), nil, tcpAddr)
+ conn, connectErr := a.net.DialTCP(NetworkTypeTCP4.String(), nil, tcpAddr)
if connectErr != nil {
- a.log.Warnf("Failed to Dial TCP Addr %s: %v\n", TURNServerAddr, connectErr)
+ a.log.Warnf("Failed to dial TCP address %s: %v", turnServerAddr, connectErr)
return
}
- RelAddr = conn.LocalAddr().(*net.TCPAddr).IP.String()
- RelPort = conn.LocalAddr().(*net.TCPAddr).Port
+ relAddr = conn.LocalAddr().(*net.TCPAddr).IP.String() //nolint:forcetypeassert
+ relPort = conn.LocalAddr().(*net.TCPAddr).Port //nolint:forcetypeassert
+ relayProtocol = tcp
locConn = turn.NewSTUNConn(conn)
- case url.Proto == ProtoTypeUDP && url.Scheme == SchemeTypeTURNS:
- udpAddr, connectErr := net.ResolveUDPAddr(network, TURNServerAddr)
+ case url.Proto == stun.ProtoTypeUDP && url.Scheme == stun.SchemeTypeTURNS:
+ udpAddr, connectErr := a.net.ResolveUDPAddr(network, turnServerAddr)
if connectErr != nil {
- a.log.Warnf("Failed to resolve UDP Addr %s: %v\n", TURNServerAddr, connectErr)
+ a.log.Warnf("Failed to resolve UDP address %s: %v", turnServerAddr, connectErr)
return
}
- conn, connectErr := dtls.Dial(network, udpAddr, &dtls.Config{
+ udpConn, dialErr := a.net.DialUDP("udp", nil, udpAddr)
+ if dialErr != nil {
+ a.log.Warnf("Failed to dial DTLS address %s: %v", turnServerAddr, dialErr)
+ return
+ }
+
+ conn, connectErr := dtls.ClientWithContext(ctx, udpConn, &dtls.Config{
+ ServerName: url.Host,
InsecureSkipVerify: a.insecureSkipVerify, //nolint:gosec
})
if connectErr != nil {
- a.log.Warnf("Failed to Dial DTLS Addr %s: %v\n", TURNServerAddr, connectErr)
+ a.log.Warnf("Failed to create DTLS client: %v", turnServerAddr, connectErr)
return
}
- RelAddr = conn.LocalAddr().(*net.UDPAddr).IP.String()
- RelPort = conn.LocalAddr().(*net.UDPAddr).Port
- locConn = &fakePacketConn{conn}
- case url.Proto == ProtoTypeTCP && url.Scheme == SchemeTypeTURNS:
- conn, connectErr := tls.Dial(NetworkTypeTCP4.String(), TURNServerAddr, &tls.Config{
- InsecureSkipVerify: a.insecureSkipVerify, //nolint:gosec
- })
- if connectErr != nil {
- a.log.Warnf("Failed to Dial TLS Addr %s: %v\n", TURNServerAddr, connectErr)
+ relAddr = conn.LocalAddr().(*net.UDPAddr).IP.String() //nolint:forcetypeassert
+ relPort = conn.LocalAddr().(*net.UDPAddr).Port //nolint:forcetypeassert
+ relayProtocol = "dtls"
+ locConn = &fakenet.PacketConn{Conn: conn}
+ case url.Proto == stun.ProtoTypeTCP && url.Scheme == stun.SchemeTypeTURNS:
+ tcpAddr, resolvErr := a.net.ResolveTCPAddr(NetworkTypeTCP4.String(), turnServerAddr)
+ if resolvErr != nil {
+ a.log.Warnf("Failed to resolve relay address %s: %v", turnServerAddr, resolvErr)
return
}
- RelAddr = conn.LocalAddr().(*net.TCPAddr).IP.String()
- RelPort = conn.LocalAddr().(*net.TCPAddr).Port
+
+ tcpConn, dialErr := a.net.DialTCP(NetworkTypeTCP4.String(), nil, tcpAddr)
+ if dialErr != nil {
+ a.log.Warnf("Failed to connect to relay: %v", dialErr)
+ return
+ }
+
+ conn := tls.Client(tcpConn, &tls.Config{
+ ServerName: url.Host,
+ InsecureSkipVerify: a.insecureSkipVerify, //nolint:gosec
+ })
+
+ if hsErr := conn.HandshakeContext(ctx); hsErr != nil {
+ if closeErr := tcpConn.Close(); closeErr != nil {
+ a.log.Errorf("Failed to close relay connection: %v", closeErr)
+ }
+ a.log.Warnf("Failed to connect to relay: %v", hsErr)
+ return
+ }
+
+ relAddr = conn.LocalAddr().(*net.TCPAddr).IP.String() //nolint:forcetypeassert
+ relPort = conn.LocalAddr().(*net.TCPAddr).Port //nolint:forcetypeassert
+ relayProtocol = "tls"
locConn = turn.NewSTUNConn(conn)
default:
- a.log.Warnf("Unable to handle URL in gatherCandidatesRelay %v\n", url)
+ a.log.Warnf("Unable to handle URL in gatherCandidatesRelay %v", url)
return
}
client, err := turn.NewClient(&turn.ClientConfig{
- TURNServerAddr: TURNServerAddr,
+ TURNServerAddr: turnServerAddr,
Conn: locConn,
Username: url.Username,
Password: url.Password,
@@ -440,31 +662,32 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //noli
Net: a.net,
})
if err != nil {
- closeConnAndLog(locConn, a.log, fmt.Sprintf("Failed to build new turn.Client %s %s\n", TURNServerAddr, err))
+ closeConnAndLog(locConn, a.log, "failed to create new TURN client %s %s", turnServerAddr, err)
return
}
if err = client.Listen(); err != nil {
client.Close()
- closeConnAndLog(locConn, a.log, fmt.Sprintf("Failed to listen on turn.Client %s %s\n", TURNServerAddr, err))
+ closeConnAndLog(locConn, a.log, "failed to listen on TURN client %s %s", turnServerAddr, err)
return
}
relayConn, err := client.Allocate()
if err != nil {
client.Close()
- closeConnAndLog(locConn, a.log, fmt.Sprintf("Failed to allocate on turn.Client %s %s\n", TURNServerAddr, err))
+ closeConnAndLog(locConn, a.log, "failed to allocate on TURN client %s %s", turnServerAddr, err)
return
}
- raddr := relayConn.LocalAddr().(*net.UDPAddr)
+ rAddr := relayConn.LocalAddr().(*net.UDPAddr) //nolint:forcetypeassert
relayConfig := CandidateRelayConfig{
- Network: network,
- Component: ComponentRTP,
- Address: raddr.IP.String(),
- Port: raddr.Port,
- RelAddr: RelAddr,
- RelPort: RelPort,
+ Network: network,
+ Component: ComponentRTP,
+ Address: rAddr.IP.String(),
+ Port: rAddr.Port,
+ RelAddr: relAddr,
+ RelPort: relPort,
+ RelayProtocol: relayProtocol,
OnClose: func() error {
client.Close()
return locConn.Close()
@@ -480,7 +703,7 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //noli
relayConnClose()
client.Close()
- closeConnAndLog(locConn, a.log, fmt.Sprintf("Failed to create relay candidate: %s %s: %v\n", network, raddr.String(), err))
+ closeConnAndLog(locConn, a.log, "failed to create relay candidate: %s %s: %v", network, rAddr.String(), err)
return
}
@@ -490,7 +713,7 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //noli
if closeErr := candidate.close(); closeErr != nil {
a.log.Warnf("Failed to close candidate: %v", closeErr)
}
- a.log.Warnf("Failed to append to localCandidates and run onCandidateHdlr: %v\n", err)
+ a.log.Warnf("Failed to append to localCandidates and run onCandidateHdlr: %v", err)
}
}(*urls[i])
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/go.mod b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/go.mod
deleted file mode 100644
index 410c2e304..000000000
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/go.mod
+++ /dev/null
@@ -1,16 +0,0 @@
-module github.com/pion/ice/v2
-
-go 1.13
-
-require (
- github.com/google/uuid v1.1.5
- github.com/pion/dtls/v2 v2.0.4
- github.com/pion/logging v0.2.2
- github.com/pion/mdns v0.0.4
- github.com/pion/randutil v0.1.0
- github.com/pion/stun v0.3.5
- github.com/pion/transport v0.12.1
- github.com/pion/turn/v2 v2.0.5
- github.com/stretchr/testify v1.6.1
- golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7
-)
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/go.sum b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/go.sum
deleted file mode 100644
index 7e8981a7f..000000000
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/go.sum
+++ /dev/null
@@ -1,60 +0,0 @@
-github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/google/uuid v1.1.5 h1:kxhtnfFVi+rYdOALN0B3k9UT86zVJKfBimRaciULW4I=
-github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/pion/dtls/v2 v2.0.4 h1:WuUcqi6oYMu/noNTz92QrF1DaFj4eXbhQ6dzaaAwOiI=
-github.com/pion/dtls/v2 v2.0.4/go.mod h1:qAkFscX0ZHoI1E07RfYPoRw3manThveu+mlTDdOxoGI=
-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 v0.0.4 h1:O4vvVqr4DGX63vzmO6Fw9vpy3lfztVWHGCQfyw0ZLSY=
-github.com/pion/mdns v0.0.4/go.mod h1:R1sL0p50l42S5lJs91oNdUL58nm0QHrhxnSegr++qC0=
-github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
-github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
-github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
-github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
-github.com/pion/transport v0.8.10/go.mod h1:tBmha/UCjpum5hqTWhfAEs3CO4/tHSg0MYRhSzR+CZ8=
-github.com/pion/transport v0.10.0/go.mod h1:BnHnUipd0rZQyTVB2SBGojFHT9CBt5C5TcsJSQGkvSE=
-github.com/pion/transport v0.10.1 h1:2W+yJT+0mOQ160ThZYUx5Zp2skzshiNgxrNE9GUfhJM=
-github.com/pion/transport v0.10.1/go.mod h1:PBis1stIILMiis0PewDw91WJeLJkyIMcEk+DwKOzf4A=
-github.com/pion/transport v0.12.1 h1:6v8lxQGVZpwSICEZjhl/CCv6aErINZlrm3O5ncFXj/c=
-github.com/pion/transport v0.12.1/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
-github.com/pion/turn/v2 v2.0.5 h1:iwMHqDfPEDEOFzwWKT56eFmh6DYC6o/+xnLAEzgISbA=
-github.com/pion/turn/v2 v2.0.5/go.mod h1:APg43CFyt/14Uy7heYUOGWdkem/Wu4PhCO/bjyrTqMw=
-github.com/pion/udp v0.1.0 h1:uGxQsNyrqG3GLINv36Ff60covYmfrLoxzwnCsIYspXI=
-github.com/pion/udp v0.1.0/go.mod h1:BPELIjbwE9PRbd/zxI/KYBnbo7B6+oA6YuEaNE8lths=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
-golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 h1:42cLlJJdEh+ySyeUUbEQ5bsTiq8voBeTuweGVkY6Puw=
-golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7 h1:3uJsdck53FDIpWwLeAXlia9p4C8j0BO2xZrqzKpL0D8=
-golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/ice.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/ice.go
index d7094f6db..bd551206e 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/ice.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/ice.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
// ConnectionState is an enum showing the state of a ICE Connection
@@ -5,8 +8,11 @@ type ConnectionState int
// List of supported States
const (
+ // ConnectionStateUnknown represents an unknown state
+ ConnectionStateUnknown ConnectionState = iota
+
// ConnectionStateNew ICE agent is gathering addresses
- ConnectionStateNew = iota + 1
+ ConnectionStateNew
// ConnectionStateChecking ICE agent has been given local and remote candidates, and is attempting to find a match
ConnectionStateChecking
@@ -52,13 +58,16 @@ func (c ConnectionState) String() string {
type GatheringState int
const (
- // GatheringStateNew indicates candidate gatering is not yet started
- GatheringStateNew GatheringState = iota + 1
+ // GatheringStateUnknown represents an unknown state
+ GatheringStateUnknown GatheringState = iota
- // GatheringStateGathering indicates candidate gatering is ongoing
+ // GatheringStateNew indicates candidate gathering is not yet started
+ GatheringStateNew
+
+ // GatheringStateGathering indicates candidate gathering is ongoing
GatheringStateGathering
- // GatheringStateComplete indicates candidate gatering has been completed
+ // GatheringStateComplete indicates candidate gathering has been completed
GatheringStateComplete
)
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/icecontrol.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/icecontrol.go
index ede2e09cb..b086bd892 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/icecontrol.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/icecontrol.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/internal/atomic/atomic.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/internal/atomic/atomic.go
new file mode 100644
index 000000000..f8caf5a2e
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/internal/atomic/atomic.go
@@ -0,0 +1,23 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+// Package atomic contains custom atomic types
+package atomic
+
+import "sync/atomic"
+
+// Error is an atomic error
+type Error struct {
+ v atomic.Value
+}
+
+// Store updates the value of the atomic variable
+func (a *Error) Store(err error) {
+ a.v.Store(struct{ error }{err})
+}
+
+// Load retrieves the current value of the atomic variable
+func (a *Error) Load() error {
+ err, _ := a.v.Load().(struct{ error })
+ return err.error
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/internal/fakenet/mock_conn.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/internal/fakenet/mock_conn.go
new file mode 100644
index 000000000..cc98849d5
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/internal/fakenet/mock_conn.go
@@ -0,0 +1,23 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+//go:build !js
+// +build !js
+
+package fakenet
+
+import (
+ "net"
+ "time"
+)
+
+// MockPacketConn for tests
+type MockPacketConn struct{}
+
+func (m *MockPacketConn) ReadFrom([]byte) (n int, addr net.Addr, err error) { return 0, nil, nil } //nolint:revive
+func (m *MockPacketConn) WriteTo([]byte, net.Addr) (n int, err error) { return 0, nil } //nolint:revive
+func (m *MockPacketConn) Close() error { return nil } //nolint:revive
+func (m *MockPacketConn) LocalAddr() net.Addr { return nil } //nolint:revive
+func (m *MockPacketConn) SetDeadline(time.Time) error { return nil } //nolint:revive
+func (m *MockPacketConn) SetReadDeadline(time.Time) error { return nil } //nolint:revive
+func (m *MockPacketConn) SetWriteDeadline(time.Time) error { return nil } //nolint:revive
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/internal/fakenet/packet_conn.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/internal/fakenet/packet_conn.go
new file mode 100644
index 000000000..0b9faaa84
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/internal/fakenet/packet_conn.go
@@ -0,0 +1,29 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+// Package fakenet contains fake network abstractions
+package fakenet
+
+import (
+ "net"
+)
+
+// Compile-time assertion
+var _ net.PacketConn = (*PacketConn)(nil)
+
+// PacketConn wraps a net.Conn and emulates net.PacketConn
+type PacketConn struct {
+ net.Conn
+}
+
+// ReadFrom reads a packet from the connection,
+func (f *PacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
+ n, err = f.Conn.Read(p)
+ addr = f.Conn.RemoteAddr()
+ return
+}
+
+// WriteTo writes a packet with payload p to addr.
+func (f *PacketConn) WriteTo(p []byte, _ net.Addr) (int, error) {
+ return f.Conn.Write(p)
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/internal/stun/stun.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/internal/stun/stun.go
new file mode 100644
index 000000000..230cf850a
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/internal/stun/stun.go
@@ -0,0 +1,72 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+// Package stun contains ICE specific STUN code
+package stun
+
+import (
+ "errors"
+ "fmt"
+ "net"
+ "time"
+
+ "github.com/pion/stun"
+)
+
+var (
+ errGetXorMappedAddrResponse = errors.New("failed to get XOR-MAPPED-ADDRESS response")
+ errMismatchUsername = errors.New("username mismatch")
+)
+
+// GetXORMappedAddr initiates a STUN requests to serverAddr using conn, reads the response and returns
+// the XORMappedAddress returned by the STUN server.
+func GetXORMappedAddr(conn net.PacketConn, serverAddr net.Addr, timeout time.Duration) (*stun.XORMappedAddress, error) {
+ if timeout > 0 {
+ if err := conn.SetReadDeadline(time.Now().Add(timeout)); err != nil {
+ return nil, err
+ }
+
+ // Reset timeout after completion
+ defer conn.SetReadDeadline(time.Time{}) //nolint:errcheck
+ }
+
+ req, err := stun.Build(stun.BindingRequest, stun.TransactionID)
+ if err != nil {
+ return nil, err
+ }
+
+ if _, err = conn.WriteTo(req.Raw, serverAddr); err != nil {
+ return nil, err
+ }
+
+ const maxMessageSize = 1280
+ buf := make([]byte, maxMessageSize)
+ n, _, err := conn.ReadFrom(buf)
+ if err != nil {
+ return nil, err
+ }
+
+ res := &stun.Message{Raw: buf[:n]}
+ if err = res.Decode(); err != nil {
+ return nil, err
+ }
+
+ var addr stun.XORMappedAddress
+ if err = addr.GetFrom(res); err != nil {
+ return nil, fmt.Errorf("%w: %v", errGetXorMappedAddrResponse, err) //nolint:errorlint
+ }
+
+ return &addr, nil
+}
+
+// AssertUsername checks that the given STUN message m has a USERNAME attribute with a given value
+func AssertUsername(m *stun.Message, expectedUsername string) error {
+ var username stun.Username
+ if err := username.GetFrom(m); err != nil {
+ return err
+ } else if string(username) != expectedUsername {
+ return fmt.Errorf("%w expected(%x) actual(%x)", errMismatchUsername, expectedUsername, string(username))
+ }
+
+ return nil
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/mdns.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/mdns.go
index 5a431d152..aa8231648 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/mdns.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/mdns.go
@@ -1,11 +1,13 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
- "net"
-
"github.com/google/uuid"
"github.com/pion/logging"
"github.com/pion/mdns"
+ "github.com/pion/transport/v2"
"golang.org/x/net/ipv4"
)
@@ -31,17 +33,17 @@ func generateMulticastDNSName() (string, error) {
return u.String() + ".local", err
}
-func createMulticastDNS(mDNSMode MulticastDNSMode, mDNSName string, log logging.LeveledLogger) (*mdns.Conn, MulticastDNSMode, error) {
+func createMulticastDNS(n transport.Net, mDNSMode MulticastDNSMode, mDNSName string, log logging.LeveledLogger) (*mdns.Conn, MulticastDNSMode, error) {
if mDNSMode == MulticastDNSModeDisabled {
return nil, mDNSMode, nil
}
- addr, mdnsErr := net.ResolveUDPAddr("udp4", mdns.DefaultAddress)
+ addr, mdnsErr := n.ResolveUDPAddr("udp4", mdns.DefaultAddress)
if mdnsErr != nil {
return nil, mDNSMode, mdnsErr
}
- l, mdnsErr := net.ListenUDP("udp4", addr)
+ l, mdnsErr := n.ListenUDP("udp4", addr)
if mdnsErr != nil {
// If ICE fails to start MulticastDNS server just warn the user and continue
log.Errorf("Failed to enable mDNS, continuing in mDNS disabled mode: (%s)", mdnsErr)
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/net.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/net.go
new file mode 100644
index 000000000..d716bc19c
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/net.go
@@ -0,0 +1,137 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package ice
+
+import (
+ "net"
+
+ "github.com/pion/logging"
+ "github.com/pion/transport/v2"
+)
+
+// The conditions of invalidation written below are defined in
+// https://tools.ietf.org/html/rfc8445#section-5.1.1.1
+func isSupportedIPv6(ip net.IP) bool {
+ if len(ip) != net.IPv6len ||
+ isZeros(ip[0:12]) || // !(IPv4-compatible IPv6)
+ ip[0] == 0xfe && ip[1]&0xc0 == 0xc0 || // !(IPv6 site-local unicast)
+ ip.IsLinkLocalUnicast() ||
+ ip.IsLinkLocalMulticast() {
+ return false
+ }
+ return true
+}
+
+func isZeros(ip net.IP) bool {
+ for i := 0; i < len(ip); i++ {
+ if ip[i] != 0 {
+ return false
+ }
+ }
+ return true
+}
+
+func localInterfaces(n transport.Net, interfaceFilter func(string) bool, ipFilter func(net.IP) bool, networkTypes []NetworkType, includeLoopback bool) ([]net.IP, error) { //nolint:gocognit
+ ips := []net.IP{}
+ ifaces, err := n.Interfaces()
+ if err != nil {
+ return ips, err
+ }
+
+ var IPv4Requested, IPv6Requested bool
+ for _, typ := range networkTypes {
+ if typ.IsIPv4() {
+ IPv4Requested = true
+ }
+
+ if typ.IsIPv6() {
+ IPv6Requested = true
+ }
+ }
+
+ for _, iface := range ifaces {
+ if iface.Flags&net.FlagUp == 0 {
+ continue // Interface down
+ }
+ if (iface.Flags&net.FlagLoopback != 0) && !includeLoopback {
+ continue // Loopback interface
+ }
+
+ if interfaceFilter != nil && !interfaceFilter(iface.Name) {
+ continue
+ }
+
+ addrs, err := iface.Addrs()
+ if err != nil {
+ continue
+ }
+
+ for _, addr := range addrs {
+ var ip net.IP
+ switch addr := addr.(type) {
+ case *net.IPNet:
+ ip = addr.IP
+ case *net.IPAddr:
+ ip = addr.IP
+ }
+ if ip == nil || (ip.IsLoopback() && !includeLoopback) {
+ continue
+ }
+
+ if ipv4 := ip.To4(); ipv4 == nil {
+ if !IPv6Requested {
+ continue
+ } else if !isSupportedIPv6(ip) {
+ continue
+ }
+ } else if !IPv4Requested {
+ continue
+ }
+
+ if ipFilter != nil && !ipFilter(ip) {
+ continue
+ }
+
+ ips = append(ips, ip)
+ }
+ }
+ return ips, nil
+}
+
+func listenUDPInPortRange(n transport.Net, log logging.LeveledLogger, portMax, portMin int, network string, lAddr *net.UDPAddr) (transport.UDPConn, error) {
+ if (lAddr.Port != 0) || ((portMin == 0) && (portMax == 0)) {
+ return n.ListenUDP(network, lAddr)
+ }
+ var i, j int
+ i = portMin
+ if i == 0 {
+ i = 1
+ }
+ j = portMax
+ if j == 0 {
+ j = 0xFFFF
+ }
+ if i > j {
+ return nil, ErrPort
+ }
+
+ portStart := globalMathRandomGenerator.Intn(j-i+1) + i
+ portCurrent := portStart
+ for {
+ lAddr = &net.UDPAddr{IP: lAddr.IP, Port: portCurrent}
+ c, e := n.ListenUDP(network, lAddr)
+ if e == nil {
+ return c, e //nolint:nilerr
+ }
+ log.Debugf("Failed to listen %s: %v", lAddr.String(), e)
+ portCurrent++
+ if portCurrent > j {
+ portCurrent = i
+ }
+ if portCurrent == portStart {
+ break
+ }
+ }
+ return nil, ErrPort
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/networktype.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/networktype.go
index 462ff2dea..57df18631 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/networktype.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/networktype.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
@@ -7,8 +10,12 @@ import (
)
const (
- udp = "udp"
- tcp = "tcp"
+ udp = "udp"
+ tcp = "tcp"
+ udp4 = "udp4"
+ udp6 = "udp6"
+ tcp4 = "tcp4"
+ tcp6 = "tcp6"
)
func supportedNetworkTypes() []NetworkType {
@@ -40,13 +47,13 @@ const (
func (t NetworkType) String() string {
switch t {
case NetworkTypeUDP4:
- return "udp4"
+ return udp4
case NetworkTypeUDP6:
- return "udp6"
+ return udp6
case NetworkTypeTCP4:
- return "tcp4"
+ return tcp4
case NetworkTypeTCP6:
- return "tcp6"
+ return tcp6
default:
return ErrUnknownType.Error()
}
@@ -126,5 +133,5 @@ func determineNetworkType(network string, ip net.IP) (NetworkType, error) {
return NetworkTypeTCP6, nil
}
- return NetworkType(0), fmt.Errorf("%w from %s %s", errDetermineNetworkType, network, ip)
+ return NetworkType(0), fmt.Errorf("%w from %s %s", ErrDetermineNetworkType, network, ip)
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/priority.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/priority.go
index 421829938..16ac5cc73 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/priority.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/priority.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/rand.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/rand.go
index 918783e02..3de1f0407 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/rand.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/rand.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import "github.com/pion/randutil"
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/renovate.json b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/renovate.json
index 4400fd9b2..f1bb98c6a 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/renovate.json
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/renovate.json
@@ -1,15 +1,6 @@
{
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
- "config:base"
- ],
- "postUpdateOptions": [
- "gomodTidy"
- ],
- "commitBody": "Generated by renovateBot",
- "packageRules": [
- {
- "packagePatterns": ["^golang.org/x/"],
- "schedule": ["on the first day of the month"]
- }
+ "github>pion/renovate-config"
]
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/role.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/role.go
index 7a8bc064a..e9a7bda94 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/role.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/role.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/selection.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/selection.go
index e0cfb1034..9f312637f 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/selection.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/selection.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
@@ -19,7 +22,7 @@ type pairCandidateSelector interface {
type controllingSelector struct {
startTime time.Time
agent *Agent
- nominatedPair *candidatePair
+ nominatedPair *CandidatePair
log logging.LeveledLogger
}
@@ -40,7 +43,7 @@ func (s *controllingSelector) isNominatable(c Candidate) bool {
return time.Since(s.startTime).Nanoseconds() > s.agent.relayAcceptanceMinWait.Nanoseconds()
}
- s.log.Errorf("isNominatable invalid candidate type %s", c.Type().String())
+ s.log.Errorf("Invalid candidate type: %s", c.Type())
return false
}
@@ -55,8 +58,8 @@ func (s *controllingSelector) ContactCandidates() {
s.nominatePair(s.nominatedPair)
default:
p := s.agent.getBestValidCandidatePair()
- if p != nil && s.isNominatable(p.local) && s.isNominatable(p.remote) {
- s.log.Tracef("Nominatable pair found, nominating (%s, %s)", p.local.String(), p.remote.String())
+ if p != nil && s.isNominatable(p.Local) && s.isNominatable(p.Remote) {
+ s.log.Tracef("Nominatable pair found, nominating (%s, %s)", p.Local.String(), p.Remote.String())
p.nominated = true
s.nominatedPair = p
s.nominatePair(p)
@@ -66,7 +69,7 @@ func (s *controllingSelector) ContactCandidates() {
}
}
-func (s *controllingSelector) nominatePair(pair *candidatePair) {
+func (s *controllingSelector) nominatePair(pair *CandidatePair) {
// The controlling agent MUST include the USE-CANDIDATE attribute in
// order to nominate a candidate pair (Section 8.1.1). The controlled
// agent MUST NOT include the USE-CANDIDATE attribute in a Binding
@@ -75,7 +78,7 @@ func (s *controllingSelector) nominatePair(pair *candidatePair) {
stun.NewUsername(s.agent.remoteUfrag+":"+s.agent.localUfrag),
UseCandidate(),
AttrControlling(s.agent.tieBreaker),
- PriorityAttr(pair.local.Priority()),
+ PriorityAttr(pair.Local.Priority()),
stun.NewShortTermIntegrity(s.agent.remotePwd),
stun.Fingerprint,
)
@@ -84,8 +87,8 @@ func (s *controllingSelector) nominatePair(pair *candidatePair) {
return
}
- s.log.Tracef("ping STUN (nominate candidate pair) from %s to %s\n", pair.local.String(), pair.remote.String())
- s.agent.sendBindingRequest(msg, pair.local, pair.remote)
+ s.log.Tracef("ping STUN (nominate candidate pair) from %s to %s", pair.Local.String(), pair.Remote.String())
+ s.agent.sendBindingRequest(msg, pair.Local, pair.Remote)
}
func (s *controllingSelector) HandleBindingRequest(m *stun.Message, local, remote Candidate) {
@@ -101,10 +104,10 @@ func (s *controllingSelector) HandleBindingRequest(m *stun.Message, local, remot
if p.state == CandidatePairStateSucceeded && s.nominatedPair == nil && s.agent.getSelectedPair() == nil {
bestPair := s.agent.getBestAvailableCandidatePair()
if bestPair == nil {
- s.log.Tracef("No best pair available\n")
- } else if bestPair.Equal(p) && s.isNominatable(p.local) && s.isNominatable(p.remote) {
- s.log.Tracef("The candidate (%s, %s) is the best candidate available, marking it as nominated\n",
- p.local.String(), p.remote.String())
+ s.log.Tracef("No best pair available")
+ } else if bestPair.equal(p) && s.isNominatable(p.Local) && s.isNominatable(p.Remote) {
+ s.log.Tracef("The candidate (%s, %s) is the best candidate available, marking it as nominated",
+ p.Local.String(), p.Remote.String())
s.nominatedPair = p
s.nominatePair(p)
}
@@ -114,7 +117,7 @@ func (s *controllingSelector) HandleBindingRequest(m *stun.Message, local, remot
func (s *controllingSelector) HandleSuccessResponse(m *stun.Message, local, remote Candidate, remoteAddr net.Addr) {
ok, pendingRequest := s.agent.handleInboundBindingSuccess(m.TransactionID)
if !ok {
- s.log.Warnf("discard message from (%s), unknown TransactionID 0x%x", remote, m.TransactionID)
+ s.log.Warnf("Discard message from (%s), unknown TransactionID 0x%x", remote, m.TransactionID)
return
}
@@ -123,7 +126,7 @@ func (s *controllingSelector) HandleSuccessResponse(m *stun.Message, local, remo
// Assert that NAT is not symmetric
// https://tools.ietf.org/html/rfc8445#section-7.2.5.2.1
if !addrEqual(transactionAddr, remoteAddr) {
- s.log.Debugf("discard message: transaction source and destination does not match expected(%s), actual(%s)", transactionAddr, remote)
+ s.log.Debugf("Discard message: transaction source and destination does not match expected(%s), actual(%s)", transactionAddr, remote)
return
}
@@ -195,7 +198,7 @@ func (s *controlledSelector) PingCandidate(local, remote Candidate) {
}
func (s *controlledSelector) HandleSuccessResponse(m *stun.Message, local, remote Candidate, remoteAddr net.Addr) {
- // nolint:godox
+ //nolint:godox
// TODO according to the standard we should specifically answer a failed nomination:
// https://tools.ietf.org/html/rfc8445#section-7.3.1.5
// If the controlled agent does not accept the request from the
@@ -205,7 +208,7 @@ func (s *controlledSelector) HandleSuccessResponse(m *stun.Message, local, remot
ok, pendingRequest := s.agent.handleInboundBindingSuccess(m.TransactionID)
if !ok {
- s.log.Warnf("discard message from (%s), unknown TransactionID 0x%x", remote, m.TransactionID)
+ s.log.Warnf("Discard message from (%s), unknown TransactionID 0x%x", remote, m.TransactionID)
return
}
@@ -214,7 +217,7 @@ func (s *controlledSelector) HandleSuccessResponse(m *stun.Message, local, remot
// Assert that NAT is not symmetric
// https://tools.ietf.org/html/rfc8445#section-7.2.5.2.1
if !addrEqual(transactionAddr, remoteAddr) {
- s.log.Debugf("discard message: transaction source and destination does not match expected(%s), actual(%s)", transactionAddr, remote)
+ s.log.Debugf("Discard message: transaction source and destination does not match expected(%s), actual(%s)", transactionAddr, remote)
return
}
@@ -229,13 +232,20 @@ func (s *controlledSelector) HandleSuccessResponse(m *stun.Message, local, remot
p.state = CandidatePairStateSucceeded
s.log.Tracef("Found valid candidate pair: %s", p)
+ if p.nominateOnBindingSuccess {
+ if selectedPair := s.agent.getSelectedPair(); selectedPair == nil ||
+ (selectedPair != p && selectedPair.priority() <= p.priority()) {
+ s.agent.setSelectedPair(p)
+ } else if selectedPair != p {
+ s.log.Tracef("ignore nominate new pair %s, already nominated pair %s", p, selectedPair)
+ }
+ }
}
func (s *controlledSelector) HandleBindingRequest(m *stun.Message, local, remote Candidate) {
useCandidate := m.Contains(stun.AttrUseCandidate)
p := s.agent.findPair(local, remote)
-
if p == nil {
p = s.agent.addPair(local, remote)
}
@@ -248,10 +258,12 @@ func (s *controlledSelector) HandleBindingRequest(m *stun.Message, local, remote
// previously sent by this pair produced a successful response and
// generated a valid pair (Section 7.2.5.3.2). The agent sets the
// nominated flag value of the valid pair to true.
- if selectedPair := s.agent.getSelectedPair(); selectedPair == nil {
+ if selectedPair := s.agent.getSelectedPair(); selectedPair == nil ||
+ (selectedPair != p && selectedPair.priority() <= p.priority()) {
s.agent.setSelectedPair(p)
+ } else if selectedPair != p {
+ s.log.Tracef("ignore nominate new pair %s, already nominated pair %s", p, selectedPair)
}
- s.agent.sendBindingSuccess(m, local, remote)
} else {
// If the received Binding request triggered a new check to be
// enqueued in the triggered-check queue (Section 7.3.1.4), once the
@@ -261,12 +273,12 @@ func (s *controlledSelector) HandleBindingRequest(m *stun.Message, local, remote
// MUST remove the candidate pair from the valid list, set the
// candidate pair state to Failed, and set the checklist state to
// Failed.
- s.PingCandidate(local, remote)
+ p.nominateOnBindingSuccess = true
}
- } else {
- s.agent.sendBindingSuccess(m, local, remote)
- s.PingCandidate(local, remote)
}
+
+ s.agent.sendBindingSuccess(m, local, remote)
+ s.PingCandidate(local, remote)
}
type liteSelector struct {
@@ -276,8 +288,8 @@ type liteSelector struct {
// A lite selector should not contact candidates
func (s *liteSelector) ContactCandidates() {
if _, ok := s.pairCandidateSelector.(*controllingSelector); ok {
- // nolint:godox
- // pion/ice#96
+ //nolint:godox
+ // https://github.com/pion/ice/issues/96
// TODO: implement lite controlling agent. For now falling back to full agent.
// This only happens if both peers are lite. See RFC 8445 S6.1.1 and S6.2
s.pairCandidateSelector.ContactCandidates()
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/stats.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/stats.go
index f59d89ff9..9b83bea85 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/stats.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/stats.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
@@ -104,7 +107,7 @@ type CandidatePairStats struct {
// ResponsesReceived represents the total number of connectivity check responses received.
ResponsesReceived uint64
- // ResponsesSent epresents the total number of connectivity check responses sent.
+ // ResponsesSent represents the total number of connectivity check responses sent.
// Since we cannot distinguish connectivity check requests and consent requests,
// all responses are counted.
ResponsesSent uint64
@@ -164,7 +167,7 @@ type CandidateStats struct {
// RelayProtocol is the protocol used by the endpoint to communicate with the
// TURN server. This is only present for local candidates. Valid values for
- // the TURN URL protocol is one of udp, tcp, or tls.
+ // the TURN URL protocol is one of UDP, TCP, or TLS.
RelayProtocol string
// Deleted is true if the candidate has been deleted/freed. For host candidates,
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/stun.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/stun.go
deleted file mode 100644
index bef7c87e5..000000000
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/stun.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package ice
-
-import (
- "fmt"
-
- "github.com/pion/stun"
-)
-
-func assertInboundUsername(m *stun.Message, expectedUsername string) error {
- var username stun.Username
- if err := username.GetFrom(m); err != nil {
- return err
- }
- if string(username) != expectedUsername {
- return fmt.Errorf("%w expected(%x) actual(%x)", errMismatchUsername, expectedUsername, string(username))
- }
-
- return nil
-}
-
-func assertInboundMessageIntegrity(m *stun.Message, key []byte) error {
- messageIntegrityAttr := stun.MessageIntegrity(key)
- return messageIntegrityAttr.Check(m)
-}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/tcp_mux.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/tcp_mux.go
index 1a9a797a5..fb4e5243e 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/tcp_mux.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/tcp_mux.go
@@ -1,7 +1,11 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
"encoding/binary"
+ "errors"
"io"
"net"
"strings"
@@ -11,38 +15,19 @@ import (
"github.com/pion/stun"
)
+// ErrGetTransportAddress can't convert net.Addr to underlying type (UDPAddr or TCPAddr).
+var ErrGetTransportAddress = errors.New("failed to get local transport address")
+
// TCPMux is allows grouping multiple TCP net.Conns and using them like UDP
// net.PacketConns. The main implementation of this is TCPMuxDefault, and this
-// interface exists to:
-// 1. prevent SEGV panics when TCPMuxDefault is not initialized by using the
-// invalidTCPMux implementation, and
-// 2. allow mocking in tests.
+// interface exists to allow mocking in tests.
type TCPMux interface {
io.Closer
- GetConnByUfrag(ufrag string) (net.PacketConn, error)
+ GetConnByUfrag(ufrag string, isIPv6 bool, local net.IP) (net.PacketConn, error)
RemoveConnByUfrag(ufrag string)
}
-// invalidTCPMux is an implementation of TCPMux that always returns ErroTCPMuxNotInitialized.
-type invalidTCPMux struct {
-}
-
-func newInvalidTCPMux() *invalidTCPMux {
- return &invalidTCPMux{}
-}
-
-// Close implements TCPMux interface.
-func (m *invalidTCPMux) Close() error {
- return ErrTCPMuxNotInitialized
-}
-
-// GetConnByUfrag implements TCPMux interface.
-func (m *invalidTCPMux) GetConnByUfrag(ufrag string) (net.PacketConn, error) {
- return nil, ErrTCPMuxNotInitialized
-}
-
-// RemoveConnByUfrag implements TCPMux interface.
-func (m *invalidTCPMux) RemoveConnByUfrag(ufrag string) {}
+type ipAddr string
// TCPMuxDefault muxes TCP net.Conns into net.PacketConns and groups them by
// Ufrag. It is a default implementation of TCPMux interface.
@@ -50,8 +35,8 @@ type TCPMuxDefault struct {
params *TCPMuxParams
closed bool
- // conns is a map of all tcpPacketConns indexed by ufrag
- conns map[string]*tcpPacketConn
+ // connsIPv4 and connsIPv6 are maps of all tcpPacketConns indexed by ufrag and local address
+ connsIPv4, connsIPv6 map[string]map[ipAddr]*tcpPacketConn
mu sync.Mutex
wg sync.WaitGroup
@@ -62,6 +47,11 @@ type TCPMuxParams struct {
Listener net.Listener
Logger logging.LeveledLogger
ReadBufferSize int
+
+ // Maximum buffer size for write op. 0 means no write buffer, the write op will block until the whole packet is written
+ // if the write buffer is full, the subsequent write packet will be dropped until it has enough space.
+ // a default 4MB is recommended.
+ WriteBufferSize int
}
// NewTCPMuxDefault creates a new instance of TCPMuxDefault.
@@ -73,7 +63,8 @@ func NewTCPMuxDefault(params TCPMuxParams) *TCPMuxDefault {
m := &TCPMuxDefault{
params: ¶ms,
- conns: map[string]*tcpPacketConn{},
+ connsIPv4: map[string]map[ipAddr]*tcpPacketConn{},
+ connsIPv6: map[string]map[ipAddr]*tcpPacketConn{},
}
m.wg.Add(1)
@@ -86,11 +77,11 @@ func NewTCPMuxDefault(params TCPMuxParams) *TCPMuxDefault {
}
func (m *TCPMuxDefault) start() {
- m.params.Logger.Infof("Listening TCP on %s\n", m.params.Listener.Addr())
+ m.params.Logger.Infof("Listening TCP on %s", m.params.Listener.Addr())
for {
conn, err := m.params.Listener.Accept()
if err != nil {
- m.params.Logger.Infof("Error accepting connection: %s\n", err)
+ m.params.Logger.Infof("Error accepting connection: %s", err)
return
}
@@ -110,7 +101,7 @@ func (m *TCPMuxDefault) LocalAddr() net.Addr {
}
// GetConnByUfrag retrieves an existing or creates a new net.PacketConn.
-func (m *TCPMuxDefault) GetConnByUfrag(ufrag string) (net.PacketConn, error) {
+func (m *TCPMuxDefault) GetConnByUfrag(ufrag string, isIPv6 bool, local net.IP) (net.PacketConn, error) {
m.mu.Lock()
defer m.mu.Unlock()
@@ -118,34 +109,50 @@ func (m *TCPMuxDefault) GetConnByUfrag(ufrag string) (net.PacketConn, error) {
return nil, io.ErrClosedPipe
}
- conn, ok := m.conns[ufrag]
-
- if ok {
+ if conn, ok := m.getConn(ufrag, isIPv6, local); ok {
return conn, nil
- // return nil, fmt.Errorf("duplicate ufrag %v", ufrag)
}
- conn = m.createConn(ufrag, m.LocalAddr())
-
- return conn, nil
+ return m.createConn(ufrag, isIPv6, local)
}
-func (m *TCPMuxDefault) createConn(ufrag string, localAddr net.Addr) *tcpPacketConn {
+func (m *TCPMuxDefault) createConn(ufrag string, isIPv6 bool, local net.IP) (*tcpPacketConn, error) {
+ addr, ok := m.LocalAddr().(*net.TCPAddr)
+ if !ok {
+ return nil, ErrGetTransportAddress
+ }
+ localAddr := *addr
+ localAddr.IP = local
+
conn := newTCPPacketConn(tcpPacketParams{
- ReadBuffer: m.params.ReadBufferSize,
- LocalAddr: localAddr,
- Logger: m.params.Logger,
+ ReadBuffer: m.params.ReadBufferSize,
+ WriteBuffer: m.params.WriteBufferSize,
+ LocalAddr: &localAddr,
+ Logger: m.params.Logger,
})
- m.conns[ufrag] = conn
+
+ var conns map[ipAddr]*tcpPacketConn
+ if isIPv6 {
+ if conns, ok = m.connsIPv6[ufrag]; !ok {
+ conns = make(map[ipAddr]*tcpPacketConn)
+ m.connsIPv6[ufrag] = conns
+ }
+ } else {
+ if conns, ok = m.connsIPv4[ufrag]; !ok {
+ conns = make(map[ipAddr]*tcpPacketConn)
+ m.connsIPv4[ufrag] = conns
+ }
+ }
+ conns[ipAddr(local.String())] = conn
m.wg.Add(1)
go func() {
defer m.wg.Done()
<-conn.CloseChannel()
- m.RemoveConnByUfrag(ufrag)
+ m.removeConnByUfragAndLocalHost(ufrag, local)
}()
- return conn
+ return conn, nil
}
func (m *TCPMuxDefault) closeAndLogError(closer io.Closer) {
@@ -160,7 +167,7 @@ func (m *TCPMuxDefault) handleConn(conn net.Conn) {
n, err := readStreamingPacket(conn, buf)
if err != nil {
- m.params.Logger.Warnf("Error reading first packet: %s", err)
+ m.params.Logger.Warnf("Error reading first packet from %s: %s", conn.RemoteAddr().String(), err)
return
}
@@ -173,41 +180,61 @@ func (m *TCPMuxDefault) handleConn(conn net.Conn) {
copy(msg.Raw, buf)
if err = msg.Decode(); err != nil {
m.closeAndLogError(conn)
- m.params.Logger.Warnf("Failed to handle decode ICE from %s to %s: %v\n", conn.RemoteAddr(), conn.LocalAddr(), err)
+ m.params.Logger.Warnf("Failed to handle decode ICE from %s to %s: %v", conn.RemoteAddr(), conn.LocalAddr(), err)
return
}
- if m == nil || msg.Type.Method != stun.MethodBinding { // not a stun
+ if m == nil || msg.Type.Method != stun.MethodBinding { // Not a STUN
m.closeAndLogError(conn)
- m.params.Logger.Warnf("Not a STUN message from %s to %s\n", conn.RemoteAddr(), conn.LocalAddr())
+ m.params.Logger.Warnf("Not a STUN message from %s to %s", conn.RemoteAddr(), conn.LocalAddr())
return
}
for _, attr := range msg.Attributes {
- m.params.Logger.Debugf("msg attr: %s\n", attr.String())
+ m.params.Logger.Debugf("msg attr: %s", attr.String())
}
attr, err := msg.Get(stun.AttrUsername)
if err != nil {
m.closeAndLogError(conn)
- m.params.Logger.Warnf("No Username attribute in STUN message from %s to %s\n", conn.RemoteAddr(), conn.LocalAddr())
+ m.params.Logger.Warnf("No Username attribute in STUN message from %s to %s", conn.RemoteAddr(), conn.LocalAddr())
return
}
ufrag := strings.Split(string(attr), ":")[0]
- m.params.Logger.Debugf("Ufrag: %s\n", ufrag)
+ m.params.Logger.Debugf("Ufrag: %s", ufrag)
m.mu.Lock()
defer m.mu.Unlock()
- packetConn, ok := m.conns[ufrag]
+ host, _, err := net.SplitHostPort(conn.RemoteAddr().String())
+ if err != nil {
+ m.closeAndLogError(conn)
+ m.params.Logger.Warnf("Failed to get host in STUN message from %s to %s", conn.RemoteAddr(), conn.LocalAddr())
+ return
+ }
+
+ isIPv6 := net.ParseIP(host).To4() == nil
+
+ localAddr, ok := conn.LocalAddr().(*net.TCPAddr)
if !ok {
- packetConn = m.createConn(ufrag, conn.LocalAddr())
+ m.closeAndLogError(conn)
+ m.params.Logger.Warnf("Failed to get local tcp address in STUN message from %s to %s", conn.RemoteAddr(), conn.LocalAddr())
+ return
+ }
+ packetConn, ok := m.getConn(ufrag, isIPv6, localAddr.IP)
+ if !ok {
+ packetConn, err = m.createConn(ufrag, isIPv6, localAddr.IP)
+ if err != nil {
+ m.closeAndLogError(conn)
+ m.params.Logger.Warnf("Failed to create packetConn for STUN message from %s to %s", conn.RemoteAddr(), conn.LocalAddr())
+ return
+ }
}
if err := packetConn.AddConn(conn, buf); err != nil {
m.closeAndLogError(conn)
- m.params.Logger.Warnf("Error adding conn to tcpPacketConn from %s to %s: %s\n", conn.RemoteAddr(), conn.LocalAddr(), err)
+ m.params.Logger.Warnf("Error adding conn to tcpPacketConn from %s to %s: %s", conn.RemoteAddr(), conn.LocalAddr(), err)
return
}
}
@@ -217,10 +244,19 @@ func (m *TCPMuxDefault) Close() error {
m.mu.Lock()
m.closed = true
- for _, conn := range m.conns {
- m.closeAndLogError(conn)
+ for _, conns := range m.connsIPv4 {
+ for _, conn := range conns {
+ m.closeAndLogError(conn)
+ }
}
- m.conns = map[string]*tcpPacketConn{}
+ for _, conns := range m.connsIPv6 {
+ for _, conn := range conns {
+ m.closeAndLogError(conn)
+ }
+ }
+
+ m.connsIPv4 = map[string]map[ipAddr]*tcpPacketConn{}
+ m.connsIPv6 = map[string]map[ipAddr]*tcpPacketConn{}
err := m.params.Listener.Close()
@@ -233,13 +269,77 @@ func (m *TCPMuxDefault) Close() error {
// RemoveConnByUfrag closes and removes a net.PacketConn by Ufrag.
func (m *TCPMuxDefault) RemoveConnByUfrag(ufrag string) {
- m.mu.Lock()
- defer m.mu.Unlock()
+ removedConns := make([]*tcpPacketConn, 0, 4)
- if conn, ok := m.conns[ufrag]; ok {
- m.closeAndLogError(conn)
- delete(m.conns, ufrag)
+ // Keep lock section small to avoid deadlock with conn lock
+ m.mu.Lock()
+ if conns, ok := m.connsIPv4[ufrag]; ok {
+ delete(m.connsIPv4, ufrag)
+ for _, conn := range conns {
+ removedConns = append(removedConns, conn)
+ }
}
+ if conns, ok := m.connsIPv6[ufrag]; ok {
+ delete(m.connsIPv6, ufrag)
+ for _, conn := range conns {
+ removedConns = append(removedConns, conn)
+ }
+ }
+
+ m.mu.Unlock()
+
+ // Close the connections outside the critical section to avoid
+ // deadlocking TCP mux if (*tcpPacketConn).Close() blocks.
+ for _, conn := range removedConns {
+ m.closeAndLogError(conn)
+ }
+}
+
+func (m *TCPMuxDefault) removeConnByUfragAndLocalHost(ufrag string, local net.IP) {
+ removedConns := make([]*tcpPacketConn, 0, 4)
+
+ localIP := ipAddr(local.String())
+ // Keep lock section small to avoid deadlock with conn lock
+ m.mu.Lock()
+ if conns, ok := m.connsIPv4[ufrag]; ok {
+ if conn, ok := conns[localIP]; ok {
+ delete(conns, localIP)
+ if len(conns) == 0 {
+ delete(m.connsIPv4, ufrag)
+ }
+ removedConns = append(removedConns, conn)
+ }
+ }
+ if conns, ok := m.connsIPv6[ufrag]; ok {
+ if conn, ok := conns[localIP]; ok {
+ delete(conns, localIP)
+ if len(conns) == 0 {
+ delete(m.connsIPv6, ufrag)
+ }
+ removedConns = append(removedConns, conn)
+ }
+ }
+ m.mu.Unlock()
+
+ // Close the connections outside the critical section to avoid
+ // deadlocking TCP mux if (*tcpPacketConn).Close() blocks.
+ for _, conn := range removedConns {
+ m.closeAndLogError(conn)
+ }
+}
+
+func (m *TCPMuxDefault) getConn(ufrag string, isIPv6 bool, local net.IP) (val *tcpPacketConn, ok bool) {
+ var conns map[ipAddr]*tcpPacketConn
+ if isIPv6 {
+ conns, ok = m.connsIPv6[ufrag]
+ } else {
+ conns, ok = m.connsIPv4[ufrag]
+ }
+ if conns != nil {
+ val, ok = conns[ipAddr(local.String())]
+ }
+
+ return
}
const streamingPacketHeaderLen = 2
@@ -247,11 +347,12 @@ const streamingPacketHeaderLen = 2
// readStreamingPacket reads 1 packet from stream
// read packet bytes https://tools.ietf.org/html/rfc4571#section-2
// 2-byte length header prepends each packet:
-// 0 1 2 3
-// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-// -----------------------------------------------------------------
-// | LENGTH | RTP or RTCP packet ... |
-// -----------------------------------------------------------------
+//
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// -----------------------------------------------------------------
+// | LENGTH | RTP or RTCP packet ... |
+// -----------------------------------------------------------------
func readStreamingPacket(conn net.Conn, buf []byte) (int, error) {
header := make([]byte, streamingPacketHeaderLen)
var bytesRead, n int
@@ -282,11 +383,11 @@ func readStreamingPacket(conn net.Conn, buf []byte) (int, error) {
}
func writeStreamingPacket(conn net.Conn, buf []byte) (int, error) {
- bufferCopy := make([]byte, streamingPacketHeaderLen+len(buf))
- binary.BigEndian.PutUint16(bufferCopy, uint16(len(buf)))
- copy(bufferCopy[2:], buf)
+ bufCopy := make([]byte, streamingPacketHeaderLen+len(buf))
+ binary.BigEndian.PutUint16(bufCopy, uint16(len(buf)))
+ copy(bufCopy[2:], buf)
- n, err := conn.Write(bufferCopy)
+ n, err := conn.Write(bufCopy)
if err != nil {
return 0, err
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/tcp_mux_multi.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/tcp_mux_multi.go
new file mode 100644
index 000000000..e32acbf3e
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/tcp_mux_multi.go
@@ -0,0 +1,81 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package ice
+
+import "net"
+
+// AllConnsGetter allows multiple fixed TCP ports to be used,
+// each of which is multiplexed like TCPMux. AllConnsGetter also acts as
+// a TCPMux, in which case it will return a single connection for one
+// of the ports.
+type AllConnsGetter interface {
+ GetAllConns(ufrag string, isIPv6 bool, localIP net.IP) ([]net.PacketConn, error)
+}
+
+// MultiTCPMuxDefault implements both TCPMux and AllConnsGetter,
+// allowing users to pass multiple TCPMux instances to the ICE agent
+// configuration.
+type MultiTCPMuxDefault struct {
+ muxes []TCPMux
+}
+
+// NewMultiTCPMuxDefault creates an instance of MultiTCPMuxDefault that
+// uses the provided TCPMux instances.
+func NewMultiTCPMuxDefault(muxes ...TCPMux) *MultiTCPMuxDefault {
+ return &MultiTCPMuxDefault{
+ muxes: muxes,
+ }
+}
+
+// GetConnByUfrag returns a PacketConn given the connection's ufrag, network and local address
+// creates the connection if an existing one can't be found. This, unlike
+// GetAllConns, will only return a single PacketConn from the first mux that was
+// passed in to NewMultiTCPMuxDefault.
+func (m *MultiTCPMuxDefault) GetConnByUfrag(ufrag string, isIPv6 bool, local net.IP) (net.PacketConn, error) {
+ // NOTE: We always use the first element here in order to maintain the
+ // behavior of using an existing connection if one exists.
+ if len(m.muxes) == 0 {
+ return nil, errNoTCPMuxAvailable
+ }
+ return m.muxes[0].GetConnByUfrag(ufrag, isIPv6, local)
+}
+
+// RemoveConnByUfrag stops and removes the muxed packet connection
+// from all underlying TCPMux instances.
+func (m *MultiTCPMuxDefault) RemoveConnByUfrag(ufrag string) {
+ for _, mux := range m.muxes {
+ mux.RemoveConnByUfrag(ufrag)
+ }
+}
+
+// GetAllConns returns a PacketConn for each underlying TCPMux
+func (m *MultiTCPMuxDefault) GetAllConns(ufrag string, isIPv6 bool, local net.IP) ([]net.PacketConn, error) {
+ if len(m.muxes) == 0 {
+ // Make sure that we either return at least one connection or an error.
+ return nil, errNoTCPMuxAvailable
+ }
+ var conns []net.PacketConn
+ for _, mux := range m.muxes {
+ conn, err := mux.GetConnByUfrag(ufrag, isIPv6, local)
+ if err != nil {
+ // For now, this implementation is all or none.
+ return nil, err
+ }
+ if conn != nil {
+ conns = append(conns, conn)
+ }
+ }
+ return conns, nil
+}
+
+// Close the multi mux, no further connections could be created
+func (m *MultiTCPMuxDefault) Close() error {
+ var err error
+ for _, mux := range m.muxes {
+ if e := mux.Close(); e != nil {
+ err = e
+ }
+ }
+ return err
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/tcp_packet_conn.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/tcp_packet_conn.go
index dc4eaf04f..8c51fd1cc 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/tcp_packet_conn.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/tcp_packet_conn.go
@@ -1,15 +1,78 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
+ "errors"
"fmt"
"io"
"net"
"sync"
+ "sync/atomic"
"time"
"github.com/pion/logging"
+ "github.com/pion/transport/v2/packetio"
)
+type bufferedConn struct {
+ net.Conn
+ buf *packetio.Buffer
+ logger logging.LeveledLogger
+ closed int32
+}
+
+func newBufferedConn(conn net.Conn, bufSize int, logger logging.LeveledLogger) net.Conn {
+ buf := packetio.NewBuffer()
+ if bufSize > 0 {
+ buf.SetLimitSize(bufSize)
+ }
+
+ bc := &bufferedConn{
+ Conn: conn,
+ buf: buf,
+ logger: logger,
+ }
+
+ go bc.writeProcess()
+ return bc
+}
+
+func (bc *bufferedConn) Write(b []byte) (int, error) {
+ n, err := bc.buf.Write(b)
+ if err != nil {
+ return n, err
+ }
+ return n, nil
+}
+
+func (bc *bufferedConn) writeProcess() {
+ pktBuf := make([]byte, receiveMTU)
+ for atomic.LoadInt32(&bc.closed) == 0 {
+ n, err := bc.buf.Read(pktBuf)
+ if errors.Is(err, io.EOF) {
+ return
+ }
+
+ if err != nil {
+ bc.logger.Warnf("read buffer error: %s", err)
+ continue
+ }
+
+ if _, err := bc.Conn.Write(pktBuf[:n]); err != nil {
+ bc.logger.Warnf("write error: %s", err)
+ continue
+ }
+ }
+}
+
+func (bc *bufferedConn) Close() error {
+ atomic.StoreInt32(&bc.closed, 1)
+ _ = bc.buf.Close()
+ return bc.Conn.Close()
+}
+
type tcpPacketConn struct {
params *tcpPacketParams
@@ -31,9 +94,10 @@ type streamingPacket struct {
}
type tcpPacketParams struct {
- ReadBuffer int
- LocalAddr net.Addr
- Logger logging.LeveledLogger
+ ReadBuffer int
+ LocalAddr net.Addr
+ Logger logging.LeveledLogger
+ WriteBuffer int
}
func newTCPPacketConn(params tcpPacketParams) *tcpPacketConn {
@@ -50,7 +114,7 @@ func newTCPPacketConn(params tcpPacketParams) *tcpPacketConn {
}
func (t *tcpPacketConn) AddConn(conn net.Conn, firstPacketData []byte) error {
- t.params.Logger.Infof("AddConn: %s %s", conn.RemoteAddr().Network(), conn.RemoteAddr())
+ t.params.Logger.Infof("AddConn: %s remote %s to local %s", conn.RemoteAddr().Network(), conn.RemoteAddr(), conn.LocalAddr())
t.mu.Lock()
defer t.mu.Unlock()
@@ -65,14 +129,25 @@ func (t *tcpPacketConn) AddConn(conn net.Conn, firstPacketData []byte) error {
return fmt.Errorf("%w: %s", errConnectionAddrAlreadyExist, conn.RemoteAddr().String())
}
+ if t.params.WriteBuffer > 0 {
+ conn = newBufferedConn(conn, t.params.WriteBuffer, t.params.Logger)
+ }
t.conns[conn.RemoteAddr().String()] = conn
t.wg.Add(1)
go func() {
- if firstPacketData != nil {
- t.recvChan <- streamingPacket{firstPacketData, conn.RemoteAddr(), nil}
- }
defer t.wg.Done()
+ if firstPacketData != nil {
+ select {
+ case <-t.closedChan:
+ // NOTE: recvChan can fill up and never drain in edge
+ // cases while closing a connection, which can cause the
+ // packetConn to never finish closing. Bail out early
+ // here to prevent that.
+ return
+ case t.recvChan <- streamingPacket{firstPacketData, conn.RemoteAddr(), nil}:
+ }
+ }
t.startReading(conn)
}()
@@ -84,9 +159,8 @@ func (t *tcpPacketConn) startReading(conn net.Conn) {
for {
n, err := readStreamingPacket(conn, buf)
- // t.params.Logger.Infof("readStreamingPacket read %d bytes", n)
if err != nil {
- t.params.Logger.Infof("%w: %s\n", errReadingStreamingPacket, err)
+ t.params.Logger.Infof("%v: %s", errReadingStreamingPacket, err)
t.handleRecv(streamingPacket{nil, conn.RemoteAddr(), err})
t.removeConn(conn)
return
@@ -95,7 +169,6 @@ func (t *tcpPacketConn) startReading(conn net.Conn) {
data := make([]byte, n)
copy(data, buf[:n])
- // t.params.Logger.Infof("Writing read streaming packet to recvChan: %d bytes", len(data))
t.handleRecv(streamingPacket{data, conn.RemoteAddr(), nil})
}
}
@@ -126,7 +199,7 @@ func (t *tcpPacketConn) isClosed() bool {
}
// WriteTo is for passive and s-o candidates.
-func (t *tcpPacketConn) ReadFrom(b []byte) (n int, raddr net.Addr, err error) {
+func (t *tcpPacketConn) ReadFrom(b []byte) (n int, rAddr net.Addr, err error) {
pkt, ok := <-t.recvChan
if !ok {
@@ -147,27 +220,18 @@ func (t *tcpPacketConn) ReadFrom(b []byte) (n int, raddr net.Addr, err error) {
}
// WriteTo is for active and s-o candidates.
-func (t *tcpPacketConn) WriteTo(buf []byte, raddr net.Addr) (n int, err error) {
+func (t *tcpPacketConn) WriteTo(buf []byte, rAddr net.Addr) (n int, err error) {
t.mu.Lock()
- defer t.mu.Unlock()
+ conn, ok := t.conns[rAddr.String()]
+ t.mu.Unlock()
- conn, ok := t.conns[raddr.String()]
if !ok {
return 0, io.ErrClosedPipe
- // conn, err := net.DialTCP(tcp, nil, raddr.(*net.TCPAddr))
-
- // if err != nil {
- // t.params.Logger.Tracef("DialTCP error: %s", err)
- // return 0, err
- // }
-
- // go t.startReading(conn)
- // t.conns[raddr.String()] = conn
}
n, err = writeStreamingPacket(conn, buf)
if err != nil {
- t.params.Logger.Tracef("%w %s\n", errWriting, raddr)
+ t.params.Logger.Tracef("%w %s", errWriting, rAddr)
return n, err
}
@@ -177,7 +241,7 @@ func (t *tcpPacketConn) WriteTo(buf []byte, raddr net.Addr) (n int, err error) {
func (t *tcpPacketConn) closeAndLogError(closer io.Closer) {
err := closer.Close()
if err != nil {
- t.params.Logger.Warnf("%w: %s", errClosingConnection, err)
+ t.params.Logger.Warnf("%v: %s", errClosingConnection, err)
}
}
@@ -219,15 +283,15 @@ func (t *tcpPacketConn) LocalAddr() net.Addr {
return t.params.LocalAddr
}
-func (t *tcpPacketConn) SetDeadline(tm time.Time) error {
+func (t *tcpPacketConn) SetDeadline(time.Time) error {
return nil
}
-func (t *tcpPacketConn) SetReadDeadline(tm time.Time) error {
+func (t *tcpPacketConn) SetReadDeadline(time.Time) error {
return nil
}
-func (t *tcpPacketConn) SetWriteDeadline(tm time.Time) error {
+func (t *tcpPacketConn) SetWriteDeadline(time.Time) error {
return nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/tcptype.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/tcptype.go
index 6700fe5ff..e500e57f5 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/tcptype.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/tcptype.go
@@ -1,9 +1,12 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import "strings"
// TCPType is the type of ICE TCP candidate as described in
-// ttps://tools.ietf.org/html/rfc6544#section-4.5
+// https://tools.ietf.org/html/rfc6544#section-4.5
type TCPType int
const (
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/test_utils.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/test_utils.go
new file mode 100644
index 000000000..235fda315
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/test_utils.go
@@ -0,0 +1,79 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+//go:build !js
+// +build !js
+
+package ice
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func newHostRemote(t *testing.T) *CandidateHost {
+ remoteHostConfig := &CandidateHostConfig{
+ Network: "udp",
+ Address: "1.2.3.5",
+ Port: 12350,
+ Component: 1,
+ }
+ hostRemote, err := NewCandidateHost(remoteHostConfig)
+ require.NoError(t, err)
+ return hostRemote
+}
+
+func newPrflxRemote(t *testing.T) *CandidatePeerReflexive {
+ prflxConfig := &CandidatePeerReflexiveConfig{
+ Network: "udp",
+ Address: "10.10.10.2",
+ Port: 19217,
+ Component: 1,
+ RelAddr: "4.3.2.1",
+ RelPort: 43211,
+ }
+ prflxRemote, err := NewCandidatePeerReflexive(prflxConfig)
+ require.NoError(t, err)
+ return prflxRemote
+}
+
+func newSrflxRemote(t *testing.T) *CandidateServerReflexive {
+ srflxConfig := &CandidateServerReflexiveConfig{
+ Network: "udp",
+ Address: "10.10.10.2",
+ Port: 19218,
+ Component: 1,
+ RelAddr: "4.3.2.1",
+ RelPort: 43212,
+ }
+ srflxRemote, err := NewCandidateServerReflexive(srflxConfig)
+ require.NoError(t, err)
+ return srflxRemote
+}
+
+func newRelayRemote(t *testing.T) *CandidateRelay {
+ relayConfig := &CandidateRelayConfig{
+ Network: "udp",
+ Address: "1.2.3.4",
+ Port: 12340,
+ Component: 1,
+ RelAddr: "4.3.2.1",
+ RelPort: 43210,
+ }
+ relayRemote, err := NewCandidateRelay(relayConfig)
+ require.NoError(t, err)
+ return relayRemote
+}
+
+func newHostLocal(t *testing.T) *CandidateHost {
+ localHostConfig := &CandidateHostConfig{
+ Network: "udp",
+ Address: "192.168.1.1",
+ Port: 19216,
+ Component: 1,
+ }
+ hostLocal, err := NewCandidateHost(localHostConfig)
+ require.NoError(t, err)
+ return hostLocal
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/transport.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/transport.go
index d1c82ffff..cd37a9b26 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/transport.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/transport.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import (
@@ -44,12 +47,12 @@ func (a *Agent) connect(ctx context.Context, isControlling bool, remoteUfrag, re
if err != nil {
return nil, err
}
- err = a.startConnectivityChecks(isControlling, remoteUfrag, remotePwd)
+ err = a.startConnectivityChecks(isControlling, remoteUfrag, remotePwd) //nolint:contextcheck
if err != nil {
return nil, err
}
- // block until pair selected
+ // Block until pair selected
select {
case <-a.done:
return nil, a.getErr()
@@ -70,7 +73,7 @@ func (c *Conn) Read(p []byte) (int, error) {
return 0, err
}
- n, err := c.agent.buffer.Read(p)
+ n, err := c.agent.buf.Read(p)
atomic.AddUint64(&c.bytesReceived, uint64(n))
return n, err
}
@@ -116,7 +119,7 @@ func (c *Conn) LocalAddr() net.Addr {
return nil
}
- return pair.local.addr()
+ return pair.Local.addr()
}
// RemoteAddr returns the remote address of the current selected pair or nil if there is none.
@@ -126,20 +129,20 @@ func (c *Conn) RemoteAddr() net.Addr {
return nil
}
- return pair.remote.addr()
+ return pair.Remote.addr()
}
// SetDeadline is a stub
-func (c *Conn) SetDeadline(t time.Time) error {
+func (c *Conn) SetDeadline(time.Time) error {
return nil
}
// SetReadDeadline is a stub
-func (c *Conn) SetReadDeadline(t time.Time) error {
+func (c *Conn) SetReadDeadline(time.Time) error {
return nil
}
// SetWriteDeadline is a stub
-func (c *Conn) SetWriteDeadline(t time.Time) error {
+func (c *Conn) SetWriteDeadline(time.Time) error {
return nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/udp_mux.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/udp_mux.go
new file mode 100644
index 000000000..405bb7b1a
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/udp_mux.go
@@ -0,0 +1,363 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package ice
+
+import (
+ "errors"
+ "io"
+ "net"
+ "os"
+ "strings"
+ "sync"
+
+ "github.com/pion/logging"
+ "github.com/pion/stun"
+ "github.com/pion/transport/v2"
+ "github.com/pion/transport/v2/stdnet"
+)
+
+// UDPMux allows multiple connections to go over a single UDP port
+type UDPMux interface {
+ io.Closer
+ GetConn(ufrag string, addr net.Addr) (net.PacketConn, error)
+ RemoveConnByUfrag(ufrag string)
+ GetListenAddresses() []net.Addr
+}
+
+// UDPMuxDefault is an implementation of the interface
+type UDPMuxDefault struct {
+ params UDPMuxParams
+
+ closedChan chan struct{}
+ closeOnce sync.Once
+
+ // connsIPv4 and connsIPv6 are maps of all udpMuxedConn indexed by ufrag|network|candidateType
+ connsIPv4, connsIPv6 map[string]*udpMuxedConn
+
+ addressMapMu sync.RWMutex
+ addressMap map[string]*udpMuxedConn
+
+ // Buffer pool to recycle buffers for net.UDPAddr encodes/decodes
+ pool *sync.Pool
+
+ mu sync.Mutex
+
+ // For UDP connection listen at unspecified address
+ localAddrsForUnspecified []net.Addr
+}
+
+const maxAddrSize = 512
+
+// UDPMuxParams are parameters for UDPMux.
+type UDPMuxParams struct {
+ Logger logging.LeveledLogger
+ UDPConn net.PacketConn
+
+ // Required for gathering local addresses
+ // in case a un UDPConn is passed which does not
+ // bind to a specific local address.
+ Net transport.Net
+}
+
+// NewUDPMuxDefault creates an implementation of UDPMux
+func NewUDPMuxDefault(params UDPMuxParams) *UDPMuxDefault {
+ if params.Logger == nil {
+ params.Logger = logging.NewDefaultLoggerFactory().NewLogger("ice")
+ }
+
+ var localAddrsForUnspecified []net.Addr
+ if addr, ok := params.UDPConn.LocalAddr().(*net.UDPAddr); !ok {
+ params.Logger.Errorf("LocalAddr is not a net.UDPAddr, got %T", params.UDPConn.LocalAddr())
+ } else if ok && addr.IP.IsUnspecified() {
+ // For unspecified addresses, the correct behavior is to return errListenUnspecified, but
+ // it will break the applications that are already using unspecified UDP connection
+ // with UDPMuxDefault, so print a warn log and create a local address list for mux.
+ params.Logger.Warn("UDPMuxDefault should not listening on unspecified address, use NewMultiUDPMuxFromPort instead")
+ var networks []NetworkType
+ switch {
+ case addr.IP.To4() != nil:
+ networks = []NetworkType{NetworkTypeUDP4}
+
+ case addr.IP.To16() != nil:
+ networks = []NetworkType{NetworkTypeUDP4, NetworkTypeUDP6}
+
+ default:
+ params.Logger.Errorf("LocalAddr expected IPV4 or IPV6, got %T", params.UDPConn.LocalAddr())
+ }
+ if len(networks) > 0 {
+ if params.Net == nil {
+ var err error
+ if params.Net, err = stdnet.NewNet(); err != nil {
+ params.Logger.Errorf("failed to get create network: %v", err)
+ }
+ }
+
+ ips, err := localInterfaces(params.Net, nil, nil, networks, true)
+ if err == nil {
+ for _, ip := range ips {
+ localAddrsForUnspecified = append(localAddrsForUnspecified, &net.UDPAddr{IP: ip, Port: addr.Port})
+ }
+ } else {
+ params.Logger.Errorf("failed to get local interfaces for unspecified addr: %v", err)
+ }
+ }
+ }
+
+ m := &UDPMuxDefault{
+ addressMap: map[string]*udpMuxedConn{},
+ params: params,
+ connsIPv4: make(map[string]*udpMuxedConn),
+ connsIPv6: make(map[string]*udpMuxedConn),
+ closedChan: make(chan struct{}, 1),
+ pool: &sync.Pool{
+ New: func() interface{} {
+ // Big enough buffer to fit both packet and address
+ return newBufferHolder(receiveMTU + maxAddrSize)
+ },
+ },
+ localAddrsForUnspecified: localAddrsForUnspecified,
+ }
+
+ go m.connWorker()
+
+ return m
+}
+
+// LocalAddr returns the listening address of this UDPMuxDefault
+func (m *UDPMuxDefault) LocalAddr() net.Addr {
+ return m.params.UDPConn.LocalAddr()
+}
+
+// GetListenAddresses returns the list of addresses that this mux is listening on
+func (m *UDPMuxDefault) GetListenAddresses() []net.Addr {
+ if len(m.localAddrsForUnspecified) > 0 {
+ return m.localAddrsForUnspecified
+ }
+
+ return []net.Addr{m.LocalAddr()}
+}
+
+// GetConn returns a PacketConn given the connection's ufrag and network address
+// creates the connection if an existing one can't be found
+func (m *UDPMuxDefault) GetConn(ufrag string, addr net.Addr) (net.PacketConn, error) {
+ // don't check addr for mux using unspecified address
+ if len(m.localAddrsForUnspecified) == 0 && m.params.UDPConn.LocalAddr().String() != addr.String() {
+ return nil, errInvalidAddress
+ }
+
+ var isIPv6 bool
+ if udpAddr, _ := addr.(*net.UDPAddr); udpAddr != nil && udpAddr.IP.To4() == nil {
+ isIPv6 = true
+ }
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ if m.IsClosed() {
+ return nil, io.ErrClosedPipe
+ }
+
+ if conn, ok := m.getConn(ufrag, isIPv6); ok {
+ return conn, nil
+ }
+
+ c := m.createMuxedConn(ufrag)
+ go func() {
+ <-c.CloseChannel()
+ m.RemoveConnByUfrag(ufrag)
+ }()
+
+ if isIPv6 {
+ m.connsIPv6[ufrag] = c
+ } else {
+ m.connsIPv4[ufrag] = c
+ }
+
+ return c, nil
+}
+
+// RemoveConnByUfrag stops and removes the muxed packet connection
+func (m *UDPMuxDefault) RemoveConnByUfrag(ufrag string) {
+ removedConns := make([]*udpMuxedConn, 0, 2)
+
+ // Keep lock section small to avoid deadlock with conn lock
+ m.mu.Lock()
+ if c, ok := m.connsIPv4[ufrag]; ok {
+ delete(m.connsIPv4, ufrag)
+ removedConns = append(removedConns, c)
+ }
+ if c, ok := m.connsIPv6[ufrag]; ok {
+ delete(m.connsIPv6, ufrag)
+ removedConns = append(removedConns, c)
+ }
+ m.mu.Unlock()
+
+ if len(removedConns) == 0 {
+ // No need to lock if no connection was found
+ return
+ }
+
+ m.addressMapMu.Lock()
+ defer m.addressMapMu.Unlock()
+
+ for _, c := range removedConns {
+ addresses := c.getAddresses()
+ for _, addr := range addresses {
+ delete(m.addressMap, addr)
+ }
+ }
+}
+
+// IsClosed returns true if the mux had been closed
+func (m *UDPMuxDefault) IsClosed() bool {
+ select {
+ case <-m.closedChan:
+ return true
+ default:
+ return false
+ }
+}
+
+// Close the mux, no further connections could be created
+func (m *UDPMuxDefault) Close() error {
+ var err error
+ m.closeOnce.Do(func() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ for _, c := range m.connsIPv4 {
+ _ = c.Close()
+ }
+ for _, c := range m.connsIPv6 {
+ _ = c.Close()
+ }
+
+ m.connsIPv4 = make(map[string]*udpMuxedConn)
+ m.connsIPv6 = make(map[string]*udpMuxedConn)
+
+ close(m.closedChan)
+
+ _ = m.params.UDPConn.Close()
+ })
+ return err
+}
+
+func (m *UDPMuxDefault) writeTo(buf []byte, rAddr net.Addr) (n int, err error) {
+ return m.params.UDPConn.WriteTo(buf, rAddr)
+}
+
+func (m *UDPMuxDefault) registerConnForAddress(conn *udpMuxedConn, addr string) {
+ if m.IsClosed() {
+ return
+ }
+
+ m.addressMapMu.Lock()
+ defer m.addressMapMu.Unlock()
+
+ existing, ok := m.addressMap[addr]
+ 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 {
+ c := newUDPMuxedConn(&udpMuxedConnParams{
+ Mux: m,
+ Key: key,
+ AddrPool: m.pool,
+ LocalAddr: m.LocalAddr(),
+ Logger: m.params.Logger,
+ })
+ return c
+}
+
+func (m *UDPMuxDefault) connWorker() {
+ logger := m.params.Logger
+
+ defer func() {
+ _ = m.Close()
+ }()
+
+ buf := make([]byte, receiveMTU)
+ for {
+ n, addr, err := m.params.UDPConn.ReadFrom(buf)
+ if m.IsClosed() {
+ return
+ } else if err != nil {
+ if os.IsTimeout(err) {
+ continue
+ } else if !errors.Is(err, io.EOF) {
+ logger.Errorf("could not read udp packet: %v", err)
+ }
+
+ return
+ }
+
+ udpAddr, ok := addr.(*net.UDPAddr)
+ if !ok {
+ logger.Errorf("underlying PacketConn did not return a UDPAddr")
+ return
+ }
+
+ // If we have already seen this address dispatch to the appropriate destination
+ m.addressMapMu.Lock()
+ destinationConn := m.addressMap[addr.String()]
+ m.addressMapMu.Unlock()
+
+ // If we haven't seen this address before but is a STUN packet lookup by ufrag
+ if destinationConn == nil && stun.IsMessage(buf[:n]) {
+ msg := &stun.Message{
+ Raw: append([]byte{}, buf[:n]...),
+ }
+
+ if err = msg.Decode(); err != nil {
+ m.params.Logger.Warnf("Failed to handle decode ICE from %s: %v", addr.String(), err)
+ continue
+ }
+
+ attr, stunAttrErr := msg.Get(stun.AttrUsername)
+ if stunAttrErr != nil {
+ m.params.Logger.Warnf("No Username attribute in STUN message from %s", addr.String())
+ continue
+ }
+
+ ufrag := strings.Split(string(attr), ":")[0]
+ isIPv6 := udpAddr.IP.To4() == nil
+
+ m.mu.Lock()
+ destinationConn, _ = m.getConn(ufrag, isIPv6)
+ m.mu.Unlock()
+ }
+
+ 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 {
+ m.params.Logger.Errorf("could not write packet: %v", err)
+ }
+ }
+}
+
+func (m *UDPMuxDefault) getConn(ufrag string, isIPv6 bool) (val *udpMuxedConn, ok bool) {
+ if isIPv6 {
+ val, ok = m.connsIPv6[ufrag]
+ } else {
+ val, ok = m.connsIPv4[ufrag]
+ }
+ return
+}
+
+type bufferHolder struct {
+ buf []byte
+}
+
+func newBufferHolder(size int) *bufferHolder {
+ return &bufferHolder{
+ buf: make([]byte, size),
+ }
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/udp_mux_multi.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/udp_mux_multi.go
new file mode 100644
index 000000000..158cbc37f
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/udp_mux_multi.go
@@ -0,0 +1,228 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package ice
+
+import (
+ "fmt"
+ "net"
+
+ "github.com/pion/logging"
+ "github.com/pion/transport/v2"
+ "github.com/pion/transport/v2/stdnet"
+)
+
+// MultiUDPMuxDefault implements both UDPMux and AllConnsGetter,
+// allowing users to pass multiple UDPMux instances to the ICE agent
+// configuration.
+type MultiUDPMuxDefault struct {
+ muxes []UDPMux
+ localAddrToMux map[string]UDPMux
+}
+
+// NewMultiUDPMuxDefault creates an instance of MultiUDPMuxDefault that
+// uses the provided UDPMux instances.
+func NewMultiUDPMuxDefault(muxes ...UDPMux) *MultiUDPMuxDefault {
+ addrToMux := make(map[string]UDPMux)
+ for _, mux := range muxes {
+ for _, addr := range mux.GetListenAddresses() {
+ addrToMux[addr.String()] = mux
+ }
+ }
+ return &MultiUDPMuxDefault{
+ muxes: muxes,
+ localAddrToMux: addrToMux,
+ }
+}
+
+// GetConn returns a PacketConn given the connection's ufrag and network
+// creates the connection if an existing one can't be found.
+func (m *MultiUDPMuxDefault) GetConn(ufrag string, addr net.Addr) (net.PacketConn, error) {
+ mux, ok := m.localAddrToMux[addr.String()]
+ if !ok {
+ return nil, errNoUDPMuxAvailable
+ }
+ return mux.GetConn(ufrag, addr)
+}
+
+// RemoveConnByUfrag stops and removes the muxed packet connection
+// from all underlying UDPMux instances.
+func (m *MultiUDPMuxDefault) RemoveConnByUfrag(ufrag string) {
+ for _, mux := range m.muxes {
+ mux.RemoveConnByUfrag(ufrag)
+ }
+}
+
+// Close the multi mux, no further connections could be created
+func (m *MultiUDPMuxDefault) Close() error {
+ var err error
+ for _, mux := range m.muxes {
+ if e := mux.Close(); e != nil {
+ err = e
+ }
+ }
+ return err
+}
+
+// GetListenAddresses returns the list of addresses that this mux is listening on
+func (m *MultiUDPMuxDefault) GetListenAddresses() []net.Addr {
+ addrs := make([]net.Addr, 0, len(m.localAddrToMux))
+ for _, mux := range m.muxes {
+ addrs = append(addrs, mux.GetListenAddresses()...)
+ }
+ return addrs
+}
+
+// NewMultiUDPMuxFromPort creates an instance of MultiUDPMuxDefault that
+// listen all interfaces on the provided port.
+func NewMultiUDPMuxFromPort(port int, opts ...UDPMuxFromPortOption) (*MultiUDPMuxDefault, error) {
+ params := multiUDPMuxFromPortParam{
+ networks: []NetworkType{NetworkTypeUDP4, NetworkTypeUDP6},
+ }
+ for _, opt := range opts {
+ opt.apply(¶ms)
+ }
+
+ if params.net == nil {
+ var err error
+ if params.net, err = stdnet.NewNet(); err != nil {
+ return nil, fmt.Errorf("failed to get create network: %w", err)
+ }
+ }
+
+ ips, err := localInterfaces(params.net, params.ifFilter, params.ipFilter, params.networks, params.includeLoopback)
+ if err != nil {
+ return nil, err
+ }
+
+ conns := make([]net.PacketConn, 0, len(ips))
+ for _, ip := range ips {
+ conn, listenErr := params.net.ListenUDP("udp", &net.UDPAddr{IP: ip, Port: port})
+ if listenErr != nil {
+ err = listenErr
+ break
+ }
+ if params.readBufferSize > 0 {
+ _ = conn.SetReadBuffer(params.readBufferSize)
+ }
+ if params.writeBufferSize > 0 {
+ _ = conn.SetWriteBuffer(params.writeBufferSize)
+ }
+ conns = append(conns, conn)
+ }
+
+ if err != nil {
+ for _, conn := range conns {
+ _ = conn.Close()
+ }
+ return nil, err
+ }
+
+ muxes := make([]UDPMux, 0, len(conns))
+ for _, conn := range conns {
+ mux := NewUDPMuxDefault(UDPMuxParams{
+ Logger: params.logger,
+ UDPConn: conn,
+ Net: params.net,
+ })
+ muxes = append(muxes, mux)
+ }
+
+ return NewMultiUDPMuxDefault(muxes...), nil
+}
+
+// UDPMuxFromPortOption provide options for NewMultiUDPMuxFromPort
+type UDPMuxFromPortOption interface {
+ apply(*multiUDPMuxFromPortParam)
+}
+
+type multiUDPMuxFromPortParam struct {
+ ifFilter func(string) bool
+ ipFilter func(ip net.IP) bool
+ networks []NetworkType
+ readBufferSize int
+ writeBufferSize int
+ logger logging.LeveledLogger
+ includeLoopback bool
+ net transport.Net
+}
+
+type udpMuxFromPortOption struct {
+ f func(*multiUDPMuxFromPortParam)
+}
+
+func (o *udpMuxFromPortOption) apply(p *multiUDPMuxFromPortParam) {
+ o.f(p)
+}
+
+// UDPMuxFromPortWithInterfaceFilter set the filter to filter out interfaces that should not be used
+func UDPMuxFromPortWithInterfaceFilter(f func(string) bool) UDPMuxFromPortOption {
+ return &udpMuxFromPortOption{
+ f: func(p *multiUDPMuxFromPortParam) {
+ p.ifFilter = f
+ },
+ }
+}
+
+// UDPMuxFromPortWithIPFilter set the filter to filter out IP addresses that should not be used
+func UDPMuxFromPortWithIPFilter(f func(ip net.IP) bool) UDPMuxFromPortOption {
+ return &udpMuxFromPortOption{
+ f: func(p *multiUDPMuxFromPortParam) {
+ p.ipFilter = f
+ },
+ }
+}
+
+// UDPMuxFromPortWithNetworks set the networks that should be used. default is both IPv4 and IPv6
+func UDPMuxFromPortWithNetworks(networks ...NetworkType) UDPMuxFromPortOption {
+ return &udpMuxFromPortOption{
+ f: func(p *multiUDPMuxFromPortParam) {
+ p.networks = networks
+ },
+ }
+}
+
+// UDPMuxFromPortWithReadBufferSize set the UDP connection read buffer size
+func UDPMuxFromPortWithReadBufferSize(size int) UDPMuxFromPortOption {
+ return &udpMuxFromPortOption{
+ f: func(p *multiUDPMuxFromPortParam) {
+ p.readBufferSize = size
+ },
+ }
+}
+
+// UDPMuxFromPortWithWriteBufferSize set the UDP connection write buffer size
+func UDPMuxFromPortWithWriteBufferSize(size int) UDPMuxFromPortOption {
+ return &udpMuxFromPortOption{
+ f: func(p *multiUDPMuxFromPortParam) {
+ p.writeBufferSize = size
+ },
+ }
+}
+
+// UDPMuxFromPortWithLogger set the logger for the created UDPMux
+func UDPMuxFromPortWithLogger(logger logging.LeveledLogger) UDPMuxFromPortOption {
+ return &udpMuxFromPortOption{
+ f: func(p *multiUDPMuxFromPortParam) {
+ p.logger = logger
+ },
+ }
+}
+
+// UDPMuxFromPortWithLoopback set loopback interface should be included
+func UDPMuxFromPortWithLoopback() UDPMuxFromPortOption {
+ return &udpMuxFromPortOption{
+ f: func(p *multiUDPMuxFromPortParam) {
+ p.includeLoopback = true
+ },
+ }
+}
+
+// UDPMuxFromPortWithNet sets the network transport to use.
+func UDPMuxFromPortWithNet(n transport.Net) UDPMuxFromPortOption {
+ return &udpMuxFromPortOption{
+ f: func(p *multiUDPMuxFromPortParam) {
+ p.net = n
+ },
+ }
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/udp_mux_universal.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/udp_mux_universal.go
new file mode 100644
index 000000000..07b6a70ea
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/udp_mux_universal.go
@@ -0,0 +1,271 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package ice
+
+import (
+ "fmt"
+ "net"
+ "time"
+
+ "github.com/pion/logging"
+ "github.com/pion/stun"
+ "github.com/pion/transport/v2"
+)
+
+// UniversalUDPMux allows multiple connections to go over a single UDP port for
+// host, server reflexive and relayed candidates.
+// Actual connection muxing is happening in the UDPMux.
+type UniversalUDPMux interface {
+ UDPMux
+ GetXORMappedAddr(stunAddr net.Addr, deadline time.Duration) (*stun.XORMappedAddress, error)
+ GetRelayedAddr(turnAddr net.Addr, deadline time.Duration) (*net.Addr, error)
+ GetConnForURL(ufrag string, url string, addr net.Addr) (net.PacketConn, error)
+}
+
+// UniversalUDPMuxDefault handles STUN and TURN servers packets by wrapping the original UDPConn overriding ReadFrom.
+// It the passes packets to the UDPMux that does the actual connection muxing.
+type UniversalUDPMuxDefault struct {
+ *UDPMuxDefault
+ params UniversalUDPMuxParams
+
+ // Since we have a shared socket, for srflx candidates it makes sense to have a shared mapped address across all the agents
+ // stun.XORMappedAddress indexed by the STUN server addr
+ xorMappedMap map[string]*xorMapped
+}
+
+// UniversalUDPMuxParams are parameters for UniversalUDPMux server reflexive.
+type UniversalUDPMuxParams struct {
+ Logger logging.LeveledLogger
+ UDPConn net.PacketConn
+ XORMappedAddrCacheTTL time.Duration
+ Net transport.Net
+}
+
+// NewUniversalUDPMuxDefault creates an implementation of UniversalUDPMux embedding UDPMux
+func NewUniversalUDPMuxDefault(params UniversalUDPMuxParams) *UniversalUDPMuxDefault {
+ if params.Logger == nil {
+ params.Logger = logging.NewDefaultLoggerFactory().NewLogger("ice")
+ }
+ if params.XORMappedAddrCacheTTL == 0 {
+ params.XORMappedAddrCacheTTL = time.Second * 25
+ }
+
+ m := &UniversalUDPMuxDefault{
+ params: params,
+ xorMappedMap: make(map[string]*xorMapped),
+ }
+
+ // Wrap UDP connection, process server reflexive messages
+ // before they are passed to the UDPMux connection handler (connWorker)
+ m.params.UDPConn = &udpConn{
+ PacketConn: params.UDPConn,
+ mux: m,
+ logger: params.Logger,
+ }
+
+ // Embed UDPMux
+ udpMuxParams := UDPMuxParams{
+ Logger: params.Logger,
+ UDPConn: m.params.UDPConn,
+ Net: m.params.Net,
+ }
+ m.UDPMuxDefault = NewUDPMuxDefault(udpMuxParams)
+
+ return m
+}
+
+// udpConn is a wrapper around UDPMux conn that overrides ReadFrom and handles STUN/TURN packets
+type udpConn struct {
+ net.PacketConn
+ mux *UniversalUDPMuxDefault
+ logger logging.LeveledLogger
+}
+
+// GetRelayedAddr creates relayed connection to the given TURN service and returns the relayed addr.
+// Not implemented yet.
+func (m *UniversalUDPMuxDefault) GetRelayedAddr(net.Addr, time.Duration) (*net.Addr, error) {
+ return nil, errNotImplemented
+}
+
+// GetConnForURL add uniques to the muxed connection by concatenating ufrag and URL (e.g. STUN URL) to be able to support multiple STUN/TURN servers
+// and return a unique connection per server.
+func (m *UniversalUDPMuxDefault) GetConnForURL(ufrag string, url string, addr net.Addr) (net.PacketConn, error) {
+ return m.UDPMuxDefault.GetConn(fmt.Sprintf("%s%s", ufrag, url), addr)
+}
+
+// ReadFrom is called by UDPMux connWorker and handles packets coming from the STUN server discovering a mapped address.
+// It passes processed packets further to the UDPMux (maybe this is not really necessary).
+func (c *udpConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
+ n, addr, err = c.PacketConn.ReadFrom(p)
+ if err != nil {
+ return
+ }
+
+ if stun.IsMessage(p[:n]) {
+ msg := &stun.Message{
+ Raw: append([]byte{}, p[:n]...),
+ }
+
+ if err = msg.Decode(); err != nil {
+ c.logger.Warnf("Failed to handle decode ICE from %s: %v", addr.String(), err)
+ err = nil
+ return
+ }
+
+ udpAddr, ok := addr.(*net.UDPAddr)
+ if !ok {
+ // Message about this err will be logged in the UDPMux
+ return
+ }
+
+ if c.mux.isXORMappedResponse(msg, udpAddr.String()) {
+ err = c.mux.handleXORMappedResponse(udpAddr, msg)
+ if err != nil {
+ c.logger.Debugf("%w: %v", errGetXorMappedAddrResponse, err)
+ err = nil
+ }
+ return
+ }
+ }
+ return n, addr, err
+}
+
+// isXORMappedResponse indicates whether the message is a XORMappedAddress and is coming from the known STUN server.
+func (m *UniversalUDPMuxDefault) isXORMappedResponse(msg *stun.Message, stunAddr string) bool {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ // Check first if it is a STUN server address because remote peer can also send similar messages but as a BindingSuccess
+ _, ok := m.xorMappedMap[stunAddr]
+ _, err := msg.Get(stun.AttrXORMappedAddress)
+ return err == nil && ok
+}
+
+// handleXORMappedResponse parses response from the STUN server, extracts XORMappedAddress attribute
+// and set the mapped address for the server
+func (m *UniversalUDPMuxDefault) handleXORMappedResponse(stunAddr *net.UDPAddr, msg *stun.Message) error {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ mappedAddr, ok := m.xorMappedMap[stunAddr.String()]
+ if !ok {
+ return errNoXorAddrMapping
+ }
+
+ var addr stun.XORMappedAddress
+ if err := addr.GetFrom(msg); err != nil {
+ return err
+ }
+
+ m.xorMappedMap[stunAddr.String()] = mappedAddr
+ mappedAddr.SetAddr(&addr)
+
+ return nil
+}
+
+// GetXORMappedAddr returns *stun.XORMappedAddress if already present for a given STUN server.
+// Makes a STUN binding request to discover mapped address otherwise.
+// Blocks until the stun.XORMappedAddress has been discovered or deadline.
+// Method is safe for concurrent use.
+func (m *UniversalUDPMuxDefault) GetXORMappedAddr(serverAddr net.Addr, deadline time.Duration) (*stun.XORMappedAddress, error) {
+ m.mu.Lock()
+ mappedAddr, ok := m.xorMappedMap[serverAddr.String()]
+ // If we already have a mapping for this STUN server (address already received)
+ // and if it is not too old we return it without making a new request to STUN server
+ if ok {
+ if mappedAddr.expired() {
+ mappedAddr.closeWaiters()
+ delete(m.xorMappedMap, serverAddr.String())
+ ok = false
+ } else if mappedAddr.pending() {
+ ok = false
+ }
+ }
+ m.mu.Unlock()
+ if ok {
+ return mappedAddr.addr, nil
+ }
+
+ // Otherwise, make a STUN request to discover the address
+ // or wait for already sent request to complete
+ waitAddrReceived, err := m.sendSTUN(serverAddr)
+ if err != nil {
+ return nil, fmt.Errorf("%w: %s", errSendSTUNPacket, err) //nolint:errorlint
+ }
+
+ // Block until response was handled by the connWorker routine and XORMappedAddress was updated
+ select {
+ case <-waitAddrReceived:
+ // When channel closed, addr was obtained
+ m.mu.Lock()
+ mappedAddr := *m.xorMappedMap[serverAddr.String()]
+ m.mu.Unlock()
+ if mappedAddr.addr == nil {
+ return nil, errNoXorAddrMapping
+ }
+ return mappedAddr.addr, nil
+ case <-time.After(deadline):
+ return nil, errXORMappedAddrTimeout
+ }
+}
+
+// sendSTUN sends a STUN request via UDP conn.
+//
+// The returned channel is closed when the STUN response has been received.
+// Method is safe for concurrent use.
+func (m *UniversalUDPMuxDefault) sendSTUN(serverAddr net.Addr) (chan struct{}, error) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ // If record present in the map, we already sent a STUN request,
+ // just wait when waitAddrReceived will be closed
+ addrMap, ok := m.xorMappedMap[serverAddr.String()]
+ if !ok {
+ addrMap = &xorMapped{
+ expiresAt: time.Now().Add(m.params.XORMappedAddrCacheTTL),
+ waitAddrReceived: make(chan struct{}),
+ }
+ m.xorMappedMap[serverAddr.String()] = addrMap
+ }
+
+ req, err := stun.Build(stun.BindingRequest, stun.TransactionID)
+ if err != nil {
+ return nil, err
+ }
+
+ if _, err = m.params.UDPConn.WriteTo(req.Raw, serverAddr); err != nil {
+ return nil, err
+ }
+
+ return addrMap.waitAddrReceived, nil
+}
+
+type xorMapped struct {
+ addr *stun.XORMappedAddress
+ waitAddrReceived chan struct{}
+ expiresAt time.Time
+}
+
+func (a *xorMapped) closeWaiters() {
+ select {
+ case <-a.waitAddrReceived:
+ // Notify was close, ok, that means we received duplicate response just exit
+ break
+ default:
+ // Notify tha twe have a new addr
+ close(a.waitAddrReceived)
+ }
+}
+
+func (a *xorMapped) pending() bool {
+ return a.addr == nil
+}
+
+func (a *xorMapped) expired() bool {
+ return a.expiresAt.Before(time.Now())
+}
+
+func (a *xorMapped) SetAddr(addr *stun.XORMappedAddress) {
+ a.addr = addr
+ a.closeWaiters()
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/udp_muxed_conn.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/udp_muxed_conn.go
new file mode 100644
index 000000000..09e4b3a8e
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/udp_muxed_conn.go
@@ -0,0 +1,246 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package ice
+
+import (
+ "encoding/binary"
+ "io"
+ "net"
+ "sync"
+ "time"
+
+ "github.com/pion/logging"
+ "github.com/pion/transport/v2/packetio"
+)
+
+type udpMuxedConnParams struct {
+ Mux *UDPMuxDefault
+ AddrPool *sync.Pool
+ Key string
+ LocalAddr net.Addr
+ Logger logging.LeveledLogger
+}
+
+// udpMuxedConn represents a logical packet conn for a single remote as identified by ufrag
+type udpMuxedConn struct {
+ params *udpMuxedConnParams
+ // Remote addresses that we have sent to on this conn
+ addresses []string
+
+ // Channel holding incoming packets
+ buf *packetio.Buffer
+ closedChan chan struct{}
+ closeOnce sync.Once
+ mu sync.Mutex
+}
+
+func newUDPMuxedConn(params *udpMuxedConnParams) *udpMuxedConn {
+ p := &udpMuxedConn{
+ params: params,
+ buf: packetio.NewBuffer(),
+ closedChan: make(chan struct{}),
+ }
+
+ return p
+}
+
+func (c *udpMuxedConn) ReadFrom(b []byte) (n int, rAddr net.Addr, err error) {
+ buf := c.params.AddrPool.Get().(*bufferHolder) //nolint:forcetypeassert
+ defer c.params.AddrPool.Put(buf)
+
+ // Read address
+ total, err := c.buf.Read(buf.buf)
+ if err != nil {
+ return 0, nil, err
+ }
+
+ dataLen := int(binary.LittleEndian.Uint16(buf.buf[:2]))
+ if dataLen > total || dataLen > len(b) {
+ return 0, nil, io.ErrShortBuffer
+ }
+
+ // Read data and then address
+ offset := 2
+ copy(b, buf.buf[offset:offset+dataLen])
+ offset += dataLen
+
+ // Read address len & decode address
+ addrLen := int(binary.LittleEndian.Uint16(buf.buf[offset : offset+2]))
+ offset += 2
+
+ if rAddr, err = decodeUDPAddr(buf.buf[offset : offset+addrLen]); err != nil {
+ return 0, nil, err
+ }
+
+ return dataLen, rAddr, nil
+}
+
+func (c *udpMuxedConn) WriteTo(buf []byte, rAddr net.Addr) (n int, err error) {
+ if c.isClosed() {
+ return 0, io.ErrClosedPipe
+ }
+ // Each time we write to a new address, we'll register it with the mux
+ addr := rAddr.String()
+ if !c.containsAddress(addr) {
+ c.addAddress(addr)
+ }
+
+ return c.params.Mux.writeTo(buf, rAddr)
+}
+
+func (c *udpMuxedConn) LocalAddr() net.Addr {
+ return c.params.LocalAddr
+}
+
+func (c *udpMuxedConn) SetDeadline(time.Time) error {
+ return nil
+}
+
+func (c *udpMuxedConn) SetReadDeadline(time.Time) error {
+ return nil
+}
+
+func (c *udpMuxedConn) SetWriteDeadline(time.Time) error {
+ return nil
+}
+
+func (c *udpMuxedConn) CloseChannel() <-chan struct{} {
+ return c.closedChan
+}
+
+func (c *udpMuxedConn) Close() error {
+ var err error
+ c.closeOnce.Do(func() {
+ err = c.buf.Close()
+ close(c.closedChan)
+ })
+ return err
+}
+
+func (c *udpMuxedConn) isClosed() bool {
+ select {
+ case <-c.closedChan:
+ return true
+ default:
+ return false
+ }
+}
+
+func (c *udpMuxedConn) getAddresses() []string {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ addresses := make([]string, len(c.addresses))
+ copy(addresses, c.addresses)
+ return addresses
+}
+
+func (c *udpMuxedConn) addAddress(addr string) {
+ c.mu.Lock()
+ c.addresses = append(c.addresses, addr)
+ c.mu.Unlock()
+
+ // Map it on mux
+ c.params.Mux.registerConnForAddress(c, addr)
+}
+
+func (c *udpMuxedConn) removeAddress(addr string) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ newAddresses := make([]string, 0, len(c.addresses))
+ for _, a := range c.addresses {
+ if a != addr {
+ newAddresses = append(newAddresses, a)
+ }
+ }
+
+ c.addresses = newAddresses
+}
+
+func (c *udpMuxedConn) containsAddress(addr string) bool {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ for _, a := range c.addresses {
+ if addr == a {
+ return true
+ }
+ }
+ return false
+}
+
+func (c *udpMuxedConn) writePacket(data []byte, addr *net.UDPAddr) error {
+ // Write two packets, address and data
+ buf := c.params.AddrPool.Get().(*bufferHolder) //nolint:forcetypeassert
+ defer c.params.AddrPool.Put(buf)
+
+ // Format of buffer | data len | data bytes | addr len | addr bytes |
+ if len(buf.buf) < len(data)+maxAddrSize {
+ return io.ErrShortBuffer
+ }
+ // Data length
+ binary.LittleEndian.PutUint16(buf.buf, uint16(len(data)))
+ offset := 2
+
+ // Data
+ copy(buf.buf[offset:], data)
+ offset += len(data)
+
+ // Write address first, leaving room for its length
+ n, err := encodeUDPAddr(addr, buf.buf[offset+2:])
+ if err != nil {
+ return err
+ }
+ total := offset + n + 2
+
+ // Address len
+ binary.LittleEndian.PutUint16(buf.buf[offset:], uint16(n))
+
+ if _, err := c.buf.Write(buf.buf[:total]); err != nil {
+ return err
+ }
+ return nil
+}
+
+func encodeUDPAddr(addr *net.UDPAddr, buf []byte) (int, error) {
+ ipData, err := addr.IP.MarshalText()
+ if err != nil {
+ return 0, err
+ }
+ total := 2 + len(ipData) + 2 + len(addr.Zone)
+ if total > len(buf) {
+ return 0, io.ErrShortBuffer
+ }
+
+ binary.LittleEndian.PutUint16(buf, uint16(len(ipData)))
+ offset := 2
+ n := copy(buf[offset:], ipData)
+ offset += n
+ binary.LittleEndian.PutUint16(buf[offset:], uint16(addr.Port))
+ offset += 2
+ copy(buf[offset:], addr.Zone)
+ return total, nil
+}
+
+func decodeUDPAddr(buf []byte) (*net.UDPAddr, error) {
+ addr := net.UDPAddr{}
+
+ offset := 0
+ ipLen := int(binary.LittleEndian.Uint16(buf[:2]))
+ offset += 2
+ // Basic bounds checking
+ if ipLen+offset > len(buf) {
+ return nil, io.ErrShortBuffer
+ }
+ if err := addr.IP.UnmarshalText(buf[offset : offset+ipLen]); err != nil {
+ return nil, err
+ }
+ offset += ipLen
+ addr.Port = int(binary.LittleEndian.Uint16(buf[offset : offset+2]))
+ offset += 2
+ zone := make([]byte, len(buf[offset:]))
+ copy(zone, buf[offset:])
+ addr.Zone = string(zone)
+
+ return &addr, nil
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/url.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/url.go
index 390591e3d..b2b9f8bd3 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/url.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/url.go
@@ -1,225 +1,82 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
-import (
- "net"
- "net/url"
- "strconv"
+import "github.com/pion/stun"
+
+type (
+ // URL represents a STUN (rfc7064) or TURN (rfc7065) URI
+ //
+ // Deprecated: Please use pion/stun.URI
+ URL = stun.URI
+
+ // ProtoType indicates the transport protocol type that is used in the ice.URL
+ // structure.
+ //
+ // Deprecated: TPlease use pion/stun.ProtoType
+ ProtoType = stun.ProtoType
+
+ // SchemeType indicates the type of server used in the ice.URL structure.
+ //
+ // Deprecated: Please use pion/stun.SchemeType
+ SchemeType = stun.SchemeType
)
-// SchemeType indicates the type of server used in the ice.URL structure.
-type SchemeType int
-
-// Unknown defines default public constant to use for "enum" like struct
-// comparisons when no value was defined.
-const Unknown = iota
-
const (
// SchemeTypeSTUN indicates the URL represents a STUN server.
- SchemeTypeSTUN SchemeType = iota + 1
+ //
+ // Deprecated: Please use pion/stun.SchemeTypeSTUN
+ SchemeTypeSTUN = stun.SchemeTypeSTUN
// SchemeTypeSTUNS indicates the URL represents a STUNS (secure) server.
- SchemeTypeSTUNS
+ //
+ // Deprecated: Please use pion/stun.SchemeTypeSTUNS
+ SchemeTypeSTUNS = stun.SchemeTypeSTUNS
// SchemeTypeTURN indicates the URL represents a TURN server.
- SchemeTypeTURN
+ //
+ // Deprecated: Please use pion/stun.SchemeTypeTURN
+ SchemeTypeTURN = stun.SchemeTypeTURN
// SchemeTypeTURNS indicates the URL represents a TURNS (secure) server.
- SchemeTypeTURNS
+ //
+ // Deprecated: Please use pion/stun.SchemeTypeTURNS
+ SchemeTypeTURNS = stun.SchemeTypeTURNS
)
-// NewSchemeType defines a procedure for creating a new SchemeType from a raw
-// string naming the scheme type.
-func NewSchemeType(raw string) SchemeType {
- switch raw {
- case "stun":
- return SchemeTypeSTUN
- case "stuns":
- return SchemeTypeSTUNS
- case "turn":
- return SchemeTypeTURN
- case "turns":
- return SchemeTypeTURNS
- default:
- return SchemeType(Unknown)
- }
-}
-
-func (t SchemeType) String() string {
- switch t {
- case SchemeTypeSTUN:
- return "stun"
- case SchemeTypeSTUNS:
- return "stuns"
- case SchemeTypeTURN:
- return "turn"
- case SchemeTypeTURNS:
- return "turns"
- default:
- return ErrUnknownType.Error()
- }
-}
-
-// ProtoType indicates the transport protocol type that is used in the ice.URL
-// structure.
-type ProtoType int
-
const (
// ProtoTypeUDP indicates the URL uses a UDP transport.
- ProtoTypeUDP ProtoType = iota + 1
+ //
+ // Deprecated: Please use pion/stun.ProtoTypeUDP
+ ProtoTypeUDP = stun.ProtoTypeUDP
// ProtoTypeTCP indicates the URL uses a TCP transport.
- ProtoTypeTCP
+ //
+ // Deprecated: Please use pion/stun.ProtoTypeTCP
+ ProtoTypeTCP = stun.ProtoTypeTCP
)
-// NewProtoType defines a procedure for creating a new ProtoType from a raw
-// string naming the transport protocol type.
-func NewProtoType(raw string) ProtoType {
- switch raw {
- case "udp":
- return ProtoTypeUDP
- case "tcp":
- return ProtoTypeTCP
- default:
- return ProtoType(Unknown)
- }
-}
-
-func (t ProtoType) String() string {
- switch t {
- case ProtoTypeUDP:
- return "udp"
- case ProtoTypeTCP:
- return "tcp"
- default:
- return ErrUnknownType.Error()
- }
-}
-
-// URL represents a STUN (rfc7064) or TURN (rfc7065) URL
-type URL struct {
- Scheme SchemeType
- Host string
- Port int
- Username string
- Password string
- Proto ProtoType
-}
+// Unknown represents and unknown ProtoType or SchemeType
+//
+// Deprecated: Please use pion/stun.SchemeTypeUnknown or pion/stun.ProtoTypeUnknown
+const Unknown = 0
// ParseURL parses a STUN or TURN urls following the ABNF syntax described in
// https://tools.ietf.org/html/rfc7064 and https://tools.ietf.org/html/rfc7065
// respectively.
-func ParseURL(raw string) (*URL, error) { //nolint:gocognit
- rawParts, err := url.Parse(raw)
- if err != nil {
- return nil, err
- }
+//
+// Deprecated: Please use pion/stun.ParseURI
+var ParseURL = stun.ParseURI //nolint:gochecknoglobals
- var u URL
- u.Scheme = NewSchemeType(rawParts.Scheme)
- if u.Scheme == SchemeType(Unknown) {
- return nil, ErrSchemeType
- }
+// NewSchemeType defines a procedure for creating a new SchemeType from a raw
+// string naming the scheme type.
+//
+// Deprecated: Please use pion/stun.NewSchemeType
+var NewSchemeType = stun.NewSchemeType //nolint:gochecknoglobals
- var rawPort string
- if u.Host, rawPort, err = net.SplitHostPort(rawParts.Opaque); err != nil {
- if e, ok := err.(*net.AddrError); ok {
- if e.Err == "missing port in address" {
- nextRawURL := u.Scheme.String() + ":" + rawParts.Opaque
- switch {
- case u.Scheme == SchemeTypeSTUN || u.Scheme == SchemeTypeTURN:
- nextRawURL += ":3478"
- if rawParts.RawQuery != "" {
- nextRawURL += "?" + rawParts.RawQuery
- }
- return ParseURL(nextRawURL)
- case u.Scheme == SchemeTypeSTUNS || u.Scheme == SchemeTypeTURNS:
- nextRawURL += ":5349"
- if rawParts.RawQuery != "" {
- nextRawURL += "?" + rawParts.RawQuery
- }
- return ParseURL(nextRawURL)
- }
- }
- }
- return nil, err
- }
-
- if u.Host == "" {
- return nil, ErrHost
- }
-
- if u.Port, err = strconv.Atoi(rawPort); err != nil {
- return nil, ErrPort
- }
-
- switch u.Scheme {
- case SchemeTypeSTUN:
- qArgs, err := url.ParseQuery(rawParts.RawQuery)
- if err != nil || len(qArgs) > 0 {
- return nil, ErrSTUNQuery
- }
- u.Proto = ProtoTypeUDP
- case SchemeTypeSTUNS:
- qArgs, err := url.ParseQuery(rawParts.RawQuery)
- if err != nil || len(qArgs) > 0 {
- return nil, ErrSTUNQuery
- }
- u.Proto = ProtoTypeTCP
- case SchemeTypeTURN:
- proto, err := parseProto(rawParts.RawQuery)
- if err != nil {
- return nil, err
- }
-
- u.Proto = proto
- if u.Proto == ProtoType(Unknown) {
- u.Proto = ProtoTypeUDP
- }
- case SchemeTypeTURNS:
- proto, err := parseProto(rawParts.RawQuery)
- if err != nil {
- return nil, err
- }
-
- u.Proto = proto
- if u.Proto == ProtoType(Unknown) {
- u.Proto = ProtoTypeTCP
- }
- }
-
- return &u, nil
-}
-
-func parseProto(raw string) (ProtoType, error) {
- qArgs, err := url.ParseQuery(raw)
- if err != nil || len(qArgs) > 1 {
- return ProtoType(Unknown), ErrInvalidQuery
- }
-
- var proto ProtoType
- if rawProto := qArgs.Get("transport"); rawProto != "" {
- if proto = NewProtoType(rawProto); proto == ProtoType(0) {
- return ProtoType(Unknown), ErrProtoType
- }
- return proto, nil
- }
-
- if len(qArgs) > 0 {
- return ProtoType(Unknown), ErrInvalidQuery
- }
-
- return proto, nil
-}
-
-func (u URL) String() string {
- rawURL := u.Scheme.String() + ":" + net.JoinHostPort(u.Host, strconv.Itoa(u.Port))
- if u.Scheme == SchemeTypeTURN || u.Scheme == SchemeTypeTURNS {
- rawURL += "?transport=" + u.Proto.String()
- }
- return rawURL
-}
-
-// IsSecure returns whether the this URL's scheme describes secure scheme or not.
-func (u URL) IsSecure() bool {
- return u.Scheme == SchemeTypeSTUNS || u.Scheme == SchemeTypeTURNS
-}
+// NewProtoType defines a procedure for creating a new ProtoType from a raw
+// string naming the transport protocol type.
+//
+// Deprecated: Please use pion/stun.NewProtoType
+var NewProtoType = stun.NewProtoType //nolint:gochecknoglobals
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/usecandidate.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/usecandidate.go
index f168c08eb..6fc7ed50c 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/usecandidate.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/usecandidate.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package ice
import "github.com/pion/stun"
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/util.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/util.go
deleted file mode 100644
index 7eb13c803..000000000
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/ice/v2/util.go
+++ /dev/null
@@ -1,233 +0,0 @@
-package ice
-
-import (
- "fmt"
- "net"
- "sync/atomic"
- "time"
-
- "github.com/pion/logging"
- "github.com/pion/stun"
- "github.com/pion/transport/vnet"
-)
-
-type atomicError struct{ v atomic.Value }
-
-func (a *atomicError) Store(err error) {
- a.v.Store(struct{ error }{err})
-}
-
-func (a *atomicError) Load() error {
- err, _ := a.v.Load().(struct{ error })
- return err.error
-}
-
-// The conditions of invalidation written below are defined in
-// https://tools.ietf.org/html/rfc8445#section-5.1.1.1
-func isSupportedIPv6(ip net.IP) bool {
- if len(ip) != net.IPv6len ||
- isZeros(ip[0:12]) || // !(IPv4-compatible IPv6)
- ip[0] == 0xfe && ip[1]&0xc0 == 0xc0 || // !(IPv6 site-local unicast)
- ip.IsLinkLocalUnicast() ||
- ip.IsLinkLocalMulticast() {
- return false
- }
- return true
-}
-
-func isZeros(ip net.IP) bool {
- for i := 0; i < len(ip); i++ {
- if ip[i] != 0 {
- return false
- }
- }
- return true
-}
-
-func parseAddr(in net.Addr) (net.IP, int, NetworkType, bool) {
- switch addr := in.(type) {
- case *net.UDPAddr:
- return addr.IP, addr.Port, NetworkTypeUDP4, true
- case *net.TCPAddr:
- return addr.IP, addr.Port, NetworkTypeTCP4, true
- }
- return nil, 0, 0, false
-}
-
-func createAddr(network NetworkType, ip net.IP, port int) net.Addr {
- switch {
- case network.IsTCP():
- return &net.TCPAddr{IP: ip, Port: port}
- default:
- return &net.UDPAddr{IP: ip, Port: port}
- }
-}
-
-func addrEqual(a, b net.Addr) bool {
- aIP, aPort, aType, aOk := parseAddr(a)
- if !aOk {
- return false
- }
-
- bIP, bPort, bType, bOk := parseAddr(b)
- if !bOk {
- return false
- }
-
- return aType == bType && aIP.Equal(bIP) && aPort == bPort
-}
-
-// getXORMappedAddr initiates a stun requests to serverAddr using conn, reads the response and returns
-// the XORMappedAddress returned by the stun server.
-//
-// Adapted from stun v0.2.
-func getXORMappedAddr(conn net.PacketConn, serverAddr net.Addr, deadline time.Duration) (*stun.XORMappedAddress, error) {
- if deadline > 0 {
- if err := conn.SetReadDeadline(time.Now().Add(deadline)); err != nil {
- return nil, err
- }
- }
- defer func() {
- if deadline > 0 {
- _ = conn.SetReadDeadline(time.Time{})
- }
- }()
- resp, err := stunRequest(
- func(p []byte) (int, error) {
- n, _, errr := conn.ReadFrom(p)
- return n, errr
- },
- func(b []byte) (int, error) {
- return conn.WriteTo(b, serverAddr)
- },
- )
- if err != nil {
- return nil, err
- }
- var addr stun.XORMappedAddress
- if err = addr.GetFrom(resp); err != nil {
- return nil, fmt.Errorf("%w: %v", errGetXorMappedAddrResponse, err)
- }
- return &addr, nil
-}
-
-func stunRequest(read func([]byte) (int, error), write func([]byte) (int, error)) (*stun.Message, error) {
- req, err := stun.Build(stun.BindingRequest, stun.TransactionID)
- if err != nil {
- return nil, err
- }
- if _, err = write(req.Raw); err != nil {
- return nil, err
- }
- const maxMessageSize = 1280
- bs := make([]byte, maxMessageSize)
- n, err := read(bs)
- if err != nil {
- return nil, err
- }
- res := &stun.Message{Raw: bs[:n]}
- if err := res.Decode(); err != nil {
- return nil, err
- }
- return res, nil
-}
-
-func localInterfaces(vnet *vnet.Net, interfaceFilter func(string) bool, networkTypes []NetworkType) ([]net.IP, error) { //nolint:gocognit
- ips := []net.IP{}
- ifaces, err := vnet.Interfaces()
- if err != nil {
- return ips, err
- }
-
- var IPv4Requested, IPv6Requested bool
- for _, typ := range networkTypes {
- if typ.IsIPv4() {
- IPv4Requested = true
- }
-
- if typ.IsIPv6() {
- IPv6Requested = true
- }
- }
-
- for _, iface := range ifaces {
- if iface.Flags&net.FlagUp == 0 {
- continue // interface down
- }
- if iface.Flags&net.FlagLoopback != 0 {
- continue // loopback interface
- }
-
- if interfaceFilter != nil && !interfaceFilter(iface.Name) {
- continue
- }
-
- addrs, err := iface.Addrs()
- if err != nil {
- continue
- }
-
- for _, addr := range addrs {
- var ip net.IP
- switch addr := addr.(type) {
- case *net.IPNet:
- ip = addr.IP
- case *net.IPAddr:
- ip = addr.IP
- }
- if ip == nil || ip.IsLoopback() {
- continue
- }
-
- if ipv4 := ip.To4(); ipv4 == nil {
- if !IPv6Requested {
- continue
- } else if !isSupportedIPv6(ip) {
- continue
- }
- } else if !IPv4Requested {
- continue
- }
-
- ips = append(ips, ip)
- }
- }
- return ips, nil
-}
-
-func listenUDPInPortRange(vnet *vnet.Net, log logging.LeveledLogger, portMax, portMin int, network string, laddr *net.UDPAddr) (vnet.UDPPacketConn, error) {
- if (laddr.Port != 0) || ((portMin == 0) && (portMax == 0)) {
- return vnet.ListenUDP(network, laddr)
- }
- var i, j int
- i = portMin
- if i == 0 {
- i = 1
- }
- j = portMax
- if j == 0 {
- j = 0xFFFF
- }
- if i > j {
- return nil, ErrPort
- }
-
- portStart := globalMathRandomGenerator.Intn(j-i+1) + i
- portCurrent := portStart
- for {
- laddr = &net.UDPAddr{IP: laddr.IP, Port: portCurrent}
- c, e := vnet.ListenUDP(network, laddr)
- if e == nil {
- return c, e
- }
- log.Debugf("failed to listen %s: %v", laddr.String(), e)
- portCurrent++
- if portCurrent > j {
- portCurrent = i
- }
- if portCurrent == portStart {
- break
- }
- }
- return nil, ErrPort
-}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/.gitignore b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/.gitignore
index 83db74ba5..6e2f206a9 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/.gitignore
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/.gitignore
@@ -1,3 +1,6 @@
+# SPDX-FileCopyrightText: 2023 The Pion community
+# SPDX-License-Identifier: MIT
+
### JetBrains IDE ###
#####################
.idea/
@@ -22,3 +25,4 @@ cover.out
*.wasm
examples/sfu-ws/cert.pem
examples/sfu-ws/key.pem
+wasm_exec.js
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/.golangci.yml b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/.golangci.yml
index d6162c970..4e3eddf42 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/.golangci.yml
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/.golangci.yml
@@ -1,3 +1,6 @@
+# SPDX-FileCopyrightText: 2023 The Pion community
+# SPDX-License-Identifier: MIT
+
linters-settings:
govet:
check-shadowing: true
@@ -10,19 +13,34 @@ linters-settings:
modules:
- github.com/pkg/errors:
recommendations:
- - errors
+ - errors
+ forbidigo:
+ forbid:
+ - ^fmt.Print(f|ln)?$
+ - ^log.(Panic|Fatal|Print)(f|ln)?$
+ - ^os.Exit$
+ - ^panic$
+ - ^print(ln)?$
linters:
enable:
- asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers
+ - bidichk # Checks for dangerous unicode character sequences
- bodyclose # checks whether HTTP response body is closed successfully
- - deadcode # Finds unused code
+ - contextcheck # check the function whether use a non-inherited context
+ - decorder # check declaration order and count of types, constants, variables and functions
- depguard # Go linter that checks if package imports are in a list of acceptable packages
- dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())
- dupl # Tool for code clone detection
+ - durationcheck # check for two durations multiplied together
- errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
+ - errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and optionally reports occations, where the check for the returned error can be omitted.
+ - errname # Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`.
+ - errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13.
- exhaustive # check exhaustiveness of enum switch statements
- exportloopref # checks for pointers to enclosing loop variables
+ - forbidigo # Forbids identifiers
+ - forcetypeassert # finds forced type assertions
- gci # Gci control golang package import order and make it always deterministic.
- gochecknoglobals # Checks that no globals are present in Go code
- gochecknoinits # Checks that no init functions are present in Go code
@@ -35,40 +53,59 @@ linters:
- gofumpt # Gofumpt checks whether code was gofumpt-ed.
- goheader # Checks is file header matches to pattern
- goimports # Goimports does everything that gofmt does. Additionally it checks unused imports
- - golint # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes
+ - gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod.
- gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations.
- goprintffuncname # Checks that printf-like functions are named with `f` at the end
- gosec # Inspects source code for security problems
- gosimple # Linter for Go source code that specializes in simplifying a code
- govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
+ - grouper # An analyzer to analyze expression groups.
+ - importas # Enforces consistent import aliases
- ineffassign # Detects when assignments to existing variables are not used
- misspell # Finds commonly misspelled English words in comments
- nakedret # Finds naked returns in functions greater than a specified function length
+ - nilerr # Finds the code that returns nil even if it checks that the error is not nil.
+ - nilnil # Checks that there is no simultaneous return of `nil` error and an invalid value.
- noctx # noctx finds sending http request without context.Context
- - scopelint # Scopelint checks for unpinned variables in go programs
+ - predeclared # find code that shadows one of Go's predeclared identifiers
+ - revive # golint replacement, finds style mistakes
- staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks
- - structcheck # Finds unused struct fields
- stylecheck # Stylecheck is a replacement for golint
+ - tagliatelle # Checks the struct tags.
+ - tenv # tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17
+ - tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes
- typecheck # Like the front-end of a Go compiler, parses and type-checks Go code
- unconvert # Remove unnecessary type conversions
- unparam # Reports unused function parameters
- unused # Checks Go code for unused constants, variables, functions and types
- - varcheck # Finds unused global variables and constants
+ - wastedassign # wastedassign finds wasted assignment statements
- whitespace # Tool for detection of leading and trailing whitespace
disable:
+ - containedctx # containedctx is a linter that detects struct contained context.Context field
+ - cyclop # checks function and package cyclomatic complexity
+ - exhaustivestruct # Checks if all struct's fields are initialized
- funlen # Tool for detection of long functions
- gocyclo # Computes and checks the cyclomatic complexity of functions
- godot # Check if comments end in a period
- gomnd # An analyzer to detect magic numbers.
+ - ifshort # Checks that your code uses short syntax for if-statements whenever possible
+ - ireturn # Accept Interfaces, Return Concrete Types
- lll # Reports long lines
+ - maintidx # maintidx measures the maintainability index of each function.
+ - makezero # Finds slice declarations with non-zero initial length
- maligned # Tool to detect Go structs that would take less memory if their fields were sorted
- nestif # Reports deeply nested if statements
- nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity
- nolintlint # Reports ill-formed or insufficient nolint directives
+ - paralleltest # paralleltest detects missing usage of t.Parallel() method in your Go test
- prealloc # Finds slice declarations that could potentially be preallocated
+ - promlinter # Check Prometheus metrics naming via promlint
- rowserrcheck # checks whether Err of rows is checked successfully
- sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed.
- testpackage # linter that makes you use a separate _test package
+ - thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers
+ - varnamelen # checks that the length of a variable's name matches its scope
+ - wrapcheck # Checks that errors returned from external packages are wrapped
- wsl # Whitespace Linter - Forces you to use empty lines!
issues:
@@ -78,12 +115,23 @@ issues:
- path: _test\.go
linters:
- gocognit
+ - forbidigo
# Allow complex main function in examples
- path: examples
text: "of func `main` is high"
linters:
- gocognit
+
+ # Allow forbidden identifiers in examples
+ - path: examples
+ linters:
+ - forbidigo
+
+ # Allow forbidden identifiers in CLI commands
+ - path: cmd
+ linters:
+ - forbidigo
run:
skip-dirs-use-default: false
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/.goreleaser.yml b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/.goreleaser.yml
new file mode 100644
index 000000000..30093e9d6
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/.goreleaser.yml
@@ -0,0 +1,5 @@
+# SPDX-FileCopyrightText: 2023 The Pion community
+# SPDX-License-Identifier: MIT
+
+builds:
+- skip: true
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/AUTHORS.txt b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/AUTHORS.txt
new file mode 100644
index 000000000..44a421ef8
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/AUTHORS.txt
@@ -0,0 +1,30 @@
+# Thank you to everyone that made Pion possible. If you are interested in contributing
+# we would love to have you https://github.com/pion/webrtc/wiki/Contributing
+#
+# This file is auto generated, using git to list all individuals contributors.
+# see https://github.com/pion/.goassets/blob/master/scripts/generate-authors.sh for the scripting
+Aaron Boushley
+Adam Kiss
+adamroach
+Aditya Kumar
+aler9 <46489434+aler9@users.noreply.github.com>
+Antoine Baché
+Atsushi Watanabe
+Bobby Peck
+boks1971
+David Zhao
+Jonathan Müller
+Kevin Caffrey
+Maksim Nesterov
+Mathis Engelbart
+Miroslav
+Miroslav Šedivý
+Quentin Renard
+Rayleigh Li
+Sean DuBois
+Steffen Vogel
+XLPolar
+ziminghua <565209960@qq.com>
+
+# List of contributors not appearing in Git history
+
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/LICENSE b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/LICENSE
index ab602974d..491caf6b0 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/LICENSE
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/LICENSE
@@ -1,21 +1,9 @@
MIT License
-Copyright (c) 2018
+Copyright (c) 2023 The Pion community
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/README.md b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/README.md
index 007c340d1..dcc856f1e 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/README.md
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/README.md
@@ -8,7 +8,8 @@
-
+
+
@@ -27,18 +28,21 @@ by anyone. With the following tenets in mind.
* Encourage modification. Add your own interceptors without forking. Mixing with the ones we provide.
* Empower learning. This code base should be useful to read and learn even if you aren't using Pion.
-#### Current Interceptors
-* NACK Generator/Responder
+### Current Interceptors
+* [NACK Generator/Responder](https://github.com/pion/interceptor/tree/master/pkg/nack)
+* [Sender and Receiver Reports](https://github.com/pion/interceptor/tree/master/pkg/report)
+* [Transport Wide Congestion Control Feedback](https://github.com/pion/interceptor/tree/master/pkg/twcc)
+* [Packet Dump](https://github.com/pion/interceptor/tree/master/pkg/packetdump)
+* [Google Congestion Control](https://github.com/pion/interceptor/tree/master/pkg/gcc)
+* [Stats](https://github.com/pion/interceptor/tree/master/pkg/stats) A [webrtc-stats](https://www.w3.org/TR/webrtc-stats/) compliant statistics generation
+* [Interval PLI](https://github.com/pion/interceptor/tree/master/pkg/intervalpli) Generate PLI on a interval. Useful when no decoder is available.
-#### Planned Interceptors
-* [Sender and Receiver Reports](https://tools.ietf.org/html/rfc3550#section-6.4)
- - Bandwidth Estimation from Receiver Reports
-* [Transport Wide Congestion Control Feedback](https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01)
+### Planned Interceptors
+* Bandwidth Estimation
- [NADA](https://tools.ietf.org/html/rfc8698)
- - [Google Congestion Control](https://tools.ietf.org/html/draft-ietf-rmcat-gcc-02)
* JitterBuffer, re-order packets and wait for arrival
* [FlexFec](https://tools.ietf.org/html/draft-ietf-payload-flexible-fec-scheme-20)
-* [webrtc-stats](https://www.w3.org/TR/webrtc-stats/) compliant statistics generation
+* [RTCP Feedback for Congestion Control](https://datatracker.ietf.org/doc/html/rfc8888) the standardized alternative to TWCC.
### Interceptor Public API
The public interface is defined in [interceptor.go](https://github.com/pion/interceptor/blob/master/interceptor.go).
@@ -62,20 +66,19 @@ sequentially as the packet moves through them.
The [examples](https://github.com/pion/interceptor/blob/master/examples) directory provides some basic examples. If you need more please file an issue!
You should also look in [pion/webrtc](https://github.com/pion/webrtc) for real world examples.
+### Roadmap
+The library is used as a part of our WebRTC implementation. Please refer to that [roadmap](https://github.com/pion/webrtc/issues/9) to track our major milestones.
+
### Community
-Pion has an active community on the [Golang Slack](https://invite.slack.golangbridge.org/). Sign up and join the **#pion** channel for discussions and support. You can also use [Pion mailing list](https://groups.google.com/forum/#!forum/pion).
+Pion has an active community on the [Slack](https://pion.ly/slack).
+
+Follow the [Pion Twitter](https://twitter.com/_pion) for project updates and important WebRTC news.
We are always looking to support **your projects**. Please reach out if you have something to build!
-
If you need commercial support or don't want to use public methods you can contact us at [team@pion.ly](mailto:team@pion.ly)
### Contributing
-Check out the **[contributing wiki](https://github.com/pion/webrtc/wiki/Contributing)** to join the group of amazing people making this project possible:
-
-* [Adam Kiss](https://github.com/masterada) - *Original Author*
-* [Sean DuBois](https://github.com/sean-der) - *Original Author*
-* [Atsushi Watanabe](https://github.com/at-wat)
-* [Alessandro Ros](https://github.com/aler9)
+Check out the [contributing wiki](https://github.com/pion/webrtc/wiki/Contributing) to join the group of amazing people making this project possible: [AUTHORS.txt](./AUTHORS.txt)
### License
MIT License - see [LICENSE](LICENSE) for full text
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/attributes.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/attributes.go
new file mode 100644
index 000000000..d7936d526
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/attributes.go
@@ -0,0 +1,68 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package interceptor
+
+import (
+ "errors"
+
+ "github.com/pion/rtcp"
+ "github.com/pion/rtp"
+)
+
+type unmarshaledDataKeyType int
+
+const (
+ rtpHeaderKey unmarshaledDataKeyType = iota
+ rtcpPacketsKey
+)
+
+var errInvalidType = errors.New("found value of invalid type in attributes map")
+
+// Attributes are a generic key/value store used by interceptors
+type Attributes map[interface{}]interface{}
+
+// Get returns the attribute associated with key.
+func (a Attributes) Get(key interface{}) interface{} {
+ return a[key]
+}
+
+// Set sets the attribute associated with key to the given value.
+func (a Attributes) Set(key interface{}, val interface{}) {
+ a[key] = val
+}
+
+// GetRTPHeader gets the RTP header if present. If it is not present, it will be
+// unmarshalled from the raw byte slice and stored in the attribtues.
+func (a Attributes) GetRTPHeader(raw []byte) (*rtp.Header, error) {
+ if val, ok := a[rtpHeaderKey]; ok {
+ if header, ok := val.(*rtp.Header); ok {
+ return header, nil
+ }
+ return nil, errInvalidType
+ }
+ header := &rtp.Header{}
+ if _, err := header.Unmarshal(raw); err != nil {
+ return nil, err
+ }
+ a[rtpHeaderKey] = header
+ return header, nil
+}
+
+// GetRTCPPackets gets the RTCP packets if present. If the packet slice is not
+// present, it will be unmarshaled from the raw byte slice and stored in the
+// attributes.
+func (a Attributes) GetRTCPPackets(raw []byte) ([]rtcp.Packet, error) {
+ if val, ok := a[rtcpPacketsKey]; ok {
+ if packets, ok := val.([]rtcp.Packet); ok {
+ return packets, nil
+ }
+ return nil, errInvalidType
+ }
+ pkts, err := rtcp.Unmarshal(raw)
+ if err != nil {
+ return nil, err
+ }
+ a[rtcpPacketsKey] = pkts
+ return pkts, nil
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/chain.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/chain.go
index d53c30714..267f36651 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/chain.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/chain.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package interceptor
// Chain is an interceptor that runs all child interceptors in order.
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/codecov.yml b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/codecov.yml
index 085200a48..263e4d45c 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/codecov.yml
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/codecov.yml
@@ -3,6 +3,8 @@
#
# It is automatically copied from https://github.com/pion/.goassets repository.
#
+# SPDX-FileCopyrightText: 2023 The Pion community
+# SPDX-License-Identifier: MIT
coverage:
status:
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/errors.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/errors.go
index 45e1252c9..3dafee3ef 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/errors.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/errors.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package interceptor
import (
@@ -18,7 +21,7 @@ func flattenErrs(errs []error) error {
return multiError(errs2)
}
-type multiError []error
+type multiError []error //nolint
func (me multiError) Error() string {
var errstrings []string
@@ -41,7 +44,7 @@ func (me multiError) Is(err error) bool {
if errors.Is(e, err) {
return true
}
- if me2, ok := e.(multiError); ok {
+ if me2, ok := e.(multiError); ok { //nolint
if me2.Is(err) {
return true
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/go.mod b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/go.mod
deleted file mode 100644
index 1370bc90d..000000000
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/go.mod
+++ /dev/null
@@ -1,10 +0,0 @@
-module github.com/pion/interceptor
-
-go 1.15
-
-require (
- github.com/pion/logging v0.2.2
- github.com/pion/rtcp v1.2.6
- github.com/pion/rtp v1.6.2
- github.com/stretchr/testify v1.7.0
-)
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/go.sum b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/go.sum
deleted file mode 100644
index 104d01865..000000000
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/go.sum
+++ /dev/null
@@ -1,21 +0,0 @@
-github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-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/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
-github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
-github.com/pion/rtcp v1.2.6 h1:1zvwBbyd0TeEuuWftrd/4d++m+/kZSeiguxU61LFWpo=
-github.com/pion/rtcp v1.2.6/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0=
-github.com/pion/rtp v1.6.2 h1:iGBerLX6JiDjB9NXuaPzHyxHFG9JsIEdgwTC0lp5n/U=
-github.com/pion/rtp v1.6.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/interceptor.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/interceptor.go
index 2d1b97e2f..c6ba53242 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/interceptor.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/interceptor.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
// Package interceptor contains the Interceptor interface, with some useful interceptors that should be safe to use
// in most cases.
package interceptor
@@ -9,10 +12,14 @@ import (
"github.com/pion/rtp"
)
+// Factory provides an interface for constructing interceptors
+type Factory interface {
+ NewInterceptor(id string) (Interceptor, error)
+}
+
// Interceptor can be used to add functionality to you PeerConnections by modifying any incoming/outgoing rtp/rtcp
// packets, or sending your own packets as needed.
type Interceptor interface {
-
// BindRTCPReader lets you modify any incoming RTCP packets. It is called once per sender/receiver, however this might
// change in the future. The returned method will be called once per packet batch.
BindRTCPReader(reader RTCPReader) RTCPReader
@@ -62,9 +69,6 @@ type RTCPReader interface {
Read([]byte, Attributes) (int, Attributes, error)
}
-// Attributes are a generic key/value store used by interceptors
-type Attributes map[interface{}]interface{}
-
// RTPWriterFunc is an adapter for RTPWrite interface
type RTPWriterFunc func(header *rtp.Header, payload []byte, attributes Attributes) (int, error)
@@ -96,13 +100,3 @@ func (f RTCPWriterFunc) Write(pkts []rtcp.Packet, attributes Attributes) (int, e
func (f RTCPReaderFunc) Read(b []byte, a Attributes) (int, Attributes, error) {
return f(b, a)
}
-
-// Get returns the attribute associated with key.
-func (a Attributes) Get(key interface{}) interface{} {
- return a[key]
-}
-
-// Set sets the attribute associated with key to the given value.
-func (a Attributes) Set(key interface{}, val interface{}) {
- a[key] = val
-}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/ntp/ntp.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/ntp/ntp.go
new file mode 100644
index 000000000..69f98d6c9
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/ntp/ntp.go
@@ -0,0 +1,30 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+// Package ntp provides conversion methods between time.Time and NTP timestamps
+// stored in uint64
+package ntp
+
+import (
+ "time"
+)
+
+// ToNTP converts a time.Time oboject to an uint64 NTP timestamp
+func ToNTP(t time.Time) uint64 {
+ // seconds since 1st January 1900
+ s := (float64(t.UnixNano()) / 1000000000) + 2208988800
+
+ // higher 32 bits are the integer part, lower 32 bits are the fractional part
+ integerPart := uint32(s)
+ fractionalPart := uint32((s - float64(integerPart)) * 0xFFFFFFFF)
+ return uint64(integerPart)<<32 | uint64(fractionalPart)
+}
+
+// ToTime converts a uint64 NTP timestamps to a time.Time object
+func ToTime(t uint64) time.Time {
+ seconds := (t & 0xFFFFFFFF00000000) >> 32
+ fractional := float64(t&0x00000000FFFFFFFF) / float64(0xFFFFFFFF)
+ d := time.Duration(seconds)*time.Second + time.Duration(fractional*1e9)*time.Nanosecond
+
+ return time.Unix(0, 0).Add(-2208988800 * time.Second).Add(d)
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/noop.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/noop.go
index 2dc4e8e2e..b0fc2a69a 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/noop.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/noop.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package interceptor
// NoOp is an Interceptor that does not modify any packets. It can embedded in other interceptors, so it's
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/errors.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/errors.go
index bbfc77361..b47ec39c2 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/errors.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/errors.go
@@ -1,6 +1,15 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package nack
import "errors"
// ErrInvalidSize is returned by newReceiveLog/newSendBuffer, when an incorrect buffer size is supplied.
var ErrInvalidSize = errors.New("invalid buffer size")
+
+var (
+ errPacketReleased = errors.New("could not retain packet, already released")
+ errFailedToCastHeaderPool = errors.New("could not access header pool, failed cast")
+ errFailedToCastPayloadPool = errors.New("could not access payload pool, failed cast")
+)
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/generator_interceptor.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/generator_interceptor.go
index 447a9490a..faf533ba4 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/generator_interceptor.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/generator_interceptor.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package nack
import (
@@ -8,9 +11,37 @@ import (
"github.com/pion/interceptor"
"github.com/pion/logging"
"github.com/pion/rtcp"
- "github.com/pion/rtp"
)
+// GeneratorInterceptorFactory is a interceptor.Factory for a GeneratorInterceptor
+type GeneratorInterceptorFactory struct {
+ opts []GeneratorOption
+}
+
+// NewInterceptor constructs a new ReceiverInterceptor
+func (g *GeneratorInterceptorFactory) NewInterceptor(_ string) (interceptor.Interceptor, error) {
+ i := &GeneratorInterceptor{
+ size: 512,
+ skipLastN: 0,
+ interval: time.Millisecond * 100,
+ receiveLogs: map[uint32]*receiveLog{},
+ close: make(chan struct{}),
+ log: logging.NewDefaultLoggerFactory().NewLogger("nack_generator"),
+ }
+
+ for _, opt := range g.opts {
+ if err := opt(i); err != nil {
+ return nil, err
+ }
+ }
+
+ if _, err := newReceiveLog(i.size); err != nil {
+ return nil, err
+ }
+
+ return i, nil
+}
+
// GeneratorInterceptor interceptor generates nack feedback messages.
type GeneratorInterceptor struct {
interceptor.NoOp
@@ -26,28 +57,9 @@ type GeneratorInterceptor struct {
receiveLogsMu sync.Mutex
}
-// NewGeneratorInterceptor returns a new GeneratorInterceptor interceptor
-func NewGeneratorInterceptor(opts ...GeneratorOption) (*GeneratorInterceptor, error) {
- r := &GeneratorInterceptor{
- size: 8192,
- skipLastN: 0,
- interval: time.Millisecond * 100,
- receiveLogs: map[uint32]*receiveLog{},
- close: make(chan struct{}),
- log: logging.NewDefaultLoggerFactory().NewLogger("nack_generator"),
- }
-
- for _, opt := range opts {
- if err := opt(r); err != nil {
- return nil, err
- }
- }
-
- if _, err := newReceiveLog(r.size); err != nil {
- return nil, err
- }
-
- return r, nil
+// NewGeneratorInterceptor returns a new GeneratorInterceptorFactory
+func NewGeneratorInterceptor(opts ...GeneratorOption) (*GeneratorInterceptorFactory, error) {
+ return &GeneratorInterceptorFactory{opts}, nil
}
// BindRTCPWriter lets you modify any outgoing RTCP packets. It is called once per PeerConnection. The returned method
@@ -86,18 +98,21 @@ func (n *GeneratorInterceptor) BindRemoteStream(info *interceptor.StreamInfo, re
return 0, nil, err
}
- pkt := rtp.Packet{}
- if err = pkt.Unmarshal(b[:i]); err != nil {
+ if attr == nil {
+ attr = make(interceptor.Attributes)
+ }
+ header, err := attr.GetRTPHeader(b[:i])
+ if err != nil {
return 0, nil, err
}
- receiveLog.add(pkt.Header.SequenceNumber)
+ receiveLog.add(header.SequenceNumber)
return i, attr, nil
})
}
-// UnbindLocalStream is called when the Stream is removed. It can be used to clean up any data related to that track.
-func (n *GeneratorInterceptor) UnbindLocalStream(info *interceptor.StreamInfo) {
+// UnbindRemoteStream is called when the Stream is removed. It can be used to clean up any data related to that track.
+func (n *GeneratorInterceptor) UnbindRemoteStream(info *interceptor.StreamInfo) {
n.receiveLogsMu.Lock()
delete(n.receiveLogs, info.SSRC)
n.receiveLogsMu.Unlock()
@@ -122,6 +137,7 @@ func (n *GeneratorInterceptor) loop(rtcpWriter interceptor.RTCPWriter) {
senderSSRC := rand.Uint32() // #nosec
ticker := time.NewTicker(n.interval)
+ defer ticker.Stop()
for {
select {
case <-ticker.C:
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/generator_option.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/generator_option.go
index 092f5db92..e4f46f7c9 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/generator_option.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/generator_option.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package nack
import (
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/nack.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/nack.go
index a658e7f39..b7589ebd9 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/nack.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/nack.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
// Package nack provides interceptors to implement sending and receiving negative acknowledgements
package nack
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/receive_log.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/receive_log.go
index 8107f59a2..6a19996e7 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/receive_log.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/receive_log.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package nack
import (
@@ -127,8 +130,9 @@ func (s *receiveLog) getReceived(seq uint16) bool {
func (s *receiveLog) fixLastConsecutive() {
i := s.lastConsecutive + 1
- for ; i != s.end+1 && s.getReceived(i); i++ {
+ for ; i != s.end+1 && s.getReceived(i); i++ { //nolint:revive
// find all consecutive packets
}
+
s.lastConsecutive = i - 1
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/responder_interceptor.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/responder_interceptor.go
index 121657e4d..8f74952dd 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/responder_interceptor.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/responder_interceptor.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package nack
import (
@@ -9,11 +12,46 @@ import (
"github.com/pion/rtp"
)
+// ResponderInterceptorFactory is a interceptor.Factory for a ResponderInterceptor
+type ResponderInterceptorFactory struct {
+ opts []ResponderOption
+}
+
+type packetFactory interface {
+ NewPacket(header *rtp.Header, payload []byte) (*retainablePacket, error)
+}
+
+// NewInterceptor constructs a new ResponderInterceptor
+func (r *ResponderInterceptorFactory) NewInterceptor(_ string) (interceptor.Interceptor, error) {
+ i := &ResponderInterceptor{
+ size: 1024,
+ log: logging.NewDefaultLoggerFactory().NewLogger("nack_responder"),
+ streams: map[uint32]*localStream{},
+ }
+
+ for _, opt := range r.opts {
+ if err := opt(i); err != nil {
+ return nil, err
+ }
+ }
+
+ if i.packetFactory == nil {
+ i.packetFactory = newPacketManager()
+ }
+
+ if _, err := newSendBuffer(i.size); err != nil {
+ return nil, err
+ }
+
+ return i, nil
+}
+
// ResponderInterceptor responds to nack feedback messages
type ResponderInterceptor struct {
interceptor.NoOp
- size uint16
- log logging.LeveledLogger
+ size uint16
+ log logging.LeveledLogger
+ packetFactory packetFactory
streams map[uint32]*localStream
streamsMu sync.Mutex
@@ -24,25 +62,9 @@ type localStream struct {
rtpWriter interceptor.RTPWriter
}
-// NewResponderInterceptor returns a new GeneratorInterceptor interceptor
-func NewResponderInterceptor(opts ...ResponderOption) (*ResponderInterceptor, error) {
- r := &ResponderInterceptor{
- size: 8192,
- log: logging.NewDefaultLoggerFactory().NewLogger("nack_responder"),
- streams: map[uint32]*localStream{},
- }
-
- for _, opt := range opts {
- if err := opt(r); err != nil {
- return nil, err
- }
- }
-
- if _, err := newSendBuffer(r.size); err != nil {
- return nil, err
- }
-
- return r, nil
+// NewResponderInterceptor returns a new ResponderInterceptorFactor
+func NewResponderInterceptor(opts ...ResponderOption) (*ResponderInterceptorFactory, error) {
+ return &ResponderInterceptorFactory{opts}, nil
}
// BindRTCPReader lets you modify any incoming RTCP packets. It is called once per sender/receiver, however this might
@@ -54,7 +76,10 @@ func (n *ResponderInterceptor) BindRTCPReader(reader interceptor.RTCPReader) int
return 0, nil, err
}
- pkts, err := rtcp.Unmarshal(b[:i])
+ if attr == nil {
+ attr = make(interceptor.Attributes)
+ }
+ pkts, err := attr.GetRTCPPackets(b[:i])
if err != nil {
return 0, nil, err
}
@@ -85,7 +110,11 @@ func (n *ResponderInterceptor) BindLocalStream(info *interceptor.StreamInfo, wri
n.streamsMu.Unlock()
return interceptor.RTPWriterFunc(func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) {
- sendBuffer.add(&rtp.Packet{Header: *header, Payload: payload})
+ pkt, err := n.packetFactory.NewPacket(header, payload)
+ if err != nil {
+ return 0, err
+ }
+ sendBuffer.add(pkt)
return writer.Write(header, payload, attributes)
})
}
@@ -108,9 +137,10 @@ func (n *ResponderInterceptor) resendPackets(nack *rtcp.TransportLayerNack) {
for i := range nack.Nacks {
nack.Nacks[i].Range(func(seq uint16) bool {
if p := stream.sendBuffer.get(seq); p != nil {
- if _, err := stream.rtpWriter.Write(&p.Header, p.Payload, interceptor.Attributes{}); err != nil {
+ if _, err := stream.rtpWriter.Write(p.Header(), p.Payload(), interceptor.Attributes{}); err != nil {
n.log.Warnf("failed resending nacked packet: %+v", err)
}
+ p.Release()
}
return true
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/responder_option.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/responder_option.go
index 7ad52c8ad..0aaa7577f 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/responder_option.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/responder_option.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package nack
import "github.com/pion/logging"
@@ -21,3 +24,12 @@ func ResponderLog(log logging.LeveledLogger) ResponderOption {
return nil
}
}
+
+// DisableCopy bypasses copy of underlying packets. It should be used when
+// you are not re-using underlying buffers of packets that have been written
+func DisableCopy() ResponderOption {
+ return func(s *ResponderInterceptor) error {
+ s.packetFactory = &noOpPacketFactory{}
+ return nil
+ }
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/retainable_packet.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/retainable_packet.go
new file mode 100644
index 000000000..31e9d832f
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/retainable_packet.go
@@ -0,0 +1,132 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package nack
+
+import (
+ "io"
+ "sync"
+
+ "github.com/pion/rtp"
+)
+
+const maxPayloadLen = 1460
+
+type packetManager struct {
+ headerPool *sync.Pool
+ payloadPool *sync.Pool
+}
+
+func newPacketManager() *packetManager {
+ return &packetManager{
+ headerPool: &sync.Pool{
+ New: func() interface{} {
+ return &rtp.Header{}
+ },
+ },
+ payloadPool: &sync.Pool{
+ New: func() interface{} {
+ buf := make([]byte, maxPayloadLen)
+ return &buf
+ },
+ },
+ }
+}
+
+func (m *packetManager) NewPacket(header *rtp.Header, payload []byte) (*retainablePacket, error) {
+ if len(payload) > maxPayloadLen {
+ return nil, io.ErrShortBuffer
+ }
+
+ p := &retainablePacket{
+ onRelease: m.releasePacket,
+ // new packets have retain count of 1
+ count: 1,
+ }
+
+ var ok bool
+ p.header, ok = m.headerPool.Get().(*rtp.Header)
+ if !ok {
+ return nil, errFailedToCastHeaderPool
+ }
+
+ *p.header = header.Clone()
+
+ if payload != nil {
+ p.buffer, ok = m.payloadPool.Get().(*[]byte)
+ if !ok {
+ return nil, errFailedToCastPayloadPool
+ }
+
+ size := copy(*p.buffer, payload)
+ p.payload = (*p.buffer)[:size]
+ }
+
+ return p, nil
+}
+
+func (m *packetManager) releasePacket(header *rtp.Header, payload *[]byte) {
+ m.headerPool.Put(header)
+ if payload != nil {
+ m.payloadPool.Put(payload)
+ }
+}
+
+type noOpPacketFactory struct{}
+
+func (f *noOpPacketFactory) NewPacket(header *rtp.Header, payload []byte) (*retainablePacket, error) {
+ return &retainablePacket{
+ onRelease: f.releasePacket,
+ count: 1,
+ header: header,
+ payload: payload,
+ }, nil
+}
+
+func (f *noOpPacketFactory) releasePacket(_ *rtp.Header, _ *[]byte) {
+ // no-op
+}
+
+type retainablePacket struct {
+ onRelease func(*rtp.Header, *[]byte)
+
+ countMu sync.Mutex
+ count int
+
+ header *rtp.Header
+ buffer *[]byte
+ payload []byte
+}
+
+func (p *retainablePacket) Header() *rtp.Header {
+ return p.header
+}
+
+func (p *retainablePacket) Payload() []byte {
+ return p.payload
+}
+
+func (p *retainablePacket) Retain() error {
+ p.countMu.Lock()
+ defer p.countMu.Unlock()
+ if p.count == 0 {
+ // already released
+ return errPacketReleased
+ }
+ p.count++
+ return nil
+}
+
+func (p *retainablePacket) Release() {
+ p.countMu.Lock()
+ defer p.countMu.Unlock()
+ p.count--
+
+ if p.count == 0 {
+ // release back to pool
+ p.onRelease(p.header, p.buffer)
+ p.header = nil
+ p.buffer = nil
+ p.payload = nil
+ }
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/send_buffer.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/send_buffer.go
index cf3f020ef..e8e816f61 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/send_buffer.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/send_buffer.go
@@ -1,9 +1,11 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package nack
import (
"fmt"
-
- "github.com/pion/rtp"
+ "sync"
)
const (
@@ -11,10 +13,12 @@ const (
)
type sendBuffer struct {
- packets []*rtp.Packet
+ packets []*retainablePacket
size uint16
lastAdded uint16
started bool
+
+ m sync.RWMutex
}
func newSendBuffer(size uint16) (*sendBuffer, error) {
@@ -33,13 +37,16 @@ func newSendBuffer(size uint16) (*sendBuffer, error) {
}
return &sendBuffer{
- packets: make([]*rtp.Packet, size),
+ packets: make([]*retainablePacket, size),
size: size,
}, nil
}
-func (s *sendBuffer) add(packet *rtp.Packet) {
- seq := packet.SequenceNumber
+func (s *sendBuffer) add(packet *retainablePacket) {
+ s.m.Lock()
+ defer s.m.Unlock()
+
+ seq := packet.Header().SequenceNumber
if !s.started {
s.packets[seq%s.size] = packet
s.lastAdded = seq
@@ -52,15 +59,28 @@ func (s *sendBuffer) add(packet *rtp.Packet) {
return
} else if diff < uint16SizeHalf {
for i := s.lastAdded + 1; i != seq; i++ {
- s.packets[i%s.size] = nil
+ idx := i % s.size
+ prevPacket := s.packets[idx]
+ if prevPacket != nil {
+ prevPacket.Release()
+ }
+ s.packets[idx] = nil
}
}
- s.packets[seq%s.size] = packet
+ idx := seq % s.size
+ prevPacket := s.packets[idx]
+ if prevPacket != nil {
+ prevPacket.Release()
+ }
+ s.packets[idx] = packet
s.lastAdded = seq
}
-func (s *sendBuffer) get(seq uint16) *rtp.Packet {
+func (s *sendBuffer) get(seq uint16) *retainablePacket {
+ s.m.RLock()
+ defer s.m.RUnlock()
+
diff := s.lastAdded - seq
if diff >= uint16SizeHalf {
return nil
@@ -70,5 +90,15 @@ func (s *sendBuffer) get(seq uint16) *rtp.Packet {
return nil
}
- return s.packets[seq%s.size]
+ pkt := s.packets[seq%s.size]
+ if pkt != nil {
+ if pkt.Header().SequenceNumber != seq {
+ return nil
+ }
+ // already released
+ if err := pkt.Retain(); err != nil {
+ return nil
+ }
+ }
+ return pkt
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_interceptor.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_interceptor.go
index 5235b9906..c126f9abc 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_interceptor.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_interceptor.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package report
import (
@@ -7,9 +10,36 @@ import (
"github.com/pion/interceptor"
"github.com/pion/logging"
"github.com/pion/rtcp"
- "github.com/pion/rtp"
)
+// ReceiverInterceptorFactory is a interceptor.Factory for a ReceiverInterceptor
+type ReceiverInterceptorFactory struct {
+ opts []ReceiverOption
+}
+
+// NewInterceptor constructs a new ReceiverInterceptor
+func (r *ReceiverInterceptorFactory) NewInterceptor(_ string) (interceptor.Interceptor, error) {
+ i := &ReceiverInterceptor{
+ interval: 1 * time.Second,
+ now: time.Now,
+ log: logging.NewDefaultLoggerFactory().NewLogger("receiver_interceptor"),
+ close: make(chan struct{}),
+ }
+
+ for _, opt := range r.opts {
+ if err := opt(i); err != nil {
+ return nil, err
+ }
+ }
+
+ return i, nil
+}
+
+// NewReceiverInterceptor returns a new ReceiverInterceptorFactory
+func NewReceiverInterceptor(opts ...ReceiverOption) (*ReceiverInterceptorFactory, error) {
+ return &ReceiverInterceptorFactory{opts}, nil
+}
+
// ReceiverInterceptor interceptor generates receiver reports.
type ReceiverInterceptor struct {
interceptor.NoOp
@@ -22,24 +52,6 @@ type ReceiverInterceptor struct {
close chan struct{}
}
-// NewReceiverInterceptor returns a new ReceiverInterceptor interceptor.
-func NewReceiverInterceptor(opts ...ReceiverOption) (*ReceiverInterceptor, error) {
- r := &ReceiverInterceptor{
- interval: 1 * time.Second,
- now: time.Now,
- log: logging.NewDefaultLoggerFactory().NewLogger("receiver_interceptor"),
- close: make(chan struct{}),
- }
-
- for _, opt := range opts {
- if err := opt(r); err != nil {
- return nil, err
- }
- }
-
- return r, nil
-}
-
func (r *ReceiverInterceptor) isClosed() bool {
select {
case <-r.close:
@@ -83,18 +95,15 @@ func (r *ReceiverInterceptor) loop(rtcpWriter interceptor.RTCPWriter) {
defer r.wg.Done()
ticker := time.NewTicker(r.interval)
+ defer ticker.Stop()
for {
select {
case <-ticker.C:
now := r.now()
r.streams.Range(func(key, value interface{}) bool {
- stream := value.(*receiverStream)
-
- var pkts []rtcp.Packet
-
- pkts = append(pkts, stream.generateReport(now))
-
- if _, err := rtcpWriter.Write(pkts, interceptor.Attributes{}); err != nil {
+ if stream, ok := value.(*receiverStream); !ok {
+ r.log.Warnf("failed to cast ReceiverInterceptor stream")
+ } else if _, err := rtcpWriter.Write([]rtcp.Packet{stream.generateReport(now)}, interceptor.Attributes{}); err != nil {
r.log.Warnf("failed sending: %+v", err)
}
@@ -119,12 +128,15 @@ func (r *ReceiverInterceptor) BindRemoteStream(info *interceptor.StreamInfo, rea
return 0, nil, err
}
- pkt := rtp.Packet{}
- if err = pkt.Unmarshal(b[:i]); err != nil {
+ if attr == nil {
+ attr = make(interceptor.Attributes)
+ }
+ header, err := attr.GetRTPHeader(b[:i])
+ if err != nil {
return 0, nil, err
}
- stream.processRTP(r.now(), &pkt)
+ stream.processRTP(r.now(), header)
return i, attr, nil
})
@@ -144,7 +156,10 @@ func (r *ReceiverInterceptor) BindRTCPReader(reader interceptor.RTCPReader) inte
return 0, nil, err
}
- pkts, err := rtcp.Unmarshal(b[:i])
+ if attr == nil {
+ attr = make(interceptor.Attributes)
+ }
+ pkts, err := attr.GetRTCPPackets(b[:i])
if err != nil {
return 0, nil, err
}
@@ -156,8 +171,11 @@ func (r *ReceiverInterceptor) BindRTCPReader(reader interceptor.RTCPReader) inte
continue
}
- stream := value.(*receiverStream)
- stream.processSenderReport(r.now(), sr)
+ if stream, ok := value.(*receiverStream); !ok {
+ r.log.Warnf("failed to cast ReceiverInterceptor stream")
+ } else {
+ stream.processSenderReport(r.now(), sr)
+ }
}
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_option.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_option.go
index 0467dc5de..337a34142 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_option.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_option.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package report
import (
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_stream.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_stream.go
index 569715d0a..b899bb1b2 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_stream.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_stream.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package report
import (
@@ -40,21 +43,21 @@ func newReceiverStream(ssrc uint32, clockRate uint32) *receiverStream {
}
}
-func (stream *receiverStream) processRTP(now time.Time, pkt *rtp.Packet) {
+func (stream *receiverStream) processRTP(now time.Time, pktHeader *rtp.Header) {
stream.m.Lock()
defer stream.m.Unlock()
if !stream.started { // first frame
stream.started = true
- stream.setReceived(pkt.SequenceNumber)
- stream.lastSeqnum = pkt.SequenceNumber
- stream.lastReportSeqnum = pkt.SequenceNumber - 1
- stream.lastRTPTimeRTP = pkt.Timestamp
+ stream.setReceived(pktHeader.SequenceNumber)
+ stream.lastSeqnum = pktHeader.SequenceNumber
+ stream.lastReportSeqnum = pktHeader.SequenceNumber - 1
+ stream.lastRTPTimeRTP = pktHeader.Timestamp
stream.lastRTPTimeTime = now
} else { // following frames
- stream.setReceived(pkt.SequenceNumber)
+ stream.setReceived(pktHeader.SequenceNumber)
- diff := int32(pkt.SequenceNumber) - int32(stream.lastSeqnum)
+ diff := int32(pktHeader.SequenceNumber) - int32(stream.lastSeqnum)
if diff > 0 || diff < -0x0FFF {
// overflow
if diff < -0x0FFF {
@@ -62,22 +65,22 @@ func (stream *receiverStream) processRTP(now time.Time, pkt *rtp.Packet) {
}
// set missing packets as missing
- for i := stream.lastSeqnum + 1; i != pkt.SequenceNumber; i++ {
+ for i := stream.lastSeqnum + 1; i != pktHeader.SequenceNumber; i++ {
stream.delReceived(i)
}
- stream.lastSeqnum = pkt.SequenceNumber
+ stream.lastSeqnum = pktHeader.SequenceNumber
}
// compute jitter
// https://tools.ietf.org/html/rfc3550#page-39
D := now.Sub(stream.lastRTPTimeTime).Seconds()*stream.clockRate -
- (float64(pkt.Timestamp) - float64(stream.lastRTPTimeRTP))
+ (float64(pktHeader.Timestamp) - float64(stream.lastRTPTimeRTP))
if D < 0 {
D = -D
}
stream.jitter += (D - stream.jitter) / 16
- stream.lastRTPTimeRTP = pkt.Timestamp
+ stream.lastRTPTimeRTP = pktHeader.Timestamp
stream.lastRTPTimeTime = now
}
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/report.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/report.go
index 0a3034ce6..e4d2e64a4 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/report.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/report.go
@@ -1,2 +1,5 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
// Package report provides interceptors to implement sending sender and receiver reports.
package report
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_interceptor.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_interceptor.go
index e56fd8c30..02d1c0001 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_interceptor.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_interceptor.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
package report
import (
@@ -10,14 +13,32 @@ import (
"github.com/pion/rtp"
)
-func ntpTime(t time.Time) uint64 {
- // seconds since 1st January 1900
- s := (float64(t.UnixNano()) / 1000000000) + 2208988800
+// SenderInterceptorFactory is a interceptor.Factory for a SenderInterceptor
+type SenderInterceptorFactory struct {
+ opts []SenderOption
+}
- // higher 32 bits are the integer part, lower 32 bits are the fractional part
- integerPart := uint32(s)
- fractionalPart := uint32((s - float64(integerPart)) * 0xFFFFFFFF)
- return uint64(integerPart)<<32 | uint64(fractionalPart)
+// NewInterceptor constructs a new SenderInterceptor
+func (s *SenderInterceptorFactory) NewInterceptor(_ string) (interceptor.Interceptor, error) {
+ i := &SenderInterceptor{
+ interval: 1 * time.Second,
+ now: time.Now,
+ log: logging.NewDefaultLoggerFactory().NewLogger("sender_interceptor"),
+ close: make(chan struct{}),
+ }
+
+ for _, opt := range s.opts {
+ if err := opt(i); err != nil {
+ return nil, err
+ }
+ }
+
+ return i, nil
+}
+
+// NewSenderInterceptor returns a new SenderInterceptorFactory
+func NewSenderInterceptor(opts ...SenderOption) (*SenderInterceptorFactory, error) {
+ return &SenderInterceptorFactory{opts}, nil
}
// SenderInterceptor interceptor generates sender reports.
@@ -32,24 +53,6 @@ type SenderInterceptor struct {
close chan struct{}
}
-// NewSenderInterceptor returns a new SenderInterceptor interceptor.
-func NewSenderInterceptor(opts ...SenderOption) (*SenderInterceptor, error) {
- s := &SenderInterceptor{
- interval: 1 * time.Second,
- now: time.Now,
- log: logging.NewDefaultLoggerFactory().NewLogger("sender_interceptor"),
- close: make(chan struct{}),
- }
-
- for _, opt := range opts {
- if err := opt(s); err != nil {
- return nil, err
- }
- }
-
- return s, nil
-}
-
func (s *SenderInterceptor) isClosed() bool {
select {
case <-s.close:
@@ -93,26 +96,15 @@ func (s *SenderInterceptor) loop(rtcpWriter interceptor.RTCPWriter) {
defer s.wg.Done()
ticker := time.NewTicker(s.interval)
+ defer ticker.Stop()
for {
select {
case <-ticker.C:
now := s.now()
s.streams.Range(func(key, value interface{}) bool {
- ssrc := key.(uint32)
- stream := value.(*senderStream)
-
- stream.m.Lock()
- defer stream.m.Unlock()
-
- sr := &rtcp.SenderReport{
- SSRC: ssrc,
- NTPTime: ntpTime(now),
- RTPTime: stream.lastRTPTimeRTP + uint32(now.Sub(stream.lastRTPTimeTime).Seconds()*stream.clockRate),
- PacketCount: stream.packetCount,
- OctetCount: stream.octetCount,
- }
-
- if _, err := rtcpWriter.Write([]rtcp.Packet{sr}, interceptor.Attributes{}); err != nil {
+ if stream, ok := value.(*senderStream); !ok {
+ s.log.Warnf("failed to cast SenderInterceptor stream")
+ } else if _, err := rtcpWriter.Write([]rtcp.Packet{stream.generateReport(now)}, interceptor.Attributes{}); err != nil {
s.log.Warnf("failed sending: %+v", err)
}
@@ -128,7 +120,7 @@ func (s *SenderInterceptor) loop(rtcpWriter interceptor.RTCPWriter) {
// BindLocalStream lets you modify any outgoing RTP packets. It is called once for per LocalStream. The returned method
// will be called once per rtp packet.
func (s *SenderInterceptor) BindLocalStream(info *interceptor.StreamInfo, writer interceptor.RTPWriter) interceptor.RTPWriter {
- stream := newSenderStream(info.ClockRate)
+ stream := newSenderStream(info.SSRC, info.ClockRate)
s.streams.Store(info.SSRC, stream)
return interceptor.RTPWriterFunc(func(header *rtp.Header, payload []byte, a interceptor.Attributes) (int, error) {
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_option.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_option.go
index 4cb161a37..6932e1c0a 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_option.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_option.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2023 The Pion community