mediasoup 3.12.8 → 3.12.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/node/lib/Router.js +2 -2
- package/node/lib/Worker.js +1 -1
- package/node/lib/index.d.ts +1 -1
- package/node/lib/index.js +1 -1
- package/package.json +8 -8
- package/worker/include/RTC/RTCP/Sdes.hpp +3 -0
- package/worker/src/Channel/ChannelSocket.cpp +4 -3
- package/worker/src/DepLibUV.cpp +3 -3
- package/worker/src/PayloadChannel/PayloadChannelSocket.cpp +4 -3
- package/worker/src/RTC/PortManager.cpp +54 -10
- package/worker/src/RTC/RTCP/Sdes.cpp +87 -11
- package/worker/src/handles/SignalsHandler.cpp +3 -3
- package/worker/src/handles/TcpConnectionHandler.cpp +11 -4
- package/worker/src/handles/TcpServerHandler.cpp +5 -5
- package/worker/src/handles/Timer.cpp +3 -3
- package/worker/src/handles/UdpSocketHandler.cpp +5 -5
- package/worker/src/handles/UnixStreamSocket.cpp +13 -6
- package/worker/test/src/RTC/RTCP/TestSdes.cpp +358 -41
- package/worker/test/src/tests.cpp +4 -0
package/node/lib/Router.js
CHANGED
|
@@ -226,11 +226,11 @@ class Router extends EnhancedEventEmitter_1.EnhancedEventEmitter {
|
|
|
226
226
|
transport.on('@producerclose', (producer) => this.#producers.delete(producer.id));
|
|
227
227
|
transport.on('@newdataproducer', (dataProducer) => (this.#dataProducers.set(dataProducer.id, dataProducer)));
|
|
228
228
|
transport.on('@dataproducerclose', (dataProducer) => (this.#dataProducers.delete(dataProducer.id)));
|
|
229
|
+
// Emit observer event.
|
|
230
|
+
this.#observer.safeEmit('newtransport', transport);
|
|
229
231
|
if (webRtcServer) {
|
|
230
232
|
webRtcServer.handleWebRtcTransport(transport);
|
|
231
233
|
}
|
|
232
|
-
// Emit observer event.
|
|
233
|
-
this.#observer.safeEmit('newtransport', transport);
|
|
234
234
|
return transport;
|
|
235
235
|
}
|
|
236
236
|
/**
|
package/node/lib/Worker.js
CHANGED
|
@@ -90,7 +90,7 @@ class Worker extends EnhancedEventEmitter_1.EnhancedEventEmitter {
|
|
|
90
90
|
// options
|
|
91
91
|
{
|
|
92
92
|
env: {
|
|
93
|
-
MEDIASOUP_VERSION: '3.12.
|
|
93
|
+
MEDIASOUP_VERSION: '3.12.9',
|
|
94
94
|
// Let the worker process inherit all environment variables, useful
|
|
95
95
|
// if a custom and not in the path GCC is used so the user can set
|
|
96
96
|
// LD_LIBRARY_PATH environment variable for runtime.
|
package/node/lib/index.d.ts
CHANGED
package/node/lib/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mediasoup",
|
|
3
|
-
"version": "3.12.
|
|
3
|
+
"version": "3.12.9",
|
|
4
4
|
"description": "Cutting Edge WebRTC Video Conferencing",
|
|
5
5
|
"contributors": [
|
|
6
6
|
"Iñaki Baz Castillo <ibc@aliax.net> (https://inakibaz.me)",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"dependencies": {
|
|
90
90
|
"debug": "^4.3.4",
|
|
91
91
|
"h264-profile-level-id": "^1.0.1",
|
|
92
|
-
"node-fetch": "^3.3.
|
|
92
|
+
"node-fetch": "^3.3.2",
|
|
93
93
|
"supports-color": "^9.4.0",
|
|
94
94
|
"tar": "^6.1.15",
|
|
95
95
|
"uuid": "^9.0.0"
|
|
@@ -98,14 +98,14 @@
|
|
|
98
98
|
"@octokit/rest": "^20.0.1",
|
|
99
99
|
"@types/debug": "^4.1.8",
|
|
100
100
|
"@types/jest": "^29.5.3",
|
|
101
|
-
"@types/node": "^20.4.
|
|
101
|
+
"@types/node": "^20.4.9",
|
|
102
102
|
"@types/uuid": "^9.0.2",
|
|
103
|
-
"@typescript-eslint/eslint-plugin": "^6.
|
|
104
|
-
"@typescript-eslint/parser": "^6.
|
|
105
|
-
"eslint": "^8.
|
|
103
|
+
"@typescript-eslint/eslint-plugin": "^6.3.0",
|
|
104
|
+
"@typescript-eslint/parser": "^6.3.0",
|
|
105
|
+
"eslint": "^8.46.0",
|
|
106
106
|
"eslint-plugin-jest": "^27.2.3",
|
|
107
|
-
"jest": "^29.6.
|
|
108
|
-
"marked": "^
|
|
107
|
+
"jest": "^29.6.2",
|
|
108
|
+
"marked": "^7.0.1",
|
|
109
109
|
"open-cli": "^7.2.0",
|
|
110
110
|
"pick-port": "^1.0.1",
|
|
111
111
|
"sctp": "^1.0.0",
|
|
@@ -121,6 +121,9 @@ namespace RTC
|
|
|
121
121
|
size += item->GetSize();
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
// Add the mandatory null octet.
|
|
125
|
+
++size;
|
|
126
|
+
|
|
124
127
|
// Consider pading to 32 bits (4 bytes) boundary.
|
|
125
128
|
// http://stackoverflow.com/questions/11642210/computing-padding-required-for-n-byte-alignment
|
|
126
129
|
return (size + 3) & ~3;
|
|
@@ -24,9 +24,9 @@ namespace Channel
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
inline static void
|
|
27
|
+
inline static void onCloseAsync(uv_handle_t* handle)
|
|
28
28
|
{
|
|
29
|
-
delete handle;
|
|
29
|
+
delete reinterpret_cast<uv_async_t*>(handle);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/* Instance methods. */
|
|
@@ -100,7 +100,8 @@ namespace Channel
|
|
|
100
100
|
|
|
101
101
|
if (this->uvReadHandle)
|
|
102
102
|
{
|
|
103
|
-
uv_close(
|
|
103
|
+
uv_close(
|
|
104
|
+
reinterpret_cast<uv_handle_t*>(this->uvReadHandle), static_cast<uv_close_cb>(onCloseAsync));
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
if (this->consumerSocket)
|
package/worker/src/DepLibUV.cpp
CHANGED
|
@@ -11,9 +11,9 @@ thread_local uv_loop_t* DepLibUV::loop{ nullptr };
|
|
|
11
11
|
|
|
12
12
|
/* Static methods for UV callbacks. */
|
|
13
13
|
|
|
14
|
-
inline static void
|
|
14
|
+
inline static void onCloseLoop(uv_handle_t* handle)
|
|
15
15
|
{
|
|
16
|
-
delete handle;
|
|
16
|
+
delete reinterpret_cast<uv_loop_t*>(handle);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
inline static void onWalk(uv_handle_t* handle, void* /*arg*/)
|
|
@@ -27,7 +27,7 @@ inline static void onWalk(uv_handle_t* handle, void* /*arg*/)
|
|
|
27
27
|
uv_has_ref(handle));
|
|
28
28
|
|
|
29
29
|
if (!uv_is_closing(handle))
|
|
30
|
-
uv_close(handle,
|
|
30
|
+
uv_close(handle, onCloseLoop);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/* Static methods. */
|
|
@@ -25,9 +25,9 @@ namespace PayloadChannel
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
inline static void
|
|
28
|
+
inline static void onCloseAsync(uv_handle_t* handle)
|
|
29
29
|
{
|
|
30
|
-
delete handle;
|
|
30
|
+
delete reinterpret_cast<uv_async_t*>(handle);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/* Instance methods. */
|
|
@@ -102,7 +102,8 @@ namespace PayloadChannel
|
|
|
102
102
|
|
|
103
103
|
if (this->uvReadHandle)
|
|
104
104
|
{
|
|
105
|
-
uv_close(
|
|
105
|
+
uv_close(
|
|
106
|
+
reinterpret_cast<uv_handle_t*>(this->uvReadHandle), static_cast<uv_close_cb>(onCloseAsync));
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
if (this->consumerSocket)
|
|
@@ -12,9 +12,16 @@
|
|
|
12
12
|
|
|
13
13
|
/* Static methods for UV callbacks. */
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
// NOTE: We have different onCloseXxx() callbacks to avoid an ASAN warning by
|
|
16
|
+
// ensuring that we call `delete xxx` with same type as `new xxx` before.
|
|
17
|
+
static inline void onCloseUdp(uv_handle_t* handle)
|
|
16
18
|
{
|
|
17
|
-
delete handle;
|
|
19
|
+
delete reinterpret_cast<uv_udp_t*>(handle);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static inline void onCloseTcp(uv_handle_t* handle)
|
|
23
|
+
{
|
|
24
|
+
delete reinterpret_cast<uv_tcp_t*>(handle);
|
|
18
25
|
}
|
|
19
26
|
|
|
20
27
|
inline static void onFakeConnection(uv_stream_t* /*handle*/, int /*status*/)
|
|
@@ -161,30 +168,44 @@ namespace RTC
|
|
|
161
168
|
switch (transport)
|
|
162
169
|
{
|
|
163
170
|
case Transport::UDP:
|
|
171
|
+
{
|
|
164
172
|
uvHandle = reinterpret_cast<uv_handle_t*>(new uv_udp_t());
|
|
165
173
|
err = uv_udp_init_ex(
|
|
166
174
|
DepLibUV::GetLoop(), reinterpret_cast<uv_udp_t*>(uvHandle), UV_UDP_RECVMMSG);
|
|
175
|
+
|
|
167
176
|
break;
|
|
177
|
+
}
|
|
168
178
|
|
|
169
179
|
case Transport::TCP:
|
|
180
|
+
{
|
|
170
181
|
uvHandle = reinterpret_cast<uv_handle_t*>(new uv_tcp_t());
|
|
171
182
|
err = uv_tcp_init(DepLibUV::GetLoop(), reinterpret_cast<uv_tcp_t*>(uvHandle));
|
|
183
|
+
|
|
172
184
|
break;
|
|
185
|
+
}
|
|
173
186
|
}
|
|
174
187
|
|
|
175
188
|
if (err != 0)
|
|
176
189
|
{
|
|
177
|
-
delete uvHandle;
|
|
178
|
-
|
|
179
190
|
switch (transport)
|
|
180
191
|
{
|
|
181
192
|
case Transport::UDP:
|
|
193
|
+
{
|
|
194
|
+
delete reinterpret_cast<uv_udp_t*>(uvHandle);
|
|
195
|
+
|
|
182
196
|
MS_THROW_ERROR("uv_udp_init_ex() failed: %s", uv_strerror(err));
|
|
197
|
+
|
|
183
198
|
break;
|
|
199
|
+
}
|
|
184
200
|
|
|
185
201
|
case Transport::TCP:
|
|
202
|
+
{
|
|
203
|
+
delete reinterpret_cast<uv_tcp_t*>(uvHandle);
|
|
204
|
+
|
|
186
205
|
MS_THROW_ERROR("uv_tcp_init() failed: %s", uv_strerror(err));
|
|
206
|
+
|
|
187
207
|
break;
|
|
208
|
+
}
|
|
188
209
|
}
|
|
189
210
|
}
|
|
190
211
|
|
|
@@ -259,7 +280,22 @@ namespace RTC
|
|
|
259
280
|
break;
|
|
260
281
|
|
|
261
282
|
// If it failed, close the handle and check the reason.
|
|
262
|
-
|
|
283
|
+
switch (transport)
|
|
284
|
+
{
|
|
285
|
+
case Transport::UDP:
|
|
286
|
+
{
|
|
287
|
+
uv_close(reinterpret_cast<uv_handle_t*>(uvHandle), static_cast<uv_close_cb>(onCloseUdp));
|
|
288
|
+
|
|
289
|
+
break;
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
case Transport::TCP:
|
|
293
|
+
{
|
|
294
|
+
uv_close(reinterpret_cast<uv_handle_t*>(uvHandle), static_cast<uv_close_cb>(onCloseTcp));
|
|
295
|
+
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
263
299
|
|
|
264
300
|
switch (err)
|
|
265
301
|
{
|
|
@@ -400,17 +436,25 @@ namespace RTC
|
|
|
400
436
|
|
|
401
437
|
if (err != 0)
|
|
402
438
|
{
|
|
403
|
-
delete uvHandle;
|
|
404
|
-
|
|
405
439
|
switch (transport)
|
|
406
440
|
{
|
|
407
441
|
case Transport::UDP:
|
|
442
|
+
{
|
|
443
|
+
delete reinterpret_cast<uv_udp_t*>(uvHandle);
|
|
444
|
+
|
|
408
445
|
MS_THROW_ERROR("uv_udp_init_ex() failed: %s", uv_strerror(err));
|
|
446
|
+
|
|
409
447
|
break;
|
|
448
|
+
}
|
|
410
449
|
|
|
411
450
|
case Transport::TCP:
|
|
451
|
+
{
|
|
452
|
+
delete reinterpret_cast<uv_tcp_t*>(uvHandle);
|
|
453
|
+
|
|
412
454
|
MS_THROW_ERROR("uv_tcp_init() failed: %s", uv_strerror(err));
|
|
455
|
+
|
|
413
456
|
break;
|
|
457
|
+
}
|
|
414
458
|
}
|
|
415
459
|
}
|
|
416
460
|
|
|
@@ -426,7 +470,7 @@ namespace RTC
|
|
|
426
470
|
if (err != 0)
|
|
427
471
|
{
|
|
428
472
|
// If it failed, close the handle and check the reason.
|
|
429
|
-
uv_close(reinterpret_cast<uv_handle_t*>(uvHandle), static_cast<uv_close_cb>(
|
|
473
|
+
uv_close(reinterpret_cast<uv_handle_t*>(uvHandle), static_cast<uv_close_cb>(onCloseUdp));
|
|
430
474
|
|
|
431
475
|
MS_THROW_ERROR(
|
|
432
476
|
"uv_udp_bind() failed [transport:%s, ip:'%s', port:%" PRIu16 "]: %s",
|
|
@@ -449,7 +493,7 @@ namespace RTC
|
|
|
449
493
|
if (err != 0)
|
|
450
494
|
{
|
|
451
495
|
// If it failed, close the handle and check the reason.
|
|
452
|
-
uv_close(reinterpret_cast<uv_handle_t*>(uvHandle), static_cast<uv_close_cb>(
|
|
496
|
+
uv_close(reinterpret_cast<uv_handle_t*>(uvHandle), static_cast<uv_close_cb>(onCloseTcp));
|
|
453
497
|
|
|
454
498
|
MS_THROW_ERROR(
|
|
455
499
|
"uv_tcp_bind() failed [transport:%s, ip:'%s', port:%" PRIu16 "]: %s",
|
|
@@ -469,7 +513,7 @@ namespace RTC
|
|
|
469
513
|
if (err != 0)
|
|
470
514
|
{
|
|
471
515
|
// If it failed, close the handle and check the reason.
|
|
472
|
-
uv_close(reinterpret_cast<uv_handle_t*>(uvHandle), static_cast<uv_close_cb>(
|
|
516
|
+
uv_close(reinterpret_cast<uv_handle_t*>(uvHandle), static_cast<uv_close_cb>(onCloseTcp));
|
|
473
517
|
|
|
474
518
|
MS_THROW_ERROR(
|
|
475
519
|
"uv_listen() failed [transport:%s, ip:'%s', port:%" PRIu16 "]: %s",
|
|
@@ -36,17 +36,21 @@ namespace RTC
|
|
|
36
36
|
// Get the header.
|
|
37
37
|
auto* header = const_cast<Header*>(reinterpret_cast<const Header*>(data));
|
|
38
38
|
|
|
39
|
+
// If item type is 0, there is no need for length field (unless padding
|
|
40
|
+
// is needed).
|
|
41
|
+
if (len > 0 && header->type == SdesItem::Type::END)
|
|
42
|
+
{
|
|
43
|
+
return nullptr;
|
|
44
|
+
}
|
|
45
|
+
|
|
39
46
|
// data size must be >= header + length value.
|
|
40
|
-
if (len < HeaderSize || len <
|
|
47
|
+
if (len < HeaderSize || len < HeaderSize + header->length)
|
|
41
48
|
{
|
|
42
49
|
MS_WARN_TAG(rtcp, "not enough space for SDES item, discarded");
|
|
43
50
|
|
|
44
51
|
return nullptr;
|
|
45
52
|
}
|
|
46
53
|
|
|
47
|
-
if (header->type == SdesItem::Type::END)
|
|
48
|
-
return nullptr;
|
|
49
|
-
|
|
50
54
|
return new SdesItem(header);
|
|
51
55
|
}
|
|
52
56
|
|
|
@@ -57,7 +61,9 @@ namespace RTC
|
|
|
57
61
|
auto it = SdesItem::type2String.find(type);
|
|
58
62
|
|
|
59
63
|
if (it == SdesItem::type2String.end())
|
|
64
|
+
{
|
|
60
65
|
return Unknown;
|
|
66
|
+
}
|
|
61
67
|
|
|
62
68
|
return it->second;
|
|
63
69
|
}
|
|
@@ -123,19 +129,77 @@ namespace RTC
|
|
|
123
129
|
|
|
124
130
|
std::unique_ptr<SdesChunk> chunk(new SdesChunk(ssrc));
|
|
125
131
|
|
|
126
|
-
size_t offset
|
|
132
|
+
size_t offset{ 4u }; /* ssrc */
|
|
133
|
+
size_t chunkLength{ 4u };
|
|
127
134
|
|
|
128
135
|
while (len > offset)
|
|
129
136
|
{
|
|
130
|
-
|
|
137
|
+
auto* item = SdesItem::Parse(data + offset, len - offset);
|
|
131
138
|
|
|
132
139
|
if (!item)
|
|
140
|
+
{
|
|
133
141
|
break;
|
|
142
|
+
}
|
|
134
143
|
|
|
135
144
|
chunk->AddItem(item);
|
|
145
|
+
chunkLength += item->GetSize();
|
|
136
146
|
offset += item->GetSize();
|
|
137
147
|
}
|
|
138
148
|
|
|
149
|
+
// Once all items have been parsed, there must be 1, 2, 3 or 4 null octets
|
|
150
|
+
// (this is mandatory). The first one (AKA item type 0) means "end of
|
|
151
|
+
// items", and the others maybe needed for padding the chunk to 4 bytes.
|
|
152
|
+
|
|
153
|
+
// First ensure that there is at least one null octet.
|
|
154
|
+
if (offset == len || (offset < len && Utils::Byte::Get1Byte(data, offset) != 0u))
|
|
155
|
+
{
|
|
156
|
+
MS_WARN_TAG(rtcp, "invalid SDES chunk (missing mandatory null octet), discarded");
|
|
157
|
+
|
|
158
|
+
return nullptr;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// So we have the mandatory null octet.
|
|
162
|
+
++chunkLength;
|
|
163
|
+
++offset;
|
|
164
|
+
|
|
165
|
+
// Then check that there are 0, 1, 2 or 3 (no more) null octets that pad
|
|
166
|
+
// the chunk to 4 bytes.
|
|
167
|
+
uint16_t neededAdditionalNullOctets =
|
|
168
|
+
Utils::Byte::PadTo4Bytes(static_cast<uint16_t>(chunkLength)) -
|
|
169
|
+
static_cast<uint16_t>(chunkLength);
|
|
170
|
+
uint16_t foundAdditionalNullOctets{ 0u };
|
|
171
|
+
|
|
172
|
+
for (uint16_t i{ 0u }; len > offset && i < neededAdditionalNullOctets; ++i)
|
|
173
|
+
{
|
|
174
|
+
if (Utils::Byte::Get1Byte(data, offset) != 0u)
|
|
175
|
+
{
|
|
176
|
+
MS_WARN_TAG(
|
|
177
|
+
rtcp,
|
|
178
|
+
"invalid SDES chunk (missing additional null octets [needed:%" PRIu16 ", found:%" PRIu16
|
|
179
|
+
"]), discarded",
|
|
180
|
+
neededAdditionalNullOctets,
|
|
181
|
+
foundAdditionalNullOctets);
|
|
182
|
+
|
|
183
|
+
return nullptr;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
++foundAdditionalNullOctets;
|
|
187
|
+
++chunkLength;
|
|
188
|
+
++offset;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (foundAdditionalNullOctets != neededAdditionalNullOctets)
|
|
192
|
+
{
|
|
193
|
+
MS_WARN_TAG(
|
|
194
|
+
rtcp,
|
|
195
|
+
"invalid SDES chunk (missing additional null octets [needed:%" PRIu16 ", found:%" PRIu16
|
|
196
|
+
"]), discarded",
|
|
197
|
+
neededAdditionalNullOctets,
|
|
198
|
+
foundAdditionalNullOctets);
|
|
199
|
+
|
|
200
|
+
return nullptr;
|
|
201
|
+
}
|
|
202
|
+
|
|
139
203
|
return chunk.release();
|
|
140
204
|
}
|
|
141
205
|
|
|
@@ -155,10 +219,15 @@ namespace RTC
|
|
|
155
219
|
offset += item->Serialize(buffer + offset);
|
|
156
220
|
}
|
|
157
221
|
|
|
222
|
+
// Add the mandatory null octet.
|
|
223
|
+
buffer[offset] = 0;
|
|
224
|
+
|
|
225
|
+
++offset;
|
|
226
|
+
|
|
158
227
|
// 32 bits padding.
|
|
159
228
|
const size_t padding = (-offset) & 3;
|
|
160
229
|
|
|
161
|
-
for (size_t i{
|
|
230
|
+
for (size_t i{ 0u }; i < padding; ++i)
|
|
162
231
|
{
|
|
163
232
|
buffer[offset + i] = 0;
|
|
164
233
|
}
|
|
@@ -195,9 +264,9 @@ namespace RTC
|
|
|
195
264
|
size_t offset = Packet::CommonHeaderSize;
|
|
196
265
|
uint8_t count = header->count;
|
|
197
266
|
|
|
198
|
-
while (
|
|
267
|
+
while (count-- && (len > offset))
|
|
199
268
|
{
|
|
200
|
-
|
|
269
|
+
auto* chunk = SdesChunk::Parse(data + offset, len - offset);
|
|
201
270
|
|
|
202
271
|
if (chunk != nullptr)
|
|
203
272
|
{
|
|
@@ -206,10 +275,17 @@ namespace RTC
|
|
|
206
275
|
}
|
|
207
276
|
else
|
|
208
277
|
{
|
|
209
|
-
|
|
278
|
+
break;
|
|
210
279
|
}
|
|
211
280
|
}
|
|
212
281
|
|
|
282
|
+
if (packet->GetCount() != header->count)
|
|
283
|
+
{
|
|
284
|
+
MS_WARN_TAG(rtcp, "RTCP count value doesn't match found number of chunks, discarded");
|
|
285
|
+
|
|
286
|
+
return nullptr;
|
|
287
|
+
}
|
|
288
|
+
|
|
213
289
|
return packet.release();
|
|
214
290
|
}
|
|
215
291
|
|
|
@@ -223,7 +299,7 @@ namespace RTC
|
|
|
223
299
|
size_t length = 0;
|
|
224
300
|
uint8_t* header = { nullptr };
|
|
225
301
|
|
|
226
|
-
for (size_t i
|
|
302
|
+
for (size_t i{ 0u }; i < this->GetCount(); ++i)
|
|
227
303
|
{
|
|
228
304
|
// Create a new SDES packet header for each 31 chunks.
|
|
229
305
|
if (i % MaxChunksPerPacket == 0)
|
|
@@ -13,9 +13,9 @@ inline static void onSignal(uv_signal_t* handle, int signum)
|
|
|
13
13
|
static_cast<SignalsHandler*>(handle->data)->OnUvSignal(signum);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
inline static void
|
|
16
|
+
inline static void onCloseSignal(uv_handle_t* handle)
|
|
17
17
|
{
|
|
18
|
-
delete handle;
|
|
18
|
+
delete reinterpret_cast<uv_signal_t*>(handle);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/* Instance methods. */
|
|
@@ -44,7 +44,7 @@ void SignalsHandler::Close()
|
|
|
44
44
|
|
|
45
45
|
for (auto* uvHandle : this->uvHandles)
|
|
46
46
|
{
|
|
47
|
-
uv_close(reinterpret_cast<uv_handle_t*>(uvHandle), static_cast<uv_close_cb>(
|
|
47
|
+
uv_close(reinterpret_cast<uv_handle_t*>(uvHandle), static_cast<uv_close_cb>(onCloseSignal));
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -40,9 +40,16 @@ inline static void onWrite(uv_write_t* req, int status)
|
|
|
40
40
|
delete writeData;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
// NOTE: We have different onCloseXxx() callbacks to avoid an ASAN warning by
|
|
44
|
+
// ensuring that we call `delete xxx` with same type as `new xxx` before.
|
|
45
|
+
inline static void onCloseTcp(uv_handle_t* handle)
|
|
44
46
|
{
|
|
45
|
-
delete handle;
|
|
47
|
+
delete reinterpret_cast<uv_tcp_t*>(handle);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
inline static void onCloseShutdown(uv_handle_t* handle)
|
|
51
|
+
{
|
|
52
|
+
delete reinterpret_cast<uv_shutdown_t*>(handle);
|
|
46
53
|
}
|
|
47
54
|
|
|
48
55
|
inline static void onShutdown(uv_shutdown_t* req, int /*status*/)
|
|
@@ -52,7 +59,7 @@ inline static void onShutdown(uv_shutdown_t* req, int /*status*/)
|
|
|
52
59
|
delete req;
|
|
53
60
|
|
|
54
61
|
// Now do close the handle.
|
|
55
|
-
uv_close(reinterpret_cast<uv_handle_t*>(handle), static_cast<uv_close_cb>(
|
|
62
|
+
uv_close(reinterpret_cast<uv_handle_t*>(handle), static_cast<uv_close_cb>(onCloseShutdown));
|
|
56
63
|
}
|
|
57
64
|
|
|
58
65
|
/* Instance methods. */
|
|
@@ -114,7 +121,7 @@ void TcpConnectionHandler::Close()
|
|
|
114
121
|
// Otherwise directly close the socket.
|
|
115
122
|
else
|
|
116
123
|
{
|
|
117
|
-
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(
|
|
124
|
+
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(onCloseTcp));
|
|
118
125
|
}
|
|
119
126
|
}
|
|
120
127
|
|
|
@@ -20,9 +20,9 @@ inline static void onConnection(uv_stream_t* handle, int status)
|
|
|
20
20
|
server->OnUvConnection(status);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
inline static void
|
|
23
|
+
inline static void onCloseTcp(uv_handle_t* handle)
|
|
24
24
|
{
|
|
25
|
-
delete handle;
|
|
25
|
+
delete reinterpret_cast<uv_tcp_t*>(handle);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/* Instance methods. */
|
|
@@ -43,7 +43,7 @@ TcpServerHandler::TcpServerHandler(uv_tcp_t* uvHandle) : uvHandle(uvHandle)
|
|
|
43
43
|
|
|
44
44
|
if (err != 0)
|
|
45
45
|
{
|
|
46
|
-
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(
|
|
46
|
+
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(onCloseTcp));
|
|
47
47
|
|
|
48
48
|
MS_THROW_ERROR("uv_listen() failed: %s", uv_strerror(err));
|
|
49
49
|
}
|
|
@@ -51,7 +51,7 @@ TcpServerHandler::TcpServerHandler(uv_tcp_t* uvHandle) : uvHandle(uvHandle)
|
|
|
51
51
|
// Set local address.
|
|
52
52
|
if (!SetLocalAddress())
|
|
53
53
|
{
|
|
54
|
-
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(
|
|
54
|
+
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(onCloseTcp));
|
|
55
55
|
|
|
56
56
|
MS_THROW_ERROR("error setting local IP and port");
|
|
57
57
|
}
|
|
@@ -84,7 +84,7 @@ void TcpServerHandler::Close()
|
|
|
84
84
|
delete connection;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(
|
|
87
|
+
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(onCloseTcp));
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
void TcpServerHandler::Dump() const
|
|
@@ -13,9 +13,9 @@ inline static void onTimer(uv_timer_t* handle)
|
|
|
13
13
|
static_cast<Timer*>(handle->data)->OnUvTimer();
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
inline static void
|
|
16
|
+
inline static void onCloseTimer(uv_handle_t* handle)
|
|
17
17
|
{
|
|
18
|
-
delete handle;
|
|
18
|
+
delete reinterpret_cast<uv_timer_t*>(handle);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/* Instance methods. */
|
|
@@ -59,7 +59,7 @@ void Timer::Close()
|
|
|
59
59
|
|
|
60
60
|
this->closed = true;
|
|
61
61
|
|
|
62
|
-
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(
|
|
62
|
+
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(onCloseTimer));
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
void Timer::Start(uint64_t timeout, uint64_t repeat)
|
|
@@ -45,9 +45,9 @@ inline static void onSend(uv_udp_send_t* req, int status)
|
|
|
45
45
|
delete sendData;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
inline static void
|
|
48
|
+
inline static void onCloseUdp(uv_handle_t* handle)
|
|
49
49
|
{
|
|
50
|
-
delete handle;
|
|
50
|
+
delete reinterpret_cast<uv_udp_t*>(handle);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/* Instance methods. */
|
|
@@ -66,7 +66,7 @@ UdpSocketHandler::UdpSocketHandler(uv_udp_t* uvHandle) : uvHandle(uvHandle)
|
|
|
66
66
|
|
|
67
67
|
if (err != 0)
|
|
68
68
|
{
|
|
69
|
-
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(
|
|
69
|
+
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(onCloseUdp));
|
|
70
70
|
|
|
71
71
|
MS_THROW_ERROR("uv_udp_recv_start() failed: %s", uv_strerror(err));
|
|
72
72
|
}
|
|
@@ -74,7 +74,7 @@ UdpSocketHandler::UdpSocketHandler(uv_udp_t* uvHandle) : uvHandle(uvHandle)
|
|
|
74
74
|
// Set local address.
|
|
75
75
|
if (!SetLocalAddress())
|
|
76
76
|
{
|
|
77
|
-
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(
|
|
77
|
+
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(onCloseUdp));
|
|
78
78
|
|
|
79
79
|
MS_THROW_ERROR("error setting local IP and port");
|
|
80
80
|
}
|
|
@@ -106,7 +106,7 @@ void UdpSocketHandler::Close()
|
|
|
106
106
|
if (err != 0)
|
|
107
107
|
MS_ABORT("uv_udp_recv_stop() failed: %s", uv_strerror(err));
|
|
108
108
|
|
|
109
|
-
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(
|
|
109
|
+
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(onCloseUdp));
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
void UdpSocketHandler::Dump() const
|
|
@@ -44,9 +44,16 @@ inline static void onWrite(uv_write_t* req, int status)
|
|
|
44
44
|
delete writeData;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
// NOTE: We have different onCloseXxx() callbacks to avoid an ASAN warning by
|
|
48
|
+
// ensuring that we call `delete xxx` with same type as `new xxx` before.
|
|
49
|
+
inline static void onClosePipe(uv_handle_t* handle)
|
|
48
50
|
{
|
|
49
|
-
delete handle;
|
|
51
|
+
delete reinterpret_cast<uv_pipe_t*>(handle);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
inline static void onCloseShutdown(uv_handle_t* handle)
|
|
55
|
+
{
|
|
56
|
+
delete reinterpret_cast<uv_shutdown_t*>(handle);
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
inline static void onShutdown(uv_shutdown_t* req, int /*status*/)
|
|
@@ -56,7 +63,7 @@ inline static void onShutdown(uv_shutdown_t* req, int /*status*/)
|
|
|
56
63
|
delete req;
|
|
57
64
|
|
|
58
65
|
// Now do close the handle.
|
|
59
|
-
uv_close(reinterpret_cast<uv_handle_t*>(handle), static_cast<uv_close_cb>(
|
|
66
|
+
uv_close(reinterpret_cast<uv_handle_t*>(handle), static_cast<uv_close_cb>(onCloseShutdown));
|
|
60
67
|
}
|
|
61
68
|
|
|
62
69
|
/* Instance methods. */
|
|
@@ -85,7 +92,7 @@ UnixStreamSocket::UnixStreamSocket(int fd, size_t bufferSize, UnixStreamSocket::
|
|
|
85
92
|
|
|
86
93
|
if (err != 0)
|
|
87
94
|
{
|
|
88
|
-
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(
|
|
95
|
+
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(onClosePipe));
|
|
89
96
|
|
|
90
97
|
MS_THROW_ERROR_STD("uv_pipe_open() failed: %s", uv_strerror(err));
|
|
91
98
|
}
|
|
@@ -100,7 +107,7 @@ UnixStreamSocket::UnixStreamSocket(int fd, size_t bufferSize, UnixStreamSocket::
|
|
|
100
107
|
|
|
101
108
|
if (err != 0)
|
|
102
109
|
{
|
|
103
|
-
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(
|
|
110
|
+
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(onClosePipe));
|
|
104
111
|
|
|
105
112
|
MS_THROW_ERROR_STD("uv_read_start() failed: %s", uv_strerror(err));
|
|
106
113
|
}
|
|
@@ -157,7 +164,7 @@ void UnixStreamSocket::Close()
|
|
|
157
164
|
// Otherwise directly close the socket.
|
|
158
165
|
else
|
|
159
166
|
{
|
|
160
|
-
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(
|
|
167
|
+
uv_close(reinterpret_cast<uv_handle_t*>(this->uvHandle), static_cast<uv_close_cb>(onClosePipe));
|
|
161
168
|
}
|
|
162
169
|
}
|
|
163
170
|
|
|
@@ -11,68 +11,378 @@ namespace TestSdes
|
|
|
11
11
|
// RTCP Sdes Packet.
|
|
12
12
|
|
|
13
13
|
// clang-format off
|
|
14
|
-
uint8_t
|
|
14
|
+
uint8_t buffer1[] =
|
|
15
15
|
{
|
|
16
16
|
0x81, 0xca, 0x00, 0x06, // Type: 202 (SDES), Count: 1, Length: 6
|
|
17
17
|
0x9f, 0x65, 0xe7, 0x42, // SSRC: 0x9f65e742
|
|
18
|
+
// Chunk 1
|
|
18
19
|
0x01, 0x10, 0x74, 0x37, // Item Type: 1 (CNAME), Length: 16, Value: t7mkYnCm46OcINy/
|
|
19
20
|
0x6d, 0x6b, 0x59, 0x6e,
|
|
20
21
|
0x43, 0x6d, 0x34, 0x36,
|
|
21
22
|
0x4f, 0x63, 0x49, 0x4e,
|
|
22
|
-
0x79, 0x2f, 0x00, 0x00
|
|
23
|
+
0x79, 0x2f, 0x00, 0x00 // 2 null octets
|
|
23
24
|
};
|
|
24
25
|
// clang-format on
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
// First chunk (chunk 1).
|
|
28
|
+
uint32_t ssrc1{ 0x9f65e742 };
|
|
29
|
+
// First item (item 1).
|
|
30
|
+
SdesItem::Type item1Type{ SdesItem::Type::CNAME };
|
|
31
|
+
std::string item1Value{ "t7mkYnCm46OcINy/" };
|
|
32
|
+
size_t item1Length{ 16u };
|
|
27
33
|
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
SdesItem::Type type{ SdesItem::Type::CNAME };
|
|
31
|
-
std::string value{ "t7mkYnCm46OcINy/" };
|
|
32
|
-
size_t length = 16;
|
|
33
|
-
|
|
34
|
-
void verify(SdesChunk* chunk)
|
|
34
|
+
// clang-format off
|
|
35
|
+
uint8_t buffer2[] =
|
|
35
36
|
{
|
|
36
|
-
|
|
37
|
+
0xa2, 0xca, 0x00, 0x0d, // Padding, Type: 202 (SDES), Count: 2, Length: 13
|
|
38
|
+
// Chunk 2
|
|
39
|
+
0x00, 0x00, 0x04, 0xd2, // SSRC: 1234
|
|
40
|
+
0x01, 0x06, 0x71, 0x77, // Item Type: 1 (CNAME), Length: 6, Text: "qwerty"
|
|
41
|
+
0x65, 0x72, 0x74, 0x79,
|
|
42
|
+
0x06, 0x06, 0x69, 0xc3, // Item Type: 6 (TOOL), Length: 6, Text: "iñaki"
|
|
43
|
+
0xb1, 0x61, 0x6b, 0x69,
|
|
44
|
+
0x00, 0x00, 0x00, 0x00, // 4 null octets
|
|
45
|
+
// Chunk 3
|
|
46
|
+
0x00, 0x00, 0x16, 0x2e, // SSRC: 5678
|
|
47
|
+
0x05, 0x11, 0x73, 0x6f, // Item Type: 5 (LOC), Length: 17, Text: "somewhere œæ€"
|
|
48
|
+
0x6d, 0x65, 0x77, 0x68,
|
|
49
|
+
0x65, 0x72, 0x65, 0x20,
|
|
50
|
+
0xc5, 0x93, 0xc3, 0xa6,
|
|
51
|
+
0xe2, 0x82, 0xac, 0x00, // 1 null octet
|
|
52
|
+
0x00, 0x00, 0x00, 0x00 // Pading (4 bytes)
|
|
53
|
+
};
|
|
54
|
+
// clang-format on
|
|
37
55
|
|
|
38
|
-
|
|
56
|
+
// First chunk (chunk 2).
|
|
57
|
+
uint32_t ssrc2{ 1234 };
|
|
58
|
+
// First item (item 2).
|
|
59
|
+
SdesItem::Type item2Type{ SdesItem::Type::CNAME };
|
|
60
|
+
std::string item2Value{ "qwerty" };
|
|
61
|
+
size_t item2Length{ 6u };
|
|
62
|
+
// First item (item 3).
|
|
63
|
+
SdesItem::Type item3Type{ SdesItem::Type::TOOL };
|
|
64
|
+
std::string item3Value{ "iñaki" };
|
|
65
|
+
size_t item3Length{ 6u };
|
|
66
|
+
|
|
67
|
+
// Second chunk (chunk 3).
|
|
68
|
+
uint32_t ssrc3{ 5678 };
|
|
69
|
+
// First item (item 4).
|
|
70
|
+
SdesItem::Type item4Type{ SdesItem::Type::LOC };
|
|
71
|
+
std::string item4Value{ "somewhere œæ€" };
|
|
72
|
+
size_t item4Length{ 17u };
|
|
39
73
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
74
|
+
// clang-format off
|
|
75
|
+
uint8_t buffer3[] =
|
|
76
|
+
{
|
|
77
|
+
0x81, 0xca, 0x00, 0x03, // Type: 202 (SDES), Count: 1, Length: 3
|
|
78
|
+
// Chunk
|
|
79
|
+
0x11, 0x22, 0x33, 0x44, // SSRC: 0x11223344
|
|
80
|
+
0x05, 0x02, 0x61, 0x62, // Item Type: 5 (LOC), Length: 2, Text: "ab"
|
|
81
|
+
0x00, 0x00, 0x00, 0x00 // 4 null octets
|
|
82
|
+
};
|
|
83
|
+
// clang-format on
|
|
84
|
+
|
|
85
|
+
// First chunk (chunk 4).
|
|
86
|
+
uint32_t ssrc4{ 0x11223344 };
|
|
87
|
+
// First item (item 5).
|
|
88
|
+
SdesItem::Type item5Type{ SdesItem::Type::LOC };
|
|
89
|
+
std::string item5Value{ "ab" };
|
|
90
|
+
size_t item5Length{ 2u };
|
|
44
91
|
} // namespace TestSdes
|
|
45
92
|
|
|
46
93
|
using namespace TestSdes;
|
|
47
94
|
|
|
48
95
|
SCENARIO("RTCP SDES parsing", "[parser][rtcp][sdes]")
|
|
49
96
|
{
|
|
50
|
-
SECTION("parse packet")
|
|
97
|
+
SECTION("parse packet 1")
|
|
51
98
|
{
|
|
52
|
-
SdesPacket* packet = SdesPacket::Parse(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
auto* header = reinterpret_cast<RTC::RTCP::Packet::CommonHeader*>(buffer);
|
|
99
|
+
SdesPacket* packet = SdesPacket::Parse(buffer1, sizeof(buffer1));
|
|
100
|
+
auto* header = reinterpret_cast<RTC::RTCP::Packet::CommonHeader*>(buffer1);
|
|
56
101
|
|
|
102
|
+
REQUIRE(packet);
|
|
57
103
|
REQUIRE(ntohs(header->length) == 6);
|
|
58
|
-
REQUIRE(
|
|
104
|
+
REQUIRE(packet->GetSize() == 28);
|
|
105
|
+
REQUIRE(packet->GetCount() == 1);
|
|
106
|
+
|
|
107
|
+
size_t chunkIdx{ 0u };
|
|
108
|
+
|
|
109
|
+
for (auto it = packet->Begin(); it != packet->End(); ++it, ++chunkIdx)
|
|
110
|
+
{
|
|
111
|
+
auto* chunk = *it;
|
|
112
|
+
|
|
113
|
+
switch (chunkIdx)
|
|
114
|
+
{
|
|
115
|
+
/* First chunk (chunk 1). */
|
|
116
|
+
case 0:
|
|
117
|
+
{
|
|
118
|
+
// Chunk size must be 24 bytes (including 4 null octets).
|
|
119
|
+
REQUIRE(chunk->GetSize() == 24);
|
|
120
|
+
REQUIRE(chunk->GetSsrc() == ssrc1);
|
|
121
|
+
|
|
122
|
+
size_t itemIdx{ 0u };
|
|
123
|
+
|
|
124
|
+
for (auto it2 = chunk->Begin(); it2 != chunk->End(); ++it2, ++itemIdx)
|
|
125
|
+
{
|
|
126
|
+
auto* item = *it2;
|
|
127
|
+
|
|
128
|
+
switch (itemIdx)
|
|
129
|
+
{
|
|
130
|
+
/* First item (item 1). */
|
|
131
|
+
case 0:
|
|
132
|
+
{
|
|
133
|
+
REQUIRE(item->GetType() == item1Type);
|
|
134
|
+
REQUIRE(item->GetLength() == item1Length);
|
|
135
|
+
REQUIRE(std::string(item->GetValue(), item1Length) == item1Value);
|
|
136
|
+
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// There is 1 item.
|
|
143
|
+
REQUIRE(itemIdx == 1);
|
|
144
|
+
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
59
149
|
|
|
60
|
-
|
|
150
|
+
// There is 1 chunk.
|
|
151
|
+
REQUIRE(chunkIdx == 1);
|
|
61
152
|
|
|
62
153
|
SECTION("serialize SdesChunk instance")
|
|
63
154
|
{
|
|
64
|
-
|
|
155
|
+
auto it = packet->Begin();
|
|
156
|
+
auto* chunk1 = *it;
|
|
157
|
+
uint8_t* chunk1Buffer = buffer1 + Packet::CommonHeaderSize;
|
|
65
158
|
|
|
66
|
-
chunk
|
|
159
|
+
// NOTE: Length of first chunk (including null octets) is 24.
|
|
160
|
+
uint8_t serialized1[24] = { 0 };
|
|
67
161
|
|
|
68
|
-
|
|
162
|
+
chunk1->Serialize(serialized1);
|
|
163
|
+
|
|
164
|
+
REQUIRE(std::memcmp(chunk1Buffer, serialized1, 24) == 0);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
delete packet;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
SECTION("parse packet 2")
|
|
171
|
+
{
|
|
172
|
+
SdesPacket* packet = SdesPacket::Parse(buffer2, sizeof(buffer2));
|
|
173
|
+
auto* header = reinterpret_cast<RTC::RTCP::Packet::CommonHeader*>(buffer2);
|
|
174
|
+
|
|
175
|
+
REQUIRE(packet);
|
|
176
|
+
REQUIRE(ntohs(header->length) == 13);
|
|
177
|
+
// Despite total buffer size is 56 bytes, our GetSize() method doesn't not
|
|
178
|
+
// consider RTCP padding (4 bytes in this case).
|
|
179
|
+
REQUIRE(packet->GetSize() == 52);
|
|
180
|
+
REQUIRE(packet->GetCount() == 2);
|
|
181
|
+
|
|
182
|
+
size_t chunkIdx{ 0u };
|
|
183
|
+
|
|
184
|
+
for (auto it = packet->Begin(); it != packet->End(); ++it, ++chunkIdx)
|
|
185
|
+
{
|
|
186
|
+
auto* chunk = *it;
|
|
187
|
+
|
|
188
|
+
switch (chunkIdx)
|
|
69
189
|
{
|
|
70
|
-
|
|
190
|
+
/* First chunk (chunk 2). */
|
|
191
|
+
case 0:
|
|
192
|
+
{
|
|
193
|
+
// Chunk size must be 24 bytes (including 4 null octets).
|
|
194
|
+
REQUIRE(chunk->GetSize() == 24);
|
|
195
|
+
REQUIRE(chunk->GetSsrc() == ssrc2);
|
|
196
|
+
|
|
197
|
+
size_t itemIdx{ 0u };
|
|
198
|
+
|
|
199
|
+
for (auto it2 = chunk->Begin(); it2 != chunk->End(); ++it2, ++itemIdx)
|
|
200
|
+
{
|
|
201
|
+
auto* item = *it2;
|
|
202
|
+
|
|
203
|
+
switch (itemIdx)
|
|
204
|
+
{
|
|
205
|
+
/* First item (item 2). */
|
|
206
|
+
case 0:
|
|
207
|
+
{
|
|
208
|
+
REQUIRE(item->GetType() == item2Type);
|
|
209
|
+
REQUIRE(item->GetLength() == item2Length);
|
|
210
|
+
REQUIRE(std::string(item->GetValue(), item2Length) == item2Value);
|
|
211
|
+
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/* Second item (item 3). */
|
|
216
|
+
case 1:
|
|
217
|
+
{
|
|
218
|
+
REQUIRE(item->GetType() == item3Type);
|
|
219
|
+
REQUIRE(item->GetLength() == item3Length);
|
|
220
|
+
REQUIRE(std::string(item->GetValue(), item3Length) == item3Value);
|
|
221
|
+
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// There are 2 items.
|
|
228
|
+
REQUIRE(itemIdx == 2);
|
|
229
|
+
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/* Second chunk (chunk 3). */
|
|
234
|
+
case 1:
|
|
235
|
+
{
|
|
236
|
+
// Chunk size must be 24 bytes (including 1 null octet).
|
|
237
|
+
REQUIRE(chunk->GetSize() == 24);
|
|
238
|
+
REQUIRE(chunk->GetSsrc() == ssrc3);
|
|
239
|
+
|
|
240
|
+
size_t itemIdx{ 0u };
|
|
241
|
+
|
|
242
|
+
for (auto it2 = chunk->Begin(); it2 != chunk->End(); ++it2, ++itemIdx)
|
|
243
|
+
{
|
|
244
|
+
auto* item = *it2;
|
|
245
|
+
|
|
246
|
+
switch (itemIdx)
|
|
247
|
+
{
|
|
248
|
+
/* First item (item 4). */
|
|
249
|
+
case 0:
|
|
250
|
+
{
|
|
251
|
+
REQUIRE(item->GetType() == item4Type);
|
|
252
|
+
REQUIRE(item->GetLength() == item4Length);
|
|
253
|
+
REQUIRE(std::string(item->GetValue(), item4Length) == item4Value);
|
|
254
|
+
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// There is 1 item.
|
|
261
|
+
REQUIRE(itemIdx == 1);
|
|
262
|
+
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
71
265
|
}
|
|
72
266
|
}
|
|
267
|
+
|
|
268
|
+
// There are 2 chunks.
|
|
269
|
+
REQUIRE(chunkIdx == 2);
|
|
270
|
+
|
|
271
|
+
SECTION("serialize SdesChunk instances")
|
|
272
|
+
{
|
|
273
|
+
auto it = packet->Begin();
|
|
274
|
+
auto* chunk1 = *it;
|
|
275
|
+
uint8_t* chunk1Buffer = buffer2 + Packet::CommonHeaderSize;
|
|
276
|
+
|
|
277
|
+
// NOTE: Length of first chunk (including null octets) is 24.
|
|
278
|
+
uint8_t serialized1[24] = { 0 };
|
|
279
|
+
|
|
280
|
+
chunk1->Serialize(serialized1);
|
|
281
|
+
|
|
282
|
+
REQUIRE(std::memcmp(chunk1Buffer, serialized1, 24) == 0);
|
|
283
|
+
|
|
284
|
+
auto* chunk2 = *(++it);
|
|
285
|
+
uint8_t* chunk2Buffer = buffer2 + Packet::CommonHeaderSize + 24;
|
|
286
|
+
|
|
287
|
+
// NOTE: Length of second chunk (including null octets) is 24.
|
|
288
|
+
uint8_t serialized2[24] = { 0 };
|
|
289
|
+
|
|
290
|
+
chunk2->Serialize(serialized2);
|
|
291
|
+
|
|
292
|
+
REQUIRE(std::memcmp(chunk2Buffer, serialized2, 24) == 0);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
delete packet;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
SECTION("parse packet 3")
|
|
299
|
+
{
|
|
300
|
+
SdesPacket* packet = SdesPacket::Parse(buffer3, sizeof(buffer3));
|
|
301
|
+
auto* header = reinterpret_cast<RTC::RTCP::Packet::CommonHeader*>(buffer3);
|
|
302
|
+
|
|
303
|
+
REQUIRE(packet);
|
|
304
|
+
REQUIRE(ntohs(header->length) == 3);
|
|
305
|
+
REQUIRE(packet->GetSize() == 16);
|
|
306
|
+
REQUIRE(packet->GetCount() == 1);
|
|
307
|
+
|
|
308
|
+
size_t chunkIdx{ 0u };
|
|
309
|
+
|
|
310
|
+
for (auto it = packet->Begin(); it != packet->End(); ++it, ++chunkIdx)
|
|
311
|
+
{
|
|
312
|
+
auto* chunk = *it;
|
|
313
|
+
|
|
314
|
+
switch (chunkIdx)
|
|
315
|
+
{
|
|
316
|
+
/* First chunk (chunk 4). */
|
|
317
|
+
case 0:
|
|
318
|
+
{
|
|
319
|
+
REQUIRE(chunk->GetSize() == 12);
|
|
320
|
+
REQUIRE(chunk->GetSsrc() == ssrc4);
|
|
321
|
+
|
|
322
|
+
size_t itemIdx{ 0u };
|
|
323
|
+
|
|
324
|
+
for (auto it2 = chunk->Begin(); it2 != chunk->End(); ++it2, ++itemIdx)
|
|
325
|
+
{
|
|
326
|
+
auto* item = *it2;
|
|
327
|
+
|
|
328
|
+
switch (itemIdx)
|
|
329
|
+
{
|
|
330
|
+
/* First item (item 5). */
|
|
331
|
+
case 0:
|
|
332
|
+
{
|
|
333
|
+
REQUIRE(item->GetType() == item5Type);
|
|
334
|
+
REQUIRE(item->GetLength() == item5Length);
|
|
335
|
+
REQUIRE(std::string(item->GetValue(), item5Length) == item5Value);
|
|
336
|
+
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// There is 1 item.
|
|
343
|
+
REQUIRE(itemIdx == 1);
|
|
344
|
+
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// There is 1 chunk.
|
|
351
|
+
REQUIRE(chunkIdx == 1);
|
|
352
|
+
|
|
353
|
+
SECTION("serialize SdesChunk instance")
|
|
354
|
+
{
|
|
355
|
+
auto it = packet->Begin();
|
|
356
|
+
auto* chunk1 = *it;
|
|
357
|
+
uint8_t* chunk1Buffer = buffer3 + Packet::CommonHeaderSize;
|
|
358
|
+
|
|
359
|
+
// NOTE: Length of first chunk (including null octets) is 12.
|
|
360
|
+
uint8_t serialized1[12] = { 0 };
|
|
361
|
+
|
|
362
|
+
chunk1->Serialize(serialized1);
|
|
363
|
+
|
|
364
|
+
REQUIRE(std::memcmp(chunk1Buffer, serialized1, 12) == 0);
|
|
365
|
+
}
|
|
366
|
+
|
|
73
367
|
delete packet;
|
|
74
368
|
}
|
|
75
369
|
|
|
370
|
+
SECTION("parsing a packet with missing null octects fails")
|
|
371
|
+
{
|
|
372
|
+
// clang-format off
|
|
373
|
+
uint8_t buffer[] =
|
|
374
|
+
{
|
|
375
|
+
0x81, 0xca, 0x00, 0x02, // Type: 202 (SDES), Count: 1, Length: 2
|
|
376
|
+
// Chunk
|
|
377
|
+
0x11, 0x22, 0x33, 0x44, // SSRC: 0x11223344
|
|
378
|
+
0x08, 0x02, 0x61, 0x62 // Item Type: 8 (PRIV), Length: 2, Text: "ab"
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
SdesPacket* packet = SdesPacket::Parse(buffer, sizeof(buffer));
|
|
382
|
+
|
|
383
|
+
REQUIRE(!packet);
|
|
384
|
+
}
|
|
385
|
+
|
|
76
386
|
SECTION("create SDES packet with more than 31 chunks")
|
|
77
387
|
{
|
|
78
388
|
const size_t count = 33;
|
|
@@ -82,23 +392,24 @@ SCENARIO("RTCP SDES parsing", "[parser][rtcp][sdes]")
|
|
|
82
392
|
for (auto i = 1; i <= count; i++)
|
|
83
393
|
{
|
|
84
394
|
// Create chunk and add to packet.
|
|
85
|
-
SdesChunk*
|
|
395
|
+
SdesChunk* chunk1 = new SdesChunk(i /*ssrc*/);
|
|
86
396
|
|
|
87
|
-
auto*
|
|
397
|
+
auto* item1 =
|
|
398
|
+
new RTC::RTCP::SdesItem(SdesItem::Type::CNAME, item1Value.size(), item1Value.c_str());
|
|
88
399
|
|
|
89
|
-
|
|
400
|
+
chunk1->AddItem(item1);
|
|
90
401
|
|
|
91
|
-
packet.AddChunk(
|
|
402
|
+
packet.AddChunk(chunk1);
|
|
92
403
|
}
|
|
93
404
|
|
|
94
405
|
REQUIRE(packet.GetCount() == count);
|
|
95
406
|
|
|
96
|
-
uint8_t
|
|
407
|
+
uint8_t buffer1[1500] = { 0 };
|
|
97
408
|
|
|
98
409
|
// Serialization must contain 2 RR packets since report count exceeds 31.
|
|
99
|
-
packet.Serialize(
|
|
410
|
+
packet.Serialize(buffer1);
|
|
100
411
|
|
|
101
|
-
auto* packet2 = static_cast<SdesPacket*>(Packet::Parse(
|
|
412
|
+
auto* packet2 = static_cast<SdesPacket*>(Packet::Parse(buffer1, sizeof(buffer1)));
|
|
102
413
|
|
|
103
414
|
REQUIRE(packet2 != nullptr);
|
|
104
415
|
REQUIRE(packet2->GetCount() == 31);
|
|
@@ -114,8 +425,8 @@ SCENARIO("RTCP SDES parsing", "[parser][rtcp][sdes]")
|
|
|
114
425
|
auto* item = *(chunk->Begin());
|
|
115
426
|
|
|
116
427
|
REQUIRE(item->GetType() == SdesItem::Type::CNAME);
|
|
117
|
-
REQUIRE(item->GetSize() == 2 +
|
|
118
|
-
REQUIRE(std::string(item->GetValue()) ==
|
|
428
|
+
REQUIRE(item->GetSize() == 2 + item1Value.size());
|
|
429
|
+
REQUIRE(std::string(item->GetValue()) == item1Value);
|
|
119
430
|
}
|
|
120
431
|
|
|
121
432
|
SdesPacket* packet3 = static_cast<SdesPacket*>(packet2->GetNext());
|
|
@@ -134,8 +445,8 @@ SCENARIO("RTCP SDES parsing", "[parser][rtcp][sdes]")
|
|
|
134
445
|
auto* item = *(chunk->Begin());
|
|
135
446
|
|
|
136
447
|
REQUIRE(item->GetType() == SdesItem::Type::CNAME);
|
|
137
|
-
REQUIRE(item->GetSize() == 2 +
|
|
138
|
-
REQUIRE(std::string(item->GetValue()) ==
|
|
448
|
+
REQUIRE(item->GetSize() == 2 + item1Value.size());
|
|
449
|
+
REQUIRE(std::string(item->GetValue()) == item1Value);
|
|
139
450
|
}
|
|
140
451
|
|
|
141
452
|
delete packet2;
|
|
@@ -144,13 +455,19 @@ SCENARIO("RTCP SDES parsing", "[parser][rtcp][sdes]")
|
|
|
144
455
|
|
|
145
456
|
SECTION("create SdesChunk")
|
|
146
457
|
{
|
|
147
|
-
auto* item = new SdesItem(
|
|
458
|
+
auto* item = new SdesItem(item1Type, item1Length, item1Value.c_str());
|
|
148
459
|
|
|
149
460
|
// Create sdes chunk.
|
|
150
|
-
SdesChunk chunk(
|
|
461
|
+
SdesChunk chunk(ssrc1);
|
|
151
462
|
|
|
152
463
|
chunk.AddItem(item);
|
|
153
464
|
|
|
154
|
-
|
|
465
|
+
REQUIRE(chunk.GetSsrc() == ssrc1);
|
|
466
|
+
|
|
467
|
+
SdesItem* item1 = *(chunk.Begin());
|
|
468
|
+
|
|
469
|
+
REQUIRE(item1->GetType() == item1Type);
|
|
470
|
+
REQUIRE(item1->GetLength() == item1Length);
|
|
471
|
+
REQUIRE(std::string(item1->GetValue(), item1Length) == item1Value);
|
|
155
472
|
}
|
|
156
473
|
}
|