143 lines
2.9 KiB
Go
143 lines
2.9 KiB
Go
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package sctp
|
|
|
|
import (
|
|
"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
|
|
}
|
|
|
|
// Pending queue errors
|
|
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()
|
|
}
|