diff options
author | Sam Whited <sam@samwhited.com> | 2022-03-11 13:22:29 -0500 |
---|---|---|
committer | Sam Whited <sam@samwhited.com> | 2022-03-15 09:26:50 -0400 |
commit | 2d95d4d069124df4a4e2473fc23ad3feed19905d (patch) | |
tree | 4e53db9f07cfda2e17745a6870f294db2d4eb756 /vendor/github.com/pion/sctp | |
parent | c8dc651f72c09ce252cee729bfc09d8ca6744c36 (diff) |
Remove vendor from git
Previously we saved the vendor tree in version control, making any
commit that changed a dependency rather large.
Go Modules gives us most of the advantages of vendoring except that if a
dependency which is not stored on the proxy is deleted we would lose
access to it.
For now, we can remove the vendor tree and when we get CI working again
we can possibly generate and save the vendor tree as a build artifact.
Signed-off-by: Sam Whited <sam@samwhited.com>
Diffstat (limited to 'vendor/github.com/pion/sctp')
54 files changed, 0 insertions, 6633 deletions
diff --git a/vendor/github.com/pion/sctp/.gitignore b/vendor/github.com/pion/sctp/.gitignore deleted file mode 100644 index d39fb86..0000000 --- a/vendor/github.com/pion/sctp/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.sw[poe] diff --git a/vendor/github.com/pion/sctp/.golangci.yml b/vendor/github.com/pion/sctp/.golangci.yml deleted file mode 100644 index 4213697..0000000 --- a/vendor/github.com/pion/sctp/.golangci.yml +++ /dev/null @@ -1,82 +0,0 @@ -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 diff --git a/vendor/github.com/pion/sctp/DESIGN.md b/vendor/github.com/pion/sctp/DESIGN.md deleted file mode 100644 index 02ac161..0000000 --- a/vendor/github.com/pion/sctp/DESIGN.md +++ /dev/null @@ -1,20 +0,0 @@ -<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. diff --git a/vendor/github.com/pion/sctp/LICENSE b/vendor/github.com/pion/sctp/LICENSE deleted file mode 100644 index ab60297..0000000 --- a/vendor/github.com/pion/sctp/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -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. diff --git a/vendor/github.com/pion/sctp/README.md b/vendor/github.com/pion/sctp/README.md deleted file mode 100644 index 18b5693..0000000 --- a/vendor/github.com/pion/sctp/README.md +++ /dev/null @@ -1,54 +0,0 @@ -<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 diff --git a/vendor/github.com/pion/sctp/ack_timer.go b/vendor/github.com/pion/sctp/ack_timer.go deleted file mode 100644 index ba23d54..0000000 --- a/vendor/github.com/pion/sctp/ack_timer.go +++ /dev/null @@ -1,105 +0,0 @@ -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) -} diff --git a/vendor/github.com/pion/sctp/association.go b/vendor/github.com/pion/sctp/association.go deleted file mode 100644 index 1393cb8..0000000 --- a/vendor/github.com/pion/sctp/association.go +++ /dev/null @@ -1,2241 +0,0 @@ -package sctp - -import ( - "bytes" - "fmt" - "io" - "math" - "net" - "sync" - "sync/atomic" - "time" - - "github.com/pion/logging" - "github.com/pion/randutil" - "github.com/pkg/errors" -) - -// Use global random generator to properly seed by crypto grade random. -var ( - globalMathRandomGenerator = randutil.NewMathRandomGenerator() // nolint:gochecknoglobals - errChunk = errors.New("Abort chunk, with following errors") -) - -const ( - receiveMTU uint32 = 8192 // MTU for inbound packet (from DTLS) - initialMTU uint32 = 1228 // initial MTU for outgoing packets (to DTLS) - initialRecvBufSize uint32 = 1024 * 1024 - commonHeaderSize uint32 = 12 - dataChunkHeaderSize uint32 = 16 - defaultMaxMessageSize uint32 = 65536 -) - -// association state enums -const ( - closed uint32 = iota - cookieWait - cookieEchoed - established - shutdownAckSent - shutdownPending - shutdownReceived - shutdownSent -) - -// retransmission timer IDs -const ( - timerT1Init int = iota - timerT1Cookie - timerT3RTX - timerReconfig -) - -// ack mode (for testing) -const ( - ackModeNormal int = iota - ackModeNoDelay - ackModeAlwaysDelay -) - -// ack transmission state -const ( - ackStateIdle int = iota // ack timer is off - ackStateImmediate // ack timer is on (ack is being delayed) - ackStateDelay // will send ack immediately -) - -// other constants -const ( - acceptChSize = 16 -) - -func getAssociationStateString(a uint32) string { - switch a { - case closed: - return "Closed" - case cookieWait: - return "CookieWait" - case cookieEchoed: - return "CookieEchoed" - case established: - return "Established" - case shutdownPending: - return "ShutdownPending" - case shutdownSent: - return "ShutdownSent" - case shutdownReceived: - return "ShutdownReceived" - case shutdownAckSent: - return "ShutdownAckSent" - default: - return fmt.Sprintf("Invalid association state %d", a) - } -} - -// Association represents an SCTP association -// 13.2. Parameters Necessary per Association (i.e., the TCB) -// Peer : Tag value to be sent in every packet and is received -// Verification: in the INIT or INIT ACK chunk. -// Tag : -// -// My : Tag expected in every inbound packet and sent in the -// Verification: INIT or INIT ACK chunk. -// -// Tag : -// State : A state variable indicating what state the association -// : is in, i.e., COOKIE-WAIT, COOKIE-ECHOED, ESTABLISHED, -// : SHUTDOWN-PENDING, SHUTDOWN-SENT, SHUTDOWN-RECEIVED, -// : SHUTDOWN-ACK-SENT. -// -// Note: No "CLOSED" state is illustrated since if a -// association is "CLOSED" its TCB SHOULD be removed. -type Association struct { - bytesReceived uint64 - bytesSent uint64 - - lock sync.RWMutex - - netConn net.Conn - - peerVerificationTag uint32 - myVerificationTag uint32 - state uint32 - myNextTSN uint32 // nextTSN - peerLastTSN uint32 // lastRcvdTSN - minTSN2MeasureRTT uint32 // for RTT measurement - willSendForwardTSN bool - willRetransmitFast bool - willRetransmitReconfig bool - - // Reconfig - myNextRSN uint32 - reconfigs map[uint32]*chunkReconfig - reconfigRequests map[uint32]*paramOutgoingResetRequest - - // Non-RFC internal data - sourcePort uint16 - destinationPort uint16 - myMaxNumInboundStreams uint16 - myMaxNumOutboundStreams uint16 - myCookie *paramStateCookie - payloadQueue *payloadQueue - inflightQueue *payloadQueue - pendingQueue *pendingQueue - controlQueue *controlQueue - mtu uint32 - maxPayloadSize uint32 // max DATA chunk payload size - cumulativeTSNAckPoint uint32 - advancedPeerTSNAckPoint uint32 - useForwardTSN bool - - // Congestion control parameters - maxReceiveBufferSize uint32 - maxMessageSize uint32 - cwnd uint32 // my congestion window size - rwnd uint32 // calculated peer's receiver windows size - ssthresh uint32 // slow start threshold - partialBytesAcked uint32 - inFastRecovery bool - fastRecoverExitPoint uint32 - - // RTX & Ack timer - rtoMgr *rtoManager - t1Init *rtxTimer - t1Cookie *rtxTimer - t3RTX *rtxTimer - tReconfig *rtxTimer - ackTimer *ackTimer - - // Chunks stored for retransmission - storedInit *chunkInit - storedCookieEcho *chunkCookieEcho - - streams map[uint16]*Stream - acceptCh chan *Stream - readLoopCloseCh chan struct{} - awakeWriteLoopCh chan struct{} - closeWriteLoopCh chan struct{} - handshakeCompletedCh chan error - - closeWriteLoopOnce sync.Once - - // local error - silentError error - - ackState int - ackMode int // for testing - - // stats - stats *associationStats - - // per inbound packet context - delayedAckTriggered bool - immediateAckTriggered bool - - name string - log logging.LeveledLogger -} - -// Config collects the arguments to createAssociation construction into -// a single structure -type Config struct { - NetConn net.Conn - MaxReceiveBufferSize uint32 - MaxMessageSize uint32 - LoggerFactory logging.LoggerFactory -} - -// Server accepts a SCTP stream over a conn -func Server(config Config) (*Association, error) { - a := createAssociation(config) - a.init(false) - - select { - case err := <-a.handshakeCompletedCh: - if err != nil { - return nil, err - } - return a, nil - case <-a.readLoopCloseCh: - return nil, errors.Errorf("association closed before connecting") - } -} - -// Client opens a SCTP stream over a conn -func Client(config Config) (*Association, error) { - a := createAssociation(config) - a.init(true) - - select { - case err := <-a.handshakeCompletedCh: - if err != nil { - return nil, err - } - return a, nil - case <-a.readLoopCloseCh: - return nil, errors.Errorf("association closed before connecting") - } -} - -func createAssociation(config Config) *Association { - var maxReceiveBufferSize uint32 - if config.MaxReceiveBufferSize == 0 { - maxReceiveBufferSize = initialRecvBufSize - } else { - maxReceiveBufferSize = config.MaxReceiveBufferSize - } - - var maxMessageSize uint32 - if config.MaxMessageSize == 0 { - maxMessageSize = defaultMaxMessageSize - } else { - maxMessageSize = config.MaxMessageSize - } - - tsn := globalMathRandomGenerator.Uint32() - a := &Association{ - netConn: config.NetConn, - maxReceiveBufferSize: maxReceiveBufferSize, - maxMessageSize: maxMessageSize, - myMaxNumOutboundStreams: math.MaxUint16, - myMaxNumInboundStreams: math.MaxUint16, - payloadQueue: newPayloadQueue(), - inflightQueue: newPayloadQueue(), - pendingQueue: newPendingQueue(), - controlQueue: newControlQueue(), - mtu: initialMTU, - maxPayloadSize: initialMTU - (commonHeaderSize + dataChunkHeaderSize), - myVerificationTag: globalMathRandomGenerator.Uint32(), - myNextTSN: tsn, - myNextRSN: tsn, - minTSN2MeasureRTT: tsn, - state: closed, - rtoMgr: newRTOManager(), - streams: map[uint16]*Stream{}, - reconfigs: map[uint32]*chunkReconfig{}, - reconfigRequests: map[uint32]*paramOutgoingResetRequest{}, - acceptCh: make(chan *Stream, acceptChSize), - readLoopCloseCh: make(chan struct{}), - awakeWriteLoopCh: make(chan struct{}, 1), - closeWriteLoopCh: make(chan struct{}), - handshakeCompletedCh: make(chan error), - cumulativeTSNAckPoint: tsn - 1, - advancedPeerTSNAckPoint: tsn - 1, - silentError: errors.Errorf("silently discard"), - stats: &associationStats{}, - log: config.LoggerFactory.NewLogger("sctp"), - } - - a.name = fmt.Sprintf("%p", a) - - // RFC 4690 Sec 7.2.1 - // o The initial cwnd before DATA transmission or after a sufficiently - // long idle period MUST be set to min(4*MTU, max (2*MTU, 4380 - // bytes)). - a.cwnd = min32(4*a.mtu, max32(2*a.mtu, 4380)) - a.log.Tracef("[%s] updated cwnd=%d ssthresh=%d inflight=%d (INI)", - a.name, a.cwnd, a.ssthresh, a.inflightQueue.getNumBytes()) - - a.t1Init = newRTXTimer(timerT1Init, a, maxInitRetrans) - a.t1Cookie = newRTXTimer(timerT1Cookie, a, maxInitRetrans) - a.t3RTX = newRTXTimer(timerT3RTX, a, noMaxRetrans) // retransmit forever - a.tReconfig = newRTXTimer(timerReconfig, a, noMaxRetrans) // retransmit forever - a.ackTimer = newAckTimer(a) - - return a -} - -func (a *Association) init(isClient bool) { - a.lock.Lock() - defer a.lock.Unlock() - - go a.readLoop() - go a.writeLoop() - - if isClient { - a.setState(cookieWait) - init := &chunkInit{} - init.initialTSN = a.myNextTSN - init.numOutboundStreams = a.myMaxNumOutboundStreams - init.numInboundStreams = a.myMaxNumInboundStreams - init.initiateTag = a.myVerificationTag - init.advertisedReceiverWindowCredit = a.maxReceiveBufferSize - setSupportedExtensions(&init.chunkInitCommon) - a.storedInit = init - - err := a.sendInit() - if err != nil { - a.log.Errorf("[%s] failed to send init: %s", a.name, err.Error()) - } - - a.t1Init.start(a.rtoMgr.getRTO()) - } -} - -// caller must hold a.lock -func (a *Association) sendInit() error { - a.log.Debugf("[%s] sending INIT", a.name) - if a.storedInit == nil { - return errors.Errorf("the init not stored to send") - } - - outbound := &packet{} - outbound.verificationTag = a.peerVerificationTag - a.sourcePort = 5000 // Spec?? - a.destinationPort = 5000 // Spec?? - outbound.sourcePort = a.sourcePort - outbound.destinationPort = a.destinationPort - - outbound.chunks = []chunk{a.storedInit} - - a.controlQueue.push(outbound) - a.awakeWriteLoop() - - return nil -} - -// caller must hold a.lock -func (a *Association) sendCookieEcho() error { - if a.storedCookieEcho == nil { - return errors.Errorf("cookieEcho not stored to send") - } - - a.log.Debugf("[%s] sending COOKIE-ECHO", a.name) - - outbound := &packet{} - outbound.verificationTag = a.peerVerificationTag - outbound.sourcePort = a.sourcePort - outbound.destinationPort = a.destinationPort - outbound.chunks = []chunk{a.storedCookieEcho} - - a.controlQueue.push(outbound) - a.awakeWriteLoop() - - return nil -} - -// Close ends the SCTP Association and cleans up any state -func (a *Association) Close() error { - a.log.Debugf("[%s] closing association..", a.name) - - a.setState(closed) - - err := a.netConn.Close() - - a.closeAllTimers() - - // awake writeLoop to exit - a.closeWriteLoopOnce.Do(func() { close(a.closeWriteLoopCh) }) - - // Wait for readLoop to end - <-a.readLoopCloseCh - - a.log.Debugf("[%s] association closed", a.name) - a.log.Debugf("[%s] stats nDATAs (in) : %d", a.name, a.stats.getNumDATAs()) - a.log.Debugf("[%s] stats nSACKs (in) : %d", a.name, a.stats.getNumSACKs()) - a.log.Debugf("[%s] stats nT3Timeouts : %d", a.name, a.stats.getNumT3Timeouts()) - a.log.Debugf("[%s] stats nAckTimeouts: %d", a.name, a.stats.getNumAckTimeouts()) - a.log.Debugf("[%s] stats nFastRetrans: %d", a.name, a.stats.getNumFastRetrans()) - return err -} - -func (a *Association) closeAllTimers() { - // Close all retransmission & ack timers - a.t1Init.close() - a.t1Cookie.close() - a.t3RTX.close() - a.tReconfig.close() - a.ackTimer.close() -} - -func (a *Association) readLoop() { - var closeErr error - defer func() { - // also stop writeLoop, otherwise writeLoop can be leaked - // if connection is lost when there is no writing packet. - a.closeWriteLoopOnce.Do(func() { close(a.closeWriteLoopCh) }) - - a.lock.Lock() - for _, s := range a.streams { - a.unregisterStream(s, closeErr) - } - a.lock.Unlock() - close(a.acceptCh) - close(a.readLoopCloseCh) - }() - - a.log.Debugf("[%s] readLoop entered", a.name) - buffer := make([]byte, receiveMTU) - - for { - n, err := a.netConn.Read(buffer) - if err != nil { - closeErr = err - break - } - // Make a buffer sized to what we read, then copy the data we - // read from the underlying transport. We do this because the - // user data is passed to the reassembly queue without - // copying. - inbound := make([]byte, n) - copy(inbound, buffer[:n]) - atomic.AddUint64(&a.bytesReceived, uint64(n)) - if err = a.handleInbound(inbound); err != nil { - closeErr = err - break - } - } - - a.log.Debugf("[%s] readLoop exited %s", a.name, closeErr) -} - -func (a *Association) writeLoop() { - a.log.Debugf("[%s] writeLoop entered", a.name) - -loop: - for { - rawPackets := a.gatherOutbound() - - for _, raw := range rawPackets { - _, err := a.netConn.Write(raw) - if err != nil { - if err != io.EOF { - a.log.Warnf("[%s] failed to write packets on netConn: %v", a.name, err) - } - a.log.Debugf("[%s] writeLoop ended", a.name) - break loop - } - atomic.AddUint64(&a.bytesSent, uint64(len(raw))) - } - - select { - case <-a.awakeWriteLoopCh: - case <-a.closeWriteLoopCh: - break loop - } - } - - a.setState(closed) - a.closeAllTimers() - - a.log.Debugf("[%s] writeLoop exited", a.name) -} - -func (a *Association) awakeWriteLoop() { - select { - case a.awakeWriteLoopCh <- struct{}{}: - default: - } -} - -// unregisterStream un-registers a stream from the association -// The caller should hold the association write lock. -func (a *Association) unregisterStream(s *Stream, err error) { - s.lock.Lock() - defer s.lock.Unlock() - - delete(a.streams, s.streamIdentifier) - s.readErr = err - s.readNotifier.Broadcast() -} - -// handleInbound parses incoming raw packets -func (a *Association) handleInbound(raw []byte) error { - p := &packet{} - if err := p.unmarshal(raw); err != nil { - a.log.Warnf("[%s] unable to parse SCTP packet %s", a.name, err) - return nil - } - - if err := checkPacket(p); err != nil { - a.log.Warnf("[%s] failed validating packet %s", a.name, err) - return nil - } - - a.handleChunkStart() - - for _, c := range p.chunks { - if err := a.handleChunk(p, c); err != nil { - return err - } - } - - a.handleChunkEnd() - - return nil -} - -// The caller should hold the lock -func (a *Association) gatherOutboundDataAndReconfigPackets(rawPackets [][]byte) [][]byte { - for _, p := range a.getDataPacketsToRetransmit() { - raw, err := p.marshal() - if err != nil { - a.log.Warnf("[%s] failed to serialize a DATA packet to be retransmitted", a.name) - continue - } - rawPackets = append(rawPackets, raw) - } - - // Pop unsent data chunks from the pending queue to send as much as - // cwnd and rwnd allow. - chunks, sisToReset := a.popPendingDataChunksToSend() - if len(chunks) > 0 { - // Start timer. (noop if already started) - a.log.Tracef("[%s] T3-rtx timer start (pt1)", a.name) - a.t3RTX.start(a.rtoMgr.getRTO()) - for _, p := range a.bundleDataChunksIntoPackets(chunks) { - raw, err := p.marshal() - if err != nil { - a.log.Warnf("[%s] failed to serialize a DATA packet", a.name) - continue - } - rawPackets = append(rawPackets, raw) - } - } - - if len(sisToReset) > 0 || a.willRetransmitReconfig { - if a.willRetransmitReconfig { - a.willRetransmitReconfig = false - a.log.Debugf("[%s] retransmit %d RECONFIG chunk(s)", a.name, len(a.reconfigs)) - for _, c := range a.reconfigs { - p := a.createPacket([]chunk{c}) - raw, err := p.marshal() - if err != nil { - a.log.Warnf("[%s] failed to serialize a RECONFIG packet to be retransmitted", a.name) - } else { - rawPackets = append(rawPackets, raw) - } - } - } - - if len(sisToReset) > 0 { - rsn := a.generateNextRSN() - tsn := a.myNextTSN - 1 - c := &chunkReconfig{ - paramA: ¶mOutgoingResetRequest{ - reconfigRequestSequenceNumber: rsn, - senderLastTSN: tsn, - streamIdentifiers: sisToReset, - }, - } - a.reconfigs[rsn] = c // store in the map for retransmission - a.log.Debugf("[%s] sending RECONFIG: rsn=%d tsn=%d streams=%v", - a.name, rsn, a.myNextTSN-1, sisToReset) - p := a.createPacket([]chunk{c}) - raw, err := p.marshal() - if err != nil { - a.log.Warnf("[%s] failed to serialize a RECONFIG packet to be transmitted", a.name) - } else { - rawPackets = append(rawPackets, raw) - } - } - - if len(a.reconfigs) > 0 { - a.tReconfig.start(a.rtoMgr.getRTO()) - } - } - - return rawPackets -} - -// The caller should hold the lock -func (a *Association) gatherOutboundFrastRetransmissionPackets(rawPackets [][]byte) [][]byte { - if a.willRetransmitFast { - a.willRetransmitFast = false - - toFastRetrans := []chunk{} - fastRetransSize := commonHeaderSize - - for i := 0; ; i++ { - c, ok := a.inflightQueue.get(a.cumulativeTSNAckPoint + uint32(i) + 1) - if !ok { - break // end of pending data - } - - if c.acked || c.abandoned() { - continue - } - - if c.nSent > 1 || c.missIndicator < 3 { - continue - } - - // RFC 4960 Sec 7.2.4 Fast Retransmit on Gap Reports - // 3) Determine how many of the earliest (i.e., lowest TSN) DATA chunks - // marked for retransmission will fit into a single packet, subject - // to constraint of the path MTU of the destination transport - // address to which the packet is being sent. Call this value K. - // Retransmit those K DATA chunks in a single packet. When a Fast - // Retransmit is being performed, the sender SHOULD ignore the value - // of cwnd and SHOULD NOT delay retransmission for this single - // packet. - - dataChunkSize := dataChunkHeaderSize + uint32(len(c.userData)) - if a.mtu < fastRetransSize+dataChunkSize { - break - } - - fastRetransSize += dataChunkSize - a.stats.incFastRetrans() - c.nSent++ - a.checkPartialReliabilityStatus(c) - toFastRetrans = append(toFastRetrans, c) - a.log.Tracef("[%s] fast-retransmit: tsn=%d sent=%d htna=%d", - a.name, c.tsn, c.nSent, a.fastRecoverExitPoint) - } - - if len(toFastRetrans) > 0 { - raw, err := a.createPacket(toFastRetrans).marshal() - if err != nil { - a.log.Warnf("[%s] failed to serialize a DATA packet to be fast-retransmitted", a.name) - } else { - rawPackets = append(rawPackets, raw) - } - } - } - - return rawPackets -} - -// The caller should hold the lock -func (a *Association) gatherOutboundSackPackets(rawPackets [][]byte) [][]byte { - if a.ackState == ackStateImmediate { - a.ackState = ackStateIdle - sack := a.createSelectiveAckChunk() - a.log.Debugf("[%s] sending SACK: %s", a.name, sack.String()) - raw, err := a.createPacket([]chunk{sack}).marshal() - if err != nil { - a.log.Warnf("[%s] failed to serialize a SACK packet", a.name) - } else { - rawPackets = append(rawPackets, raw) - } - } - - return rawPackets -} - -// The caller should hold the lock -func (a *Association) gatherOutboundForwardTSNPackets(rawPackets [][]byte) [][]byte { - if a.willSendForwardTSN { - a.willSendForwardTSN = false - if sna32GT(a.advancedPeerTSNAckPoint, a.cumulativeTSNAckPoint) { - fwdtsn := a.createForwardTSN() - raw, err := a.createPacket([]chunk{fwdtsn}).marshal() - if err != nil { - a.log.Warnf("[%s] failed to serialize a Forward TSN packet", a.name) - } else { - rawPackets = append(rawPackets, raw) - } - } - } - - return rawPackets -} - -// gatherOutbound gathers outgoing packets -func (a *Association) gatherOutbound() [][]byte { - a.lock.Lock() - defer a.lock.Unlock() - - rawPackets := [][]byte{} - - if a.controlQueue.size() > 0 { - for _, p := range a.controlQueue.popAll() { - raw, err := p.marshal() - if err != nil { - a.log.Warnf("[%s] failed to serialize a control packet", a.name) - continue - } - rawPackets = append(rawPackets, raw) - } - } - - state := a.getState() - - if state == established { - rawPackets = a.gatherOutboundDataAndReconfigPackets(rawPackets) - rawPackets = a.gatherOutboundFrastRetransmissionPackets(rawPackets) - rawPackets = a.gatherOutboundSackPackets(rawPackets) - rawPackets = a.gatherOutboundForwardTSNPackets(rawPackets) - } - - return rawPackets -} - -func checkPacket(p *packet) error { - // All packets must adhere to these rules - - // This is the SCTP sender's port number. It can be used by the - // receiver in combination with the source IP address, the SCTP - // destination port, and possibly the destination IP address to - // identify the association to which this packet belongs. The port - // number 0 MUST NOT be used. - if p.sourcePort == 0 { - return errors.Errorf("sctp packet must not have a source port of 0") - } - - // This is the SCTP port number to which this packet is destined. - // The receiving host will use this port number to de-multiplex the - // SCTP packet to the correct receiving endpoint/application. The - // port number 0 MUST NOT be used. - if p.destinationPort == 0 { - return errors.Errorf("sctp packet must not have a destination port of 0") - } - - // Check values on the packet that are specific to a particular chunk type - for _, c := range p.chunks { - switch c.(type) { // nolint:gocritic - case *chunkInit: - // An INIT or INIT ACK chunk MUST NOT be bundled with any other chunk. - // They MUST be the only chunks present in the SCTP packets that carry - // them. - if len(p.chunks) != 1 { - return errors.Errorf("init chunk must not be bundled with any other chunk") - } - - // A packet containing an INIT chunk MUST have a zero Verification - // Tag. - if p.verificationTag != 0 { - return errors.Errorf("init chunk expects a verification tag of 0 on the packet when out-of-the-blue") - } - } - } - - return nil -} - -func min16(a, b uint16) uint16 { - if a < b { - return a - } - return b -} - -func max32(a, b uint32) uint32 { - if a > b { - return a - } - return b -} - -func min32(a, b uint32) uint32 { - if a < b { - return a - } - return b -} - -// setState atomically sets the state of the Association. -// The caller should hold the lock. -func (a *Association) setState(newState uint32) { - oldState := atomic.SwapUint32(&a.state, newState) - if newState != oldState { - a.log.Debugf("[%s] state change: '%s' => '%s'", - a.name, - getAssociationStateString(oldState), - getAssociationStateString(newState)) - } -} - -// getState atomically returns the state of the Association. -func (a *Association) getState() uint32 { - return atomic.LoadUint32(&a.state) -} - -// BytesSent returns the number of bytes sent -func (a *Association) BytesSent() uint64 { - return atomic.LoadUint64(&a.bytesSent) -} - -// BytesReceived returns the number of bytes received -func (a *Association) BytesReceived() uint64 { - return atomic.LoadUint64(&a.bytesReceived) -} - -func setSupportedExtensions(init *chunkInitCommon) { - // nolint:godox - // TODO RFC5061 https://tools.ietf.org/html/rfc6525#section-5.2 - // An implementation supporting this (Supported Extensions Parameter) - // extension MUST list the ASCONF, the ASCONF-ACK, and the AUTH chunks - // in its INIT and INIT-ACK parameters. - init.params = append(init.params, ¶mSupportedExtensions{ - ChunkTypes: []chunkType{ctReconfig, ctForwardTSN}, - }) -} - -// The caller should hold the lock. -func (a *Association) handleInit(p *packet, i *chunkInit) ([]*packet, error) { - state := a.getState() - a.log.Debugf("[%s] chunkInit received in state '%s'", a.name, getAssociationStateString(state)) - - // https://tools.ietf.org/html/rfc4960#section-5.2.1 - // Upon receipt of an INIT in the COOKIE-WAIT state, an endpoint MUST - // respond with an INIT ACK using the same parameters it sent in its - // original INIT chunk (including its Initiate Tag, unchanged). When - // responding, the endpoint MUST send the INIT ACK back to the same - // address that the original INIT (sent by this endpoint) was sent. - - if state != closed && state != cookieWait && state != cookieEchoed { - // 5.2.2. Unexpected INIT in States Other than CLOSED, COOKIE-ECHOED, - // COOKIE-WAIT, and SHUTDOWN-ACK-SENT - return nil, errors.Errorf("todo: handle Init when in state %s", getAssociationStateString(state)) - } - - // Should we be setting any of these permanently until we've ACKed further? - a.myMaxNumInboundStreams = min16(i.numInboundStreams, a.myMaxNumInboundStreams) - a.myMaxNumOutboundStreams = min16(i.numOutboundStreams, a.myMaxNumOutboundStreams) - a.peerVerificationTag = i.initiateTag - a.sourcePort = p.destinationPort - a.destinationPort = p.sourcePort - - // 13.2 This is the last TSN received in sequence. This value - // is set initially by taking the peer's initial TSN, - // received in the INIT or INIT ACK chunk, and - // subtracting one from it. - a.peerLastTSN = i.initialTSN - 1 - - for _, param := range i.params { - switch v := param.(type) { // nolint:gocritic - case *paramSupportedExtensions: - for _, t := range v.ChunkTypes { - if t == ctForwardTSN { - a.log.Debugf("[%s] use ForwardTSN (on init)\n", a.name) - a.useForwardTSN = true - } - } - } - } - if !a.useForwardTSN { - a.log.Warnf("[%s] not using ForwardTSN (on init)\n", a.name) - } - - outbound := &packet{} - outbound.verificationTag = a.peerVerificationTag - outbound.sourcePort = a.sourcePort - outbound.destinationPort = a.destinationPort - - initAck := &chunkInitAck{} - - initAck.initialTSN = a.myNextTSN - initAck.numOutboundStreams = a.myMaxNumOutboundStreams - initAck.numInboundStreams = a.myMaxNumInboundStreams - initAck.initiateTag = a.myVerificationTag - initAck.advertisedReceiverWindowCredit = a.maxReceiveBufferSize - - if a.myCookie == nil { - var err error - if a.myCookie, err = newRandomStateCookie(); err != nil { - return nil, err - } - } - - initAck.params = []param{a.myCookie} - - setSupportedExtensions(&initAck.chunkInitCommon) - - outbound.chunks = []chunk{initAck} - - return pack(outbound), nil -} - -// The caller should hold the lock. -func (a *Association) handleInitAck(p *packet, i *chunkInitAck) error { - state := a.getState() - a.log.Debugf("[%s] chunkInitAck received in state '%s'", a.name, getAssociationStateString(state)) - if state != cookieWait { - // RFC 4960 - // 5.2.3. Unexpected INIT ACK - // If an INIT ACK is received by an endpoint in any state other than the - // COOKIE-WAIT state, the endpoint should discard the INIT ACK chunk. - // An unexpected INIT ACK usually indicates the processing of an old or - // duplicated INIT chunk. - return nil - } - - a.myMaxNumInboundStreams = min16(i.numInboundStreams, a.myMaxNumInboundStreams) - a.myMaxNumOutboundStreams = min16(i.numOutboundStreams, a.myMaxNumOutboundStreams) - a.peerVerificationTag = i.initiateTag - a.peerLastTSN = i.initialTSN - 1 - if a.sourcePort != p.destinationPort || - a.destinationPort != p.sourcePort { - a.log.Warnf("[%s] handleInitAck: port mismatch", a.name) - return nil - } - - a.rwnd = i.advertisedReceiverWindowCredit - a.log.Debugf("[%s] initial rwnd=%d", a.name, a.rwnd) - - // RFC 4690 Sec 7.2.1 - // o The initial value of ssthresh MAY be arbitrarily high (for - // example, implementations MAY use the size of the receiver - // advertised window). - a.ssthresh = a.rwnd - a.log.Tracef("[%s] updated cwnd=%d ssthresh=%d inflight=%d (INI)", - a.name, a.cwnd, a.ssthresh, a.inflightQueue.getNumBytes()) - - a.t1Init.stop() - a.storedInit = nil - - var cookieParam *paramStateCookie - for _, param := range i.params { - switch v := param.(type) { - case *paramStateCookie: - cookieParam = v - case *paramSupportedExtensions: - for _, t := range v.ChunkTypes { - if t == ctForwardTSN { - a.log.Debugf("[%s] use ForwardTSN (on initAck)\n", a.name) - a.useForwardTSN = true - } - } - } - } - if !a.useForwardTSN { - a.log.Warnf("[%s] not using ForwardTSN (on initAck)\n", a.name) - } - if cookieParam == nil { - return errors.Errorf("no cookie in InitAck") - } - - a.storedCookieEcho = &chunkCookieEcho{} - a.storedCookieEcho.cookie = cookieParam.cookie - - err := a.sendCookieEcho() - if err != nil { - a.log.Errorf("[%s] failed to send init: %s", a.name, err.Error()) - } - - a.t1Cookie.start(a.rtoMgr.getRTO()) - a.setState(cookieEchoed) - return nil -} - -// The caller should hold the lock. -func (a *Association) handleHeartbeat(c *chunkHeartbeat) []*packet { - a.log.Tracef("[%s] chunkHeartbeat", a.name) - hbi, ok := c.params[0].(*paramHeartbeatInfo) - if !ok { - a.log.Warnf("[%s] failed to handle Heartbeat, no ParamHeartbeatInfo", a.name) - } - - return pack(&packet{ - verificationTag: a.peerVerificationTag, - sourcePort: a.sourcePort, - destinationPort: a.destinationPort, - chunks: []chunk{&chunkHeartbeatAck{ - params: []param{ - ¶mHeartbeatInfo{ - heartbeatInformation: hbi.heartbeatInformation, - }, - }, - }}, - }) -} - -// The caller should hold the lock. -func (a *Association) handleCookieEcho(c *chunkCookieEcho) []*packet { - state := a.getState() - a.log.Debugf("[%s] COOKIE-ECHO received in state '%s'", a.name, getAssociationStateString(state)) - switch state { - default: - return nil - case established: - if !bytes.Equal(a.myCookie.cookie, c.cookie) { - return nil - } - case closed, cookieWait, cookieEchoed: - if !bytes.Equal(a.myCookie.cookie, c.cookie) { - return nil - } - - a.t1Init.stop() - a.storedInit = nil - - a.t1Cookie.stop() - a.storedCookieEcho = nil - - a.setState(established) - a.handshakeCompletedCh <- nil - } - - p := &packet{ - verificationTag: a.peerVerificationTag, - sourcePort: a.sourcePort, - destinationPort: a.destinationPort, - chunks: []chunk{&chunkCookieAck{}}, - } - return pack(p) -} - -// The caller should hold the lock. -func (a *Association) handleCookieAck() { - state := a.getState() - a.log.Debugf("[%s] COOKIE-ACK received in state '%s'", a.name, getAssociationStateString(state)) - if state != cookieEchoed { - // RFC 4960 - // 5.2.5. Handle Duplicate COOKIE-ACK. - // At any state other than COOKIE-ECHOED, an endpoint should silently - // discard a received COOKIE ACK chunk. - return - } - - a.t1Cookie.stop() - a.storedCookieEcho = nil - - a.setState(established) - a.handshakeCompletedCh <- nil -} - -// The caller should hold the lock. -func (a *Association) handleData(d *chunkPayloadData) []*packet { - a.log.Tracef("[%s] DATA: tsn=%d immediateSack=%v len=%d", - a.name, d.tsn, d.immediateSack, len(d.userData)) - a.stats.incDATAs() - - canPush := a.payloadQueue.canPush(d, a.peerLastTSN) - if canPush { - s := a.getOrCreateStream(d.streamIdentifier) - if s == nil { - // silentely discard the data. (sender will retry on T3-rtx timeout) - // see pion/sctp#30 - a.log.Debugf("discard %d", d.streamSequenceNumber) - return nil - } - - if a.getMyReceiverWindowCredit() > 0 { - // Pass the new chunk to stream level as soon as it arrives - a.payloadQueue.push(d, a.peerLastTSN) - s.handleData(d) - } else { - // Receive buffer is full - lastTSN, ok := a.payloadQueue.getLastTSNReceived() - if ok && sna32LT(d.tsn, lastTSN) { - a.log.Debugf("[%s] receive buffer full, but accepted as this is a missing chunk with tsn=%d ssn=%d", a.name, d.tsn, d.streamSequenceNumber) - a.payloadQueue.push(d, a.peerLastTSN) - s.handleData(d) - } else { - a.log.Debugf("[%s] receive buffer full. dropping DATA with tsn=%d ssn=%d", a.name, d.tsn, d.streamSequenceNumber) - } - } - } - - return a.handlePeerLastTSNAndAcknowledgement(d.immediateSack) -} - -// A common routine for handleData and handleForwardTSN routines -// The caller should hold the lock. -func (a *Association) handlePeerLastTSNAndAcknowledgement(sackImmediately bool) []*packet { - var reply []*packet - - // Try to advance peerLastTSN - - // From RFC 3758 Sec 3.6: - // .. and then MUST further advance its cumulative TSN point locally - // if possible - // Meaning, if peerLastTSN+1 points to a chunk that is received, - // advance peerLastTSN until peerLastTSN+1 points to unreceived chunk. - for { - if _, popOk := a.payloadQueue.pop(a.peerLastTSN + 1); !popOk { - break - } - a.peerLastTSN++ - - for _, rstReq := range a.reconfigRequests { - resp := a.resetStreamsIfAny(rstReq) - if resp != nil { - a.log.Debugf("[%s] RESET RESPONSE: %+v", a.name, resp) - reply = append(reply, resp) - } - } - } - - hasPacketLoss := (a.payloadQueue.size() > 0) - if hasPacketLoss { - a.log.Tracef("[%s] packetloss: %s", a.name, a.payloadQueue.getGapAckBlocksString(a.peerLastTSN)) - } - - if (a.ackState != ackStateImmediate && !sackImmediately && !hasPacketLoss && a.ackMode == ackModeNormal) || a.ackMode == ackModeAlwaysDelay { - if a.ackState == ackStateIdle { - a.delayedAckTriggered = true - } else { - a.immediateAckTriggered = true - } - } else { - a.immediateAckTriggered = true - } - - return reply -} - -// The caller should hold the lock. -func (a *Association) getMyReceiverWindowCredit() uint32 { - var bytesQueued uint32 - for _, s := range a.streams { - bytesQueued += uint32(s.getNumBytesInReassemblyQueue()) - } - - if bytesQueued >= a.maxReceiveBufferSize { - return 0 - } - return a.maxReceiveBufferSize - bytesQueued -} - -// OpenStream opens a stream -func (a *Association) OpenStream(streamIdentifier uint16, defaultPayloadType PayloadProtocolIdentifier) (*Stream, error) { - a.lock.Lock() - defer a.lock.Unlock() - - if _, ok := a.streams[streamIdentifier]; ok { - return nil, errors.Errorf("there already exists a stream with identifier %d", streamIdentifier) - } - - s := a.createStream(streamIdentifier, false) - s.setDefaultPayloadType(defaultPayloadType) - - return s, nil -} - -// AcceptStream accepts a stream -func (a *Association) AcceptStream() (*Stream, error) { - s, ok := <-a.acceptCh - if !ok { - return nil, io.EOF // no more incoming streams - } - return s, nil -} - -// createStream creates a stream. The caller should hold the lock and check no stream exists for this id. -func (a *Association) createStream(streamIdentifier uint16, accept bool) *Stream { - s := &Stream{ - association: a, - streamIdentifier: streamIdentifier, - reassemblyQueue: newReassemblyQueue(streamIdentifier), - log: a.log, - name: fmt.Sprintf("%d:%s", streamIdentifier, a.name), - } - - s.readNotifier = sync.NewCond(&s.lock) - - if accept { - select { - case a.acceptCh <- s: - a.streams[streamIdentifier] = s - a.log.Debugf("[%s] accepted a new stream (streamIdentifier: %d)", - a.name, streamIdentifier) - default: - a.log.Debugf("[%s] dropped a new stream (acceptCh size: %d)", - a.name, len(a.acceptCh)) - return nil - } - } else { - a.streams[streamIdentifier] = s - } - - return s -} - -// getOrCreateStream gets or creates a stream. The caller should hold the lock. -func (a *Association) getOrCreateStream(streamIdentifier uint16) *Stream { - if s, ok := a.streams[streamIdentifier]; ok { - return s - } - - return a.createStream(streamIdentifier, true) -} - -// The caller should hold the lock. -func (a *Association) processSelectiveAck(d *chunkSelectiveAck) (map[uint16]int, uint32, error) { // nolint:gocognit - bytesAckedPerStream := map[uint16]int{} - - // New ack point, so pop all ACKed packets from inflightQueue - // We add 1 because the "currentAckPoint" has already been popped from the inflight queue - // For the first SACK we take care of this by setting the ackpoint to cumAck - 1 - for i := a.cumulativeTSNAckPoint + 1; sna32LTE(i, d.cumulativeTSNAck); i++ { - c, ok := a.inflightQueue.pop(i) - if !ok { - return nil, 0, errors.Errorf("tsn %v unable to be popped from inflight queue", i) - } - - if !c.acked { - // RFC 4096 sec 6.3.2. Retransmission Timer Rules - // R3) Whenever a SACK is received that acknowledges the DATA chunk - // with the earliest outstanding TSN for that address, restart the - // T3-rtx timer for that address with its current RTO (if there is - // still outstanding data on that address). - if i == a.cumulativeTSNAckPoint+1 { - // T3 timer needs to be reset. Stop it for now. - a.t3RTX.stop() - } - - nBytesAcked := len(c.userData) - - // Sum the number of bytes acknowledged per stream - if amount, ok := bytesAckedPerStream[c.streamIdentifier]; ok { - bytesAckedPerStream[c.streamIdentifier] = amount + nBytesAcked - } else { - bytesAckedPerStream[c.streamIdentifier] = nBytesAcked - } - - // RFC 4960 sec 6.3.1. RTO Calculation - // C4) When data is in flight and when allowed by rule C5 below, a new - // RTT measurement MUST be made each round trip. Furthermore, new - // RTT measurements SHOULD be made no more than once per round trip - // for a given destination transport address. - // C5) Karn's algorithm: RTT measurements MUST NOT be made using - // packets that were retransmitted (and thus for which it is - // ambiguous whether the reply was for the first instance of the - // chunk or for a later instance) - if c.nSent == 1 && sna32GTE(c.tsn, a.minTSN2MeasureRTT) { - a.minTSN2MeasureRTT = a.myNextTSN - rtt := time.Since(c.since).Seconds() * 1000.0 - srtt := a.rtoMgr.setNewRTT(rtt) - a.log.Tracef("[%s] SACK: measured-rtt=%f srtt=%f new-rto=%f", - a.name, rtt, srtt, a.rtoMgr.getRTO()) - } - } - - if a.inFastRecovery && c.tsn == a.fastRecoverExitPoint { - a.log.Debugf("[%s] exit fast-recovery", a.name) - a.inFastRecovery = false - } - } - - htna := d.cumulativeTSNAck - - // Mark selectively acknowledged chunks as "acked" - for _, g := range d.gapAckBlocks { - for i := g.start; i <= g.end; i++ { - tsn := d.cumulativeTSNAck + uint32(i) - c, ok := a.inflightQueue.get(tsn) - if !ok { - return nil, 0, errors.Errorf("requested non-existent TSN %v", tsn) - } - - if !c.acked { - nBytesAcked := a.inflightQueue.markAsAcked(tsn) - - // Sum the number of bytes acknowledged per stream - if amount, ok := bytesAckedPerStream[c.streamIdentifier]; ok { - bytesAckedPerStream[c.streamIdentifier] = amount + nBytesAcked - } else { - bytesAckedPerStream[c.streamIdentifier] = nBytesAcked - } - - a.log.Tracef("[%s] tsn=%d has been sacked", a.name, c.tsn) - - if c.nSent == 1 { - a.minTSN2MeasureRTT = a.myNextTSN - rtt := time.Since(c.since).Seconds() * 1000.0 - srtt := a.rtoMgr.setNewRTT(rtt) - a.log.Tracef("[%s] SACK: measured-rtt=%f srtt=%f new-rto=%f", - a.name, rtt, srtt, a.rtoMgr.getRTO()) - } - - if sna32LT(htna, tsn) { - htna = tsn - } - } - } - } - - return bytesAckedPerStream, htna, nil -} - -// The caller should hold the lock. -func (a *Association) onCumulativeTSNAckPointAdvanced(totalBytesAcked int) { - // RFC 4096, sec 6.3.2. Retransmission Timer Rules - // R2) Whenever all outstanding data sent to an address have been - // acknowledged, turn off the T3-rtx timer of that address. - if a.inflightQueue.size() == 0 { - a.log.Tracef("[%s] SACK: no more packet in-flight (pending=%d)", a.name, a.pendingQueue.size()) - a.t3RTX.stop() - } else { - a.log.Tracef("[%s] T3-rtx timer start (pt2)", a.name) - a.t3RTX.start(a.rtoMgr.getRTO()) - } - - // Update congestion control parameters - if a.cwnd <= a.ssthresh { - // RFC 4096, sec 7.2.1. Slow-Start - // o When cwnd is less than or equal to ssthresh, an SCTP endpoint MUST - // use the slow-start algorithm to increase cwnd only if the current - // congestion window is being fully utilized, an incoming SACK - // advances the Cumulative TSN Ack Point, and the data sender is not - // in Fast Recovery. Only when these three conditions are met can - // the cwnd be increased; otherwise, the cwnd MUST not be increased. - // If these conditions are met, then cwnd MUST be increased by, at - // most, the lesser of 1) the total size of the previously - // outstanding DATA chunk(s) acknowledged, and 2) the destination's - // path MTU. - if !a.inFastRecovery && - a.pendingQueue.size() > 0 { - a.cwnd += min32(uint32(totalBytesAcked), a.cwnd) // TCP way - // a.cwnd += min32(uint32(totalBytesAcked), a.mtu) // SCTP way (slow) - a.log.Tracef("[%s] updated cwnd=%d ssthresh=%d acked=%d (SS)", - a.name, a.cwnd, a.ssthresh, totalBytesAcked) - } else { - a.log.Tracef("[%s] cwnd did not grow: cwnd=%d ssthresh=%d acked=%d FR=%v pending=%d", - a.name, a.cwnd, a.ssthresh, totalBytesAcked, a.inFastRecovery, a.pendingQueue.size()) - } - } else { - // RFC 4096, sec 7.2.2. Congestion Avoidance - // o Whenever cwnd is greater than ssthresh, upon each SACK arrival - // that advances the Cumulative TSN Ack Point, increase - // partial_bytes_acked by the total number of bytes of all new chunks - // acknowledged in that SACK including chunks acknowledged by the new - // Cumulative TSN Ack and by Gap Ack Blocks. - a.partialBytesAcked += uint32(totalBytesAcked) - - // o When partial_bytes_acked is equal to or greater than cwnd and - // before the arrival of the SACK the sender had cwnd or more bytes - // of data outstanding (i.e., before arrival of the SACK, flight size - // was greater than or equal to cwnd), increase cwnd by MTU, and - // reset partial_bytes_acked to (partial_bytes_acked - cwnd). - if a.partialBytesAcked >= a.cwnd && a.pendingQueue.size() > 0 { - a.partialBytesAcked -= a.cwnd - a.cwnd += a.mtu - a.log.Tracef("[%s] updated cwnd=%d ssthresh=%d acked=%d (CA)", - a.name, a.cwnd, a.ssthresh, totalBytesAcked) - } - } -} - -// The caller should hold the lock. -func (a *Association) processFastRetransmission(cumTSNAckPoint, htna uint32, cumTSNAckPointAdvanced bool) error { - // HTNA algorithm - RFC 4960 Sec 7.2.4 - // Increment missIndicator of each chunks that the SACK reported missing - // when either of the following is met: - // a) Not in fast-recovery - // miss indications are incremented only for missing TSNs prior to the - // highest TSN newly acknowledged in the SACK. - // b) In fast-recovery AND the Cumulative TSN Ack Point advanced - // the miss indications are incremented for all TSNs reported missing - // in the SACK. - if !a.inFastRecovery || (a.inFastRecovery && cumTSNAckPointAdvanced) { - var maxTSN uint32 - if !a.inFastRecovery { - // a) increment only for missing TSNs prior to the HTNA - maxTSN = htna - } else { - // b) increment for all TSNs reported missing - maxTSN = cumTSNAckPoint + uint32(a.inflightQueue.size()) + 1 - } - - for tsn := cumTSNAckPoint + 1; sna32LT(tsn, maxTSN); tsn++ { - c, ok := a.inflightQueue.get(tsn) - if !ok { - return errors.Errorf("requested non-existent TSN %v", tsn) - } - if !c.acked && !c.abandoned() && c.missIndicator < 3 { - c.missIndicator++ - if c.missIndicator == 3 { - if !a.inFastRecovery { - // 2) If not in Fast Recovery, adjust the ssthresh and cwnd of the - // destination address(es) to which the missing DATA chunks were - // last sent, according to the formula described in Section 7.2.3. - a.inFastRecovery = true - a.fastRecoverExitPoint = htna - a.ssthresh = max32(a.cwnd/2, 4*a.mtu) - a.cwnd = a.ssthresh - a.partialBytesAcked = 0 - a.willRetransmitFast = true - - a.log.Tracef("[%s] updated cwnd=%d ssthresh=%d inflight=%d (FR)", - a.name, a.cwnd, a.ssthresh, a.inflightQueue.getNumBytes()) - } - } - } - } - } - - if a.inFastRecovery && cumTSNAckPointAdvanced { - a.willRetransmitFast = true - } - - return nil -} - -// The caller should hold the lock. -func (a *Association) handleSack(d *chunkSelectiveAck) error { - a.log.Tracef("[%s] SACK: cumTSN=%d a_rwnd=%d", a.name, d.cumulativeTSNAck, d.advertisedReceiverWindowCredit) - state := a.getState() - if state != established { - return nil - } - - a.stats.incSACKs() - - if sna32GT(a.cumulativeTSNAckPoint, d.cumulativeTSNAck) { - // RFC 4960 sec 6.2.1. Processing a Received SACK - // D) - // i) If Cumulative TSN Ack is less than the Cumulative TSN Ack - // Point, then drop the SACK. Since Cumulative TSN Ack is - // monotonically increasing, a SACK whose Cumulative TSN Ack is - // less than the Cumulative TSN Ack Point indicates an out-of- - // order SACK. - - a.log.Debugf("[%s] SACK Cumulative ACK %v is older than ACK point %v", - a.name, - d.cumulativeTSNAck, - a.cumulativeTSNAckPoint) - - return nil - } - - // Process selective ack - bytesAckedPerStream, htna, err := a.processSelectiveAck(d) - if err != nil { - return err - } - - var totalBytesAcked int - for _, nBytesAcked := range bytesAckedPerStream { - totalBytesAcked += nBytesAcked - } - - cumTSNAckPointAdvanced := false - if sna32LT(a.cumulativeTSNAckPoint, d.cumulativeTSNAck) { - a.log.Tracef("[%s] SACK: cumTSN advanced: %d -> %d", - a.name, - a.cumulativeTSNAckPoint, - d.cumulativeTSNAck) - - a.cumulativeTSNAckPoint = d.cumulativeTSNAck - cumTSNAckPointAdvanced = true - a.onCumulativeTSNAckPointAdvanced(totalBytesAcked) - } - - for si, nBytesAcked := range bytesAckedPerStream { - if s, ok := a.streams[si]; ok { - a.lock.Unlock() - s.onBufferReleased(nBytesAcked) - a.lock.Lock() - } - } - - // New rwnd value - // RFC 4960 sec 6.2.1. Processing a Received SACK - // D) - // ii) Set rwnd equal to the newly received a_rwnd minus the number - // of bytes still outstanding after processing the Cumulative - // TSN Ack and the Gap Ack Blocks. - - // bytes acked were already subtracted by markAsAcked() method - bytesOutstanding := uint32(a.inflightQueue.getNumBytes()) - if bytesOutstanding >= d.advertisedReceiverWindowCredit { - a.rwnd = 0 - } else { - a.rwnd = d.advertisedReceiverWindowCredit - bytesOutstanding - } - - err = a.processFastRetransmission(d.cumulativeTSNAck, htna, cumTSNAckPointAdvanced) - if err != nil { - return err - } - - if a.useForwardTSN { - // RFC 3758 Sec 3.5 C1 - if sna32LT(a.advancedPeerTSNAckPoint, a.cumulativeTSNAckPoint) { - a.advancedPeerTSNAckPoint = a.cumulativeTSNAckPoint - } - - // RFC 3758 Sec 3.5 C2 - for i := a.advancedPeerTSNAckPoint + 1; ; i++ { - c, ok := a.inflightQueue.get(i) - if !ok { - break - } - if !c.abandoned() { - break - } - a.advancedPeerTSNAckPoint = i - } - - // RFC 3758 Sec 3.5 C3 - if sna32GT(a.advancedPeerTSNAckPoint, a.cumulativeTSNAckPoint) { - a.willSendForwardTSN = true - } - a.awakeWriteLoop() - } - - if a.inflightQueue.size() > 0 { - // Start timer. (noop if already started) - a.log.Tracef("[%s] T3-rtx timer start (pt3)", a.name) - a.t3RTX.start(a.rtoMgr.getRTO()) - } - - if cumTSNAckPointAdvanced { - a.awakeWriteLoop() - } - - return nil -} - -// createForwardTSN generates ForwardTSN chunk. -// This method will be be called if useForwardTSN is set to false. -// The caller should hold the lock. -func (a *Association) createForwardTSN() *chunkForwardTSN { - // RFC 3758 Sec 3.5 C4 - streamMap := map[uint16]uint16{} // to report only once per SI - for i := a.cumulativeTSNAckPoint + 1; sna32LTE(i, a.advancedPeerTSNAckPoint); i++ { - c, ok := a.inflightQueue.get(i) - if !ok { - break - } - - ssn, ok := streamMap[c.streamIdentifier] - if !ok { - streamMap[c.streamIdentifier] = c.streamSequenceNumber - } else if sna16LT(ssn, c.streamSequenceNumber) { - // to report only once with greatest SSN - streamMap[c.streamIdentifier] = c.streamSequenceNumber - } - } - - fwdtsn := &chunkForwardTSN{ - newCumulativeTSN: a.advancedPeerTSNAckPoint, - streams: []chunkForwardTSNStream{}, - } - - var streamStr string - for si, ssn := range streamMap { - streamStr += fmt.Sprintf("(si=%d ssn=%d)", si, ssn) - fwdtsn.streams = append(fwdtsn.streams, chunkForwardTSNStream{ - identifier: si, - sequence: ssn, - }) - } - a.log.Tracef("[%s] building fwdtsn: newCumulativeTSN=%d cumTSN=%d - %s", a.name, fwdtsn.newCumulativeTSN, a.cumulativeTSNAckPoint, streamStr) - - return fwdtsn -} - -// createPacket wraps chunks in a packet. -// The caller should hold the read lock. -func (a *Association) createPacket(cs []chunk) *packet { - return &packet{ - verificationTag: a.peerVerificationTag, - sourcePort: a.sourcePort, - destinationPort: a.destinationPort, - chunks: cs, - } -} - -// The caller should hold the lock. -func (a *Association) handleReconfig(c *chunkReconfig) ([]*packet, error) { - a.log.Tracef("[%s] handleReconfig", a.name) - - pp := make([]*packet, 0) - - p, err := a.handleReconfigParam(c.paramA) - if err != nil { - return nil, err - } - if p != nil { - pp = append(pp, p) - } - - if c.paramB != nil { - p, err = a.handleReconfigParam(c.paramB) - if err != nil { - return nil, err - } - if p != nil { - pp = append(pp, p) - } - } - return pp, nil -} - -// The caller should hold the lock. -func (a *Association) handleForwardTSN(c *chunkForwardTSN) []*packet { - a.log.Tracef("[%s] FwdTSN: %s", a.name, c.String()) - - if !a.useForwardTSN { - a.log.Warn("[%s] received FwdTSN but not enabled") - // Return an error chunk - cerr := &chunkError{ - errorCauses: []errorCause{&errorCauseUnrecognizedChunkType{}}, - } - outbound := &packet{} - outbound.verificationTag = a.peerVerificationTag - outbound.sourcePort = a.sourcePort - outbound.destinationPort = a.destinationPort - outbound.chunks = []chunk{cerr} - return []*packet{outbound} - } - - // From RFC 3758 Sec 3.6: - // Note, if the "New Cumulative TSN" value carried in the arrived - // FORWARD TSN chunk is found to be behind or at the current cumulative - // TSN point, the data receiver MUST treat this FORWARD TSN as out-of- - // date and MUST NOT update its Cumulative TSN. The receiver SHOULD - // send a SACK to its peer (the sender of the FORWARD TSN) since such a - // duplicate may indicate the previous SACK was lost in the network. - - a.log.Tracef("[%s] should send ack? newCumTSN=%d peerLastTSN=%d\n", - a.name, c.newCumulativeTSN, a.peerLastTSN) - if sna32LTE(c.newCumulativeTSN, a.peerLastTSN) { - a.log.Tracef("[%s] sending ack on Forward TSN", a.name) - a.ackState = ackStateImmediate - a.ackTimer.stop() - a.awakeWriteLoop() - return nil - } - - // From RFC 3758 Sec 3.6: - // the receiver MUST perform the same TSN handling, including duplicate - // detection, gap detection, SACK generation, cumulative TSN - // advancement, etc. as defined in RFC 2960 [2]---with the following - // exceptions and additions. - - // When a FORWARD TSN chunk arrives, the data receiver MUST first update - // its cumulative TSN point to the value carried in the FORWARD TSN - // chunk, - - // Advance peerLastTSN - for sna32LT(a.peerLastTSN, c.newCumulativeTSN) { - a.payloadQueue.pop(a.peerLastTSN + 1) // may not exist - a.peerLastTSN++ - } - - // Report new peerLastTSN value and abandoned largest SSN value to - // corresponding streams so that the abandoned chunks can be removed - // from the reassemblyQueue. - for _, forwarded := range c.streams { - if s, ok := a.streams[forwarded.identifier]; ok { - s.handleForwardTSNForOrdered(forwarded.sequence) - } - } - - // TSN may be forewared for unordered chunks. ForwardTSN chunk does not - // report which stream identifier it skipped for unordered chunks. - // Therefore, we need to broadcast this event to all existing streams for - // unordered chunks. - // See https://github.com/pion/sctp/issues/106 - for _, s := range a.streams { - s.handleForwardTSNForUnordered(c.newCumulativeTSN) - } - - return a.handlePeerLastTSNAndAcknowledgement(false) -} - -func (a *Association) sendResetRequest(streamIdentifier uint16) error { - a.lock.Lock() - defer a.lock.Unlock() - - state := a.getState() - if state != established { - return errors.Errorf("sending reset packet in non-established state: state=%s", - getAssociationStateString(state)) - } - - // Create DATA chunk which only contains valid stream identifier with - // nil userData and use it as a EOS from the stream. - c := &chunkPayloadData{ - streamIdentifier: streamIdentifier, - beginningFragment: true, - endingFragment: true, - userData: nil, - } - - a.pendingQueue.push(c) - a.awakeWriteLoop() - return nil -} - -// The caller should hold the lock. -func (a *Association) handleReconfigParam(raw param) (*packet, error) { - switch p := raw.(type) { - case *paramOutgoingResetRequest: - a.reconfigRequests[p.reconfigRequestSequenceNumber] = p - resp := a.resetStreamsIfAny(p) - if resp != nil { - return resp, nil - } - return nil, nil - - case *paramReconfigResponse: - delete(a.reconfigs, p.reconfigResponseSequenceNumber) - if len(a.reconfigs) == 0 { - a.tReconfig.stop() - } - return nil, nil - default: - return nil, errors.Errorf("unexpected parameter type %T", p) - } -} - -// The caller should hold the lock. -func (a *Association) resetStreamsIfAny(p *paramOutgoingResetRequest) *packet { - result := reconfigResultSuccessPerformed - if sna32LTE(p.senderLastTSN, a.peerLastTSN) { - a.log.Debugf("[%s] resetStream(): senderLastTSN=%d <= peerLastTSN=%d", - a.name, p.senderLastTSN, a.peerLastTSN) - for _, id := range p.streamIdentifiers { - s, ok := a.streams[id] - if !ok { - continue - } - a.unregisterStream(s, io.EOF) - } - delete(a.reconfigRequests, p.reconfigRequestSequenceNumber) - } else { - a.log.Debugf("[%s] resetStream(): senderLastTSN=%d > peerLastTSN=%d", - a.name, p.senderLastTSN, a.peerLastTSN) - result = reconfigResultInProgress - } - - return a.createPacket([]chunk{&chunkReconfig{ - paramA: ¶mReconfigResponse{ - reconfigResponseSequenceNumber: p.reconfigRequestSequenceNumber, - result: result, - }, - }}) -} - -// Move the chunk peeked with a.pendingQueue.peek() to the inflightQueue. -// The caller should hold the lock. -func (a *Association) movePendingDataChunkToInflightQueue(c *chunkPayloadData) { - if err := a.pendingQueue.pop(c); err != nil { - a.log.Errorf("[%s] failed to pop from pending queue: %s", a.name, err.Error()) - } - - // Mark all fragements are in-flight now - if c.endingFragment { - c.setAllInflight() - } - - // Assign TSN - c.tsn = a.generateNextTSN() - - c.since = time.Now() // use to calculate RTT and also for maxPacketLifeTime - c.nSent = 1 // being sent for the first time - - a.checkPartialReliabilityStatus(c) - - a.log.Tracef("[%s] sending ppi=%d tsn=%d ssn=%d sent=%d len=%d (%v,%v)", - a.name, c.payloadType, c.tsn, c.streamSequenceNumber, c.nSent, len(c.userData), c.beginningFragment, c.endingFragment) - - // Push it into the inflightQueue - a.inflightQueue.pushNoCheck(c) -} - -// popPendingDataChunksToSend pops chunks from the pending queues as many as -// the cwnd and rwnd allows to send. -// The caller should hold the lock. -func (a *Association) popPendingDataChunksToSend() ([]*chunkPayloadData, []uint16) { - chunks := []*chunkPayloadData{} - var sisToReset []uint16 // stream identifieres to reset - - if a.pendingQueue.size() > 0 { - // RFC 4960 sec 6.1. Transmission of DATA Chunks - // A) At any given time, the data sender MUST NOT transmit new data to - // any destination transport address if its peer's rwnd indicates - // that the peer has no buffer space (i.e., rwnd is 0; see Section - // 6.2.1). However, regardless of the value of rwnd (including if it - // is 0), the data sender can always have one DATA chunk in flight to - // the receiver if allowed by cwnd (see rule B, below). - - for { - c := a.pendingQueue.peek() - if c == nil { - break // no more pending data - } - - dataLen := uint32(len(c.userData)) - if dataLen == 0 { - sisToReset = append(sisToReset, c.streamIdentifier) - err := a.pendingQueue.pop(c) - if err != nil { - a.log.Errorf("failed to pop from pending queue: %s", err.Error()) - } - continue - } - - if uint32(a.inflightQueue.getNumBytes())+dataLen > a.cwnd { - break // would exceeds cwnd - } - - if dataLen > a.rwnd { - break // no more rwnd - } - - a.rwnd -= dataLen - - a.movePendingDataChunkToInflightQueue(c) - chunks = append(chunks, c) - } - - // the data sender can always have one DATA chunk in flight to the receiver - if len(chunks) == 0 && a.inflightQueue.size() == 0 { - // Send zero window probe - c := a.pendingQueue.peek() - if c != nil { - a.movePendingDataChunkToInflightQueue(c) - chunks = append(chunks, c) - } - } - } - - return chunks, sisToReset -} - -// bundleDataChunksIntoPackets packs DATA chunks into packets. It tries to bundle -// DATA chunks into a packet so long as the resulting packet size does not exceed -// the path MTU. -// The caller should hold the lock. -func (a *Association) bundleDataChunksIntoPackets(chunks []*chunkPayloadData) []*packet { - packets := []*packet{} - chunksToSend := []chunk{} - bytesInPacket := int(commonHeaderSize) - - for _, c := range chunks { - // RFC 4960 sec 6.1. Transmission of DATA Chunks - // Multiple DATA chunks committed for transmission MAY be bundled in a - // single packet. Furthermore, DATA chunks being retransmitted MAY be - // bundled with new DATA chunks, as long as the resulting packet size - // does not exceed the path MTU. - if bytesInPacket+len(c.userData) > int(a.mtu) { - packets = append(packets, a.createPacket(chunksToSend)) - chunksToSend = []chunk{} - bytesInPacket = int(commonHeaderSize) - } - - chunksToSend = append(chunksToSend, c) - bytesInPacket += int(dataChunkHeaderSize) + len(c.userData) - } - - if len(chunksToSend) > 0 { - packets = append(packets, a.createPacket(chunksToSend)) - } - - return packets -} - -// sendPayloadData sends the data chunks. -func (a *Association) sendPayloadData(chunks []*chunkPayloadData) error { - a.lock.Lock() - defer a.lock.Unlock() - - state := a.getState() - if state != established { - return errors.Errorf("sending payload data in non-established state: state=%s", - getAssociationStateString(state)) - } - - // Push the chunks into the pending queue first. - for _, c := range chunks { - a.pendingQueue.push(c) - } - - a.awakeWriteLoop() - return nil -} - -// The caller should hold the lock. -func (a *Association) checkPartialReliabilityStatus(c *chunkPayloadData) { - if !a.useForwardTSN { - return - } - - // draft-ietf-rtcweb-data-protocol-09.txt section 6 - // 6. Procedures - // All Data Channel Establishment Protocol messages MUST be sent using - // ordered delivery and reliable transmission. - // - if c.payloadType == PayloadTypeWebRTCDCEP { - return - } - - // PR-SCTP - if s, ok := a.streams[c.streamIdentifier]; ok { - s.lock.RLock() - if s.reliabilityType == ReliabilityTypeRexmit { - if c.nSent >= s.reliabilityValue { - c.setAbandoned(true) - a.log.Tracef("[%s] marked as abandoned: tsn=%d ppi=%d (remix: %d)", a.name, c.tsn, c.payloadType, c.nSent) - } - } else if s.reliabilityType == ReliabilityTypeTimed { - elapsed := int64(time.Since(c.since).Seconds() * 1000) - if elapsed >= int64(s.reliabilityValue) { - c.setAbandoned(true) - a.log.Tracef("[%s] marked as abandoned: tsn=%d ppi=%d (timed: %d)", a.name, c.tsn, c.payloadType, elapsed) - } - } - s.lock.RUnlock() - } else { - a.log.Errorf("[%s] stream %d not found)", a.name, c.streamIdentifier) - } -} - -// getDataPacketsToRetransmit is called when T3-rtx is timed out and retransmit outstanding data chunks -// that are not acked or abandoned yet. -// The caller should hold the lock. -func (a *Association) getDataPacketsToRetransmit() []*packet { - awnd := min32(a.cwnd, a.rwnd) - chunks := []*chunkPayloadData{} - var bytesToSend int - var done bool - - for i := 0; !done; i++ { - c, ok := a.inflightQueue.get(a.cumulativeTSNAckPoint + uint32(i) + 1) - if !ok { - break // end of pending data - } - - if !c.retransmit { - continue - } - - if i == 0 && int(a.rwnd) < len(c.userData) { - // Send it as a zero window probe - done = true - } else if bytesToSend+len(c.userData) > int(awnd) { - break - } - - // reset the retransmit flag not to retransmit again before the next - // t3-rtx timer fires - c.retransmit = false - bytesToSend += len(c.userData) - - c.nSent++ - - a.checkPartialReliabilityStatus(c) - - a.log.Tracef("[%s] retransmitting tsn=%d ssn=%d sent=%d", a.name, c.tsn, c.streamSequenceNumber, c.nSent) - - chunks = append(chunks, c) - } - - return a.bundleDataChunksIntoPackets(chunks) -} - -// generateNextTSN returns the myNextTSN and increases it. The caller should hold the lock. -// The caller should hold the lock. -func (a *Association) generateNextTSN() uint32 { - tsn := a.myNextTSN - a.myNextTSN++ - return tsn -} - -// generateNextRSN returns the myNextRSN and increases it. The caller should hold the lock. -// The caller should hold the lock. -func (a *Association) generateNextRSN() uint32 { - rsn := a.myNextRSN - a.myNextRSN++ - return rsn -} - -func (a *Association) createSelectiveAckChunk() *chunkSelectiveAck { - sack := &chunkSelectiveAck{} - sack.cumulativeTSNAck = a.peerLastTSN - sack.advertisedReceiverWindowCredit = a.getMyReceiverWindowCredit() - sack.duplicateTSN = a.payloadQueue.popDuplicates() - sack.gapAckBlocks = a.payloadQueue.getGapAckBlocks(a.peerLastTSN) - return sack -} - -func pack(p *packet) []*packet { - return []*packet{p} -} - -func (a *Association) handleChunkStart() { - a.lock.Lock() - defer a.lock.Unlock() - - a.delayedAckTriggered = false - a.immediateAckTriggered = false -} - -func (a *Association) handleChunkEnd() { - a.lock.Lock() - defer a.lock.Unlock() - - if a.immediateAckTriggered { - // Send SACK now! - a.ackState = ackStateImmediate - a.ackTimer.stop() - a.awakeWriteLoop() - } else if a.delayedAckTriggered { - // Will send delayed ack in the next ack timeout - a.ackState = ackStateDelay - a.ackTimer.start() - } -} - -func (a *Association) handleChunk(p *packet, c chunk) error { - a.lock.Lock() - defer a.lock.Unlock() - - var packets []*packet - var err error - - if _, err = c.check(); err != nil { - a.log.Errorf("[ %s ] failed validating chunk: %s ", a.name, err) - return nil - } - - switch c := c.(type) { - case *chunkInit: - packets, err = a.handleInit(p, c) - - case *chunkInitAck: - err = a.handleInitAck(p, c) - - case *chunkAbort: - var errStr string - for _, e := range c.errorCauses { - errStr += fmt.Sprintf("(%s)", e) - } - return fmt.Errorf("[%s] %w: %s", a.name, errChunk, errStr) - - case *chunkError: - var errStr string - for _, e := range c.errorCauses { - errStr += fmt.Sprintf("(%s)", e) - } - a.log.Debugf("[%s] Error chunk, with following errors: %s", a.name, errStr) - - case *chunkHeartbeat: - packets = a.handleHeartbeat(c) - - case *chunkCookieEcho: - packets = a.handleCookieEcho(c) - - case *chunkCookieAck: - a.handleCookieAck() - - case *chunkPayloadData: - packets = a.handleData(c) - - case *chunkSelectiveAck: - err = a.handleSack(c) - - case *chunkReconfig: - packets, err = a.handleReconfig(c) - - case *chunkForwardTSN: - packets = a.handleForwardTSN(c) - - default: - err = errors.Errorf("unhandled chunk type") - } - - // Log and return, the only condition that is fatal is a ABORT chunk - if err != nil { - a.log.Errorf("Failed to handle chunk: %v", err) - return nil - } - - if len(packets) > 0 { - a.controlQueue.pushAll(packets) - a.awakeWriteLoop() - } - - return nil -} - -func (a *Association) onRetransmissionTimeout(id int, nRtos uint) { - a.lock.Lock() - defer a.lock.Unlock() - - if id == timerT1Init { - err := a.sendInit() - if err != nil { - a.log.Debugf("[%s] failed to retransmit init (nRtos=%d): %v", a.name, nRtos, err) - } - return - } - - if id == timerT1Cookie { - err := a.sendCookieEcho() - if err != nil { - a.log.Debugf("[%s] failed to retransmit cookie-echo (nRtos=%d): %v", a.name, nRtos, err) - } - return - } - - if id == timerT3RTX { - a.stats.incT3Timeouts() - - // RFC 4960 sec 6.3.3 - // E1) For the destination address for which the timer expires, adjust - // its ssthresh with rules defined in Section 7.2.3 and set the - // cwnd <- MTU. - // RFC 4960 sec 7.2.3 - // When the T3-rtx timer expires on an address, SCTP should perform slow - // start by: - // ssthresh = max(cwnd/2, 4*MTU) - // cwnd = 1*MTU - - a.ssthresh = max32(a.cwnd/2, 4*a.mtu) - a.cwnd = a.mtu - a.log.Tracef("[%s] updated cwnd=%d ssthresh=%d inflight=%d (RTO)", - a.name, a.cwnd, a.ssthresh, a.inflightQueue.getNumBytes()) - - // RFC 3758 sec 3.5 - // A5) Any time the T3-rtx timer expires, on any destination, the sender - // SHOULD try to advance the "Advanced.Peer.Ack.Point" by following - // the procedures outlined in C2 - C5. - if a.useForwardTSN { - // RFC 3758 Sec 3.5 C2 - for i := a.advancedPeerTSNAckPoint + 1; ; i++ { - c, ok := a.inflightQueue.get(i) - if !ok { - break - } - if !c.abandoned() { - break - } - a.advancedPeerTSNAckPoint = i - } - - // RFC 3758 Sec 3.5 C3 - if sna32GT(a.advancedPeerTSNAckPoint, a.cumulativeTSNAckPoint) { - a.willSendForwardTSN = true - } - } - - a.log.Debugf("[%s] T3-rtx timed out: nRtos=%d cwnd=%d ssthresh=%d", a.name, nRtos, a.cwnd, a.ssthresh) - - /* - a.log.Debugf(" - advancedPeerTSNAckPoint=%d", a.advancedPeerTSNAckPoint) - a.log.Debugf(" - cumulativeTSNAckPoint=%d", a.cumulativeTSNAckPoint) - a.inflightQueue.updateSortedKeys() - for i, tsn := range a.inflightQueue.sorted { - if c, ok := a.inflightQueue.get(tsn); ok { - a.log.Debugf(" - [%d] tsn=%d acked=%v abandoned=%v (%v,%v) len=%d", - i, c.tsn, c.acked, c.abandoned(), c.beginningFragment, c.endingFragment, len(c.userData)) - } - } - */ - - a.inflightQueue.markAllToRetrasmit() - a.awakeWriteLoop() - - return - } - - if id == timerReconfig { - a.willRetransmitReconfig = true - a.awakeWriteLoop() - } -} - -func (a *Association) onRetransmissionFailure(id int) { - a.lock.Lock() - defer a.lock.Unlock() - - if id == timerT1Init { - a.log.Errorf("[%s] retransmission failure: T1-init", a.name) - a.handshakeCompletedCh <- errors.Errorf("handshake failed (INIT ACK)") - return - } - - if id == timerT1Cookie { - a.log.Errorf("[%s] retransmission failure: T1-cookie", a.name) - a.handshakeCompletedCh <- errors.Errorf("handshake failed (COOKIE ECHO)") - return - } - - if id == timerT3RTX { - // T3-rtx timer will not fail by design - // Justifications: - // * ICE would fail if the connectivity is lost - // * WebRTC spec is not clear how this incident should be reported to ULP - a.log.Errorf("[%s] retransmission failure: T3-rtx (DATA)", a.name) - return - } -} - -func (a *Association) onAckTimeout() { - a.lock.Lock() - defer a.lock.Unlock() - - a.log.Tracef("[%s] ack timed out (ackState: %d)", a.name, a.ackState) - a.stats.incAckTimeouts() - - a.ackState = ackStateImmediate - a.awakeWriteLoop() -} - -// bufferedAmount returns total amount (in bytes) of currently buffered user data. -// This is used only by testing. -func (a *Association) bufferedAmount() int { - a.lock.RLock() - defer a.lock.RUnlock() - - return a.pendingQueue.getNumBytes() + a.inflightQueue.getNumBytes() -} - -// MaxMessageSize returns the maximum message size you can send. -func (a *Association) MaxMessageSize() uint32 { - return atomic.LoadUint32(&a.maxMessageSize) -} - -// SetMaxMessageSize sets the maximum message size you can send. -func (a *Association) SetMaxMessageSize(maxMsgSize uint32) { - atomic.StoreUint32(&a.maxMessageSize, maxMsgSize) -} diff --git a/vendor/github.com/pion/sctp/association_stats.go b/vendor/github.com/pion/sctp/association_stats.go deleted file mode 100644 index 4ccb7be..0000000 --- a/vendor/github.com/pion/sctp/association_stats.go +++ /dev/null @@ -1,61 +0,0 @@ -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) -} diff --git a/vendor/github.com/pion/sctp/chunk.go b/vendor/github.com/pion/sctp/chunk.go deleted file mode 100644 index ec47da1..0000000 --- a/vendor/github.com/pion/sctp/chunk.go +++ /dev/null @@ -1,9 +0,0 @@ -package sctp - -type chunk interface { - unmarshal(raw []byte) error - marshal() ([]byte, error) - check() (bool, error) - - valueLength() int -} diff --git a/vendor/github.com/pion/sctp/chunk_abort.go b/vendor/github.com/pion/sctp/chunk_abort.go deleted file mode 100644 index 9fd4692..0000000 --- a/vendor/github.com/pion/sctp/chunk_abort.go +++ /dev/null @@ -1,88 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/chunk_cookie_ack.go b/vendor/github.com/pion/sctp/chunk_cookie_ack.go deleted file mode 100644 index 83b6f71..0000000 --- a/vendor/github.com/pion/sctp/chunk_cookie_ack.go +++ /dev/null @@ -1,44 +0,0 @@ -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() -} diff --git a/vendor/github.com/pion/sctp/chunk_cookie_echo.go b/vendor/github.com/pion/sctp/chunk_cookie_echo.go deleted file mode 100644 index 3f0ed36..0000000 --- a/vendor/github.com/pion/sctp/chunk_cookie_echo.go +++ /dev/null @@ -1,46 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/chunk_error.go b/vendor/github.com/pion/sctp/chunk_error.go deleted file mode 100644 index eb29324..0000000 --- a/vendor/github.com/pion/sctp/chunk_error.go +++ /dev/null @@ -1,95 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/chunk_forward_tsn.go b/vendor/github.com/pion/sctp/chunk_forward_tsn.go deleted file mode 100644 index f6ff357..0000000 --- a/vendor/github.com/pion/sctp/chunk_forward_tsn.go +++ /dev/null @@ -1,145 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/chunk_heartbeat.go b/vendor/github.com/pion/sctp/chunk_heartbeat.go deleted file mode 100644 index f2026a4..0000000 --- a/vendor/github.com/pion/sctp/chunk_heartbeat.go +++ /dev/null @@ -1,75 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/chunk_heartbeat_ack.go b/vendor/github.com/pion/sctp/chunk_heartbeat_ack.go deleted file mode 100644 index ff84090..0000000 --- a/vendor/github.com/pion/sctp/chunk_heartbeat_ack.go +++ /dev/null @@ -1,86 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/chunk_init.go b/vendor/github.com/pion/sctp/chunk_init.go deleted file mode 100644 index 65b9b1a..0000000 --- a/vendor/github.com/pion/sctp/chunk_init.go +++ /dev/null @@ -1,123 +0,0 @@ -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) -} diff --git a/vendor/github.com/pion/sctp/chunk_init_ack.go b/vendor/github.com/pion/sctp/chunk_init_ack.go deleted file mode 100644 index 551bcea..0000000 --- a/vendor/github.com/pion/sctp/chunk_init_ack.go +++ /dev/null @@ -1,126 +0,0 @@ -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) -} diff --git a/vendor/github.com/pion/sctp/chunk_init_common.go b/vendor/github.com/pion/sctp/chunk_init_common.go deleted file mode 100644 index f64be78..0000000 --- a/vendor/github.com/pion/sctp/chunk_init_common.go +++ /dev/null @@ -1,155 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/chunk_payload_data.go b/vendor/github.com/pion/sctp/chunk_payload_data.go deleted file mode 100644 index 3e5e346..0000000 --- a/vendor/github.com/pion/sctp/chunk_payload_data.go +++ /dev/null @@ -1,195 +0,0 @@ -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 - } - } -} diff --git a/vendor/github.com/pion/sctp/chunk_reconfig.go b/vendor/github.com/pion/sctp/chunk_reconfig.go deleted file mode 100644 index a53ad5e..0000000 --- a/vendor/github.com/pion/sctp/chunk_reconfig.go +++ /dev/null @@ -1,99 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/chunk_selective_ack.go b/vendor/github.com/pion/sctp/chunk_selective_ack.go deleted file mode 100644 index 920d562..0000000 --- a/vendor/github.com/pion/sctp/chunk_selective_ack.go +++ /dev/null @@ -1,142 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/chunkheader.go b/vendor/github.com/pion/sctp/chunkheader.go deleted file mode 100644 index a4a78db..0000000 --- a/vendor/github.com/pion/sctp/chunkheader.go +++ /dev/null @@ -1,90 +0,0 @@ -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() -} diff --git a/vendor/github.com/pion/sctp/chunktype.go b/vendor/github.com/pion/sctp/chunktype.go deleted file mode 100644 index 65b57a4..0000000 --- a/vendor/github.com/pion/sctp/chunktype.go +++ /dev/null @@ -1,67 +0,0 @@ -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) - } -} diff --git a/vendor/github.com/pion/sctp/codecov.yml b/vendor/github.com/pion/sctp/codecov.yml deleted file mode 100644 index 085200a..0000000 --- a/vendor/github.com/pion/sctp/codecov.yml +++ /dev/null @@ -1,20 +0,0 @@ -# -# 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/**/*" diff --git a/vendor/github.com/pion/sctp/control_queue.go b/vendor/github.com/pion/sctp/control_queue.go deleted file mode 100644 index 7e13469..0000000 --- a/vendor/github.com/pion/sctp/control_queue.go +++ /dev/null @@ -1,29 +0,0 @@ -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) -} diff --git a/vendor/github.com/pion/sctp/error_cause.go b/vendor/github.com/pion/sctp/error_cause.go deleted file mode 100644 index e94cc5c..0000000 --- a/vendor/github.com/pion/sctp/error_cause.go +++ /dev/null @@ -1,91 +0,0 @@ -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) - } -} diff --git a/vendor/github.com/pion/sctp/error_cause_header.go b/vendor/github.com/pion/sctp/error_cause_header.go deleted file mode 100644 index 1ad6e1d..0000000 --- a/vendor/github.com/pion/sctp/error_cause_header.go +++ /dev/null @@ -1,47 +0,0 @@ -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() -} diff --git a/vendor/github.com/pion/sctp/error_cause_invalid_mandatory_parameter.go b/vendor/github.com/pion/sctp/error_cause_invalid_mandatory_parameter.go deleted file mode 100644 index 3da8b47..0000000 --- a/vendor/github.com/pion/sctp/error_cause_invalid_mandatory_parameter.go +++ /dev/null @@ -1,19 +0,0 @@ -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() -} diff --git a/vendor/github.com/pion/sctp/error_cause_protocol_violation.go b/vendor/github.com/pion/sctp/error_cause_protocol_violation.go deleted file mode 100644 index 8b457f4..0000000 --- a/vendor/github.com/pion/sctp/error_cause_protocol_violation.go +++ /dev/null @@ -1,50 +0,0 @@ -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) -} diff --git a/vendor/github.com/pion/sctp/error_cause_unrecognized_chunk_type.go b/vendor/github.com/pion/sctp/error_cause_unrecognized_chunk_type.go deleted file mode 100644 index fee9a36..0000000 --- a/vendor/github.com/pion/sctp/error_cause_unrecognized_chunk_type.go +++ /dev/null @@ -1,28 +0,0 @@ -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() -} diff --git a/vendor/github.com/pion/sctp/go.mod b/vendor/github.com/pion/sctp/go.mod deleted file mode 100644 index 022e2fc..0000000 --- a/vendor/github.com/pion/sctp/go.mod +++ /dev/null @@ -1,14 +0,0 @@ -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 diff --git a/vendor/github.com/pion/sctp/go.sum b/vendor/github.com/pion/sctp/go.sum deleted file mode 100644 index 3744262..0000000 --- a/vendor/github.com/pion/sctp/go.sum +++ /dev/null @@ -1,36 +0,0 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/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= diff --git a/vendor/github.com/pion/sctp/packet.go b/vendor/github.com/pion/sctp/packet.go deleted file mode 100644 index dcc650b..0000000 --- a/vendor/github.com/pion/sctp/packet.go +++ /dev/null @@ -1,178 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/param.go b/vendor/github.com/pion/sctp/param.go deleted file mode 100644 index 08e46d1..0000000 --- a/vendor/github.com/pion/sctp/param.go +++ /dev/null @@ -1,35 +0,0 @@ -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) - } -} diff --git a/vendor/github.com/pion/sctp/param_chunk_list.go b/vendor/github.com/pion/sctp/param_chunk_list.go deleted file mode 100644 index 4ea484c..0000000 --- a/vendor/github.com/pion/sctp/param_chunk_list.go +++ /dev/null @@ -1,28 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/param_forward_tsn_supported.go b/vendor/github.com/pion/sctp/param_forward_tsn_supported.go deleted file mode 100644 index 62de155..0000000 --- a/vendor/github.com/pion/sctp/param_forward_tsn_supported.go +++ /dev/null @@ -1,28 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/param_heartbeat_info.go b/vendor/github.com/pion/sctp/param_heartbeat_info.go deleted file mode 100644 index 47f64eb..0000000 --- a/vendor/github.com/pion/sctp/param_heartbeat_info.go +++ /dev/null @@ -1,21 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/param_outgoing_reset_request.go b/vendor/github.com/pion/sctp/param_outgoing_reset_request.go deleted file mode 100644 index ceae178..0000000 --- a/vendor/github.com/pion/sctp/param_outgoing_reset_request.go +++ /dev/null @@ -1,88 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/param_random.go b/vendor/github.com/pion/sctp/param_random.go deleted file mode 100644 index dc454b3..0000000 --- a/vendor/github.com/pion/sctp/param_random.go +++ /dev/null @@ -1,21 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/param_reconfig_response.go b/vendor/github.com/pion/sctp/param_reconfig_response.go deleted file mode 100644 index d9eab55..0000000 --- a/vendor/github.com/pion/sctp/param_reconfig_response.go +++ /dev/null @@ -1,92 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/param_requested_hmac_algorithm.go b/vendor/github.com/pion/sctp/param_requested_hmac_algorithm.go deleted file mode 100644 index b520fe3..0000000 --- a/vendor/github.com/pion/sctp/param_requested_hmac_algorithm.go +++ /dev/null @@ -1,73 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/param_state_cookie.go b/vendor/github.com/pion/sctp/param_state_cookie.go deleted file mode 100644 index 9681267..0000000 --- a/vendor/github.com/pion/sctp/param_state_cookie.go +++ /dev/null @@ -1,46 +0,0 @@ -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) -} diff --git a/vendor/github.com/pion/sctp/param_supported_extensions.go b/vendor/github.com/pion/sctp/param_supported_extensions.go deleted file mode 100644 index 2935524..0000000 --- a/vendor/github.com/pion/sctp/param_supported_extensions.go +++ /dev/null @@ -1,29 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/paramheader.go b/vendor/github.com/pion/sctp/paramheader.go deleted file mode 100644 index d88642b..0000000 --- a/vendor/github.com/pion/sctp/paramheader.go +++ /dev/null @@ -1,63 +0,0 @@ -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)) -} diff --git a/vendor/github.com/pion/sctp/paramtype.go b/vendor/github.com/pion/sctp/paramtype.go deleted file mode 100644 index bb0ee82..0000000 --- a/vendor/github.com/pion/sctp/paramtype.go +++ /dev/null @@ -1,106 +0,0 @@ -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) - } -} diff --git a/vendor/github.com/pion/sctp/payload_queue.go b/vendor/github.com/pion/sctp/payload_queue.go deleted file mode 100644 index 2d1a35a..0000000 --- a/vendor/github.com/pion/sctp/payload_queue.go +++ /dev/null @@ -1,179 +0,0 @@ -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) -} diff --git a/vendor/github.com/pion/sctp/pending_queue.go b/vendor/github.com/pion/sctp/pending_queue.go deleted file mode 100644 index 5f204d3..0000000 --- a/vendor/github.com/pion/sctp/pending_queue.go +++ /dev/null @@ -1,138 +0,0 @@ -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() -} diff --git a/vendor/github.com/pion/sctp/reassembly_queue.go b/vendor/github.com/pion/sctp/reassembly_queue.go deleted file mode 100644 index f71d59c..0000000 --- a/vendor/github.com/pion/sctp/reassembly_queue.go +++ /dev/null @@ -1,353 +0,0 @@ -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)) -} diff --git a/vendor/github.com/pion/sctp/renovate.json b/vendor/github.com/pion/sctp/renovate.json deleted file mode 100644 index 4400fd9..0000000 --- a/vendor/github.com/pion/sctp/renovate.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": [ - "config:base" - ], - "postUpdateOptions": [ - "gomodTidy" - ], - "commitBody": "Generated by renovateBot", - "packageRules": [ - { - "packagePatterns": ["^golang.org/x/"], - "schedule": ["on the first day of the month"] - } - ] -} diff --git a/vendor/github.com/pion/sctp/rtx_timer.go b/vendor/github.com/pion/sctp/rtx_timer.go deleted file mode 100644 index 14bc39d..0000000 --- a/vendor/github.com/pion/sctp/rtx_timer.go +++ /dev/null @@ -1,219 +0,0 @@ -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 -} diff --git a/vendor/github.com/pion/sctp/sctp.go b/vendor/github.com/pion/sctp/sctp.go deleted file mode 100644 index e601342..0000000 --- a/vendor/github.com/pion/sctp/sctp.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package sctp implements the SCTP spec -package sctp diff --git a/vendor/github.com/pion/sctp/stream.go b/vendor/github.com/pion/sctp/stream.go deleted file mode 100644 index 8a17b97..0000000 --- a/vendor/github.com/pion/sctp/stream.go +++ /dev/null @@ -1,357 +0,0 @@ -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() -} diff --git a/vendor/github.com/pion/sctp/util.go b/vendor/github.com/pion/sctp/util.go deleted file mode 100644 index e2e54ab..0000000 --- a/vendor/github.com/pion/sctp/util.go +++ /dev/null @@ -1,58 +0,0 @@ -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 -} |