1 /*
2 * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10 #include "net/dcsctp/packet/chunk/data_chunk.h"
11
12 #include <stdint.h>
13
14 #include <string>
15 #include <type_traits>
16 #include <vector>
17
18 #include "absl/types/optional.h"
19 #include "api/array_view.h"
20 #include "net/dcsctp/packet/bounded_byte_reader.h"
21 #include "net/dcsctp/packet/bounded_byte_writer.h"
22 #include "net/dcsctp/packet/chunk/data_common.h"
23 #include "rtc_base/strings/string_builder.h"
24
25 namespace dcsctp {
26
27 // https://tools.ietf.org/html/rfc4960#section-3.3.1
28
29 // 0 1 2 3
30 // 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
31 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32 // | Type = 0 | Reserved|U|B|E| Length |
33 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34 // | TSN |
35 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 // | Stream Identifier S | Stream Sequence Number n |
37 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 // | Payload Protocol Identifier |
39 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 // \ \
41 // / User Data (seq n of Stream S) /
42 // \ \
43 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 constexpr int DataChunk::kType;
45
Parse(rtc::ArrayView<const uint8_t> data)46 absl::optional<DataChunk> DataChunk::Parse(rtc::ArrayView<const uint8_t> data) {
47 absl::optional<BoundedByteReader<kHeaderSize>> reader = ParseTLV(data);
48 if (!reader.has_value()) {
49 return absl::nullopt;
50 }
51
52 uint8_t flags = reader->Load8<1>();
53 TSN tsn(reader->Load32<4>());
54 StreamID stream_identifier(reader->Load16<8>());
55 SSN ssn(reader->Load16<10>());
56 PPID ppid(reader->Load32<12>());
57
58 Options options;
59 options.is_end = Data::IsEnd((flags & (1 << kFlagsBitEnd)) != 0);
60 options.is_beginning =
61 Data::IsBeginning((flags & (1 << kFlagsBitBeginning)) != 0);
62 options.is_unordered = IsUnordered((flags & (1 << kFlagsBitUnordered)) != 0);
63 options.immediate_ack =
64 ImmediateAckFlag((flags & (1 << kFlagsBitImmediateAck)) != 0);
65
66 return DataChunk(tsn, stream_identifier, ssn, ppid,
67 std::vector<uint8_t>(reader->variable_data().begin(),
68 reader->variable_data().end()),
69 options);
70 }
71
SerializeTo(std::vector<uint8_t> & out) const72 void DataChunk::SerializeTo(std::vector<uint8_t>& out) const {
73 BoundedByteWriter<kHeaderSize> writer = AllocateTLV(out, payload().size());
74
75 writer.Store8<1>(
76 (*options().is_end ? (1 << kFlagsBitEnd) : 0) |
77 (*options().is_beginning ? (1 << kFlagsBitBeginning) : 0) |
78 (*options().is_unordered ? (1 << kFlagsBitUnordered) : 0) |
79 (*options().immediate_ack ? (1 << kFlagsBitImmediateAck) : 0));
80 writer.Store32<4>(*tsn());
81 writer.Store16<8>(*stream_id());
82 writer.Store16<10>(*ssn());
83 writer.Store32<12>(*ppid());
84
85 writer.CopyToVariableData(payload());
86 }
87
ToString() const88 std::string DataChunk::ToString() const {
89 rtc::StringBuilder sb;
90 sb << "DATA, type=" << (options().is_unordered ? "unordered" : "ordered")
91 << "::"
92 << (*options().is_beginning && *options().is_end
93 ? "complete"
94 : *options().is_beginning ? "first"
95 : *options().is_end ? "last" : "middle")
96 << ", tsn=" << *tsn() << ", sid=" << *stream_id() << ", ssn=" << *ssn()
97 << ", ppid=" << *ppid() << ", length=" << payload().size();
98 return sb.Release();
99 }
100
101 } // namespace dcsctp
102