-
Notifications
You must be signed in to change notification settings - Fork 79
/
chunk_forward_tsn.go
151 lines (122 loc) · 4.51 KB
/
chunk_forward_tsn.go
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
146
147
148
149
150
151
// 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
}