status-go/vendor/github.com/pion/sctp/chunk_forward_tsn.go

152 lines
4.5 KiB
Go

// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT
package sctp
import (
"encoding/binary"
"errors"
"fmt"
)
// 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
)
// Forward TSN chunk errors
var (
ErrMarshalStreamFailed = errors.New("failed to marshal stream")
ErrChunkTooShort = errors.New("chunk too short")
)
func (c *chunkForwardTSN) unmarshal(raw []byte) error {
if err := c.chunkHeader.unmarshal(raw); err != nil {
return err
}
if len(c.raw) < newCumulativeTSNLength {
return ErrChunkTooShort
}
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("%w: %v", ErrMarshalStreamFailed, err) //nolint:errorlint
}
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) //nolint:errorlint
}
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 ErrChunkTooShort
}
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
}