Skip to content

Commit 03387bd

Browse files
committed
more
1 parent 88ec66d commit 03387bd

File tree

11 files changed

+214
-124
lines changed

11 files changed

+214
-124
lines changed

worker/include/RTC/SCTP/Chunk.hpp

Lines changed: 75 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
#define MS_RTC_SCTP_CHUNK_HPP
33

44
#include "common.hpp"
5-
#include <absl/container/flat_hash_map.h>
5+
#include "RTC/Serializable.hpp"
66
#include <string>
7+
#include <unordered_map>
78

89
namespace RTC
910
{
@@ -21,9 +22,25 @@ namespace RTC
2122
* / Chunk Value /
2223
* \ \
2324
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
25+
*
26+
* - Chunk Type (8 bits): Unsigned integer.
27+
* - Chunk Flags (8 bits).
28+
* - Chunk Length (16 bits): Unsigned integer. Total length of the Chunk
29+
* excluding padding bytes. Minimum value is 4 (if Chunk Value is 0
30+
* bytes).
31+
* - Chunk Value (variable length).
32+
* - Padding: Bytes of padding to make the Packet length be multiple of 4
33+
* bytes.
2434
*/
25-
class Chunk
35+
36+
// Forward declaration.
37+
class Packet;
38+
39+
class Chunk : public Serializable
2640
{
41+
private:
42+
friend class Packet;
43+
2744
public:
2845
/**
2946
* Chunk types.
@@ -50,7 +67,7 @@ namespace RTC
5067
/**
5168
* Struct of a SCTP Chunk Header.
5269
*/
53-
struct Header
70+
struct ChunkHeader
5471
{
5572
ChunkType type;
5673
uint8_t flags;
@@ -65,88 +82,97 @@ namespace RTC
6582
};
6683

6784
public:
68-
static const size_t HeaderLength{ 4 };
85+
static const size_t ChunkHeaderLength{ 4 };
6986

87+
public:
7088
/**
71-
* Parses given `data` with length `len` and returns an allocated instance
72-
* of Chunk (or nullptr if it's not a valid SCTP chunk).
89+
* Whether given buffer could be a a valid Chunk.
7390
*
74-
* If `exactLen` is set to true, then given `len` must be the total length
75-
* of this chunk. Otherwise we assume that other chunks could follow this
76-
* one.
77-
*
78-
* So if `exactLen` is set to true, `len` must be multiple of 4 bytes (it
79-
* must include padding if needed).
91+
* @param buffer
92+
* @param bufferLength - Can be greater than real Chunk length.
93+
* @param chunkType - If given buffer is a valid FooItem then `chunkType`
94+
* is rewritten to parsed ChunkType.
95+
* @param valueLength - If given buffer is a valid Chunk then
96+
* `valueLength` is rewritten to the length of the Chunk.
8097
*/
81-
static Chunk* Parse(const uint8_t* data, size_t len, bool exactLen);
98+
static bool IsChunk(
99+
const uint8_t* buffer, size_t bufferLength, ChunkType& chunkType, uint16_t& chunkLength);
82100

83101
static const std::string& ChunkType2String(ChunkType chunkType);
84102

85103
private:
86-
static absl::flat_hash_map<ChunkType, std::string> chunkType2String;
104+
static std::unordered_map<ChunkType, std::string> chunkType2String;
105+
106+
protected:
107+
/**
108+
* Constructor is protected because we only want to create Chunk
109+
* instances via Parse() and Factory() in subclasses.
110+
*/
111+
Chunk(const uint8_t* buffer, size_t bufferLength);
87112

88113
public:
89-
Chunk(const uint8_t* data, size_t size);
114+
virtual ~Chunk() override;
90115

91-
virtual ~Chunk();
116+
/**
117+
* NOTE: Should be overridden by each subclass.
118+
*/
119+
virtual void Dump() const override;
92120

93-
void Dump() const;
121+
/**
122+
* Can be overridden by each subclass.
123+
*/
124+
virtual Chunk* Clone(uint8_t* buffer, size_t bufferLength) const override;
94125

95-
const uint8_t* GetData() const
126+
virtual ChunkType GetType() const final
96127
{
97-
return reinterpret_cast<const uint8_t*>(this->data);
128+
return GetHeaderPointer()->type;
98129
}
99130

100-
size_t GetSize() const
131+
virtual uint8_t GetFlags() const final
101132
{
102-
return this->size;
133+
return GetHeaderPointer()->flags;
103134
}
104135

105-
ChunkType GetType() const
136+
virtual bool HasValue() const final
106137
{
107-
return static_cast<ChunkType>(this->header->type);
138+
return GetLengthField() > Chunk::ChunkHeaderLength;
108139
}
109140

110-
void SetType(ChunkType type)
141+
virtual uint16_t GetValueLength() const final
111142
{
112-
this->header->type = static_cast<ChunkType>(type);
113-
}
143+
if (!HasValue())
144+
{
145+
return 0u;
146+
}
114147

115-
uint8_t GetFlags() const
116-
{
117-
return this->header->flags;
148+
return GetLengthField() - Chunk::ChunkHeaderLength;
118149
}
119150

120-
void SetFlags(uint8_t flags)
151+
protected:
152+
virtual void InitializeHeader(ChunkType chunkType, uint8_t flags, uint16_t valueLength) final;
153+
154+
/**
155+
* NOTE: Return ChunkHeader* instead of const ChunkHeader* since we may
156+
* want to modify its fields.
157+
*/
158+
virtual ChunkHeader* GetHeaderPointer() const final
121159
{
122-
this->header->flags = flags;
160+
return reinterpret_cast<ChunkHeader*>(const_cast<uint8_t*>(GetBuffer()));
123161
}
124162

125163
/**
126-
* The length of the Chunk Value field. It does not count any padding.
127-
*
128-
* @remarks
129-
* This is not the value of the Chunk Length field in the Chunk Header
130-
* but the real length of the Chunk Value.
164+
* Private private because it returns the value of the Value Length field,
165+
* which is not useful for the application.
131166
*/
132-
uint16_t GetValueLength() const
167+
virtual uint16_t GetLengthField() const final
133168
{
134-
return uint16_t{ ntohs(this->header->length) } - Chunk::HeaderLength;
169+
return GetHeaderPointer()->length;
135170
}
136171

137-
private:
138-
void SetSize(size_t size)
172+
virtual void SetLengthField(uint16_t length) final
139173
{
140-
this->size = size;
174+
GetHeaderPointer()->length = length;
141175
}
142-
143-
private:
144-
// Pointer to the data buffer containing the chunk.
145-
uint8_t* data{ nullptr };
146-
// Full size of the chunk in bytes.
147-
size_t size{ 0u };
148-
// Pointer to the Chunk Header (it points to `data` too).
149-
Header* header{ nullptr };
150176
};
151177
} // namespace SCTP
152178
} // namespace RTC

