mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
For regression test, add srs-bench to 3rdparty
This commit is contained in:
parent
de87dd427d
commit
876210f6c9
1158 changed files with 256967 additions and 3 deletions
1
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/.gitignore
generated
vendored
Normal file
1
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
*.sw[poe]
|
82
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/.golangci.yml
generated
vendored
Normal file
82
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/.golangci.yml
generated
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
linters-settings:
|
||||
govet:
|
||||
check-shadowing: true
|
||||
misspell:
|
||||
locale: US
|
||||
exhaustive:
|
||||
default-signifies-exhaustive: true
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers
|
||||
- bodyclose # checks whether HTTP response body is closed successfully
|
||||
- deadcode # Finds unused code
|
||||
- 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
|
||||
- errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
|
||||
- exhaustive # check exhaustiveness of enum switch statements
|
||||
- exportloopref # checks for pointers to enclosing loop variables
|
||||
- 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
|
||||
- gocognit # Computes and checks the cognitive complexity of functions
|
||||
- goconst # Finds repeated strings that could be replaced by a constant
|
||||
- gocritic # The most opinionated Go source code linter
|
||||
- godox # Tool for detection of FIXME, TODO and other comment keywords
|
||||
- goerr113 # Golang linter to check the errors handling expressions
|
||||
- gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
|
||||
- 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
|
||||
- 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
|
||||
- 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
|
||||
- noctx # noctx finds sending http request without context.Context
|
||||
- scopelint # Scopelint checks for unpinned variables in go programs
|
||||
- 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
|
||||
- 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
|
||||
- whitespace # Tool for detection of leading and trailing whitespace
|
||||
disable:
|
||||
- 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.
|
||||
- lll # Reports long lines
|
||||
- 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
|
||||
- prealloc # Finds slice declarations that could potentially be preallocated
|
||||
- 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
|
||||
- wsl # Whitespace Linter - Forces you to use empty lines!
|
||||
|
||||
issues:
|
||||
exclude-rules:
|
||||
# Allow complex tests, better to be self contained
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- gocognit
|
||||
|
||||
# Allow complex main function in examples
|
||||
- path: examples
|
||||
text: "of func `main` is high"
|
||||
linters:
|
||||
- gocognit
|
||||
|
||||
run:
|
||||
skip-dirs-use-default: false
|
20
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/DESIGN.md
generated
vendored
Normal file
20
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/DESIGN.md
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
<h1 align="center">
|
||||
Design
|
||||
</h1>
|
||||
|
||||
### Portable
|
||||
Pion SCTP is written in Go and extremely portable. Anywhere Golang runs, Pion SCTP should work as well! Instead of dealing with complicated
|
||||
cross-compiling of multiple libraries, you now can run anywhere with one `go build`
|
||||
|
||||
### Simple API
|
||||
The API is based on an io.ReadWriteCloser.
|
||||
|
||||
### Readable
|
||||
If code comes from an RFC we try to make sure everything is commented with a link to the spec.
|
||||
This makes learning and debugging easier, this library was written to also serve as a guide for others.
|
||||
|
||||
### Tested
|
||||
Every commit is tested via travis-ci Go provides fantastic facilities for testing, and more will be added as time goes on.
|
||||
|
||||
### Shared libraries
|
||||
Every pion product is built using shared libraries, allowing others to review and reuse our libraries.
|
21
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/LICENSE
generated
vendored
Normal file
21
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2018
|
||||
|
||||
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 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.
|
54
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/README.md
generated
vendored
Normal file
54
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/README.md
generated
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
<h1 align="center">
|
||||
<br>
|
||||
Pion SCTP
|
||||
<br>
|
||||
</h1>
|
||||
<h4 align="center">A Go implementation of SCTP</h4>
|
||||
<p align="center">
|
||||
<a href="https://pion.ly"><img src="https://img.shields.io/badge/pion-sctp-gray.svg?longCache=true&colorB=brightgreen" alt="Pion SCTP"></a>
|
||||
<!--<a href="https://sourcegraph.com/github.com/pion/webrtc?badge"><img src="https://sourcegraph.com/github.com/pion/webrtc/-/badge.svg" alt="Sourcegraph Widget"></a>-->
|
||||
<a href="https://pion.ly/slack"><img src="https://img.shields.io/badge/join-us%20on%20slack-gray.svg?longCache=true&logo=slack&colorB=brightgreen" alt="Slack Widget"></a>
|
||||
<br>
|
||||
<a href="https://travis-ci.org/pion/sctp"><img src="https://travis-ci.org/pion/sctp.svg?branch=master" alt="Build Status"></a>
|
||||
<a href="https://pkg.go.dev/github.com/pion/sctp"><img src="https://godoc.org/github.com/pion/sctp?status.svg" alt="GoDoc"></a>
|
||||
<a href="https://codecov.io/gh/pion/sctp"><img src="https://codecov.io/gh/pion/sctp/branch/master/graph/badge.svg" alt="Coverage Status"></a>
|
||||
<a href="https://goreportcard.com/report/github.com/pion/sctp"><img src="https://goreportcard.com/badge/github.com/pion/sctp" alt="Go Report Card"></a>
|
||||
<!--<a href="https://www.codacy.com/app/Sean-Der/webrtc"><img src="https://api.codacy.com/project/badge/Grade/18f4aec384894e6aac0b94effe51961d" alt="Codacy Badge"></a>-->
|
||||
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
|
||||
</p>
|
||||
<br>
|
||||
|
||||
See [DESIGN.md](DESIGN.md) for an overview of features and future goals.
|
||||
|
||||
### 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).
|
||||
|
||||
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*
|
||||
* [Michiel De Backker](https://github.com/backkem) - *Public API, Initialization*
|
||||
* [Konstantin Itskov](https://github.com/trivigy) - *Fix documentation*
|
||||
* [chenkaiC4](https://github.com/chenkaiC4) - *Fix GolangCI Linter*
|
||||
* [Ronan J](https://github.com/ronanj) - *Fix PPID*
|
||||
* [Michael MacDonald](https://github.com/mjmac) - *Fix races*
|
||||
* [Yutaka Takeda](https://github.com/enobufs) - *PR-SCTP, Retransmissions, Congestion Control*
|
||||
* [Antoine Baché](https://github.com/Antonito) - *SCTP Profiling*
|
||||
* [Cecylia Bocovich](https://github.com/cohosh) - *Fix SCTP reads*
|
||||
* [Hugo Arregui](https://github.com/hugoArregui)
|
||||
* [Atsushi Watanabe](https://github.com/at-wat)
|
||||
* [Lukas Herman](https://github.com/lherman-cs)
|
||||
* [Luke Curley](https://github.com/kixelated) - *Performance*
|
||||
* [Aaron France](https://github.com/AeroNotix)
|
||||
* [ZHENK](https://github.com/scorpionknifes)
|
||||
|
||||
### License
|
||||
MIT License - see [LICENSE](LICENSE) for full text
|
105
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/ack_timer.go
generated
vendored
Normal file
105
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/ack_timer.go
generated
vendored
Normal file
|
@ -0,0 +1,105 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
ackInterval time.Duration = 200 * time.Millisecond
|
||||
)
|
||||
|
||||
// ackTimerObserver is the inteface to an ack timer observer.
|
||||
type ackTimerObserver interface {
|
||||
onAckTimeout()
|
||||
}
|
||||
|
||||
// ackTimer provides the retnransmission timer conforms with RFC 4960 Sec 6.3.1
|
||||
type ackTimer struct {
|
||||
observer ackTimerObserver
|
||||
interval time.Duration
|
||||
stopFunc stopAckTimerLoop
|
||||
closed bool
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
|
||||
type stopAckTimerLoop func()
|
||||
|
||||
// newAckTimer creates a new acknowledgement timer used to enable delayed ack.
|
||||
func newAckTimer(observer ackTimerObserver) *ackTimer {
|
||||
return &ackTimer{
|
||||
observer: observer,
|
||||
interval: ackInterval,
|
||||
}
|
||||
}
|
||||
|
||||
// start starts the timer.
|
||||
func (t *ackTimer) start() bool {
|
||||
t.mutex.Lock()
|
||||
defer t.mutex.Unlock()
|
||||
|
||||
// this timer is already closed
|
||||
if t.closed {
|
||||
return false
|
||||
}
|
||||
|
||||
// this is a noop if the timer is already running
|
||||
if t.stopFunc != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
cancelCh := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
timer := time.NewTimer(t.interval)
|
||||
|
||||
select {
|
||||
case <-timer.C:
|
||||
t.stop()
|
||||
t.observer.onAckTimeout()
|
||||
case <-cancelCh:
|
||||
timer.Stop()
|
||||
}
|
||||
}()
|
||||
|
||||
t.stopFunc = func() {
|
||||
close(cancelCh)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// stops the timer. this is similar to stop() but subsequent start() call
|
||||
// will fail (the timer is no longer usable)
|
||||
func (t *ackTimer) stop() {
|
||||
t.mutex.Lock()
|
||||
defer t.mutex.Unlock()
|
||||
|
||||
if t.stopFunc != nil {
|
||||
t.stopFunc()
|
||||
t.stopFunc = nil
|
||||
}
|
||||
}
|
||||
|
||||
// closes the timer. this is similar to stop() but subsequent start() call
|
||||
// will fail (the timer is no longer usable)
|
||||
func (t *ackTimer) close() {
|
||||
t.mutex.Lock()
|
||||
defer t.mutex.Unlock()
|
||||
|
||||
if t.stopFunc != nil {
|
||||
t.stopFunc()
|
||||
t.stopFunc = nil
|
||||
}
|
||||
|
||||
t.closed = true
|
||||
}
|
||||
|
||||
// isRunning tests if the timer is running.
|
||||
// Debug purpose only
|
||||
func (t *ackTimer) isRunning() bool {
|
||||
t.mutex.RLock()
|
||||
defer t.mutex.RUnlock()
|
||||
|
||||
return (t.stopFunc != nil)
|
||||
}
|
2241
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/association.go
generated
vendored
Normal file
2241
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/association.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
61
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/association_stats.go
generated
vendored
Normal file
61
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/association_stats.go
generated
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type associationStats struct {
|
||||
nDATAs uint64
|
||||
nSACKs uint64
|
||||
nT3Timeouts uint64
|
||||
nAckTimeouts uint64
|
||||
nFastRetrans uint64
|
||||
}
|
||||
|
||||
func (s *associationStats) incDATAs() {
|
||||
atomic.AddUint64(&s.nDATAs, 1)
|
||||
}
|
||||
|
||||
func (s *associationStats) getNumDATAs() uint64 {
|
||||
return atomic.LoadUint64(&s.nDATAs)
|
||||
}
|
||||
|
||||
func (s *associationStats) incSACKs() {
|
||||
atomic.AddUint64(&s.nSACKs, 1)
|
||||
}
|
||||
|
||||
func (s *associationStats) getNumSACKs() uint64 {
|
||||
return atomic.LoadUint64(&s.nSACKs)
|
||||
}
|
||||
|
||||
func (s *associationStats) incT3Timeouts() {
|
||||
atomic.AddUint64(&s.nT3Timeouts, 1)
|
||||
}
|
||||
|
||||
func (s *associationStats) getNumT3Timeouts() uint64 {
|
||||
return atomic.LoadUint64(&s.nT3Timeouts)
|
||||
}
|
||||
|
||||
func (s *associationStats) incAckTimeouts() {
|
||||
atomic.AddUint64(&s.nAckTimeouts, 1)
|
||||
}
|
||||
|
||||
func (s *associationStats) getNumAckTimeouts() uint64 {
|
||||
return atomic.LoadUint64(&s.nAckTimeouts)
|
||||
}
|
||||
|
||||
func (s *associationStats) incFastRetrans() {
|
||||
atomic.AddUint64(&s.nFastRetrans, 1)
|
||||
}
|
||||
|
||||
func (s *associationStats) getNumFastRetrans() uint64 {
|
||||
return atomic.LoadUint64(&s.nFastRetrans)
|
||||
}
|
||||
|
||||
func (s *associationStats) reset() {
|
||||
atomic.StoreUint64(&s.nDATAs, 0)
|
||||
atomic.StoreUint64(&s.nSACKs, 0)
|
||||
atomic.StoreUint64(&s.nT3Timeouts, 0)
|
||||
atomic.StoreUint64(&s.nAckTimeouts, 0)
|
||||
atomic.StoreUint64(&s.nFastRetrans, 0)
|
||||
}
|
9
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk.go
generated
vendored
Normal file
9
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk.go
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
package sctp
|
||||
|
||||
type chunk interface {
|
||||
unmarshal(raw []byte) error
|
||||
marshal() ([]byte, error)
|
||||
check() (bool, error)
|
||||
|
||||
valueLength() int
|
||||
}
|
88
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_abort.go
generated
vendored
Normal file
88
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_abort.go
generated
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
package sctp // nolint:dupl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
/*
|
||||
Abort represents an SCTP Chunk of type ABORT
|
||||
|
||||
The ABORT chunk is sent to the peer of an association to close the
|
||||
association. The ABORT chunk may contain Cause Parameters to inform
|
||||
the receiver about the reason of the abort. DATA chunks MUST NOT be
|
||||
bundled with ABORT. Control chunks (except for INIT, INIT ACK, and
|
||||
SHUTDOWN COMPLETE) MAY be bundled with an ABORT, but they MUST be
|
||||
placed before the ABORT in the SCTP packet or they will be ignored by
|
||||
the receiver.
|
||||
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type = 6 |Reserved |T| Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
| zero or more Error Causes |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
type chunkAbort struct {
|
||||
chunkHeader
|
||||
errorCauses []errorCause
|
||||
}
|
||||
|
||||
func (a *chunkAbort) unmarshal(raw []byte) error {
|
||||
if err := a.chunkHeader.unmarshal(raw); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if a.typ != ctAbort {
|
||||
return errors.Errorf("ChunkType is not of type ABORT, actually is %s", a.typ.String())
|
||||
}
|
||||
|
||||
offset := chunkHeaderSize
|
||||
for {
|
||||
if len(raw)-offset < 4 {
|
||||
break
|
||||
}
|
||||
|
||||
e, err := buildErrorCause(raw[offset:])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed build Abort Chunk")
|
||||
}
|
||||
|
||||
offset += int(e.length())
|
||||
a.errorCauses = append(a.errorCauses, e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *chunkAbort) marshal() ([]byte, error) {
|
||||
a.chunkHeader.typ = ctAbort
|
||||
a.flags = 0x00
|
||||
a.raw = []byte{}
|
||||
for _, ec := range a.errorCauses {
|
||||
raw, err := ec.marshal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a.raw = append(a.raw, raw...)
|
||||
}
|
||||
return a.chunkHeader.marshal()
|
||||
}
|
||||
|
||||
func (a *chunkAbort) check() (abort bool, err error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// String makes chunkAbort printable
|
||||
func (a *chunkAbort) String() string {
|
||||
res := a.chunkHeader.String()
|
||||
|
||||
for _, cause := range a.errorCauses {
|
||||
res += fmt.Sprintf("\n - %s", cause)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
44
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_cookie_ack.go
generated
vendored
Normal file
44
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_cookie_ack.go
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
/*
|
||||
chunkCookieAck represents an SCTP Chunk of type chunkCookieAck
|
||||
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type = 11 |Chunk Flags | Length = 4 |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
type chunkCookieAck struct {
|
||||
chunkHeader
|
||||
}
|
||||
|
||||
func (c *chunkCookieAck) unmarshal(raw []byte) error {
|
||||
if err := c.chunkHeader.unmarshal(raw); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.typ != ctCookieAck {
|
||||
return errors.Errorf("ChunkType is not of type COOKIEACK, actually is %s", c.typ.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *chunkCookieAck) marshal() ([]byte, error) {
|
||||
c.chunkHeader.typ = ctCookieAck
|
||||
return c.chunkHeader.marshal()
|
||||
}
|
||||
|
||||
func (c *chunkCookieAck) check() (abort bool, err error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// String makes chunkCookieAck printable
|
||||
func (c *chunkCookieAck) String() string {
|
||||
return c.chunkHeader.String()
|
||||
}
|
46
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_cookie_echo.go
generated
vendored
Normal file
46
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_cookie_echo.go
generated
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
/*
|
||||
CookieEcho represents an SCTP Chunk of type CookieEcho
|
||||
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type = 10 |Chunk Flags | Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Cookie |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
*/
|
||||
type chunkCookieEcho struct {
|
||||
chunkHeader
|
||||
cookie []byte
|
||||
}
|
||||
|
||||
func (c *chunkCookieEcho) unmarshal(raw []byte) error {
|
||||
if err := c.chunkHeader.unmarshal(raw); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.typ != ctCookieEcho {
|
||||
return errors.Errorf("ChunkType is not of type COOKIEECHO, actually is %s", c.typ.String())
|
||||
}
|
||||
c.cookie = c.raw
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *chunkCookieEcho) marshal() ([]byte, error) {
|
||||
c.chunkHeader.typ = ctCookieEcho
|
||||
c.chunkHeader.raw = c.cookie
|
||||
return c.chunkHeader.marshal()
|
||||
}
|
||||
|
||||
func (c *chunkCookieEcho) check() (abort bool, err error) {
|
||||
return false, nil
|
||||
}
|
95
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_error.go
generated
vendored
Normal file
95
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_error.go
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
package sctp // nolint:dupl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
/*
|
||||
Operation Error (ERROR) (9)
|
||||
|
||||
An endpoint sends this chunk to its peer endpoint to notify it of
|
||||
certain error conditions. It contains one or more error causes. An
|
||||
Operation Error is not considered fatal in and of itself, but may be
|
||||
used with an ERROR chunk to report a fatal condition. It has the
|
||||
following parameters:
|
||||
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type = 9 | Chunk Flags | Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
\ \
|
||||
/ one or more Error Causes /
|
||||
\ \
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
Chunk Flags: 8 bits
|
||||
|
||||
Set to 0 on transmit and ignored on receipt.
|
||||
|
||||
Length: 16 bits (unsigned integer)
|
||||
|
||||
Set to the size of the chunk in bytes, including the chunk header
|
||||
and all the Error Cause fields present.
|
||||
*/
|
||||
type chunkError struct {
|
||||
chunkHeader
|
||||
errorCauses []errorCause
|
||||
}
|
||||
|
||||
func (a *chunkError) unmarshal(raw []byte) error {
|
||||
if err := a.chunkHeader.unmarshal(raw); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if a.typ != ctError {
|
||||
return errors.Errorf("ChunkType is not of type ctError, actually is %s", a.typ.String())
|
||||
}
|
||||
|
||||
offset := chunkHeaderSize
|
||||
for {
|
||||
if len(raw)-offset < 4 {
|
||||
break
|
||||
}
|
||||
|
||||
e, err := buildErrorCause(raw[offset:])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed build Error Chunk")
|
||||
}
|
||||
|
||||
offset += int(e.length())
|
||||
a.errorCauses = append(a.errorCauses, e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *chunkError) marshal() ([]byte, error) {
|
||||
a.chunkHeader.typ = ctError
|
||||
a.flags = 0x00
|
||||
a.raw = []byte{}
|
||||
for _, ec := range a.errorCauses {
|
||||
raw, err := ec.marshal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a.raw = append(a.raw, raw...)
|
||||
}
|
||||
return a.chunkHeader.marshal()
|
||||
}
|
||||
|
||||
func (a *chunkError) check() (abort bool, err error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// String makes chunkError printable
|
||||
func (a *chunkError) String() string {
|
||||
res := a.chunkHeader.String()
|
||||
|
||||
for _, cause := range a.errorCauses {
|
||||
res += fmt.Sprintf("\n - %s", cause)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
145
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_forward_tsn.go
generated
vendored
Normal file
145
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_forward_tsn.go
generated
vendored
Normal file
|
@ -0,0 +1,145 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// This chunk shall be used by the data sender to inform the data
|
||||
// receiver to adjust its cumulative received TSN point forward because
|
||||
// some missing TSNs are associated with data chunks that SHOULD NOT be
|
||||
// transmitted or retransmitted by the sender.
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Type = 192 | Flags = 0x00 | Length = Variable |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | New Cumulative TSN |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Stream-1 | Stream Sequence-1 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// \ /
|
||||
// / \
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Stream-N | Stream Sequence-N |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
type chunkForwardTSN struct {
|
||||
chunkHeader
|
||||
|
||||
// This indicates the new cumulative TSN to the data receiver. Upon
|
||||
// the reception of this value, the data receiver MUST consider
|
||||
// any missing TSNs earlier than or equal to this value as received,
|
||||
// and stop reporting them as gaps in any subsequent SACKs.
|
||||
newCumulativeTSN uint32
|
||||
|
||||
streams []chunkForwardTSNStream
|
||||
}
|
||||
|
||||
const (
|
||||
newCumulativeTSNLength = 4
|
||||
forwardTSNStreamLength = 4
|
||||
)
|
||||
|
||||
var errMarshalStreamFailed = errors.New("failed to marshal stream")
|
||||
|
||||
func (c *chunkForwardTSN) unmarshal(raw []byte) error {
|
||||
if err := c.chunkHeader.unmarshal(raw); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(c.raw) < newCumulativeTSNLength {
|
||||
return errors.New("chunk to short")
|
||||
}
|
||||
|
||||
c.newCumulativeTSN = binary.BigEndian.Uint32(c.raw[0:])
|
||||
|
||||
offset := newCumulativeTSNLength
|
||||
remaining := len(c.raw) - offset
|
||||
for remaining > 0 {
|
||||
s := chunkForwardTSNStream{}
|
||||
|
||||
if err := s.unmarshal(c.raw[offset:]); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal stream: %w", err)
|
||||
}
|
||||
|
||||
c.streams = append(c.streams, s)
|
||||
|
||||
offset += s.length()
|
||||
remaining -= s.length()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *chunkForwardTSN) marshal() ([]byte, error) {
|
||||
out := make([]byte, newCumulativeTSNLength)
|
||||
binary.BigEndian.PutUint32(out[0:], c.newCumulativeTSN)
|
||||
|
||||
for _, s := range c.streams {
|
||||
b, err := s.marshal()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", errMarshalStreamFailed, err)
|
||||
}
|
||||
out = append(out, b...)
|
||||
}
|
||||
|
||||
c.typ = ctForwardTSN
|
||||
c.raw = out
|
||||
return c.chunkHeader.marshal()
|
||||
}
|
||||
|
||||
func (c *chunkForwardTSN) check() (abort bool, err error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// String makes chunkForwardTSN printable
|
||||
func (c *chunkForwardTSN) String() string {
|
||||
res := fmt.Sprintf("New Cumulative TSN: %d\n", c.newCumulativeTSN)
|
||||
for _, s := range c.streams {
|
||||
res += fmt.Sprintf(" - si=%d, ssn=%d\n", s.identifier, s.sequence)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
type chunkForwardTSNStream struct {
|
||||
// This field holds a stream number that was skipped by this
|
||||
// FWD-TSN.
|
||||
identifier uint16
|
||||
|
||||
// This field holds the sequence number associated with the stream
|
||||
// that was skipped. The stream sequence field holds the largest
|
||||
// stream sequence number in this stream being skipped. The receiver
|
||||
// of the FWD-TSN's can use the Stream-N and Stream Sequence-N fields
|
||||
// to enable delivery of any stranded TSN's that remain on the stream
|
||||
// re-ordering queues. This field MUST NOT report TSN's corresponding
|
||||
// to DATA chunks that are marked as unordered. For ordered DATA
|
||||
// chunks this field MUST be filled in.
|
||||
sequence uint16
|
||||
}
|
||||
|
||||
func (s *chunkForwardTSNStream) length() int {
|
||||
return forwardTSNStreamLength
|
||||
}
|
||||
|
||||
func (s *chunkForwardTSNStream) unmarshal(raw []byte) error {
|
||||
if len(raw) < forwardTSNStreamLength {
|
||||
return errors.New("stream to short")
|
||||
}
|
||||
s.identifier = binary.BigEndian.Uint16(raw[0:])
|
||||
s.sequence = binary.BigEndian.Uint16(raw[2:])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *chunkForwardTSNStream) marshal() ([]byte, error) { // nolint:unparam
|
||||
out := make([]byte, forwardTSNStreamLength)
|
||||
|
||||
binary.BigEndian.PutUint16(out[0:], s.identifier)
|
||||
binary.BigEndian.PutUint16(out[2:], s.sequence)
|
||||
|
||||
return out, nil
|
||||
}
|
75
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_heartbeat.go
generated
vendored
Normal file
75
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_heartbeat.go
generated
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
/*
|
||||
chunkHeartbeat represents an SCTP Chunk of type HEARTBEAT
|
||||
|
||||
An endpoint should send this chunk to its peer endpoint to probe the
|
||||
reachability of a particular destination transport address defined in
|
||||
the present association.
|
||||
|
||||
The parameter field contains the Heartbeat Information, which is a
|
||||
variable-length opaque data structure understood only by the sender.
|
||||
|
||||
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type = 4 | Chunk Flags | Heartbeat Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
| Heartbeat Information TLV (Variable-Length) |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
Defined as a variable-length parameter using the format described
|
||||
in Section 3.2.1, i.e.:
|
||||
|
||||
Variable Parameters Status Type Value
|
||||
-------------------------------------------------------------
|
||||
heartbeat Info Mandatory 1
|
||||
|
||||
*/
|
||||
type chunkHeartbeat struct {
|
||||
chunkHeader
|
||||
params []param
|
||||
}
|
||||
|
||||
func (h *chunkHeartbeat) unmarshal(raw []byte) error {
|
||||
if err := h.chunkHeader.unmarshal(raw); err != nil {
|
||||
return err
|
||||
} else if h.typ != ctHeartbeat {
|
||||
return errors.Errorf("ChunkType is not of type HEARTBEAT, actually is %s", h.typ.String())
|
||||
}
|
||||
|
||||
if len(raw) <= chunkHeaderSize {
|
||||
return errors.Errorf("Heartbeat is not long enough to contain Heartbeat Info %d", len(raw))
|
||||
}
|
||||
|
||||
pType, err := parseParamType(raw[chunkHeaderSize:])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to parse param type")
|
||||
}
|
||||
if pType != heartbeatInfo {
|
||||
return errors.Errorf("Heartbeat should only have HEARTBEAT param, instead have %s", pType.String())
|
||||
}
|
||||
|
||||
p, err := buildParam(pType, raw[chunkHeaderSize:])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed unmarshalling param in Heartbeat Chunk")
|
||||
}
|
||||
h.params = append(h.params, p)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *chunkHeartbeat) Marshal() ([]byte, error) {
|
||||
return nil, errors.Errorf("Unimplemented")
|
||||
}
|
||||
|
||||
func (h *chunkHeartbeat) check() (abort bool, err error) {
|
||||
return false, nil
|
||||
}
|
86
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_heartbeat_ack.go
generated
vendored
Normal file
86
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_heartbeat_ack.go
generated
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
/*
|
||||
chunkHeartbeatAck represents an SCTP Chunk of type HEARTBEAT ACK
|
||||
|
||||
An endpoint should send this chunk to its peer endpoint as a response
|
||||
to a HEARTBEAT chunk (see Section 8.3). A HEARTBEAT ACK is always
|
||||
sent to the source IP address of the IP datagram containing the
|
||||
HEARTBEAT chunk to which this ack is responding.
|
||||
|
||||
The parameter field contains a variable-length opaque data structure.
|
||||
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type = 5 | Chunk Flags | Heartbeat Ack Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
| Heartbeat Information TLV (Variable-Length) |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
|
||||
Defined as a variable-length parameter using the format described
|
||||
in Section 3.2.1, i.e.:
|
||||
|
||||
Variable Parameters Status Type Value
|
||||
-------------------------------------------------------------
|
||||
Heartbeat Info Mandatory 1
|
||||
|
||||
*/
|
||||
type chunkHeartbeatAck struct {
|
||||
chunkHeader
|
||||
params []param
|
||||
}
|
||||
|
||||
func (h *chunkHeartbeatAck) unmarshal(raw []byte) error {
|
||||
return errors.Errorf("Unimplemented")
|
||||
}
|
||||
|
||||
func (h *chunkHeartbeatAck) marshal() ([]byte, error) {
|
||||
if len(h.params) != 1 {
|
||||
return nil, errors.Errorf("Heartbeat Ack must have one param")
|
||||
}
|
||||
|
||||
switch h.params[0].(type) {
|
||||
case *paramHeartbeatInfo:
|
||||
// ParamHeartbeatInfo is valid
|
||||
default:
|
||||
return nil, errors.Errorf("Heartbeat Ack must have one param, and it should be a HeartbeatInfo")
|
||||
}
|
||||
|
||||
out := make([]byte, 0)
|
||||
for idx, p := range h.params {
|
||||
pp, err := p.marshal()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to marshal parameter for Heartbeat Ack")
|
||||
}
|
||||
|
||||
out = append(out, pp...)
|
||||
|
||||
// Chunks (including Type, Length, and Value fields) are padded out
|
||||
// by the sender with all zero bytes to be a multiple of 4 bytes
|
||||
// long. This padding MUST NOT be more than 3 bytes in total. The
|
||||
// Chunk Length value does not include terminating padding of the
|
||||
// chunk. *However, it does include padding of any variable-length
|
||||
// parameter except the last parameter in the chunk.* The receiver
|
||||
// MUST ignore the padding.
|
||||
if idx != len(h.params)-1 {
|
||||
out = padByte(out, getPadding(len(pp)))
|
||||
}
|
||||
}
|
||||
|
||||
h.chunkHeader.typ = ctHeartbeatAck
|
||||
h.chunkHeader.raw = out
|
||||
|
||||
return h.chunkHeader.marshal()
|
||||
}
|
||||
|
||||
func (h *chunkHeartbeatAck) check() (abort bool, err error) {
|
||||
return false, nil
|
||||
}
|
123
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_init.go
generated
vendored
Normal file
123
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_init.go
generated
vendored
Normal file
|
@ -0,0 +1,123 @@
|
|||
package sctp // nolint:dupl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
/*
|
||||
Init represents an SCTP Chunk of type INIT
|
||||
|
||||
See chunkInitCommon for the fixed headers
|
||||
|
||||
Variable Parameters Status Type Value
|
||||
-------------------------------------------------------------
|
||||
IPv4 IP (Note 1) Optional 5
|
||||
IPv6 IP (Note 1) Optional 6
|
||||
Cookie Preservative Optional 9
|
||||
Reserved for ECN Capable (Note 2) Optional 32768 (0x8000)
|
||||
Host Name IP (Note 3) Optional 11
|
||||
Supported IP Types (Note 4) Optional 12
|
||||
*/
|
||||
type chunkInit struct {
|
||||
chunkHeader
|
||||
chunkInitCommon
|
||||
}
|
||||
|
||||
func (i *chunkInit) unmarshal(raw []byte) error {
|
||||
if err := i.chunkHeader.unmarshal(raw); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if i.typ != ctInit {
|
||||
return errors.Errorf("ChunkType is not of type INIT, actually is %s", i.typ.String())
|
||||
} else if len(i.raw) < initChunkMinLength {
|
||||
return errors.Errorf("Chunk Value isn't long enough for mandatory parameters exp: %d actual: %d", initChunkMinLength, len(i.raw))
|
||||
}
|
||||
|
||||
// The Chunk Flags field in INIT is reserved, and all bits in it should
|
||||
// be set to 0 by the sender and ignored by the receiver. The sequence
|
||||
// of parameters within an INIT can be processed in any order.
|
||||
if i.flags != 0 {
|
||||
return errors.New("ChunkType of type INIT flags must be all 0")
|
||||
}
|
||||
|
||||
if err := i.chunkInitCommon.unmarshal(i.raw); err != nil {
|
||||
return errors.Wrap(err, "Failed to unmarshal INIT body")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *chunkInit) marshal() ([]byte, error) {
|
||||
initShared, err := i.chunkInitCommon.marshal()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed marshaling INIT common data")
|
||||
}
|
||||
|
||||
i.chunkHeader.typ = ctInit
|
||||
i.chunkHeader.raw = initShared
|
||||
return i.chunkHeader.marshal()
|
||||
}
|
||||
|
||||
func (i *chunkInit) check() (abort bool, err error) {
|
||||
// The receiver of the INIT (the responding end) records the value of
|
||||
// the Initiate Tag parameter. This value MUST be placed into the
|
||||
// Verification Tag field of every SCTP packet that the receiver of
|
||||
// the INIT transmits within this association.
|
||||
//
|
||||
// The Initiate Tag is allowed to have any value except 0. See
|
||||
// Section 5.3.1 for more on the selection of the tag value.
|
||||
//
|
||||
// If the value of the Initiate Tag in a received INIT chunk is found
|
||||
// to be 0, the receiver MUST treat it as an error and close the
|
||||
// association by transmitting an ABORT.
|
||||
if i.initiateTag == 0 {
|
||||
abort = true
|
||||
return abort, errors.New("ChunkType of type INIT InitiateTag must not be 0")
|
||||
}
|
||||
|
||||
// Defines the maximum number of streams the sender of this INIT
|
||||
// chunk allows the peer end to create in this association. The
|
||||
// value 0 MUST NOT be used.
|
||||
//
|
||||
// Note: There is no negotiation of the actual number of streams but
|
||||
// instead the two endpoints will use the min(requested, offered).
|
||||
// See Section 5.1.1 for details.
|
||||
//
|
||||
// Note: A receiver of an INIT with the MIS value of 0 SHOULD abort
|
||||
// the association.
|
||||
if i.numInboundStreams == 0 {
|
||||
abort = true
|
||||
return abort, errors.New("INIT inbound stream request must be > 0")
|
||||
}
|
||||
|
||||
// Defines the number of outbound streams the sender of this INIT
|
||||
// chunk wishes to create in this association. The value of 0 MUST
|
||||
// NOT be used.
|
||||
//
|
||||
// Note: A receiver of an INIT with the OS value set to 0 SHOULD
|
||||
// abort the association.
|
||||
|
||||
if i.numOutboundStreams == 0 {
|
||||
abort = true
|
||||
return abort, errors.New("INIT outbound stream request must be > 0")
|
||||
}
|
||||
|
||||
// An SCTP receiver MUST be able to receive a minimum of 1500 bytes in
|
||||
// one SCTP packet. This means that an SCTP endpoint MUST NOT indicate
|
||||
// less than 1500 bytes in its initial a_rwnd sent in the INIT or INIT
|
||||
// ACK.
|
||||
if i.advertisedReceiverWindowCredit < 1500 {
|
||||
abort = true
|
||||
return abort, errors.New("INIT Advertised Receiver Window Credit (a_rwnd) must be >= 1500")
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// String makes chunkInit printable
|
||||
func (i *chunkInit) String() string {
|
||||
return fmt.Sprintf("%s\n%s", i.chunkHeader, i.chunkInitCommon)
|
||||
}
|
126
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_init_ack.go
generated
vendored
Normal file
126
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_init_ack.go
generated
vendored
Normal file
|
@ -0,0 +1,126 @@
|
|||
package sctp // nolint:dupl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
/*
|
||||
chunkInitAck represents an SCTP Chunk of type INIT ACK
|
||||
|
||||
See chunkInitCommon for the fixed headers
|
||||
|
||||
Variable Parameters Status Type Value
|
||||
-------------------------------------------------------------
|
||||
State Cookie Mandatory 7
|
||||
IPv4 IP (Note 1) Optional 5
|
||||
IPv6 IP (Note 1) Optional 6
|
||||
Unrecognized Parameter Optional 8
|
||||
Reserved for ECN Capable (Note 2) Optional 32768 (0x8000)
|
||||
Host Name IP (Note 3) Optional 11<Paste>
|
||||
|
||||
*/
|
||||
type chunkInitAck struct {
|
||||
chunkHeader
|
||||
chunkInitCommon
|
||||
}
|
||||
|
||||
func (i *chunkInitAck) unmarshal(raw []byte) error {
|
||||
if err := i.chunkHeader.unmarshal(raw); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if i.typ != ctInitAck {
|
||||
return errors.Errorf("ChunkType is not of type INIT ACK, actually is %s", i.typ.String())
|
||||
} else if len(i.raw) < initChunkMinLength {
|
||||
return errors.Errorf("Chunk Value isn't long enough for mandatory parameters exp: %d actual: %d", initChunkMinLength, len(i.raw))
|
||||
}
|
||||
|
||||
// The Chunk Flags field in INIT is reserved, and all bits in it should
|
||||
// be set to 0 by the sender and ignored by the receiver. The sequence
|
||||
// of parameters within an INIT can be processed in any order.
|
||||
if i.flags != 0 {
|
||||
return errors.New("ChunkType of type INIT ACK flags must be all 0")
|
||||
}
|
||||
|
||||
if err := i.chunkInitCommon.unmarshal(i.raw); err != nil {
|
||||
return errors.Wrap(err, "Failed to unmarshal INIT body")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *chunkInitAck) marshal() ([]byte, error) {
|
||||
initShared, err := i.chunkInitCommon.marshal()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed marshaling INIT common data")
|
||||
}
|
||||
|
||||
i.chunkHeader.typ = ctInitAck
|
||||
i.chunkHeader.raw = initShared
|
||||
return i.chunkHeader.marshal()
|
||||
}
|
||||
|
||||
func (i *chunkInitAck) check() (abort bool, err error) {
|
||||
// The receiver of the INIT ACK records the value of the Initiate Tag
|
||||
// parameter. This value MUST be placed into the Verification Tag
|
||||
// field of every SCTP packet that the INIT ACK receiver transmits
|
||||
// within this association.
|
||||
//
|
||||
// The Initiate Tag MUST NOT take the value 0. See Section 5.3.1 for
|
||||
// more on the selection of the Initiate Tag value.
|
||||
//
|
||||
// If the value of the Initiate Tag in a received INIT ACK chunk is
|
||||
// found to be 0, the receiver MUST destroy the association
|
||||
// discarding its TCB. The receiver MAY send an ABORT for debugging
|
||||
// purpose.
|
||||
if i.initiateTag == 0 {
|
||||
abort = true
|
||||
return abort, errors.New("ChunkType of type INIT ACK InitiateTag must not be 0")
|
||||
}
|
||||
|
||||
// Defines the maximum number of streams the sender of this INIT ACK
|
||||
// chunk allows the peer end to create in this association. The
|
||||
// value 0 MUST NOT be used.
|
||||
//
|
||||
// Note: There is no negotiation of the actual number of streams but
|
||||
// instead the two endpoints will use the min(requested, offered).
|
||||
// See Section 5.1.1 for details.
|
||||
//
|
||||
// Note: A receiver of an INIT ACK with the MIS value set to 0 SHOULD
|
||||
// destroy the association discarding its TCB.
|
||||
if i.numInboundStreams == 0 {
|
||||
abort = true
|
||||
return abort, errors.New("INIT ACK inbound stream request must be > 0")
|
||||
}
|
||||
|
||||
// Defines the number of outbound streams the sender of this INIT ACK
|
||||
// chunk wishes to create in this association. The value of 0 MUST
|
||||
// NOT be used, and the value MUST NOT be greater than the MIS value
|
||||
// sent in the INIT chunk.
|
||||
//
|
||||
// Note: A receiver of an INIT ACK with the OS value set to 0 SHOULD
|
||||
// destroy the association discarding its TCB.
|
||||
|
||||
if i.numOutboundStreams == 0 {
|
||||
abort = true
|
||||
return abort, errors.New("INIT ACK outbound stream request must be > 0")
|
||||
}
|
||||
|
||||
// An SCTP receiver MUST be able to receive a minimum of 1500 bytes in
|
||||
// one SCTP packet. This means that an SCTP endpoint MUST NOT indicate
|
||||
// less than 1500 bytes in its initial a_rwnd sent in the INIT or INIT
|
||||
// ACK.
|
||||
if i.advertisedReceiverWindowCredit < 1500 {
|
||||
abort = true
|
||||
return abort, errors.New("INIT ACK Advertised Receiver Window Credit (a_rwnd) must be >= 1500")
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// String makes chunkInitAck printable
|
||||
func (i *chunkInitAck) String() string {
|
||||
return fmt.Sprintf("%s\n%s", i.chunkHeader, i.chunkInitCommon)
|
||||
}
|
155
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_init_common.go
generated
vendored
Normal file
155
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_init_common.go
generated
vendored
Normal file
|
@ -0,0 +1,155 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
/*
|
||||
chunkInitCommon represents an SCTP Chunk body of type INIT and INIT ACK
|
||||
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type = 1 | Chunk Flags | Chunk Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Initiate Tag |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Advertised Receiver Window Credit (a_rwnd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Number of Outbound Streams | Number of Inbound Streams |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Initial TSN |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
| Optional/Variable-Length Parameters |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
The INIT chunk contains the following parameters. Unless otherwise
|
||||
noted, each parameter MUST only be included once in the INIT chunk.
|
||||
|
||||
Fixed Parameters Status
|
||||
----------------------------------------------
|
||||
Initiate Tag Mandatory
|
||||
Advertised Receiver Window Credit Mandatory
|
||||
Number of Outbound Streams Mandatory
|
||||
Number of Inbound Streams Mandatory
|
||||
Initial TSN Mandatory
|
||||
*/
|
||||
|
||||
type chunkInitCommon struct {
|
||||
initiateTag uint32
|
||||
advertisedReceiverWindowCredit uint32
|
||||
numOutboundStreams uint16
|
||||
numInboundStreams uint16
|
||||
initialTSN uint32
|
||||
params []param
|
||||
}
|
||||
|
||||
const (
|
||||
initChunkMinLength = 16
|
||||
initOptionalVarHeaderLength = 4
|
||||
)
|
||||
|
||||
func (i *chunkInitCommon) unmarshal(raw []byte) error {
|
||||
i.initiateTag = binary.BigEndian.Uint32(raw[0:])
|
||||
i.advertisedReceiverWindowCredit = binary.BigEndian.Uint32(raw[4:])
|
||||
i.numOutboundStreams = binary.BigEndian.Uint16(raw[8:])
|
||||
i.numInboundStreams = binary.BigEndian.Uint16(raw[10:])
|
||||
i.initialTSN = binary.BigEndian.Uint32(raw[12:])
|
||||
|
||||
// https://tools.ietf.org/html/rfc4960#section-3.2.1
|
||||
//
|
||||
// Chunk values of SCTP control chunks consist of a chunk-type-specific
|
||||
// header of required fields, followed by zero or more parameters. The
|
||||
// optional and variable-length parameters contained in a chunk are
|
||||
// defined in a Type-Length-Value format as shown below.
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Parameter Type | Parameter Length |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | |
|
||||
// | Parameter Value |
|
||||
// | |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
offset := initChunkMinLength
|
||||
remaining := len(raw) - offset
|
||||
for remaining > 0 {
|
||||
if remaining > initOptionalVarHeaderLength {
|
||||
pType, err := parseParamType(raw[offset:])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to parse param type")
|
||||
}
|
||||
p, err := buildParam(pType, raw[offset:])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed unmarshalling param in Init Chunk")
|
||||
}
|
||||
i.params = append(i.params, p)
|
||||
padding := getPadding(p.length())
|
||||
offset += p.length() + padding
|
||||
remaining -= p.length() + padding
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *chunkInitCommon) marshal() ([]byte, error) {
|
||||
out := make([]byte, initChunkMinLength)
|
||||
binary.BigEndian.PutUint32(out[0:], i.initiateTag)
|
||||
binary.BigEndian.PutUint32(out[4:], i.advertisedReceiverWindowCredit)
|
||||
binary.BigEndian.PutUint16(out[8:], i.numOutboundStreams)
|
||||
binary.BigEndian.PutUint16(out[10:], i.numInboundStreams)
|
||||
binary.BigEndian.PutUint32(out[12:], i.initialTSN)
|
||||
for idx, p := range i.params {
|
||||
pp, err := p.marshal()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to marshal parameter for INIT/INITACK")
|
||||
}
|
||||
|
||||
out = append(out, pp...)
|
||||
|
||||
// Chunks (including Type, Length, and Value fields) are padded out
|
||||
// by the sender with all zero bytes to be a multiple of 4 bytes
|
||||
// long. This padding MUST NOT be more than 3 bytes in total. The
|
||||
// Chunk Length value does not include terminating padding of the
|
||||
// chunk. *However, it does include padding of any variable-length
|
||||
// parameter except the last parameter in the chunk.* The receiver
|
||||
// MUST ignore the padding.
|
||||
if idx != len(i.params)-1 {
|
||||
out = padByte(out, getPadding(len(pp)))
|
||||
}
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// String makes chunkInitCommon printable
|
||||
func (i chunkInitCommon) String() string {
|
||||
format := `initiateTag: %d
|
||||
advertisedReceiverWindowCredit: %d
|
||||
numOutboundStreams: %d
|
||||
numInboundStreams: %d
|
||||
initialTSN: %d`
|
||||
|
||||
res := fmt.Sprintf(format,
|
||||
i.initiateTag,
|
||||
i.advertisedReceiverWindowCredit,
|
||||
i.numOutboundStreams,
|
||||
i.numInboundStreams,
|
||||
i.initialTSN,
|
||||
)
|
||||
|
||||
for i, param := range i.params {
|
||||
res += fmt.Sprintf("Param %d:\n %s", i, param)
|
||||
}
|
||||
return res
|
||||
}
|
195
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_payload_data.go
generated
vendored
Normal file
195
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_payload_data.go
generated
vendored
Normal file
|
@ -0,0 +1,195 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
chunkPayloadData represents an SCTP Chunk of type DATA
|
||||
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type = 0 | Reserved|U|B|E| Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| TSN |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Stream Identifier S | Stream Sequence Number n |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Payload Protocol Identifier |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
| User Data (seq n of Stream S) |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
|
||||
An unfragmented user message shall have both the B and E bits set to
|
||||
'1'. Setting both B and E bits to '0' indicates a middle fragment of
|
||||
a multi-fragment user message, as summarized in the following table:
|
||||
B E Description
|
||||
============================================================
|
||||
| 1 0 | First piece of a fragmented user message |
|
||||
+----------------------------------------------------------+
|
||||
| 0 0 | Middle piece of a fragmented user message |
|
||||
+----------------------------------------------------------+
|
||||
| 0 1 | Last piece of a fragmented user message |
|
||||
+----------------------------------------------------------+
|
||||
| 1 1 | Unfragmented message |
|
||||
============================================================
|
||||
| Table 1: Fragment Description Flags |
|
||||
============================================================
|
||||
*/
|
||||
type chunkPayloadData struct {
|
||||
chunkHeader
|
||||
|
||||
unordered bool
|
||||
beginningFragment bool
|
||||
endingFragment bool
|
||||
immediateSack bool
|
||||
|
||||
tsn uint32
|
||||
streamIdentifier uint16
|
||||
streamSequenceNumber uint16
|
||||
payloadType PayloadProtocolIdentifier
|
||||
userData []byte
|
||||
|
||||
// Whether this data chunk was acknowledged (received by peer)
|
||||
acked bool
|
||||
missIndicator uint32
|
||||
|
||||
// Partial-reliability parameters used only by sender
|
||||
since time.Time
|
||||
nSent uint32 // number of transmission made for this chunk
|
||||
_abandoned bool
|
||||
_allInflight bool // valid only with the first fragment
|
||||
|
||||
// Retransmission flag set when T1-RTX timeout occurred and this
|
||||
// chunk is still in the inflight queue
|
||||
retransmit bool
|
||||
|
||||
head *chunkPayloadData // link to the head of the fragment
|
||||
}
|
||||
|
||||
const (
|
||||
payloadDataEndingFragmentBitmask = 1
|
||||
payloadDataBeginingFragmentBitmask = 2
|
||||
payloadDataUnorderedBitmask = 4
|
||||
payloadDataImmediateSACK = 8
|
||||
|
||||
payloadDataHeaderSize = 12
|
||||
)
|
||||
|
||||
// PayloadProtocolIdentifier is an enum for DataChannel payload types
|
||||
type PayloadProtocolIdentifier uint32
|
||||
|
||||
// PayloadProtocolIdentifier enums
|
||||
// https://www.iana.org/assignments/sctp-parameters/sctp-parameters.xhtml#sctp-parameters-25
|
||||
const (
|
||||
PayloadTypeWebRTCDCEP PayloadProtocolIdentifier = 50
|
||||
PayloadTypeWebRTCString PayloadProtocolIdentifier = 51
|
||||
PayloadTypeWebRTCBinary PayloadProtocolIdentifier = 53
|
||||
PayloadTypeWebRTCStringEmpty PayloadProtocolIdentifier = 56
|
||||
PayloadTypeWebRTCBinaryEmpty PayloadProtocolIdentifier = 57
|
||||
)
|
||||
|
||||
func (p PayloadProtocolIdentifier) String() string {
|
||||
switch p {
|
||||
case PayloadTypeWebRTCDCEP:
|
||||
return "WebRTC DCEP"
|
||||
case PayloadTypeWebRTCString:
|
||||
return "WebRTC String"
|
||||
case PayloadTypeWebRTCBinary:
|
||||
return "WebRTC Binary"
|
||||
case PayloadTypeWebRTCStringEmpty:
|
||||
return "WebRTC String (Empty)"
|
||||
case PayloadTypeWebRTCBinaryEmpty:
|
||||
return "WebRTC Binary (Empty)"
|
||||
default:
|
||||
return fmt.Sprintf("Unknown Payload Protocol Identifier: %d", p)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *chunkPayloadData) unmarshal(raw []byte) error {
|
||||
if err := p.chunkHeader.unmarshal(raw); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.immediateSack = p.flags&payloadDataImmediateSACK != 0
|
||||
p.unordered = p.flags&payloadDataUnorderedBitmask != 0
|
||||
p.beginningFragment = p.flags&payloadDataBeginingFragmentBitmask != 0
|
||||
p.endingFragment = p.flags&payloadDataEndingFragmentBitmask != 0
|
||||
|
||||
p.tsn = binary.BigEndian.Uint32(p.raw[0:])
|
||||
p.streamIdentifier = binary.BigEndian.Uint16(p.raw[4:])
|
||||
p.streamSequenceNumber = binary.BigEndian.Uint16(p.raw[6:])
|
||||
p.payloadType = PayloadProtocolIdentifier(binary.BigEndian.Uint32(p.raw[8:]))
|
||||
p.userData = p.raw[payloadDataHeaderSize:]
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *chunkPayloadData) marshal() ([]byte, error) {
|
||||
payRaw := make([]byte, payloadDataHeaderSize+len(p.userData))
|
||||
|
||||
binary.BigEndian.PutUint32(payRaw[0:], p.tsn)
|
||||
binary.BigEndian.PutUint16(payRaw[4:], p.streamIdentifier)
|
||||
binary.BigEndian.PutUint16(payRaw[6:], p.streamSequenceNumber)
|
||||
binary.BigEndian.PutUint32(payRaw[8:], uint32(p.payloadType))
|
||||
copy(payRaw[payloadDataHeaderSize:], p.userData)
|
||||
|
||||
flags := uint8(0)
|
||||
if p.endingFragment {
|
||||
flags = 1
|
||||
}
|
||||
if p.beginningFragment {
|
||||
flags |= 1 << 1
|
||||
}
|
||||
if p.unordered {
|
||||
flags |= 1 << 2
|
||||
}
|
||||
if p.immediateSack {
|
||||
flags |= 1 << 3
|
||||
}
|
||||
|
||||
p.chunkHeader.flags = flags
|
||||
p.chunkHeader.typ = ctPayloadData
|
||||
p.chunkHeader.raw = payRaw
|
||||
return p.chunkHeader.marshal()
|
||||
}
|
||||
|
||||
func (p *chunkPayloadData) check() (abort bool, err error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// String makes chunkPayloadData printable
|
||||
func (p *chunkPayloadData) String() string {
|
||||
return fmt.Sprintf("%s\n%d", p.chunkHeader, p.tsn)
|
||||
}
|
||||
|
||||
func (p *chunkPayloadData) abandoned() bool {
|
||||
if p.head != nil {
|
||||
return p.head._abandoned && p.head._allInflight
|
||||
}
|
||||
return p._abandoned && p._allInflight
|
||||
}
|
||||
|
||||
func (p *chunkPayloadData) setAbandoned(abandoned bool) {
|
||||
if p.head != nil {
|
||||
p.head._abandoned = abandoned
|
||||
return
|
||||
}
|
||||
p._abandoned = abandoned
|
||||
}
|
||||
|
||||
func (p *chunkPayloadData) setAllInflight() {
|
||||
if p.endingFragment {
|
||||
if p.head != nil {
|
||||
p.head._allInflight = true
|
||||
} else {
|
||||
p._allInflight = true
|
||||
}
|
||||
}
|
||||
}
|
99
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_reconfig.go
generated
vendored
Normal file
99
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_reconfig.go
generated
vendored
Normal file
|
@ -0,0 +1,99 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// https://tools.ietf.org/html/rfc6525#section-3.1
|
||||
// chunkReconfig represents an SCTP Chunk used to reconfigure streams.
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Type = 130 | Chunk Flags | Chunk Length |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// \ \
|
||||
// / Re-configuration Parameter /
|
||||
// \ \
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// \ \
|
||||
// / Re-configuration Parameter (optional) /
|
||||
// \ \
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
type chunkReconfig struct {
|
||||
chunkHeader
|
||||
paramA param
|
||||
paramB param
|
||||
}
|
||||
|
||||
func (c *chunkReconfig) unmarshal(raw []byte) error {
|
||||
if err := c.chunkHeader.unmarshal(raw); err != nil {
|
||||
return err
|
||||
}
|
||||
pType, err := parseParamType(c.raw)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to parse param type")
|
||||
}
|
||||
a, err := buildParam(pType, c.raw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.paramA = a
|
||||
|
||||
padding := getPadding(a.length())
|
||||
offset := a.length() + padding
|
||||
if len(c.raw) > offset {
|
||||
pType, err := parseParamType(c.raw[offset:])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to parse param type")
|
||||
}
|
||||
b, err := buildParam(pType, c.raw[offset:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.paramB = b
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *chunkReconfig) marshal() ([]byte, error) {
|
||||
out, err := c.paramA.marshal()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to marshal parameter A for reconfig")
|
||||
}
|
||||
if c.paramB != nil {
|
||||
// Pad param A
|
||||
out = padByte(out, getPadding(len(out)))
|
||||
|
||||
outB, err := c.paramB.marshal()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to marshal parameter B for reconfig")
|
||||
}
|
||||
|
||||
out = append(out, outB...)
|
||||
}
|
||||
|
||||
c.typ = ctReconfig
|
||||
c.raw = out
|
||||
return c.chunkHeader.marshal()
|
||||
}
|
||||
|
||||
func (c *chunkReconfig) check() (abort bool, err error) {
|
||||
// nolint:godox
|
||||
// TODO: check allowed combinations:
|
||||
// https://tools.ietf.org/html/rfc6525#section-3.1
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// String makes chunkReconfig printable
|
||||
func (c *chunkReconfig) String() string {
|
||||
res := fmt.Sprintf("Param A:\n %s", c.paramA)
|
||||
if c.paramB != nil {
|
||||
res += fmt.Sprintf("Param B:\n %s", c.paramB)
|
||||
}
|
||||
return res
|
||||
}
|
142
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_selective_ack.go
generated
vendored
Normal file
142
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunk_selective_ack.go
generated
vendored
Normal file
|
@ -0,0 +1,142 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
/*
|
||||
chunkSelectiveAck represents an SCTP Chunk of type SACK
|
||||
|
||||
This chunk is sent to the peer endpoint to acknowledge received DATA
|
||||
chunks and to inform the peer endpoint of gaps in the received
|
||||
subsequences of DATA chunks as represented by their TSNs.
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type = 3 |Chunk Flags | Chunk Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Cumulative TSN Ack |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Advertised Receiver Window Credit (a_rwnd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Number of Gap Ack Blocks = N | Number of Duplicate TSNs = X |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Gap Ack Block #1 Start | Gap Ack Block #1 End |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
/ /
|
||||
\ ... \
|
||||
/ /
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Gap Ack Block #N Start | Gap Ack Block #N End |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Duplicate TSN 1 |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
/ /
|
||||
\ ... \
|
||||
/ /
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Duplicate TSN X |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
|
||||
type gapAckBlock struct {
|
||||
start uint16
|
||||
end uint16
|
||||
}
|
||||
|
||||
// String makes gapAckBlock printable
|
||||
func (g gapAckBlock) String() string {
|
||||
return fmt.Sprintf("%d - %d", g.start, g.end)
|
||||
}
|
||||
|
||||
type chunkSelectiveAck struct {
|
||||
chunkHeader
|
||||
cumulativeTSNAck uint32
|
||||
advertisedReceiverWindowCredit uint32
|
||||
gapAckBlocks []gapAckBlock
|
||||
duplicateTSN []uint32
|
||||
}
|
||||
|
||||
const (
|
||||
selectiveAckHeaderSize = 12
|
||||
)
|
||||
|
||||
func (s *chunkSelectiveAck) unmarshal(raw []byte) error {
|
||||
if err := s.chunkHeader.unmarshal(raw); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if s.typ != ctSack {
|
||||
return errors.Errorf("ChunkType is not of type SACK, actually is %s", s.typ.String())
|
||||
}
|
||||
|
||||
if len(s.raw) < selectiveAckHeaderSize {
|
||||
return errors.Errorf("SACK Chunk size is not large enough to contain header (%v remaining, needs %v bytes)",
|
||||
len(s.raw), selectiveAckHeaderSize)
|
||||
}
|
||||
|
||||
s.cumulativeTSNAck = binary.BigEndian.Uint32(s.raw[0:])
|
||||
s.advertisedReceiverWindowCredit = binary.BigEndian.Uint32(s.raw[4:])
|
||||
s.gapAckBlocks = make([]gapAckBlock, binary.BigEndian.Uint16(s.raw[8:]))
|
||||
s.duplicateTSN = make([]uint32, binary.BigEndian.Uint16(s.raw[10:]))
|
||||
|
||||
if len(s.raw) != selectiveAckHeaderSize+(4*len(s.gapAckBlocks)+(4*len(s.duplicateTSN))) {
|
||||
return errors.Errorf("SACK Chunk size does not match predicted amount from header values")
|
||||
}
|
||||
|
||||
offset := selectiveAckHeaderSize
|
||||
for i := range s.gapAckBlocks {
|
||||
s.gapAckBlocks[i].start = binary.BigEndian.Uint16(s.raw[offset:])
|
||||
s.gapAckBlocks[i].end = binary.BigEndian.Uint16(s.raw[offset+2:])
|
||||
offset += 4
|
||||
}
|
||||
for i := range s.duplicateTSN {
|
||||
s.duplicateTSN[i] = binary.BigEndian.Uint32(s.raw[offset:])
|
||||
offset += 4
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *chunkSelectiveAck) marshal() ([]byte, error) {
|
||||
sackRaw := make([]byte, selectiveAckHeaderSize+(4*len(s.gapAckBlocks)+(4*len(s.duplicateTSN))))
|
||||
binary.BigEndian.PutUint32(sackRaw[0:], s.cumulativeTSNAck)
|
||||
binary.BigEndian.PutUint32(sackRaw[4:], s.advertisedReceiverWindowCredit)
|
||||
binary.BigEndian.PutUint16(sackRaw[8:], uint16(len(s.gapAckBlocks)))
|
||||
binary.BigEndian.PutUint16(sackRaw[10:], uint16(len(s.duplicateTSN)))
|
||||
offset := selectiveAckHeaderSize
|
||||
for _, g := range s.gapAckBlocks {
|
||||
binary.BigEndian.PutUint16(sackRaw[offset:], g.start)
|
||||
binary.BigEndian.PutUint16(sackRaw[offset+2:], g.end)
|
||||
offset += 4
|
||||
}
|
||||
for _, t := range s.duplicateTSN {
|
||||
binary.BigEndian.PutUint32(sackRaw[offset:], t)
|
||||
offset += 4
|
||||
}
|
||||
|
||||
s.chunkHeader.typ = ctSack
|
||||
s.chunkHeader.raw = sackRaw
|
||||
return s.chunkHeader.marshal()
|
||||
}
|
||||
|
||||
func (s *chunkSelectiveAck) check() (abort bool, err error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// String makes chunkSelectiveAck printable
|
||||
func (s *chunkSelectiveAck) String() string {
|
||||
res := fmt.Sprintf("SACK cumTsnAck=%d arwnd=%d dupTsn=%d",
|
||||
s.cumulativeTSNAck,
|
||||
s.advertisedReceiverWindowCredit,
|
||||
s.duplicateTSN)
|
||||
|
||||
for _, gap := range s.gapAckBlocks {
|
||||
res = fmt.Sprintf("%s\n gap ack: %s", res, gap)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
90
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunkheader.go
generated
vendored
Normal file
90
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunkheader.go
generated
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
/*
|
||||
chunkHeader represents a SCTP Chunk header, defined in https://tools.ietf.org/html/rfc4960#section-3.2
|
||||
The figure below illustrates the field format for the chunks to be
|
||||
transmitted in the SCTP packet. Each chunk is formatted with a Chunk
|
||||
Type field, a chunk-specific Flag field, a Chunk Length field, and a
|
||||
Value field.
|
||||
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Chunk Type | Chunk Flags | Chunk Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
| Chunk Value |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
type chunkHeader struct {
|
||||
typ chunkType
|
||||
flags byte
|
||||
raw []byte
|
||||
}
|
||||
|
||||
const (
|
||||
chunkHeaderSize = 4
|
||||
)
|
||||
|
||||
func (c *chunkHeader) unmarshal(raw []byte) error {
|
||||
if len(raw) < chunkHeaderSize {
|
||||
return errors.Errorf("raw only %d bytes, %d is the minimum length for a SCTP chunk", len(raw), chunkHeaderSize)
|
||||
}
|
||||
|
||||
c.typ = chunkType(raw[0])
|
||||
c.flags = raw[1]
|
||||
length := binary.BigEndian.Uint16(raw[2:])
|
||||
|
||||
// Length includes Chunk header
|
||||
valueLength := int(length - chunkHeaderSize)
|
||||
lengthAfterValue := len(raw) - (chunkHeaderSize + valueLength)
|
||||
|
||||
if lengthAfterValue < 0 {
|
||||
return errors.Errorf("Not enough data left in SCTP packet to satisfy requested length remain %d req %d ", valueLength, len(raw)-chunkHeaderSize)
|
||||
} else if lengthAfterValue < 4 {
|
||||
// https://tools.ietf.org/html/rfc4960#section-3.2
|
||||
// The Chunk Length field does not count any chunk padding.
|
||||
// Chunks (including Type, Length, and Value fields) are padded out
|
||||
// by the sender with all zero bytes to be a multiple of 4 bytes
|
||||
// long. This padding MUST NOT be more than 3 bytes in total. The
|
||||
// Chunk Length value does not include terminating padding of the
|
||||
// chunk. However, it does include padding of any variable-length
|
||||
// parameter except the last parameter in the chunk. The receiver
|
||||
// MUST ignore the padding.
|
||||
for i := lengthAfterValue; i > 0; i-- {
|
||||
paddingOffset := chunkHeaderSize + valueLength + (i - 1)
|
||||
if raw[paddingOffset] != 0 {
|
||||
return errors.Errorf("Chunk padding is non-zero at offset %d ", paddingOffset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.raw = raw[chunkHeaderSize : chunkHeaderSize+valueLength]
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *chunkHeader) marshal() ([]byte, error) {
|
||||
raw := make([]byte, 4+len(c.raw))
|
||||
|
||||
raw[0] = uint8(c.typ)
|
||||
raw[1] = c.flags
|
||||
binary.BigEndian.PutUint16(raw[2:], uint16(len(c.raw)+chunkHeaderSize))
|
||||
copy(raw[4:], c.raw)
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
func (c *chunkHeader) valueLength() int {
|
||||
return len(c.raw)
|
||||
}
|
||||
|
||||
// String makes chunkHeader printable
|
||||
func (c chunkHeader) String() string {
|
||||
return c.typ.String()
|
||||
}
|
67
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunktype.go
generated
vendored
Normal file
67
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/chunktype.go
generated
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
package sctp
|
||||
|
||||
import "fmt"
|
||||
|
||||
// chunkType is an enum for SCTP Chunk Type field
|
||||
// This field identifies the type of information contained in the
|
||||
// Chunk Value field.
|
||||
type chunkType uint8
|
||||
|
||||
// List of known chunkType enums
|
||||
const (
|
||||
ctPayloadData chunkType = 0
|
||||
ctInit chunkType = 1
|
||||
ctInitAck chunkType = 2
|
||||
ctSack chunkType = 3
|
||||
ctHeartbeat chunkType = 4
|
||||
ctHeartbeatAck chunkType = 5
|
||||
ctAbort chunkType = 6
|
||||
ctShutdown chunkType = 7
|
||||
ctShutdownAck chunkType = 8
|
||||
ctError chunkType = 9
|
||||
ctCookieEcho chunkType = 10
|
||||
ctCookieAck chunkType = 11
|
||||
ctCWR chunkType = 13
|
||||
ctShutdownComplete chunkType = 14
|
||||
ctReconfig chunkType = 130
|
||||
ctForwardTSN chunkType = 192
|
||||
)
|
||||
|
||||
func (c chunkType) String() string {
|
||||
switch c {
|
||||
case ctPayloadData:
|
||||
return "DATA"
|
||||
case ctInit:
|
||||
return "INIT"
|
||||
case ctInitAck:
|
||||
return "INIT-ACK"
|
||||
case ctSack:
|
||||
return "SACK"
|
||||
case ctHeartbeat:
|
||||
return "HEARTBEAT"
|
||||
case ctHeartbeatAck:
|
||||
return "HEARTBEAT-ACK"
|
||||
case ctAbort:
|
||||
return "ABORT"
|
||||
case ctShutdown:
|
||||
return "SHUTDOWN"
|
||||
case ctShutdownAck:
|
||||
return "SHUTDOWN-ACK"
|
||||
case ctError:
|
||||
return "ERROR"
|
||||
case ctCookieEcho:
|
||||
return "COOKIE-ECHO"
|
||||
case ctCookieAck:
|
||||
return "COOKIE-ACK"
|
||||
case ctCWR:
|
||||
return "ECNE" // Explicit Congestion Notification Echo
|
||||
case ctShutdownComplete:
|
||||
return "SHUTDOWN-COMPLETE"
|
||||
case ctReconfig:
|
||||
return "RECONFIG" // Re-configuration
|
||||
case ctForwardTSN:
|
||||
return "FORWARD-TSN"
|
||||
default:
|
||||
return fmt.Sprintf("Unknown ChunkType: %d", c)
|
||||
}
|
||||
}
|
20
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/codecov.yml
generated
vendored
Normal file
20
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/codecov.yml
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
#
|
||||
# DO NOT EDIT THIS FILE
|
||||
#
|
||||
# It is automatically copied from https://github.com/pion/.goassets repository.
|
||||
#
|
||||
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
# Allow decreasing 2% of total coverage to avoid noise.
|
||||
threshold: 2%
|
||||
patch:
|
||||
default:
|
||||
target: 70%
|
||||
only_pulls: true
|
||||
|
||||
ignore:
|
||||
- "examples/*"
|
||||
- "examples/**/*"
|
29
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/control_queue.go
generated
vendored
Normal file
29
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/control_queue.go
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
package sctp
|
||||
|
||||
// control queue
|
||||
|
||||
type controlQueue struct {
|
||||
queue []*packet
|
||||
}
|
||||
|
||||
func newControlQueue() *controlQueue {
|
||||
return &controlQueue{queue: []*packet{}}
|
||||
}
|
||||
|
||||
func (q *controlQueue) push(c *packet) {
|
||||
q.queue = append(q.queue, c)
|
||||
}
|
||||
|
||||
func (q *controlQueue) pushAll(packets []*packet) {
|
||||
q.queue = append(q.queue, packets...)
|
||||
}
|
||||
|
||||
func (q *controlQueue) popAll() []*packet {
|
||||
packets := q.queue
|
||||
q.queue = []*packet{}
|
||||
return packets
|
||||
}
|
||||
|
||||
func (q *controlQueue) size() int {
|
||||
return len(q.queue)
|
||||
}
|
91
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/error_cause.go
generated
vendored
Normal file
91
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/error_cause.go
generated
vendored
Normal file
|
@ -0,0 +1,91 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// errorCauseCode is a cause code that appears in either a ERROR or ABORT chunk
|
||||
type errorCauseCode uint16
|
||||
|
||||
type errorCause interface {
|
||||
unmarshal([]byte) error
|
||||
marshal() ([]byte, error)
|
||||
length() uint16
|
||||
String() string
|
||||
|
||||
errorCauseCode() errorCauseCode
|
||||
}
|
||||
|
||||
// buildErrorCause delegates the building of a error cause from raw bytes to the correct structure
|
||||
func buildErrorCause(raw []byte) (errorCause, error) {
|
||||
var e errorCause
|
||||
|
||||
c := errorCauseCode(binary.BigEndian.Uint16(raw[0:]))
|
||||
switch c {
|
||||
case invalidMandatoryParameter:
|
||||
e = &errorCauseInvalidMandatoryParameter{}
|
||||
case unrecognizedChunkType:
|
||||
e = &errorCauseUnrecognizedChunkType{}
|
||||
case protocolViolation:
|
||||
e = &errorCauseProtocolViolation{}
|
||||
default:
|
||||
return nil, errors.Errorf("BuildErrorCause does not handle %s", c.String())
|
||||
}
|
||||
|
||||
if err := e.unmarshal(raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
const (
|
||||
invalidStreamIdentifier errorCauseCode = 1
|
||||
missingMandatoryParameter errorCauseCode = 2
|
||||
staleCookieError errorCauseCode = 3
|
||||
outOfResource errorCauseCode = 4
|
||||
unresolvableAddress errorCauseCode = 5
|
||||
unrecognizedChunkType errorCauseCode = 6
|
||||
invalidMandatoryParameter errorCauseCode = 7
|
||||
unrecognizedParameters errorCauseCode = 8
|
||||
noUserData errorCauseCode = 9
|
||||
cookieReceivedWhileShuttingDown errorCauseCode = 10
|
||||
restartOfAnAssociationWithNewAddresses errorCauseCode = 11
|
||||
userInitiatedAbort errorCauseCode = 12
|
||||
protocolViolation errorCauseCode = 13
|
||||
)
|
||||
|
||||
func (e errorCauseCode) String() string {
|
||||
switch e {
|
||||
case invalidStreamIdentifier:
|
||||
return "Invalid Stream Identifier"
|
||||
case missingMandatoryParameter:
|
||||
return "Missing Mandatory Parameter"
|
||||
case staleCookieError:
|
||||
return "Stale Cookie Error"
|
||||
case outOfResource:
|
||||
return "Out Of Resource"
|
||||
case unresolvableAddress:
|
||||
return "Unresolvable IP"
|
||||
case unrecognizedChunkType:
|
||||
return "Unrecognized Chunk Type"
|
||||
case invalidMandatoryParameter:
|
||||
return "Invalid Mandatory Parameter"
|
||||
case unrecognizedParameters:
|
||||
return "Unrecognized Parameters"
|
||||
case noUserData:
|
||||
return "No User Data"
|
||||
case cookieReceivedWhileShuttingDown:
|
||||
return "Cookie Received While Shutting Down"
|
||||
case restartOfAnAssociationWithNewAddresses:
|
||||
return "Restart Of An Association With New Addresses"
|
||||
case userInitiatedAbort:
|
||||
return "User Initiated Abort"
|
||||
case protocolViolation:
|
||||
return "Protocol Violation"
|
||||
default:
|
||||
return fmt.Sprintf("Unknown CauseCode: %d", e)
|
||||
}
|
||||
}
|
47
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/error_cause_header.go
generated
vendored
Normal file
47
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/error_cause_header.go
generated
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// errorCauseHeader represents the shared header that is shared by all error causes
|
||||
type errorCauseHeader struct {
|
||||
code errorCauseCode
|
||||
len uint16
|
||||
raw []byte
|
||||
}
|
||||
|
||||
const (
|
||||
errorCauseHeaderLength = 4
|
||||
)
|
||||
|
||||
func (e *errorCauseHeader) marshal() ([]byte, error) {
|
||||
e.len = uint16(len(e.raw)) + uint16(errorCauseHeaderLength)
|
||||
raw := make([]byte, e.len)
|
||||
binary.BigEndian.PutUint16(raw[0:], uint16(e.code))
|
||||
binary.BigEndian.PutUint16(raw[2:], e.len)
|
||||
copy(raw[errorCauseHeaderLength:], e.raw)
|
||||
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
func (e *errorCauseHeader) unmarshal(raw []byte) error {
|
||||
e.code = errorCauseCode(binary.BigEndian.Uint16(raw[0:]))
|
||||
e.len = binary.BigEndian.Uint16(raw[2:])
|
||||
valueLength := e.len - errorCauseHeaderLength
|
||||
e.raw = raw[errorCauseHeaderLength : errorCauseHeaderLength+valueLength]
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *errorCauseHeader) length() uint16 {
|
||||
return e.len
|
||||
}
|
||||
|
||||
func (e *errorCauseHeader) errorCauseCode() errorCauseCode {
|
||||
return e.code
|
||||
}
|
||||
|
||||
// String makes errorCauseHeader printable
|
||||
func (e errorCauseHeader) String() string {
|
||||
return e.code.String()
|
||||
}
|
19
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/error_cause_invalid_mandatory_parameter.go
generated
vendored
Normal file
19
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/error_cause_invalid_mandatory_parameter.go
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
package sctp
|
||||
|
||||
// errorCauseInvalidMandatoryParameter represents an SCTP error cause
|
||||
type errorCauseInvalidMandatoryParameter struct {
|
||||
errorCauseHeader
|
||||
}
|
||||
|
||||
func (e *errorCauseInvalidMandatoryParameter) marshal() ([]byte, error) {
|
||||
return e.errorCauseHeader.marshal()
|
||||
}
|
||||
|
||||
func (e *errorCauseInvalidMandatoryParameter) unmarshal(raw []byte) error {
|
||||
return e.errorCauseHeader.unmarshal(raw)
|
||||
}
|
||||
|
||||
// String makes errorCauseInvalidMandatoryParameter printable
|
||||
func (e *errorCauseInvalidMandatoryParameter) String() string {
|
||||
return e.errorCauseHeader.String()
|
||||
}
|
50
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/error_cause_protocol_violation.go
generated
vendored
Normal file
50
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/error_cause_protocol_violation.go
generated
vendored
Normal file
|
@ -0,0 +1,50 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
/*
|
||||
This error cause MAY be included in ABORT chunks that are sent
|
||||
because an SCTP endpoint detects a protocol violation of the peer
|
||||
that is not covered by the error causes described in Section 3.3.10.1
|
||||
to Section 3.3.10.12. An implementation MAY provide additional
|
||||
information specifying what kind of protocol violation has been
|
||||
detected.
|
||||
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Cause Code=13 | Cause Length=Variable |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
/ Additional Information /
|
||||
\ \
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
type errorCauseProtocolViolation struct {
|
||||
errorCauseHeader
|
||||
additionalInformation []byte
|
||||
}
|
||||
|
||||
func (e *errorCauseProtocolViolation) marshal() ([]byte, error) {
|
||||
e.raw = e.additionalInformation
|
||||
return e.errorCauseHeader.marshal()
|
||||
}
|
||||
|
||||
func (e *errorCauseProtocolViolation) unmarshal(raw []byte) error {
|
||||
err := e.errorCauseHeader.unmarshal(raw)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Unable to unmarshal Protocol Violation error")
|
||||
}
|
||||
|
||||
e.additionalInformation = e.raw
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// String makes errorCauseProtocolViolation printable
|
||||
func (e *errorCauseProtocolViolation) String() string {
|
||||
return fmt.Sprintf("%s: %s", e.errorCauseHeader, e.additionalInformation)
|
||||
}
|
28
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/error_cause_unrecognized_chunk_type.go
generated
vendored
Normal file
28
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/error_cause_unrecognized_chunk_type.go
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
package sctp
|
||||
|
||||
// errorCauseUnrecognizedChunkType represents an SCTP error cause
|
||||
type errorCauseUnrecognizedChunkType struct {
|
||||
errorCauseHeader
|
||||
unrecognizedChunk []byte
|
||||
}
|
||||
|
||||
func (e *errorCauseUnrecognizedChunkType) marshal() ([]byte, error) {
|
||||
e.code = unrecognizedChunkType
|
||||
e.errorCauseHeader.raw = e.unrecognizedChunk
|
||||
return e.errorCauseHeader.marshal()
|
||||
}
|
||||
|
||||
func (e *errorCauseUnrecognizedChunkType) unmarshal(raw []byte) error {
|
||||
err := e.errorCauseHeader.unmarshal(raw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
e.unrecognizedChunk = e.errorCauseHeader.raw
|
||||
return nil
|
||||
}
|
||||
|
||||
// String makes errorCauseUnrecognizedChunkType printable
|
||||
func (e *errorCauseUnrecognizedChunkType) String() string {
|
||||
return e.errorCauseHeader.String()
|
||||
}
|
14
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/go.mod
generated
vendored
Normal file
14
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/go.mod
generated
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
module github.com/pion/sctp
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/pion/logging v0.2.2
|
||||
github.com/pion/randutil v0.1.0
|
||||
github.com/pion/transport v0.10.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/stretchr/testify v1.6.1
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
)
|
||||
|
||||
go 1.13
|
36
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/go.sum
generated
vendored
Normal file
36
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/go.sum
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
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/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/pion/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/transport v0.10.1 h1:2W+yJT+0mOQ160ThZYUx5Zp2skzshiNgxrNE9GUfhJM=
|
||||
github.com/pion/transport v0.10.1/go.mod h1:PBis1stIILMiis0PewDw91WJeLJkyIMcEk+DwKOzf4A=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
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/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
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=
|
178
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/packet.go
generated
vendored
Normal file
178
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/packet.go
generated
vendored
Normal file
|
@ -0,0 +1,178 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Create the crc32 table we'll use for the checksum
|
||||
var castagnoliTable = crc32.MakeTable(crc32.Castagnoli) // nolint:gochecknoglobals
|
||||
|
||||
// Allocate and zero this data once.
|
||||
// We need to use it for the checksum and don't want to allocate/clear each time.
|
||||
var fourZeroes [4]byte // nolint:gochecknoglobals
|
||||
|
||||
/*
|
||||
Packet represents an SCTP packet, defined in https://tools.ietf.org/html/rfc4960#section-3
|
||||
An SCTP packet is composed of a common header and chunks. A chunk
|
||||
contains either control information or user data.
|
||||
|
||||
|
||||
SCTP Packet Format
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Common Header |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Chunk #1 |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| ... |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Chunk #n |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
|
||||
SCTP Common Header Format
|
||||
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source Value Number | Destination Value Number |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Verification Tag |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Checksum |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
|
||||
*/
|
||||
type packet struct {
|
||||
sourcePort uint16
|
||||
destinationPort uint16
|
||||
verificationTag uint32
|
||||
chunks []chunk
|
||||
}
|
||||
|
||||
const (
|
||||
packetHeaderSize = 12
|
||||
)
|
||||
|
||||
func (p *packet) unmarshal(raw []byte) error {
|
||||
if len(raw) < packetHeaderSize {
|
||||
return errors.Errorf("raw only %d bytes, %d is the minimum length for a SCTP packet", len(raw), packetHeaderSize)
|
||||
}
|
||||
|
||||
p.sourcePort = binary.BigEndian.Uint16(raw[0:])
|
||||
p.destinationPort = binary.BigEndian.Uint16(raw[2:])
|
||||
p.verificationTag = binary.BigEndian.Uint32(raw[4:])
|
||||
|
||||
offset := packetHeaderSize
|
||||
for {
|
||||
// Exact match, no more chunks
|
||||
if offset == len(raw) {
|
||||
break
|
||||
} else if offset+chunkHeaderSize > len(raw) {
|
||||
return errors.Errorf("Unable to parse SCTP chunk, not enough data for complete header: offset %d remaining %d", offset, len(raw))
|
||||
}
|
||||
|
||||
var c chunk
|
||||
switch chunkType(raw[offset]) {
|
||||
case ctInit:
|
||||
c = &chunkInit{}
|
||||
case ctInitAck:
|
||||
c = &chunkInitAck{}
|
||||
case ctAbort:
|
||||
c = &chunkAbort{}
|
||||
case ctCookieEcho:
|
||||
c = &chunkCookieEcho{}
|
||||
case ctCookieAck:
|
||||
c = &chunkCookieAck{}
|
||||
case ctHeartbeat:
|
||||
c = &chunkHeartbeat{}
|
||||
case ctPayloadData:
|
||||
c = &chunkPayloadData{}
|
||||
case ctSack:
|
||||
c = &chunkSelectiveAck{}
|
||||
case ctReconfig:
|
||||
c = &chunkReconfig{}
|
||||
case ctForwardTSN:
|
||||
c = &chunkForwardTSN{}
|
||||
case ctError:
|
||||
c = &chunkError{}
|
||||
default:
|
||||
return errors.Errorf("Failed to unmarshal, contains unknown chunk type %s", chunkType(raw[offset]).String())
|
||||
}
|
||||
|
||||
if err := c.unmarshal(raw[offset:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.chunks = append(p.chunks, c)
|
||||
chunkValuePadding := getPadding(c.valueLength())
|
||||
offset += chunkHeaderSize + c.valueLength() + chunkValuePadding
|
||||
}
|
||||
theirChecksum := binary.LittleEndian.Uint32(raw[8:])
|
||||
ourChecksum := generatePacketChecksum(raw)
|
||||
if theirChecksum != ourChecksum {
|
||||
return errors.Errorf("Checksum mismatch theirs: %d ours: %d", theirChecksum, ourChecksum)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *packet) marshal() ([]byte, error) {
|
||||
raw := make([]byte, packetHeaderSize)
|
||||
|
||||
// Populate static headers
|
||||
// 8-12 is Checksum which will be populated when packet is complete
|
||||
binary.BigEndian.PutUint16(raw[0:], p.sourcePort)
|
||||
binary.BigEndian.PutUint16(raw[2:], p.destinationPort)
|
||||
binary.BigEndian.PutUint32(raw[4:], p.verificationTag)
|
||||
|
||||
// Populate chunks
|
||||
for _, c := range p.chunks {
|
||||
chunkRaw, err := c.marshal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
raw = append(raw, chunkRaw...)
|
||||
|
||||
paddingNeeded := getPadding(len(raw))
|
||||
if paddingNeeded != 0 {
|
||||
raw = append(raw, make([]byte, paddingNeeded)...)
|
||||
}
|
||||
}
|
||||
|
||||
// Checksum is already in BigEndian
|
||||
// Using LittleEndian.PutUint32 stops it from being flipped
|
||||
binary.LittleEndian.PutUint32(raw[8:], generatePacketChecksum(raw))
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
func generatePacketChecksum(raw []byte) (sum uint32) {
|
||||
// Fastest way to do a crc32 without allocating.
|
||||
sum = crc32.Update(sum, castagnoliTable, raw[0:8])
|
||||
sum = crc32.Update(sum, castagnoliTable, fourZeroes[:])
|
||||
sum = crc32.Update(sum, castagnoliTable, raw[12:])
|
||||
return sum
|
||||
}
|
||||
|
||||
// String makes packet printable
|
||||
func (p *packet) String() string {
|
||||
format := `Packet:
|
||||
sourcePort: %d
|
||||
destinationPort: %d
|
||||
verificationTag: %d
|
||||
`
|
||||
res := fmt.Sprintf(format,
|
||||
p.sourcePort,
|
||||
p.destinationPort,
|
||||
p.verificationTag,
|
||||
)
|
||||
for i, chunk := range p.chunks {
|
||||
res += fmt.Sprintf("Chunk %d:\n %s", i, chunk)
|
||||
}
|
||||
return res
|
||||
}
|
35
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param.go
generated
vendored
Normal file
35
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param.go
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type param interface {
|
||||
marshal() ([]byte, error)
|
||||
length() int
|
||||
}
|
||||
|
||||
func buildParam(t paramType, rawParam []byte) (param, error) {
|
||||
switch t {
|
||||
case forwardTSNSupp:
|
||||
return (¶mForwardTSNSupported{}).unmarshal(rawParam)
|
||||
case supportedExt:
|
||||
return (¶mSupportedExtensions{}).unmarshal(rawParam)
|
||||
case random:
|
||||
return (¶mRandom{}).unmarshal(rawParam)
|
||||
case reqHMACAlgo:
|
||||
return (¶mRequestedHMACAlgorithm{}).unmarshal(rawParam)
|
||||
case chunkList:
|
||||
return (¶mChunkList{}).unmarshal(rawParam)
|
||||
case stateCookie:
|
||||
return (¶mStateCookie{}).unmarshal(rawParam)
|
||||
case heartbeatInfo:
|
||||
return (¶mHeartbeatInfo{}).unmarshal(rawParam)
|
||||
case outSSNResetReq:
|
||||
return (¶mOutgoingResetRequest{}).unmarshal(rawParam)
|
||||
case reconfigResp:
|
||||
return (¶mReconfigResponse{}).unmarshal(rawParam)
|
||||
default:
|
||||
return nil, errors.Errorf("Unhandled ParamType %v", t)
|
||||
}
|
||||
}
|
28
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param_chunk_list.go
generated
vendored
Normal file
28
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param_chunk_list.go
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
package sctp
|
||||
|
||||
type paramChunkList struct {
|
||||
paramHeader
|
||||
chunkTypes []chunkType
|
||||
}
|
||||
|
||||
func (c *paramChunkList) marshal() ([]byte, error) {
|
||||
c.typ = chunkList
|
||||
c.raw = make([]byte, len(c.chunkTypes))
|
||||
for i, t := range c.chunkTypes {
|
||||
c.raw[i] = byte(t)
|
||||
}
|
||||
|
||||
return c.paramHeader.marshal()
|
||||
}
|
||||
|
||||
func (c *paramChunkList) unmarshal(raw []byte) (param, error) {
|
||||
err := c.paramHeader.unmarshal(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, t := range c.raw {
|
||||
c.chunkTypes = append(c.chunkTypes, chunkType(t))
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
28
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param_forward_tsn_supported.go
generated
vendored
Normal file
28
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param_forward_tsn_supported.go
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
package sctp
|
||||
|
||||
// At the initialization of the association, the sender of the INIT or
|
||||
// INIT ACK chunk MAY include this OPTIONAL parameter to inform its peer
|
||||
// that it is able to support the Forward TSN chunk
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Parameter Type = 49152 | Parameter Length = 4 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
type paramForwardTSNSupported struct {
|
||||
paramHeader
|
||||
}
|
||||
|
||||
func (f *paramForwardTSNSupported) marshal() ([]byte, error) {
|
||||
f.typ = forwardTSNSupp
|
||||
f.raw = []byte{}
|
||||
return f.paramHeader.marshal()
|
||||
}
|
||||
|
||||
func (f *paramForwardTSNSupported) unmarshal(raw []byte) (param, error) {
|
||||
err := f.paramHeader.unmarshal(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
21
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param_heartbeat_info.go
generated
vendored
Normal file
21
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param_heartbeat_info.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
package sctp
|
||||
|
||||
type paramHeartbeatInfo struct {
|
||||
paramHeader
|
||||
heartbeatInformation []byte
|
||||
}
|
||||
|
||||
func (h *paramHeartbeatInfo) marshal() ([]byte, error) {
|
||||
h.typ = heartbeatInfo
|
||||
h.raw = h.heartbeatInformation
|
||||
return h.paramHeader.marshal()
|
||||
}
|
||||
|
||||
func (h *paramHeartbeatInfo) unmarshal(raw []byte) (param, error) {
|
||||
err := h.paramHeader.unmarshal(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h.heartbeatInformation = h.raw
|
||||
return h, nil
|
||||
}
|
88
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param_outgoing_reset_request.go
generated
vendored
Normal file
88
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param_outgoing_reset_request.go
generated
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
paramOutgoingResetRequestStreamIdentifiersOffset = 12
|
||||
)
|
||||
|
||||
// This parameter is used by the sender to request the reset of some or
|
||||
// all outgoing streams.
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Parameter Type = 13 | Parameter Length = 16 + 2 * N |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Re-configuration Request Sequence Number |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Re-configuration Response Sequence Number |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Sender's Last Assigned TSN |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Stream Number 1 (optional) | Stream Number 2 (optional) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// / ...... /
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Stream Number N-1 (optional) | Stream Number N (optional) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
type paramOutgoingResetRequest struct {
|
||||
paramHeader
|
||||
// reconfigRequestSequenceNumber is used to identify the request. It is a monotonically
|
||||
// increasing number that is initialized to the same value as the
|
||||
// initial TSN. It is increased by 1 whenever sending a new Re-
|
||||
// configuration Request Parameter.
|
||||
reconfigRequestSequenceNumber uint32
|
||||
// When this Outgoing SSN Reset Request Parameter is sent in response
|
||||
// to an Incoming SSN Reset Request Parameter, this parameter is also
|
||||
// an implicit response to the incoming request. This field then
|
||||
// holds the Re-configuration Request Sequence Number of the incoming
|
||||
// request. In other cases, it holds the next expected
|
||||
// Re-configuration Request Sequence Number minus 1.
|
||||
reconfigResponseSequenceNumber uint32
|
||||
// This value holds the next TSN minus 1 -- in other words, the last
|
||||
// TSN that this sender assigned.
|
||||
senderLastTSN uint32
|
||||
// This optional field, if included, is used to indicate specific
|
||||
// streams that are to be reset. If no streams are listed, then all
|
||||
// streams are to be reset.
|
||||
streamIdentifiers []uint16
|
||||
}
|
||||
|
||||
var errSSNResetRequestParamTooShort = errors.New("outgoing SSN reset request parameter too short")
|
||||
|
||||
func (r *paramOutgoingResetRequest) marshal() ([]byte, error) {
|
||||
r.typ = outSSNResetReq
|
||||
r.raw = make([]byte, paramOutgoingResetRequestStreamIdentifiersOffset+2*len(r.streamIdentifiers))
|
||||
binary.BigEndian.PutUint32(r.raw, r.reconfigRequestSequenceNumber)
|
||||
binary.BigEndian.PutUint32(r.raw[4:], r.reconfigResponseSequenceNumber)
|
||||
binary.BigEndian.PutUint32(r.raw[8:], r.senderLastTSN)
|
||||
for i, sID := range r.streamIdentifiers {
|
||||
binary.BigEndian.PutUint16(r.raw[paramOutgoingResetRequestStreamIdentifiersOffset+2*i:], sID)
|
||||
}
|
||||
return r.paramHeader.marshal()
|
||||
}
|
||||
|
||||
func (r *paramOutgoingResetRequest) unmarshal(raw []byte) (param, error) {
|
||||
err := r.paramHeader.unmarshal(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(r.raw) < paramOutgoingResetRequestStreamIdentifiersOffset {
|
||||
return nil, errSSNResetRequestParamTooShort
|
||||
}
|
||||
r.reconfigRequestSequenceNumber = binary.BigEndian.Uint32(r.raw)
|
||||
r.reconfigResponseSequenceNumber = binary.BigEndian.Uint32(r.raw[4:])
|
||||
r.senderLastTSN = binary.BigEndian.Uint32(r.raw[8:])
|
||||
|
||||
lim := (len(r.raw) - paramOutgoingResetRequestStreamIdentifiersOffset) / 2
|
||||
r.streamIdentifiers = make([]uint16, lim)
|
||||
for i := 0; i < lim; i++ {
|
||||
r.streamIdentifiers[i] = binary.BigEndian.Uint16(r.raw[paramOutgoingResetRequestStreamIdentifiersOffset+2*i:])
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
21
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param_random.go
generated
vendored
Normal file
21
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param_random.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
package sctp
|
||||
|
||||
type paramRandom struct {
|
||||
paramHeader
|
||||
randomData []byte
|
||||
}
|
||||
|
||||
func (r *paramRandom) marshal() ([]byte, error) {
|
||||
r.typ = random
|
||||
r.raw = r.randomData
|
||||
return r.paramHeader.marshal()
|
||||
}
|
||||
|
||||
func (r *paramRandom) unmarshal(raw []byte) (param, error) {
|
||||
err := r.paramHeader.unmarshal(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.randomData = r.raw
|
||||
return r, nil
|
||||
}
|
92
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param_reconfig_response.go
generated
vendored
Normal file
92
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param_reconfig_response.go
generated
vendored
Normal file
|
@ -0,0 +1,92 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// This parameter is used by the receiver of a Re-configuration Request
|
||||
// Parameter to respond to the request.
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Parameter Type = 16 | Parameter Length |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Re-configuration Response Sequence Number |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Result |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Sender's Next TSN (optional) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Receiver's Next TSN (optional) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
type paramReconfigResponse struct {
|
||||
paramHeader
|
||||
// This value is copied from the request parameter and is used by the
|
||||
// receiver of the Re-configuration Response Parameter to tie the
|
||||
// response to the request.
|
||||
reconfigResponseSequenceNumber uint32
|
||||
// This value describes the result of the processing of the request.
|
||||
result reconfigResult
|
||||
}
|
||||
|
||||
type reconfigResult uint32
|
||||
|
||||
const (
|
||||
reconfigResultSuccessNOP reconfigResult = 0
|
||||
reconfigResultSuccessPerformed reconfigResult = 1
|
||||
reconfigResultDenied reconfigResult = 2
|
||||
reconfigResultErrorWrongSSN reconfigResult = 3
|
||||
reconfigResultErrorRequestAlreadyInProgress reconfigResult = 4
|
||||
reconfigResultErrorBadSequenceNumber reconfigResult = 5
|
||||
reconfigResultInProgress reconfigResult = 6
|
||||
)
|
||||
|
||||
var errReconfigRespParamTooShort = errors.New("reconfig response parameter too short")
|
||||
|
||||
func (t reconfigResult) String() string {
|
||||
switch t {
|
||||
case reconfigResultSuccessNOP:
|
||||
return "0: Success - Nothing to do"
|
||||
case reconfigResultSuccessPerformed:
|
||||
return "1: Success - Performed"
|
||||
case reconfigResultDenied:
|
||||
return "2: Denied"
|
||||
case reconfigResultErrorWrongSSN:
|
||||
return "3: Error - Wrong SSN"
|
||||
case reconfigResultErrorRequestAlreadyInProgress:
|
||||
return "4: Error - Request already in progress"
|
||||
case reconfigResultErrorBadSequenceNumber:
|
||||
return "5: Error - Bad Sequence Number"
|
||||
case reconfigResultInProgress:
|
||||
return "6: In progress"
|
||||
default:
|
||||
return fmt.Sprintf("Unknown reconfigResult: %d", t)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *paramReconfigResponse) marshal() ([]byte, error) {
|
||||
r.typ = reconfigResp
|
||||
r.raw = make([]byte, 8)
|
||||
binary.BigEndian.PutUint32(r.raw, r.reconfigResponseSequenceNumber)
|
||||
binary.BigEndian.PutUint32(r.raw[4:], uint32(r.result))
|
||||
|
||||
return r.paramHeader.marshal()
|
||||
}
|
||||
|
||||
func (r *paramReconfigResponse) unmarshal(raw []byte) (param, error) {
|
||||
err := r.paramHeader.unmarshal(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(r.raw) < 8 {
|
||||
return nil, errReconfigRespParamTooShort
|
||||
}
|
||||
r.reconfigResponseSequenceNumber = binary.BigEndian.Uint32(r.raw)
|
||||
r.result = reconfigResult(binary.BigEndian.Uint32(r.raw[4:]))
|
||||
|
||||
return r, nil
|
||||
}
|
73
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param_requested_hmac_algorithm.go
generated
vendored
Normal file
73
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param_requested_hmac_algorithm.go
generated
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type hmacAlgorithm uint16
|
||||
|
||||
const (
|
||||
hmacResv1 hmacAlgorithm = 0
|
||||
hmacSHA128 = 1
|
||||
hmacResv2 hmacAlgorithm = 2
|
||||
hmacSHA256 hmacAlgorithm = 3
|
||||
)
|
||||
|
||||
func (c hmacAlgorithm) String() string {
|
||||
switch c {
|
||||
case hmacResv1:
|
||||
return "HMAC Reserved (0x00)"
|
||||
case hmacSHA128:
|
||||
return "HMAC SHA-128"
|
||||
case hmacResv2:
|
||||
return "HMAC Reserved (0x02)"
|
||||
case hmacSHA256:
|
||||
return "HMAC SHA-256"
|
||||
default:
|
||||
return fmt.Sprintf("Unknown HMAC Algorithm type: %d", c)
|
||||
}
|
||||
}
|
||||
|
||||
type paramRequestedHMACAlgorithm struct {
|
||||
paramHeader
|
||||
availableAlgorithms []hmacAlgorithm
|
||||
}
|
||||
|
||||
func (r *paramRequestedHMACAlgorithm) marshal() ([]byte, error) {
|
||||
r.typ = reqHMACAlgo
|
||||
r.raw = make([]byte, len(r.availableAlgorithms)*2)
|
||||
i := 0
|
||||
for _, a := range r.availableAlgorithms {
|
||||
binary.BigEndian.PutUint16(r.raw[i:], uint16(a))
|
||||
i += 2
|
||||
}
|
||||
|
||||
return r.paramHeader.marshal()
|
||||
}
|
||||
|
||||
func (r *paramRequestedHMACAlgorithm) unmarshal(raw []byte) (param, error) {
|
||||
err := r.paramHeader.unmarshal(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
i := 0
|
||||
for i < len(r.raw) {
|
||||
a := hmacAlgorithm(binary.BigEndian.Uint16(r.raw[i:]))
|
||||
switch a {
|
||||
case hmacSHA128:
|
||||
fallthrough
|
||||
case hmacSHA256:
|
||||
r.availableAlgorithms = append(r.availableAlgorithms, a)
|
||||
default:
|
||||
return nil, errors.Errorf("Invalid algorithm type '%v'", a)
|
||||
}
|
||||
|
||||
i += 2
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
46
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param_state_cookie.go
generated
vendored
Normal file
46
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param_state_cookie.go
generated
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type paramStateCookie struct {
|
||||
paramHeader
|
||||
cookie []byte
|
||||
}
|
||||
|
||||
func newRandomStateCookie() (*paramStateCookie, error) {
|
||||
randCookie := make([]byte, 32)
|
||||
_, err := rand.Read(randCookie)
|
||||
// crypto/rand.Read returns n == len(b) if and only if err == nil.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := ¶mStateCookie{
|
||||
cookie: randCookie,
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *paramStateCookie) marshal() ([]byte, error) {
|
||||
s.typ = stateCookie
|
||||
s.raw = s.cookie
|
||||
return s.paramHeader.marshal()
|
||||
}
|
||||
|
||||
func (s *paramStateCookie) unmarshal(raw []byte) (param, error) {
|
||||
err := s.paramHeader.unmarshal(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.cookie = s.raw
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// String makes paramStateCookie printable
|
||||
func (s *paramStateCookie) String() string {
|
||||
return fmt.Sprintf("%s: %s", s.paramHeader, s.cookie)
|
||||
}
|
29
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param_supported_extensions.go
generated
vendored
Normal file
29
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/param_supported_extensions.go
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
package sctp
|
||||
|
||||
type paramSupportedExtensions struct {
|
||||
paramHeader
|
||||
ChunkTypes []chunkType
|
||||
}
|
||||
|
||||
func (s *paramSupportedExtensions) marshal() ([]byte, error) {
|
||||
s.typ = supportedExt
|
||||
s.raw = make([]byte, len(s.ChunkTypes))
|
||||
for i, c := range s.ChunkTypes {
|
||||
s.raw[i] = byte(c)
|
||||
}
|
||||
|
||||
return s.paramHeader.marshal()
|
||||
}
|
||||
|
||||
func (s *paramSupportedExtensions) unmarshal(raw []byte) (param, error) {
|
||||
err := s.paramHeader.unmarshal(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, t := range s.raw {
|
||||
s.ChunkTypes = append(s.ChunkTypes, chunkType(t))
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
63
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/paramheader.go
generated
vendored
Normal file
63
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/paramheader.go
generated
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type paramHeader struct {
|
||||
typ paramType
|
||||
len int
|
||||
raw []byte
|
||||
}
|
||||
|
||||
const (
|
||||
paramHeaderLength = 4
|
||||
)
|
||||
|
||||
func (p *paramHeader) marshal() ([]byte, error) {
|
||||
paramLengthPlusHeader := paramHeaderLength + len(p.raw)
|
||||
|
||||
rawParam := make([]byte, paramLengthPlusHeader)
|
||||
binary.BigEndian.PutUint16(rawParam[0:], uint16(p.typ))
|
||||
binary.BigEndian.PutUint16(rawParam[2:], uint16(paramLengthPlusHeader))
|
||||
copy(rawParam[paramHeaderLength:], p.raw)
|
||||
|
||||
return rawParam, nil
|
||||
}
|
||||
|
||||
func (p *paramHeader) unmarshal(raw []byte) error {
|
||||
if len(raw) < paramHeaderLength {
|
||||
return errors.New("param header too short")
|
||||
}
|
||||
|
||||
paramLengthPlusHeader := binary.BigEndian.Uint16(raw[2:])
|
||||
if int(paramLengthPlusHeader) < paramHeaderLength {
|
||||
return errors.Errorf("param self reported length (%d) smaller than header length (%d)", int(paramLengthPlusHeader), paramHeaderLength)
|
||||
}
|
||||
if len(raw) < int(paramLengthPlusHeader) {
|
||||
return errors.Errorf("param length (%d) shorter than its self reported length (%d)", len(raw), int(paramLengthPlusHeader))
|
||||
}
|
||||
|
||||
typ, err := parseParamType(raw[0:])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to parse param type")
|
||||
}
|
||||
p.typ = typ
|
||||
p.raw = raw[paramHeaderLength:paramLengthPlusHeader]
|
||||
p.len = int(paramLengthPlusHeader)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *paramHeader) length() int {
|
||||
return p.len
|
||||
}
|
||||
|
||||
// String makes paramHeader printable
|
||||
func (p paramHeader) String() string {
|
||||
return fmt.Sprintf("%s (%d): %s", p.typ, p.len, hex.Dump(p.raw))
|
||||
}
|
106
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/paramtype.go
generated
vendored
Normal file
106
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/paramtype.go
generated
vendored
Normal file
|
@ -0,0 +1,106 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// paramType represents a SCTP INIT/INITACK parameter
|
||||
type paramType uint16
|
||||
|
||||
const (
|
||||
heartbeatInfo paramType = 1 // Heartbeat Info [RFC4960]
|
||||
ipV4Addr paramType = 5 // IPv4 IP [RFC4960]
|
||||
ipV6Addr paramType = 6 // IPv6 IP [RFC4960]
|
||||
stateCookie paramType = 7 // State Cookie [RFC4960]
|
||||
unrecognizedParam paramType = 8 // Unrecognized Parameters [RFC4960]
|
||||
cookiePreservative paramType = 9 // Cookie Preservative [RFC4960]
|
||||
hostNameAddr paramType = 11 // Host Name IP [RFC4960]
|
||||
supportedAddrTypes paramType = 12 // Supported IP Types [RFC4960]
|
||||
outSSNResetReq paramType = 13 // Outgoing SSN Reset Request Parameter [RFC6525]
|
||||
incSSNResetReq paramType = 14 // Incoming SSN Reset Request Parameter [RFC6525]
|
||||
ssnTSNResetReq paramType = 15 // SSN/TSN Reset Request Parameter [RFC6525]
|
||||
reconfigResp paramType = 16 // Re-configuration Response Parameter [RFC6525]
|
||||
addOutStreamsReq paramType = 17 // Add Outgoing Streams Request Parameter [RFC6525]
|
||||
addIncStreamsReq paramType = 18 // Add Incoming Streams Request Parameter [RFC6525]
|
||||
random paramType = 32770 // Random (0x8002) [RFC4805]
|
||||
chunkList paramType = 32771 // Chunk List (0x8003) [RFC4895]
|
||||
reqHMACAlgo paramType = 32772 // Requested HMAC Algorithm Parameter (0x8004) [RFC4895]
|
||||
padding paramType = 32773 // Padding (0x8005)
|
||||
supportedExt paramType = 32776 // Supported Extensions (0x8008) [RFC5061]
|
||||
forwardTSNSupp paramType = 49152 // Forward TSN supported (0xC000) [RFC3758]
|
||||
addIPAddr paramType = 49153 // Add IP IP (0xC001) [RFC5061]
|
||||
delIPAddr paramType = 49154 // Delete IP IP (0xC002) [RFC5061]
|
||||
errClauseInd paramType = 49155 // Error Cause Indication (0xC003) [RFC5061]
|
||||
setPriAddr paramType = 49156 // Set Primary IP (0xC004) [RFC5061]
|
||||
successInd paramType = 49157 // Success Indication (0xC005) [RFC5061]
|
||||
adaptLayerInd paramType = 49158 // Adaptation Layer Indication (0xC006) [RFC5061]
|
||||
)
|
||||
|
||||
func parseParamType(raw []byte) (paramType, error) {
|
||||
if len(raw) < 2 {
|
||||
return paramType(0), errors.New("packet to short")
|
||||
}
|
||||
return paramType(binary.BigEndian.Uint16(raw)), nil
|
||||
}
|
||||
|
||||
func (p paramType) String() string {
|
||||
switch p {
|
||||
case heartbeatInfo:
|
||||
return "Heartbeat Info"
|
||||
case ipV4Addr:
|
||||
return "IPv4 IP"
|
||||
case ipV6Addr:
|
||||
return "IPv6 IP"
|
||||
case stateCookie:
|
||||
return "State Cookie"
|
||||
case unrecognizedParam:
|
||||
return "Unrecognized Parameters"
|
||||
case cookiePreservative:
|
||||
return "Cookie Preservative"
|
||||
case hostNameAddr:
|
||||
return "Host Name IP"
|
||||
case supportedAddrTypes:
|
||||
return "Supported IP Types"
|
||||
case outSSNResetReq:
|
||||
return "Outgoing SSN Reset Request Parameter"
|
||||
case incSSNResetReq:
|
||||
return "Incoming SSN Reset Request Parameter"
|
||||
case ssnTSNResetReq:
|
||||
return "SSN/TSN Reset Request Parameter"
|
||||
case reconfigResp:
|
||||
return "Re-configuration Response Parameter"
|
||||
case addOutStreamsReq:
|
||||
return "Add Outgoing Streams Request Parameter"
|
||||
case addIncStreamsReq:
|
||||
return "Add Incoming Streams Request Parameter"
|
||||
case random:
|
||||
return "Random"
|
||||
case chunkList:
|
||||
return "Chunk List"
|
||||
case reqHMACAlgo:
|
||||
return "Requested HMAC Algorithm Parameter"
|
||||
case padding:
|
||||
return "Padding"
|
||||
case supportedExt:
|
||||
return "Supported Extensions"
|
||||
case forwardTSNSupp:
|
||||
return "Forward TSN supported"
|
||||
case addIPAddr:
|
||||
return "Add IP IP"
|
||||
case delIPAddr:
|
||||
return "Delete IP IP"
|
||||
case errClauseInd:
|
||||
return "Error Cause Indication"
|
||||
case setPriAddr:
|
||||
return "Set Primary IP"
|
||||
case successInd:
|
||||
return "Success Indication"
|
||||
case adaptLayerInd:
|
||||
return "Adaptation Layer Indication"
|
||||
default:
|
||||
return fmt.Sprintf("Unknown ParamType: %d", p)
|
||||
}
|
||||
}
|
179
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/payload_queue.go
generated
vendored
Normal file
179
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/payload_queue.go
generated
vendored
Normal file
|
@ -0,0 +1,179 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type payloadQueue struct {
|
||||
chunkMap map[uint32]*chunkPayloadData
|
||||
sorted []uint32
|
||||
dupTSN []uint32
|
||||
nBytes int
|
||||
}
|
||||
|
||||
func newPayloadQueue() *payloadQueue {
|
||||
return &payloadQueue{chunkMap: map[uint32]*chunkPayloadData{}}
|
||||
}
|
||||
|
||||
func (q *payloadQueue) updateSortedKeys() {
|
||||
if q.sorted != nil {
|
||||
return
|
||||
}
|
||||
|
||||
q.sorted = make([]uint32, len(q.chunkMap))
|
||||
i := 0
|
||||
for k := range q.chunkMap {
|
||||
q.sorted[i] = k
|
||||
i++
|
||||
}
|
||||
|
||||
sort.Slice(q.sorted, func(i, j int) bool {
|
||||
return sna32LT(q.sorted[i], q.sorted[j])
|
||||
})
|
||||
}
|
||||
|
||||
func (q *payloadQueue) canPush(p *chunkPayloadData, cumulativeTSN uint32) bool {
|
||||
_, ok := q.chunkMap[p.tsn]
|
||||
if ok || sna32LTE(p.tsn, cumulativeTSN) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (q *payloadQueue) pushNoCheck(p *chunkPayloadData) {
|
||||
q.chunkMap[p.tsn] = p
|
||||
q.nBytes += len(p.userData)
|
||||
q.sorted = nil
|
||||
}
|
||||
|
||||
// push pushes a payload data. If the payload data is already in our queue or
|
||||
// older than our cumulativeTSN marker, it will be recored as duplications,
|
||||
// which can later be retrieved using popDuplicates.
|
||||
func (q *payloadQueue) push(p *chunkPayloadData, cumulativeTSN uint32) bool {
|
||||
_, ok := q.chunkMap[p.tsn]
|
||||
if ok || sna32LTE(p.tsn, cumulativeTSN) {
|
||||
// Found the packet, log in dups
|
||||
q.dupTSN = append(q.dupTSN, p.tsn)
|
||||
return false
|
||||
}
|
||||
|
||||
q.chunkMap[p.tsn] = p
|
||||
q.nBytes += len(p.userData)
|
||||
q.sorted = nil
|
||||
return true
|
||||
}
|
||||
|
||||
// pop pops only if the oldest chunk's TSN matches the given TSN.
|
||||
func (q *payloadQueue) pop(tsn uint32) (*chunkPayloadData, bool) {
|
||||
q.updateSortedKeys()
|
||||
|
||||
if len(q.chunkMap) > 0 && tsn == q.sorted[0] {
|
||||
q.sorted = q.sorted[1:]
|
||||
if c, ok := q.chunkMap[tsn]; ok {
|
||||
delete(q.chunkMap, tsn)
|
||||
q.nBytes -= len(c.userData)
|
||||
return c, true
|
||||
}
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// get returns reference to chunkPayloadData with the given TSN value.
|
||||
func (q *payloadQueue) get(tsn uint32) (*chunkPayloadData, bool) {
|
||||
c, ok := q.chunkMap[tsn]
|
||||
return c, ok
|
||||
}
|
||||
|
||||
// popDuplicates returns an array of TSN values that were found duplicate.
|
||||
func (q *payloadQueue) popDuplicates() []uint32 {
|
||||
dups := q.dupTSN
|
||||
q.dupTSN = []uint32{}
|
||||
return dups
|
||||
}
|
||||
|
||||
func (q *payloadQueue) getGapAckBlocks(cumulativeTSN uint32) (gapAckBlocks []gapAckBlock) {
|
||||
var b gapAckBlock
|
||||
|
||||
if len(q.chunkMap) == 0 {
|
||||
return []gapAckBlock{}
|
||||
}
|
||||
|
||||
q.updateSortedKeys()
|
||||
|
||||
for i, tsn := range q.sorted {
|
||||
if i == 0 {
|
||||
b.start = uint16(tsn - cumulativeTSN)
|
||||
b.end = b.start
|
||||
continue
|
||||
}
|
||||
diff := uint16(tsn - cumulativeTSN)
|
||||
if b.end+1 == diff {
|
||||
b.end++
|
||||
} else {
|
||||
gapAckBlocks = append(gapAckBlocks, gapAckBlock{
|
||||
start: b.start,
|
||||
end: b.end,
|
||||
})
|
||||
b.start = diff
|
||||
b.end = diff
|
||||
}
|
||||
}
|
||||
|
||||
gapAckBlocks = append(gapAckBlocks, gapAckBlock{
|
||||
start: b.start,
|
||||
end: b.end,
|
||||
})
|
||||
|
||||
return gapAckBlocks
|
||||
}
|
||||
|
||||
func (q *payloadQueue) getGapAckBlocksString(cumulativeTSN uint32) string {
|
||||
gapAckBlocks := q.getGapAckBlocks(cumulativeTSN)
|
||||
str := fmt.Sprintf("cumTSN=%d", cumulativeTSN)
|
||||
for _, b := range gapAckBlocks {
|
||||
str += fmt.Sprintf(",%d-%d", b.start, b.end)
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func (q *payloadQueue) markAsAcked(tsn uint32) int {
|
||||
var nBytesAcked int
|
||||
if c, ok := q.chunkMap[tsn]; ok {
|
||||
c.acked = true
|
||||
c.retransmit = false
|
||||
nBytesAcked = len(c.userData)
|
||||
q.nBytes -= nBytesAcked
|
||||
c.userData = []byte{}
|
||||
}
|
||||
|
||||
return nBytesAcked
|
||||
}
|
||||
|
||||
func (q *payloadQueue) getLastTSNReceived() (uint32, bool) {
|
||||
q.updateSortedKeys()
|
||||
|
||||
qlen := len(q.sorted)
|
||||
if qlen == 0 {
|
||||
return 0, false
|
||||
}
|
||||
return q.sorted[qlen-1], true
|
||||
}
|
||||
|
||||
func (q *payloadQueue) markAllToRetrasmit() {
|
||||
for _, c := range q.chunkMap {
|
||||
if c.acked || c.abandoned() {
|
||||
continue
|
||||
}
|
||||
c.retransmit = true
|
||||
}
|
||||
}
|
||||
|
||||
func (q *payloadQueue) getNumBytes() int {
|
||||
return q.nBytes
|
||||
}
|
||||
|
||||
func (q *payloadQueue) size() int {
|
||||
return len(q.chunkMap)
|
||||
}
|
138
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/pending_queue.go
generated
vendored
Normal file
138
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/pending_queue.go
generated
vendored
Normal file
|
@ -0,0 +1,138 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// pendingBaseQueue
|
||||
|
||||
type pendingBaseQueue struct {
|
||||
queue []*chunkPayloadData
|
||||
}
|
||||
|
||||
func newPendingBaseQueue() *pendingBaseQueue {
|
||||
return &pendingBaseQueue{queue: []*chunkPayloadData{}}
|
||||
}
|
||||
|
||||
func (q *pendingBaseQueue) push(c *chunkPayloadData) {
|
||||
q.queue = append(q.queue, c)
|
||||
}
|
||||
|
||||
func (q *pendingBaseQueue) pop() *chunkPayloadData {
|
||||
if len(q.queue) == 0 {
|
||||
return nil
|
||||
}
|
||||
c := q.queue[0]
|
||||
q.queue = q.queue[1:]
|
||||
return c
|
||||
}
|
||||
|
||||
func (q *pendingBaseQueue) get(i int) *chunkPayloadData {
|
||||
if len(q.queue) == 0 || i < 0 || i >= len(q.queue) {
|
||||
return nil
|
||||
}
|
||||
return q.queue[i]
|
||||
}
|
||||
|
||||
func (q *pendingBaseQueue) size() int {
|
||||
return len(q.queue)
|
||||
}
|
||||
|
||||
// pendingQueue
|
||||
|
||||
type pendingQueue struct {
|
||||
unorderedQueue *pendingBaseQueue
|
||||
orderedQueue *pendingBaseQueue
|
||||
nBytes int
|
||||
selected bool
|
||||
unorderedIsSelected bool
|
||||
}
|
||||
|
||||
var (
|
||||
errUnexpectedChuckPoppedUnordered = errors.New("unexpected chunk popped (unordered)")
|
||||
errUnexpectedChuckPoppedOrdered = errors.New("unexpected chunk popped (ordered)")
|
||||
errUnexpectedQState = errors.New("unexpected q state (should've been selected)")
|
||||
)
|
||||
|
||||
func newPendingQueue() *pendingQueue {
|
||||
return &pendingQueue{
|
||||
unorderedQueue: newPendingBaseQueue(),
|
||||
orderedQueue: newPendingBaseQueue(),
|
||||
}
|
||||
}
|
||||
|
||||
func (q *pendingQueue) push(c *chunkPayloadData) {
|
||||
if c.unordered {
|
||||
q.unorderedQueue.push(c)
|
||||
} else {
|
||||
q.orderedQueue.push(c)
|
||||
}
|
||||
q.nBytes += len(c.userData)
|
||||
}
|
||||
|
||||
func (q *pendingQueue) peek() *chunkPayloadData {
|
||||
if q.selected {
|
||||
if q.unorderedIsSelected {
|
||||
return q.unorderedQueue.get(0)
|
||||
}
|
||||
return q.orderedQueue.get(0)
|
||||
}
|
||||
|
||||
if c := q.unorderedQueue.get(0); c != nil {
|
||||
return c
|
||||
}
|
||||
return q.orderedQueue.get(0)
|
||||
}
|
||||
|
||||
func (q *pendingQueue) pop(c *chunkPayloadData) error {
|
||||
if q.selected {
|
||||
var popped *chunkPayloadData
|
||||
if q.unorderedIsSelected {
|
||||
popped = q.unorderedQueue.pop()
|
||||
if popped != c {
|
||||
return errUnexpectedChuckPoppedUnordered
|
||||
}
|
||||
} else {
|
||||
popped = q.orderedQueue.pop()
|
||||
if popped != c {
|
||||
return errUnexpectedChuckPoppedOrdered
|
||||
}
|
||||
}
|
||||
if popped.endingFragment {
|
||||
q.selected = false
|
||||
}
|
||||
} else {
|
||||
if !c.beginningFragment {
|
||||
return errUnexpectedQState
|
||||
}
|
||||
if c.unordered {
|
||||
popped := q.unorderedQueue.pop()
|
||||
if popped != c {
|
||||
return errUnexpectedChuckPoppedUnordered
|
||||
}
|
||||
if !popped.endingFragment {
|
||||
q.selected = true
|
||||
q.unorderedIsSelected = true
|
||||
}
|
||||
} else {
|
||||
popped := q.orderedQueue.pop()
|
||||
if popped != c {
|
||||
return errUnexpectedChuckPoppedOrdered
|
||||
}
|
||||
if !popped.endingFragment {
|
||||
q.selected = true
|
||||
q.unorderedIsSelected = false
|
||||
}
|
||||
}
|
||||
}
|
||||
q.nBytes -= len(c.userData)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *pendingQueue) getNumBytes() int {
|
||||
return q.nBytes
|
||||
}
|
||||
|
||||
func (q *pendingQueue) size() int {
|
||||
return q.unorderedQueue.size() + q.orderedQueue.size()
|
||||
}
|
353
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/reassembly_queue.go
generated
vendored
Normal file
353
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/reassembly_queue.go
generated
vendored
Normal file
|
@ -0,0 +1,353 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"io"
|
||||
"sort"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func sortChunksByTSN(a []*chunkPayloadData) {
|
||||
sort.Slice(a, func(i, j int) bool {
|
||||
return sna32LT(a[i].tsn, a[j].tsn)
|
||||
})
|
||||
}
|
||||
|
||||
func sortChunksBySSN(a []*chunkSet) {
|
||||
sort.Slice(a, func(i, j int) bool {
|
||||
return sna16LT(a[i].ssn, a[j].ssn)
|
||||
})
|
||||
}
|
||||
|
||||
// chunkSet is a set of chunks that share the same SSN
|
||||
type chunkSet struct {
|
||||
ssn uint16 // used only with the ordered chunks
|
||||
ppi PayloadProtocolIdentifier
|
||||
chunks []*chunkPayloadData
|
||||
}
|
||||
|
||||
func newChunkSet(ssn uint16, ppi PayloadProtocolIdentifier) *chunkSet {
|
||||
return &chunkSet{
|
||||
ssn: ssn,
|
||||
ppi: ppi,
|
||||
chunks: []*chunkPayloadData{},
|
||||
}
|
||||
}
|
||||
|
||||
func (set *chunkSet) push(chunk *chunkPayloadData) bool {
|
||||
// check if dup
|
||||
for _, c := range set.chunks {
|
||||
if c.tsn == chunk.tsn {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// append and sort
|
||||
set.chunks = append(set.chunks, chunk)
|
||||
sortChunksByTSN(set.chunks)
|
||||
|
||||
// Check if we now have a complete set
|
||||
complete := set.isComplete()
|
||||
return complete
|
||||
}
|
||||
|
||||
func (set *chunkSet) isComplete() bool {
|
||||
// Condition for complete set
|
||||
// 0. Has at least one chunk.
|
||||
// 1. Begins with beginningFragment set to true
|
||||
// 2. Ends with endingFragment set to true
|
||||
// 3. TSN monotinically increase by 1 from beginning to end
|
||||
|
||||
// 0.
|
||||
nChunks := len(set.chunks)
|
||||
if nChunks == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// 1.
|
||||
if !set.chunks[0].beginningFragment {
|
||||
return false
|
||||
}
|
||||
|
||||
// 2.
|
||||
if !set.chunks[nChunks-1].endingFragment {
|
||||
return false
|
||||
}
|
||||
|
||||
// 3.
|
||||
var lastTSN uint32
|
||||
for i, c := range set.chunks {
|
||||
if i > 0 {
|
||||
// Fragments must have contiguous TSN
|
||||
// From RFC 4960 Section 3.3.1:
|
||||
// When a user message is fragmented into multiple chunks, the TSNs are
|
||||
// used by the receiver to reassemble the message. This means that the
|
||||
// TSNs for each fragment of a fragmented user message MUST be strictly
|
||||
// sequential.
|
||||
if c.tsn != lastTSN+1 {
|
||||
// mid or end fragment is missing
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
lastTSN = c.tsn
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
type reassemblyQueue struct {
|
||||
si uint16
|
||||
nextSSN uint16 // expected SSN for next ordered chunk
|
||||
ordered []*chunkSet
|
||||
unordered []*chunkSet
|
||||
unorderedChunks []*chunkPayloadData
|
||||
nBytes uint64
|
||||
}
|
||||
|
||||
var errTryAgain = errors.New("try again")
|
||||
|
||||
func newReassemblyQueue(si uint16) *reassemblyQueue {
|
||||
// From RFC 4960 Sec 6.5:
|
||||
// The Stream Sequence Number in all the streams MUST start from 0 when
|
||||
// the association is established. Also, when the Stream Sequence
|
||||
// Number reaches the value 65535 the next Stream Sequence Number MUST
|
||||
// be set to 0.
|
||||
return &reassemblyQueue{
|
||||
si: si,
|
||||
nextSSN: 0, // From RFC 4960 Sec 6.5:
|
||||
ordered: make([]*chunkSet, 0),
|
||||
unordered: make([]*chunkSet, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *reassemblyQueue) push(chunk *chunkPayloadData) bool {
|
||||
var cset *chunkSet
|
||||
|
||||
if chunk.streamIdentifier != r.si {
|
||||
return false
|
||||
}
|
||||
|
||||
if chunk.unordered {
|
||||
// First, insert into unorderedChunks array
|
||||
r.unorderedChunks = append(r.unorderedChunks, chunk)
|
||||
atomic.AddUint64(&r.nBytes, uint64(len(chunk.userData)))
|
||||
sortChunksByTSN(r.unorderedChunks)
|
||||
|
||||
// Scan unorderedChunks that are contiguous (in TSN)
|
||||
cset = r.findCompleteUnorderedChunkSet()
|
||||
|
||||
// If found, append the complete set to the unordered array
|
||||
if cset != nil {
|
||||
r.unordered = append(r.unordered, cset)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// This is an ordered chunk
|
||||
|
||||
if sna16LT(chunk.streamSequenceNumber, r.nextSSN) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if a chunkSet with the SSN already exists
|
||||
for _, set := range r.ordered {
|
||||
if set.ssn == chunk.streamSequenceNumber {
|
||||
cset = set
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If not found, create a new chunkSet
|
||||
if cset == nil {
|
||||
cset = newChunkSet(chunk.streamSequenceNumber, chunk.payloadType)
|
||||
r.ordered = append(r.ordered, cset)
|
||||
if !chunk.unordered {
|
||||
sortChunksBySSN(r.ordered)
|
||||
}
|
||||
}
|
||||
|
||||
atomic.AddUint64(&r.nBytes, uint64(len(chunk.userData)))
|
||||
|
||||
return cset.push(chunk)
|
||||
}
|
||||
|
||||
func (r *reassemblyQueue) findCompleteUnorderedChunkSet() *chunkSet {
|
||||
startIdx := -1
|
||||
nChunks := 0
|
||||
var lastTSN uint32
|
||||
var found bool
|
||||
|
||||
for i, c := range r.unorderedChunks {
|
||||
// seek beigining
|
||||
if c.beginningFragment {
|
||||
startIdx = i
|
||||
nChunks = 1
|
||||
lastTSN = c.tsn
|
||||
|
||||
if c.endingFragment {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if startIdx < 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if contiguous in TSN
|
||||
if c.tsn != lastTSN+1 {
|
||||
startIdx = -1
|
||||
continue
|
||||
}
|
||||
|
||||
lastTSN = c.tsn
|
||||
nChunks++
|
||||
|
||||
if c.endingFragment {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Extract the range of chunks
|
||||
var chunks []*chunkPayloadData
|
||||
chunks = append(chunks, r.unorderedChunks[startIdx:startIdx+nChunks]...)
|
||||
|
||||
r.unorderedChunks = append(
|
||||
r.unorderedChunks[:startIdx],
|
||||
r.unorderedChunks[startIdx+nChunks:]...)
|
||||
|
||||
chunkSet := newChunkSet(0, chunks[0].payloadType)
|
||||
chunkSet.chunks = chunks
|
||||
|
||||
return chunkSet
|
||||
}
|
||||
|
||||
func (r *reassemblyQueue) isReadable() bool {
|
||||
// Check unordered first
|
||||
if len(r.unordered) > 0 {
|
||||
// The chunk sets in r.unordered should all be complete.
|
||||
return true
|
||||
}
|
||||
|
||||
// Check ordered sets
|
||||
if len(r.ordered) > 0 {
|
||||
cset := r.ordered[0]
|
||||
if cset.isComplete() {
|
||||
if sna16LTE(cset.ssn, r.nextSSN) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *reassemblyQueue) read(buf []byte) (int, PayloadProtocolIdentifier, error) {
|
||||
var cset *chunkSet
|
||||
// Check unordered first
|
||||
switch {
|
||||
case len(r.unordered) > 0:
|
||||
cset = r.unordered[0]
|
||||
r.unordered = r.unordered[1:]
|
||||
case len(r.ordered) > 0:
|
||||
// Now, check ordered
|
||||
cset = r.ordered[0]
|
||||
if !cset.isComplete() {
|
||||
return 0, 0, errTryAgain
|
||||
}
|
||||
if sna16GT(cset.ssn, r.nextSSN) {
|
||||
return 0, 0, errTryAgain
|
||||
}
|
||||
r.ordered = r.ordered[1:]
|
||||
if cset.ssn == r.nextSSN {
|
||||
r.nextSSN++
|
||||
}
|
||||
default:
|
||||
return 0, 0, errTryAgain
|
||||
}
|
||||
|
||||
// Concat all fragments into the buffer
|
||||
nWritten := 0
|
||||
ppi := cset.ppi
|
||||
var err error
|
||||
for _, c := range cset.chunks {
|
||||
toCopy := len(c.userData)
|
||||
r.subtractNumBytes(toCopy)
|
||||
if err == nil {
|
||||
n := copy(buf[nWritten:], c.userData)
|
||||
nWritten += n
|
||||
if n < toCopy {
|
||||
err = io.ErrShortBuffer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nWritten, ppi, err
|
||||
}
|
||||
|
||||
func (r *reassemblyQueue) forwardTSNForOrdered(lastSSN uint16) {
|
||||
// Use lastSSN to locate a chunkSet then remove it if the set has
|
||||
// not been complete
|
||||
keep := []*chunkSet{}
|
||||
for _, set := range r.ordered {
|
||||
if sna16LTE(set.ssn, lastSSN) {
|
||||
if !set.isComplete() {
|
||||
// drop the set
|
||||
for _, c := range set.chunks {
|
||||
r.subtractNumBytes(len(c.userData))
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
keep = append(keep, set)
|
||||
}
|
||||
r.ordered = keep
|
||||
|
||||
// Finally, forward nextSSN
|
||||
if sna16LTE(r.nextSSN, lastSSN) {
|
||||
r.nextSSN = lastSSN + 1
|
||||
}
|
||||
}
|
||||
|
||||
func (r *reassemblyQueue) forwardTSNForUnordered(newCumulativeTSN uint32) {
|
||||
// Remove all fragments in the unordered sets that contains chunks
|
||||
// equal to or older than `newCumulativeTSN`.
|
||||
// We know all sets in the r.unordered are complete ones.
|
||||
// Just remove chunks that are equal to or older than newCumulativeTSN
|
||||
// from the unorderedChunks
|
||||
lastIdx := -1
|
||||
for i, c := range r.unorderedChunks {
|
||||
if sna32GT(c.tsn, newCumulativeTSN) {
|
||||
break
|
||||
}
|
||||
lastIdx = i
|
||||
}
|
||||
if lastIdx >= 0 {
|
||||
for _, c := range r.unorderedChunks[0 : lastIdx+1] {
|
||||
r.subtractNumBytes(len(c.userData))
|
||||
}
|
||||
r.unorderedChunks = r.unorderedChunks[lastIdx+1:]
|
||||
}
|
||||
}
|
||||
|
||||
func (r *reassemblyQueue) subtractNumBytes(nBytes int) {
|
||||
cur := atomic.LoadUint64(&r.nBytes)
|
||||
if int(cur) >= nBytes {
|
||||
atomic.AddUint64(&r.nBytes, -uint64(nBytes))
|
||||
} else {
|
||||
atomic.StoreUint64(&r.nBytes, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *reassemblyQueue) getNumBytes() int {
|
||||
return int(atomic.LoadUint64(&r.nBytes))
|
||||
}
|
15
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/renovate.json
generated
vendored
Normal file
15
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/renovate.json
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"extends": [
|
||||
"config:base"
|
||||
],
|
||||
"postUpdateOptions": [
|
||||
"gomodTidy"
|
||||
],
|
||||
"commitBody": "Generated by renovateBot",
|
||||
"packageRules": [
|
||||
{
|
||||
"packagePatterns": ["^golang.org/x/"],
|
||||
"schedule": ["on the first day of the month"]
|
||||
}
|
||||
]
|
||||
}
|
219
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/rtx_timer.go
generated
vendored
Normal file
219
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/rtx_timer.go
generated
vendored
Normal file
|
@ -0,0 +1,219 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
rtoInitial float64 = 3.0 * 1000 // msec
|
||||
rtoMin float64 = 1.0 * 1000 // msec
|
||||
rtoMax float64 = 60.0 * 1000 // msec
|
||||
rtoAlpha float64 = 0.125
|
||||
rtoBeta float64 = 0.25
|
||||
maxInitRetrans uint = 8
|
||||
pathMaxRetrans uint = 5
|
||||
noMaxRetrans uint = 0
|
||||
)
|
||||
|
||||
// rtoManager manages Rtx timeout values.
|
||||
// This is an implementation of RFC 4960 sec 6.3.1.
|
||||
type rtoManager struct {
|
||||
srtt float64
|
||||
rttvar float64
|
||||
rto float64
|
||||
noUpdate bool
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
|
||||
// newRTOManager creates a new rtoManager.
|
||||
func newRTOManager() *rtoManager {
|
||||
return &rtoManager{
|
||||
rto: rtoInitial,
|
||||
}
|
||||
}
|
||||
|
||||
// setNewRTT takes a newly measured RTT then adjust the RTO in msec.
|
||||
func (m *rtoManager) setNewRTT(rtt float64) float64 {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
if m.noUpdate {
|
||||
return m.srtt
|
||||
}
|
||||
|
||||
if m.srtt == 0 {
|
||||
// First measurement
|
||||
m.srtt = rtt
|
||||
m.rttvar = rtt / 2
|
||||
} else {
|
||||
// Subsequent rtt measurement
|
||||
m.rttvar = (1-rtoBeta)*m.rttvar + rtoBeta*(math.Abs(m.srtt-rtt))
|
||||
m.srtt = (1-rtoAlpha)*m.srtt + rtoAlpha*rtt
|
||||
}
|
||||
m.rto = math.Min(math.Max(m.srtt+4*m.rttvar, rtoMin), rtoMax)
|
||||
return m.srtt
|
||||
}
|
||||
|
||||
// getRTO simply returns the current RTO in msec.
|
||||
func (m *rtoManager) getRTO() float64 {
|
||||
m.mutex.RLock()
|
||||
defer m.mutex.RUnlock()
|
||||
|
||||
return m.rto
|
||||
}
|
||||
|
||||
// reset resets the RTO variables to the initial values.
|
||||
func (m *rtoManager) reset() {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
if m.noUpdate {
|
||||
return
|
||||
}
|
||||
|
||||
m.srtt = 0
|
||||
m.rttvar = 0
|
||||
m.rto = rtoInitial
|
||||
}
|
||||
|
||||
// set RTO value for testing
|
||||
func (m *rtoManager) setRTO(rto float64, noUpdate bool) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
m.rto = rto
|
||||
m.noUpdate = noUpdate
|
||||
}
|
||||
|
||||
// rtxTimerObserver is the inteface to a timer observer.
|
||||
// NOTE: Observers MUST NOT call start() or stop() method on rtxTimer
|
||||
// from within these callbacks.
|
||||
type rtxTimerObserver interface {
|
||||
onRetransmissionTimeout(timerID int, n uint)
|
||||
onRetransmissionFailure(timerID int)
|
||||
}
|
||||
|
||||
// rtxTimer provides the retnransmission timer conforms with RFC 4960 Sec 6.3.1
|
||||
type rtxTimer struct {
|
||||
id int
|
||||
observer rtxTimerObserver
|
||||
maxRetrans uint
|
||||
stopFunc stopTimerLoop
|
||||
closed bool
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
|
||||
type stopTimerLoop func()
|
||||
|
||||
// newRTXTimer creates a new retransmission timer.
|
||||
// if maxRetrans is set to 0, it will keep retransmitting until stop() is called.
|
||||
// (it will never make onRetransmissionFailure() callback.
|
||||
func newRTXTimer(id int, observer rtxTimerObserver, maxRetrans uint) *rtxTimer {
|
||||
return &rtxTimer{
|
||||
id: id,
|
||||
observer: observer,
|
||||
maxRetrans: maxRetrans,
|
||||
}
|
||||
}
|
||||
|
||||
// start starts the timer.
|
||||
func (t *rtxTimer) start(rto float64) bool {
|
||||
t.mutex.Lock()
|
||||
defer t.mutex.Unlock()
|
||||
|
||||
// this timer is already closed
|
||||
if t.closed {
|
||||
return false
|
||||
}
|
||||
|
||||
// this is a noop if the timer is always running
|
||||
if t.stopFunc != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Note: rto value is intentionally not capped by RTO.Min to allow
|
||||
// fast timeout for the tests. Non-test code should pass in the
|
||||
// rto generated by rtoManager getRTO() method which caps the
|
||||
// value at RTO.Min or at RTO.Max.
|
||||
var nRtos uint
|
||||
|
||||
cancelCh := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
canceling := false
|
||||
|
||||
for !canceling {
|
||||
timeout := calculateNextTimeout(rto, nRtos)
|
||||
timer := time.NewTimer(time.Duration(timeout) * time.Millisecond)
|
||||
|
||||
select {
|
||||
case <-timer.C:
|
||||
nRtos++
|
||||
if t.maxRetrans == 0 || nRtos <= t.maxRetrans {
|
||||
t.observer.onRetransmissionTimeout(t.id, nRtos)
|
||||
} else {
|
||||
t.stop()
|
||||
t.observer.onRetransmissionFailure(t.id)
|
||||
}
|
||||
case <-cancelCh:
|
||||
canceling = true
|
||||
timer.Stop()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
t.stopFunc = func() {
|
||||
close(cancelCh)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// stop stops the timer.
|
||||
func (t *rtxTimer) stop() {
|
||||
t.mutex.Lock()
|
||||
defer t.mutex.Unlock()
|
||||
|
||||
if t.stopFunc != nil {
|
||||
t.stopFunc()
|
||||
t.stopFunc = nil
|
||||
}
|
||||
}
|
||||
|
||||
// closes the timer. this is similar to stop() but subsequent start() call
|
||||
// will fail (the timer is no longer usable)
|
||||
func (t *rtxTimer) close() {
|
||||
t.mutex.Lock()
|
||||
defer t.mutex.Unlock()
|
||||
|
||||
if t.stopFunc != nil {
|
||||
t.stopFunc()
|
||||
t.stopFunc = nil
|
||||
}
|
||||
|
||||
t.closed = true
|
||||
}
|
||||
|
||||
// isRunning tests if the timer is running.
|
||||
// Debug purpose only
|
||||
func (t *rtxTimer) isRunning() bool {
|
||||
t.mutex.RLock()
|
||||
defer t.mutex.RUnlock()
|
||||
|
||||
return (t.stopFunc != nil)
|
||||
}
|
||||
|
||||
func calculateNextTimeout(rto float64, nRtos uint) float64 {
|
||||
// RFC 4096 sec 6.3.3. Handle T3-rtx Expiration
|
||||
// E2) For the destination address for which the timer expires, set RTO
|
||||
// <- RTO * 2 ("back off the timer"). The maximum value discussed
|
||||
// in rule C7 above (RTO.max) may be used to provide an upper bound
|
||||
// to this doubling operation.
|
||||
if nRtos < 31 {
|
||||
m := 1 << nRtos
|
||||
return math.Min(rto*float64(m), rtoMax)
|
||||
}
|
||||
return rtoMax
|
||||
}
|
2
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/sctp.go
generated
vendored
Normal file
2
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/sctp.go
generated
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
// Package sctp implements the SCTP spec
|
||||
package sctp
|
357
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/stream.go
generated
vendored
Normal file
357
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/stream.go
generated
vendored
Normal file
|
@ -0,0 +1,357 @@
|
|||
package sctp
|
||||
|
||||
import (
|
||||
"io"
|
||||
"math"
|
||||
"sync"
|
||||
|
||||
"github.com/pion/logging"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// ReliabilityTypeReliable is used for reliable transmission
|
||||
ReliabilityTypeReliable byte = 0
|
||||
// ReliabilityTypeRexmit is used for partial reliability by retransmission count
|
||||
ReliabilityTypeRexmit byte = 1
|
||||
// ReliabilityTypeTimed is used for partial reliability by retransmission duration
|
||||
ReliabilityTypeTimed byte = 2
|
||||
)
|
||||
|
||||
// Stream represents an SCTP stream
|
||||
type Stream struct {
|
||||
association *Association
|
||||
lock sync.RWMutex
|
||||
streamIdentifier uint16
|
||||
defaultPayloadType PayloadProtocolIdentifier
|
||||
reassemblyQueue *reassemblyQueue
|
||||
sequenceNumber uint16
|
||||
readNotifier *sync.Cond
|
||||
readErr error
|
||||
writeErr error
|
||||
unordered bool
|
||||
reliabilityType byte
|
||||
reliabilityValue uint32
|
||||
bufferedAmount uint64
|
||||
bufferedAmountLow uint64
|
||||
onBufferedAmountLow func()
|
||||
log logging.LeveledLogger
|
||||
name string
|
||||
}
|
||||
|
||||
// StreamIdentifier returns the Stream identifier associated to the stream.
|
||||
func (s *Stream) StreamIdentifier() uint16 {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
return s.streamIdentifier
|
||||
}
|
||||
|
||||
// SetDefaultPayloadType sets the default payload type used by Write.
|
||||
func (s *Stream) SetDefaultPayloadType(defaultPayloadType PayloadProtocolIdentifier) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
s.setDefaultPayloadType(defaultPayloadType)
|
||||
}
|
||||
|
||||
// setDefaultPayloadType sets the defaultPayloadType. The caller should hold the lock.
|
||||
func (s *Stream) setDefaultPayloadType(defaultPayloadType PayloadProtocolIdentifier) {
|
||||
s.defaultPayloadType = defaultPayloadType
|
||||
}
|
||||
|
||||
// SetReliabilityParams sets reliability parameters for this stream.
|
||||
func (s *Stream) SetReliabilityParams(unordered bool, relType byte, relVal uint32) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
s.setReliabilityParams(unordered, relType, relVal)
|
||||
}
|
||||
|
||||
// setReliabilityParams sets reliability parameters for this stream.
|
||||
// The caller should hold the lock.
|
||||
func (s *Stream) setReliabilityParams(unordered bool, relType byte, relVal uint32) {
|
||||
s.log.Debugf("[%s] reliability params: ordered=%v type=%d value=%d",
|
||||
s.name, !unordered, relType, relVal)
|
||||
s.unordered = unordered
|
||||
s.reliabilityType = relType
|
||||
s.reliabilityValue = relVal
|
||||
}
|
||||
|
||||
// Read reads a packet of len(p) bytes, dropping the Payload Protocol Identifier.
|
||||
// Returns EOF when the stream is reset or an error if the stream is closed
|
||||
// otherwise.
|
||||
func (s *Stream) Read(p []byte) (int, error) {
|
||||
n, _, err := s.ReadSCTP(p)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// ReadSCTP reads a packet of len(p) bytes and returns the associated Payload
|
||||
// Protocol Identifier.
|
||||
// Returns EOF when the stream is reset or an error if the stream is closed
|
||||
// otherwise.
|
||||
func (s *Stream) ReadSCTP(p []byte) (int, PayloadProtocolIdentifier, error) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
for {
|
||||
n, ppi, err := s.reassemblyQueue.read(p)
|
||||
if err == nil {
|
||||
return n, ppi, nil
|
||||
} else if errors.Is(err, io.ErrShortBuffer) {
|
||||
return 0, PayloadProtocolIdentifier(0), err
|
||||
}
|
||||
|
||||
err = s.readErr
|
||||
if err != nil {
|
||||
return 0, PayloadProtocolIdentifier(0), err
|
||||
}
|
||||
|
||||
s.readNotifier.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Stream) handleData(pd *chunkPayloadData) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
var readable bool
|
||||
if s.reassemblyQueue.push(pd) {
|
||||
readable = s.reassemblyQueue.isReadable()
|
||||
s.log.Debugf("[%s] reassemblyQueue readable=%v", s.name, readable)
|
||||
if readable {
|
||||
s.log.Debugf("[%s] readNotifier.signal()", s.name)
|
||||
s.readNotifier.Signal()
|
||||
s.log.Debugf("[%s] readNotifier.signal() done", s.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Stream) handleForwardTSNForOrdered(ssn uint16) {
|
||||
var readable bool
|
||||
|
||||
func() {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
if s.unordered {
|
||||
return // unordered chunks are handled by handleForwardUnordered method
|
||||
}
|
||||
|
||||
// Remove all chunks older than or equal to the new TSN from
|
||||
// the reassemblyQueue.
|
||||
s.reassemblyQueue.forwardTSNForOrdered(ssn)
|
||||
readable = s.reassemblyQueue.isReadable()
|
||||
}()
|
||||
|
||||
// Notify the reader asynchronously if there's a data chunk to read.
|
||||
if readable {
|
||||
s.readNotifier.Signal()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Stream) handleForwardTSNForUnordered(newCumulativeTSN uint32) {
|
||||
var readable bool
|
||||
|
||||
func() {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
if !s.unordered {
|
||||
return // ordered chunks are handled by handleForwardTSNOrdered method
|
||||
}
|
||||
|
||||
// Remove all chunks older than or equal to the new TSN from
|
||||
// the reassemblyQueue.
|
||||
s.reassemblyQueue.forwardTSNForUnordered(newCumulativeTSN)
|
||||
readable = s.reassemblyQueue.isReadable()
|
||||
}()
|
||||
|
||||
// Notify the reader asynchronously if there's a data chunk to read.
|
||||
if readable {
|
||||
s.readNotifier.Signal()
|
||||
}
|
||||
}
|
||||
|
||||
// Write writes len(p) bytes from p with the default Payload Protocol Identifier
|
||||
func (s *Stream) Write(p []byte) (n int, err error) {
|
||||
return s.WriteSCTP(p, s.defaultPayloadType)
|
||||
}
|
||||
|
||||
// WriteSCTP writes len(p) bytes from p to the DTLS connection
|
||||
func (s *Stream) WriteSCTP(p []byte, ppi PayloadProtocolIdentifier) (n int, err error) {
|
||||
maxMessageSize := s.association.MaxMessageSize()
|
||||
if len(p) > int(maxMessageSize) {
|
||||
return 0, errors.Errorf("Outbound packet larger than maximum message size %v", math.MaxUint16)
|
||||
}
|
||||
|
||||
s.lock.RLock()
|
||||
err = s.writeErr
|
||||
s.lock.RUnlock()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
chunks := s.packetize(p, ppi)
|
||||
|
||||
return len(p), s.association.sendPayloadData(chunks)
|
||||
}
|
||||
|
||||
func (s *Stream) packetize(raw []byte, ppi PayloadProtocolIdentifier) []*chunkPayloadData {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
i := uint32(0)
|
||||
remaining := uint32(len(raw))
|
||||
|
||||
// From draft-ietf-rtcweb-data-protocol-09, section 6:
|
||||
// All Data Channel Establishment Protocol messages MUST be sent using
|
||||
// ordered delivery and reliable transmission.
|
||||
unordered := ppi != PayloadTypeWebRTCDCEP && s.unordered
|
||||
|
||||
var chunks []*chunkPayloadData
|
||||
var head *chunkPayloadData
|
||||
for remaining != 0 {
|
||||
fragmentSize := min32(s.association.maxPayloadSize, remaining)
|
||||
|
||||
// Copy the userdata since we'll have to store it until acked
|
||||
// and the caller may re-use the buffer in the mean time
|
||||
userData := make([]byte, fragmentSize)
|
||||
copy(userData, raw[i:i+fragmentSize])
|
||||
|
||||
chunk := &chunkPayloadData{
|
||||
streamIdentifier: s.streamIdentifier,
|
||||
userData: userData,
|
||||
unordered: unordered,
|
||||
beginningFragment: i == 0,
|
||||
endingFragment: remaining-fragmentSize == 0,
|
||||
immediateSack: false,
|
||||
payloadType: ppi,
|
||||
streamSequenceNumber: s.sequenceNumber,
|
||||
head: head,
|
||||
}
|
||||
|
||||
if head == nil {
|
||||
head = chunk
|
||||
}
|
||||
|
||||
chunks = append(chunks, chunk)
|
||||
|
||||
remaining -= fragmentSize
|
||||
i += fragmentSize
|
||||
}
|
||||
|
||||
// RFC 4960 Sec 6.6
|
||||
// Note: When transmitting ordered and unordered data, an endpoint does
|
||||
// not increment its Stream Sequence Number when transmitting a DATA
|
||||
// chunk with U flag set to 1.
|
||||
if !unordered {
|
||||
s.sequenceNumber++
|
||||
}
|
||||
|
||||
s.bufferedAmount += uint64(len(raw))
|
||||
s.log.Tracef("[%s] bufferedAmount = %d", s.name, s.bufferedAmount)
|
||||
|
||||
return chunks
|
||||
}
|
||||
|
||||
// Close closes the write-direction of the stream.
|
||||
// Future calls to Write are not permitted after calling Close.
|
||||
func (s *Stream) Close() error {
|
||||
if sid, isOpen := func() (uint16, bool) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
isOpen := true
|
||||
if s.writeErr == nil {
|
||||
s.writeErr = errors.New("Stream closed")
|
||||
} else {
|
||||
isOpen = false
|
||||
}
|
||||
|
||||
if s.readErr == nil {
|
||||
s.readErr = io.EOF
|
||||
} else {
|
||||
isOpen = false
|
||||
}
|
||||
s.readNotifier.Broadcast() // broadcast regardless
|
||||
|
||||
return s.streamIdentifier, isOpen
|
||||
}(); isOpen {
|
||||
// Reset the outgoing stream
|
||||
// https://tools.ietf.org/html/rfc6525
|
||||
return s.association.sendResetRequest(sid)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// BufferedAmount returns the number of bytes of data currently queued to be sent over this stream.
|
||||
func (s *Stream) BufferedAmount() uint64 {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
return s.bufferedAmount
|
||||
}
|
||||
|
||||
// BufferedAmountLowThreshold returns the number of bytes of buffered outgoing data that is
|
||||
// considered "low." Defaults to 0.
|
||||
func (s *Stream) BufferedAmountLowThreshold() uint64 {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
return s.bufferedAmountLow
|
||||
}
|
||||
|
||||
// SetBufferedAmountLowThreshold is used to update the threshold.
|
||||
// See BufferedAmountLowThreshold().
|
||||
func (s *Stream) SetBufferedAmountLowThreshold(th uint64) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
s.bufferedAmountLow = th
|
||||
}
|
||||
|
||||
// OnBufferedAmountLow sets the callback handler which would be called when the number of
|
||||
// bytes of outgoing data buffered is lower than the threshold.
|
||||
func (s *Stream) OnBufferedAmountLow(f func()) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
s.onBufferedAmountLow = f
|
||||
}
|
||||
|
||||
// This method is called by association's readLoop (go-)routine to notify this stream
|
||||
// of the specified amount of outgoing data has been delivered to the peer.
|
||||
func (s *Stream) onBufferReleased(nBytesReleased int) {
|
||||
if nBytesReleased <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
s.lock.Lock()
|
||||
|
||||
fromAmount := s.bufferedAmount
|
||||
|
||||
if s.bufferedAmount < uint64(nBytesReleased) {
|
||||
s.bufferedAmount = 0
|
||||
s.log.Errorf("[%s] released buffer size %d should be <= %d",
|
||||
s.name, nBytesReleased, s.bufferedAmount)
|
||||
} else {
|
||||
s.bufferedAmount -= uint64(nBytesReleased)
|
||||
}
|
||||
|
||||
s.log.Tracef("[%s] bufferedAmount = %d", s.name, s.bufferedAmount)
|
||||
|
||||
if s.onBufferedAmountLow != nil && fromAmount > s.bufferedAmountLow && s.bufferedAmount <= s.bufferedAmountLow {
|
||||
f := s.onBufferedAmountLow
|
||||
s.lock.Unlock()
|
||||
f()
|
||||
return
|
||||
}
|
||||
|
||||
s.lock.Unlock()
|
||||
}
|
||||
|
||||
func (s *Stream) getNumBytesInReassemblyQueue() int {
|
||||
// No lock is required as it reads the size with atomic load function.
|
||||
return s.reassemblyQueue.getNumBytes()
|
||||
}
|
58
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/util.go
generated
vendored
Normal file
58
trunk/3rdparty/srs-bench/vendor/github.com/pion/sctp/util.go
generated
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
package sctp
|
||||
|
||||
const (
|
||||
paddingMultiple = 4
|
||||
)
|
||||
|
||||
func getPadding(len int) int {
|
||||
return (paddingMultiple - (len % paddingMultiple)) % paddingMultiple
|
||||
}
|
||||
|
||||
func padByte(in []byte, cnt int) []byte {
|
||||
if cnt < 0 {
|
||||
cnt = 0
|
||||
}
|
||||
padding := make([]byte, cnt)
|
||||
return append(in, padding...)
|
||||
}
|
||||
|
||||
// Serial Number Arithmetic (RFC 1982)
|
||||
func sna32LT(i1, i2 uint32) bool {
|
||||
return (i1 < i2 && i2-i1 < 1<<31) || (i1 > i2 && i1-i2 > 1<<31)
|
||||
}
|
||||
|
||||
func sna32LTE(i1, i2 uint32) bool {
|
||||
return i1 == i2 || sna32LT(i1, i2)
|
||||
}
|
||||
|
||||
func sna32GT(i1, i2 uint32) bool {
|
||||
return (i1 < i2 && (i2-i1) >= 1<<31) || (i1 > i2 && (i1-i2) <= 1<<31)
|
||||
}
|
||||
|
||||
func sna32GTE(i1, i2 uint32) bool {
|
||||
return i1 == i2 || sna32GT(i1, i2)
|
||||
}
|
||||
|
||||
func sna32EQ(i1, i2 uint32) bool {
|
||||
return i1 == i2
|
||||
}
|
||||
|
||||
func sna16LT(i1, i2 uint16) bool {
|
||||
return (i1 < i2 && (i2-i1) < 1<<15) || (i1 > i2 && (i1-i2) > 1<<15)
|
||||
}
|
||||
|
||||
func sna16LTE(i1, i2 uint16) bool {
|
||||
return i1 == i2 || sna16LT(i1, i2)
|
||||
}
|
||||
|
||||
func sna16GT(i1, i2 uint16) bool {
|
||||
return (i1 < i2 && (i2-i1) >= 1<<15) || (i1 > i2 && (i1-i2) <= 1<<15)
|
||||
}
|
||||
|
||||
func sna16GTE(i1, i2 uint16) bool {
|
||||
return i1 == i2 || sna16GT(i1, i2)
|
||||
}
|
||||
|
||||
func sna16EQ(i1, i2 uint16) bool {
|
||||
return i1 == i2
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue