diff options
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 -} |