summaryrefslogtreecommitdiff
path: root/vendor/github.com/pion/sctp/chunk_forward_tsn.go
blob: f6ff357f1f737dd70f99e4afd9694cfbe814fb45 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
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
}