worker/include/RTC/SCTP/Packet.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace RTC
1212
{
1313
/**
1414
* SCTP Packet.
15+
*
1516
* 0 1 2 3
1617
* 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
1718
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -23,6 +24,8 @@ namespace RTC
2324
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2425
* | Chunk #n |
2526
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
27+
*
28+
* It's mandatory that the Packet total length is multiple of 4 bytes.
2629
*/
2730

2831
/**
@@ -37,7 +40,13 @@ namespace RTC
3740
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3841
* | Checksum |
3942
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43+
*
44+
* - Source port (16 bits): Unsigned integer.
45+
* - Destination port (16 bits): Unsigned integer.
46+
* - Verification Tag (32 bits): Unsigned integer.
47+
* - Checksum (32 bits): Unsigned integer.
4048
*/
49+
4150
class Packet : public Serializable
4251
{
4352
public:

worker/src/RTC/SCTP/Chunk.cpp

Lines changed: 52 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
#include "RTC/SCTP/Chunk.hpp"
55
#include "Logger.hpp"
6-
#include "Utils.hpp"
7-
#include <bitset> // std::bitset()
6+
#include "MediaSoupErrors.hpp"
7+
#include <cstring> // std::memcpy()
88

99
namespace RTC
1010
{
@@ -13,7 +13,7 @@ namespace RTC
1313
/* Class variables. */
1414

1515
// clang-format off
16-
absl::flat_hash_map<Chunk::ChunkType, std::string> Chunk::chunkType2String =
16+
std::unordered_map<Chunk::ChunkType, std::string> Chunk::chunkType2String =
1717
{
1818
{ Chunk::ChunkType::DATA, "DATA" },
1919
{ Chunk::ChunkType::INIT, "INIT" },
@@ -35,69 +35,32 @@ namespace RTC
3535

3636
/* Class methods. */
3737

38-
Chunk* Chunk::Parse(const uint8_t* data, size_t len, bool exactLen)
38+
bool Chunk::IsChunk(
39+
const uint8_t* buffer, size_t bufferLength, ChunkType& chunkType, uint16_t& chunkLength)
3940
{
4041
MS_TRACE();
4142

42-
// Ensure there are at least 4 bytes (chunk value is zero-length).
43-
if (len < Chunk::HeaderLength)
43+
if (bufferLength < Chunk::ChunkHeaderLength)
4444
{
45-
MS_WARN_TAG(sctp, "not an SCTP chunk");
45+
MS_WARN_DEV("no space for Chunk header");
4646

47-
return nullptr;
47+
return false;
4848
}
4949

50-
auto* chunk = new Chunk(data, len);
50+
const auto* chunkHeader = reinterpret_cast<const Chunk::ChunkHeader*>(buffer);
51+
auto length = uint16_t{ ntohs(chunkHeader->length) };
5152

52-
// Pointer that initially points to the given data buffer and is later
53-
// incremented to point to other parts of the chunk.
54-
auto* ptr = const_cast<uint8_t*>(data);
55-
56-
// Inspect data after the header length, so move to the chunk value.
57-
ptr += Chunk::HeaderLength;
58-
59-
auto valueLengthWithPadding = Utils::Byte::PadTo4Bytes(chunk->GetValueLength());
60-
61-
// Ensure there is space for the chunk value and its possible padding.
62-
if (len - (ptr - data) < valueLengthWithPadding)
53+
if (bufferLength < Chunk::ChunkHeaderLength + length)
6354
{
64-
MS_WARN_TAG(sctp, "the chunk length exceeds the remaining size, chunk discarded");
55+
MS_WARN_DEV("no space for announced chunk length");
6556

66-
delete chunk;
67-
return nullptr;
57+
return false;
6858
}
6959

70-
// switch (chunk->GetType())
71-
// {
72-
// TODO
73-
// }
74-
75-
// Move pointer after chunk value and its padding.
76-
ptr += valueLengthWithPadding;
60+
chunkType = chunkHeader->type;
61+
chunkLength = length;
7762

78-
// If `exactLen` is set, ensure current position matches the total length.
79-
if (exactLen)
80-
{
81-
//
82-
// TODO: As per RFC 9260:
83-
//
84-
// Note: A robust implementation is expected to accept the chunk whether
85-
// or not the final padding has been included in the Chunk Length.
86-
if (ptr - data != len)
87-
{
88-
MS_WARN_TAG(sctp, "computed chunk size does not match total size, chunk discarded");
89-
90-
delete chunk;
91-
return nullptr;
92-
}
93-
}
94-
// Otherwise we have to fix chunk total size.
95-
else
96-
{
97-
chunk->SetSize(ptr - data);
98-
}
99-
100-
return chunk;
63+
return true;
10164
}
10265

10366
const std::string& Chunk::ChunkType2String(ChunkType chunkType)
@@ -118,9 +81,7 @@ namespace RTC
11881

11982
/* Instance methods. */
12083

121-
Chunk::Chunk(const uint8_t* data, size_t size)
122-
: data(const_cast<uint8_t*>(data)), size(size),
123-
header(reinterpret_cast<Header*>(const_cast<uint8_t*>(data)))
84+
Chunk::Chunk(const uint8_t* buffer, size_t bufferLength) : Serializable(buffer, bufferLength)
12485
{
12586
MS_TRACE();
12687
}
@@ -133,20 +94,48 @@ namespace RTC
13394
void Chunk::Dump() const
13495
{
13596
MS_TRACE();
136-
13797
MS_DUMP("<Chunk>");
98+
MS_DUMP(" length: %zu (buffer length: %zu)", GetLength(), GetBufferLength());
99+
MS_DUMP(" type: %" PRIu8 " (%s)", GetType(), Chunk::ChunkType2String(GetType()).c_str());
100+
MS_DUMP(" flags: " MS_UINT8_4BITS_TO_BINARY_PATTERN, MS_UINT8_4BITS_TO_BINARY(GetFlags()));
101+
MS_DUMP(
102+
" length field: %" PRIu16 " (computed chunk length: %" PRIu16 ")",
103+
GetLengthField(),
104+
GetValueLength());
105+
MS_DUMP("</Chunk>");
106+
}
138107

139-
MS_DUMP(" size: %zu", GetSize());
108+
Chunk* Chunk::Clone(uint8_t* buffer, size_t bufferLength) const
109+
{
110+
MS_TRACE();
140111

141-
MS_DUMP(" type: %" PRIu8 " (%s)", GetType(), Chunk::ChunkType2String(GetType()).c_str());
112+
if (bufferLength < GetLength())
113+
{
114+
MS_THROW_TYPE_ERROR(
115+
"bufferLength (%zu bytes) is lower than current length (%zu bytes)",
116+
bufferLength,
117+
GetLength());
118+
}
142119

143-
std::bitset<8> flagsBitset(this->GetFlags());
120+
std::memcpy(buffer, GetBuffer(), GetLength());
144121

145-
MS_DUMP(" flags: %s", flagsBitset.to_string().c_str());
122+
auto* clonedChunk = new Chunk(buffer, bufferLength);
146123

147-
MS_DUMP(" value length: %" PRIu16, GetValueLength());
124+
// NOTE: The `frozen` flag will be false in the cloned Chunk by default.
148125

149-
MS_DUMP("</Chunk>");
126+
// Need to manually set Serializable length.
127+
clonedChunk->SetLength(GetLength());
128+
129+
return clonedChunk;
130+
}
131+
132+
void Chunk::InitializeHeader(ChunkType chunkType, uint8_t flags, uint16_t valueLength)
133+
{
134+
MS_TRACE();
135+
136+
GetHeaderPointer()->type = chunkType;
137+
GetHeaderPointer()->flags = flags;
138+
SetLengthField(Chunk::ChunkHeaderLength + valueLength);
150139
}
151140
} // namespace SCTP
152141
} // namespace RTC

0 commit comments

Comments
 (0)