123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- 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)
- }
|