diff options
author | iphydf <iphydf@users.noreply.github.com> | 2018-01-21 22:38:08 +0000 |
---|---|---|
committer | iphydf <iphydf@users.noreply.github.com> | 2018-02-01 23:35:44 +0000 |
commit | 83779a21eaf19bbf6aa5d61d8f59681a306e4f65 (patch) | |
tree | b713524d8ce29ca05500fb95f315de94a4d4ae75 /toxav | |
parent | d9413d557696e3aecde9d019e1738e99882d4579 (diff) |
Manually serialise RTPHeader struct instead of memcpy.
Diffstat (limited to 'toxav')
-rw-r--r-- | toxav/BUILD.bazel | 10 | ||||
-rw-r--r-- | toxav/rtp.c | 183 | ||||
-rw-r--r-- | toxav/rtp.h | 66 | ||||
-rw-r--r-- | toxav/rtp_test.cpp | 19 |
4 files changed, 193 insertions, 85 deletions
diff --git a/toxav/BUILD.bazel b/toxav/BUILD.bazel index e9649c36..ff775fdd 100644 --- a/toxav/BUILD.bazel +++ b/toxav/BUILD.bazel | |||
@@ -35,6 +35,16 @@ cc_library( | |||
35 | deps = [":bwcontroller"], | 35 | deps = [":bwcontroller"], |
36 | ) | 36 | ) |
37 | 37 | ||
38 | cc_test( | ||
39 | name = "rtp_test", | ||
40 | srcs = ["rtp_test.cpp"], | ||
41 | deps = [ | ||
42 | ":rtp", | ||
43 | "//c-toxcore/toxcore:crypto_core", | ||
44 | "@gtest", | ||
45 | ], | ||
46 | ) | ||
47 | |||
38 | cc_library( | 48 | cc_library( |
39 | name = "audio", | 49 | name = "audio", |
40 | srcs = ["audio.c"], | 50 | srcs = ["audio.c"], |
diff --git a/toxav/rtp.c b/toxav/rtp.c index 01d4258a..650fbaf0 100644 --- a/toxav/rtp.c +++ b/toxav/rtp.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright © 2016-2017 The TokTok team. | 2 | * Copyright © 2016-2018 The TokTok team. |
3 | * Copyright © 2013-2015 Tox project. | 3 | * Copyright © 2013-2015 Tox project. |
4 | * | 4 | * |
5 | * This file is part of Tox, the free peer to peer instant messenger. | 5 | * This file is part of Tox, the free peer to peer instant messenger. |
@@ -34,6 +34,67 @@ | |||
34 | #include <stdlib.h> | 34 | #include <stdlib.h> |
35 | 35 | ||
36 | 36 | ||
37 | size_t rtp_header_pack(uint8_t *const rdata, const struct RTPHeader *header) | ||
38 | { | ||
39 | uint8_t *p = rdata; | ||
40 | *p++ = (header->protocol_version & 3) << 6 | ||
41 | | (header->pe & 1) << 5 | ||
42 | | (header->xe & 1) << 4 | ||
43 | | (header->cc & 0xf); | ||
44 | *p++ = (header->ma & 1) << 7 | ||
45 | | (header->pt & 0x7f); | ||
46 | |||
47 | p += net_pack_u16(p, header->sequnum); | ||
48 | p += net_pack_u32(p, header->timestamp); | ||
49 | p += net_pack_u32(p, header->ssrc); | ||
50 | p += net_pack_u64(p, header->flags); | ||
51 | p += net_pack_u32(p, header->offset_full); | ||
52 | p += net_pack_u32(p, header->data_length_full); | ||
53 | p += net_pack_u32(p, header->received_length_full); | ||
54 | |||
55 | for (size_t i = 0; i < sizeof header->csrc / sizeof header->csrc[0]; i++) { | ||
56 | p += net_pack_u32(p, header->csrc[i]); | ||
57 | } | ||
58 | |||
59 | p += net_pack_u16(p, header->offset_lower); | ||
60 | p += net_pack_u16(p, header->data_length_lower); | ||
61 | assert(p == rdata + RTP_HEADER_SIZE); | ||
62 | return p - rdata; | ||
63 | } | ||
64 | |||
65 | |||
66 | size_t rtp_header_unpack(const uint8_t *data, struct RTPHeader *header) | ||
67 | { | ||
68 | const uint8_t *p = data; | ||
69 | header->protocol_version = (*p >> 6) & 3; | ||
70 | header->pe = (*p >> 5) & 1; | ||
71 | header->xe = (*p >> 4) & 1; | ||
72 | header->cc = *p & 0xf; | ||
73 | ++p; | ||
74 | |||
75 | header->ma = (*p >> 7) & 1; | ||
76 | header->pt = *p & 0x7f; | ||
77 | ++p; | ||
78 | |||
79 | p += net_unpack_u16(p, &header->sequnum); | ||
80 | p += net_unpack_u32(p, &header->timestamp); | ||
81 | p += net_unpack_u32(p, &header->ssrc); | ||
82 | p += net_unpack_u64(p, &header->flags); | ||
83 | p += net_unpack_u32(p, &header->offset_full); | ||
84 | p += net_unpack_u32(p, &header->data_length_full); | ||
85 | p += net_unpack_u32(p, &header->received_length_full); | ||
86 | |||
87 | for (size_t i = 0; i < sizeof header->csrc / sizeof header->csrc[0]; i++) { | ||
88 | p += net_unpack_u32(p, &header->csrc[i]); | ||
89 | } | ||
90 | |||
91 | p += net_unpack_u16(p, &header->offset_lower); | ||
92 | p += net_unpack_u16(p, &header->data_length_lower); | ||
93 | assert(p == data + RTP_HEADER_SIZE); | ||
94 | return p - data; | ||
95 | } | ||
96 | |||
97 | |||
37 | int handle_rtp_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object); | 98 | int handle_rtp_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object); |
38 | 99 | ||
39 | 100 | ||
@@ -116,36 +177,37 @@ int rtp_send_data(RTPSession *session, const uint8_t *data, uint16_t length, Log | |||
116 | return -1; | 177 | return -1; |
117 | } | 178 | } |
118 | 179 | ||
119 | VLA(uint8_t, rdata, length + sizeof(struct RTPHeader) + 1); | 180 | VLA(uint8_t, rdata, length + RTP_HEADER_SIZE + 1); |
120 | memset(rdata, 0, SIZEOF_VLA(rdata)); | 181 | memset(rdata, 0, SIZEOF_VLA(rdata)); |
121 | 182 | ||
122 | rdata[0] = session->payload_type; | 183 | rdata[0] = session->payload_type; |
123 | 184 | ||
124 | struct RTPHeader *header = (struct RTPHeader *)(rdata + 1); | 185 | struct RTPHeader header = {0}; |
125 | 186 | ||
126 | header->protocol_version = 2; | 187 | header.protocol_version = 2; |
127 | header->pe = 0; | 188 | header.pe = 0; |
128 | header->xe = 0; | 189 | header.xe = 0; |
129 | header->cc = 0; | 190 | header.cc = 0; |
130 | 191 | ||
131 | header->ma = 0; | 192 | header.ma = 0; |
132 | header->pt = session->payload_type % 128; | 193 | header.pt = session->payload_type % 128; |
133 | 194 | ||
134 | header->sequnum = net_htons(session->sequnum); | 195 | header.sequnum = session->sequnum; |
135 | header->timestamp = net_htonl(current_time_monotonic()); | 196 | header.timestamp = current_time_monotonic(); |
136 | header->ssrc = net_htonl(session->ssrc); | 197 | header.ssrc = session->ssrc; |
137 | 198 | ||
138 | header->offset_lower = 0; | 199 | header.offset_lower = 0; |
139 | header->data_length_lower = net_htons(length); | 200 | header.data_length_lower = length; |
140 | 201 | ||
141 | if (MAX_CRYPTO_DATA_SIZE > length + sizeof(struct RTPHeader) + 1) { | 202 | if (MAX_CRYPTO_DATA_SIZE > length + RTP_HEADER_SIZE + 1) { |
142 | 203 | ||
143 | /** | 204 | /** |
144 | * The length is lesser than the maximum allowed length (including header) | 205 | * The length is lesser than the maximum allowed length (including header) |
145 | * Send the packet in single piece. | 206 | * Send the packet in single piece. |
146 | */ | 207 | */ |
147 | 208 | ||
148 | memcpy(rdata + 1 + sizeof(struct RTPHeader), data, length); | 209 | rtp_header_pack(rdata + 1, &header); |
210 | memcpy(rdata + 1 + RTP_HEADER_SIZE, data, length); | ||
149 | 211 | ||
150 | if (-1 == m_send_custom_lossy_packet(session->m, session->friend_number, rdata, SIZEOF_VLA(rdata))) { | 212 | if (-1 == m_send_custom_lossy_packet(session->m, session->friend_number, rdata, SIZEOF_VLA(rdata))) { |
151 | LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! std error: %s", SIZEOF_VLA(rdata), strerror(errno)); | 213 | LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! std error: %s", SIZEOF_VLA(rdata), strerror(errno)); |
@@ -158,31 +220,33 @@ int rtp_send_data(RTPSession *session, const uint8_t *data, uint16_t length, Log | |||
158 | */ | 220 | */ |
159 | 221 | ||
160 | uint16_t sent = 0; | 222 | uint16_t sent = 0; |
161 | uint16_t piece = MAX_CRYPTO_DATA_SIZE - (sizeof(struct RTPHeader) + 1); | 223 | uint16_t piece = MAX_CRYPTO_DATA_SIZE - (RTP_HEADER_SIZE + 1); |
162 | 224 | ||
163 | while ((length - sent) + sizeof(struct RTPHeader) + 1 > MAX_CRYPTO_DATA_SIZE) { | 225 | while ((length - sent) + RTP_HEADER_SIZE + 1 > MAX_CRYPTO_DATA_SIZE) { |
164 | memcpy(rdata + 1 + sizeof(struct RTPHeader), data + sent, piece); | 226 | rtp_header_pack(rdata + 1, &header); |
227 | memcpy(rdata + 1 + RTP_HEADER_SIZE, data + sent, piece); | ||
165 | 228 | ||
166 | if (-1 == m_send_custom_lossy_packet(session->m, session->friend_number, | 229 | if (-1 == m_send_custom_lossy_packet(session->m, session->friend_number, |
167 | rdata, piece + sizeof(struct RTPHeader) + 1)) { | 230 | rdata, piece + RTP_HEADER_SIZE + 1)) { |
168 | LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! std error: %s", | 231 | LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! std error: %s", |
169 | piece + sizeof(struct RTPHeader) + 1, strerror(errno)); | 232 | piece + RTP_HEADER_SIZE + 1, strerror(errno)); |
170 | } | 233 | } |
171 | 234 | ||
172 | sent += piece; | 235 | sent += piece; |
173 | header->offset_lower = net_htons(sent); | 236 | header.offset_lower = sent; |
174 | } | 237 | } |
175 | 238 | ||
176 | /* Send remaining */ | 239 | /* Send remaining */ |
177 | piece = length - sent; | 240 | piece = length - sent; |
178 | 241 | ||
179 | if (piece) { | 242 | if (piece) { |
180 | memcpy(rdata + 1 + sizeof(struct RTPHeader), data + sent, piece); | 243 | rtp_header_pack(rdata + 1, &header); |
244 | memcpy(rdata + 1 + RTP_HEADER_SIZE, data + sent, piece); | ||
181 | 245 | ||
182 | if (-1 == m_send_custom_lossy_packet(session->m, session->friend_number, rdata, | 246 | if (-1 == m_send_custom_lossy_packet(session->m, session->friend_number, rdata, |
183 | piece + sizeof(struct RTPHeader) + 1)) { | 247 | piece + RTP_HEADER_SIZE + 1)) { |
184 | LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! std error: %s", | 248 | LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! std error: %s", |
185 | piece + sizeof(struct RTPHeader) + 1, strerror(errno)); | 249 | piece + RTP_HEADER_SIZE + 1, strerror(errno)); |
186 | } | 250 | } |
187 | } | 251 | } |
188 | } | 252 | } |
@@ -194,10 +258,10 @@ int rtp_send_data(RTPSession *session, const uint8_t *data, uint16_t length, Log | |||
194 | 258 | ||
195 | static bool chloss(const RTPSession *session, const struct RTPHeader *header) | 259 | static bool chloss(const RTPSession *session, const struct RTPHeader *header) |
196 | { | 260 | { |
197 | if (net_ntohl(header->timestamp) < session->rtimestamp) { | 261 | if (header->timestamp < session->rtimestamp) { |
198 | uint16_t hosq, lost = 0; | 262 | uint16_t hosq, lost = 0; |
199 | 263 | ||
200 | hosq = net_ntohs(header->sequnum); | 264 | hosq = header->sequnum; |
201 | 265 | ||
202 | lost = (hosq > session->rsequnum) ? | 266 | lost = (hosq > session->rsequnum) ? |
203 | (session->rsequnum + 65535) - hosq : | 267 | (session->rsequnum + 65535) - hosq : |
@@ -218,21 +282,20 @@ static struct RTPMessage *new_message(size_t allocate_len, const uint8_t *data, | |||
218 | { | 282 | { |
219 | assert(allocate_len >= data_length); | 283 | assert(allocate_len >= data_length); |
220 | 284 | ||
221 | struct RTPMessage *msg = (struct RTPMessage *)calloc(sizeof(struct RTPMessage) + (allocate_len - sizeof( | 285 | struct RTPMessage *msg = (struct RTPMessage *)calloc(sizeof(struct RTPMessage) + |
222 | struct RTPHeader)), 1); | 286 | (allocate_len - RTP_HEADER_SIZE), 1); |
223 | |||
224 | msg->len = data_length - sizeof(struct RTPHeader); | ||
225 | memcpy(&msg->header, data, data_length); | ||
226 | 287 | ||
227 | msg->header.sequnum = net_ntohs(msg->header.sequnum); | 288 | if (msg == nullptr) { |
228 | msg->header.timestamp = net_ntohl(msg->header.timestamp); | 289 | return nullptr; |
229 | msg->header.ssrc = net_ntohl(msg->header.ssrc); | 290 | } |
230 | 291 | ||
231 | msg->header.offset_lower = net_ntohs(msg->header.offset_lower); | 292 | msg->len = data_length - RTP_HEADER_SIZE; |
232 | msg->header.data_length_lower = net_ntohs(msg->header.data_length_lower); | 293 | rtp_header_unpack(data, &msg->header); |
294 | memcpy(msg->data, data + RTP_HEADER_SIZE, allocate_len - RTP_HEADER_SIZE); | ||
233 | 295 | ||
234 | return msg; | 296 | return msg; |
235 | } | 297 | } |
298 | |||
236 | int handle_rtp_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object) | 299 | int handle_rtp_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object) |
237 | { | 300 | { |
238 | (void) m; | 301 | (void) m; |
@@ -243,38 +306,40 @@ int handle_rtp_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, | |||
243 | data ++; | 306 | data ++; |
244 | length--; | 307 | length--; |
245 | 308 | ||
246 | if (!session || length < sizeof(struct RTPHeader)) { | 309 | if (!session || length < RTP_HEADER_SIZE) { |
247 | LOGGER_WARNING(m->log, "No session or invalid length of received buffer!"); | 310 | LOGGER_WARNING(m->log, "No session or invalid length of received buffer!"); |
248 | return -1; | 311 | return -1; |
249 | } | 312 | } |
250 | 313 | ||
251 | const struct RTPHeader *header = (const struct RTPHeader *) data; | 314 | struct RTPHeader header; |
315 | |||
316 | rtp_header_unpack(data, &header); | ||
252 | 317 | ||
253 | if (header->pt != session->payload_type % 128) { | 318 | if (header.pt != session->payload_type % 128) { |
254 | LOGGER_WARNING(m->log, "Invalid payload type with the session"); | 319 | LOGGER_WARNING(m->log, "Invalid payload type with the session"); |
255 | return -1; | 320 | return -1; |
256 | } | 321 | } |
257 | 322 | ||
258 | if (net_ntohs(header->offset_lower) >= net_ntohs(header->data_length_lower)) { | 323 | if (header.offset_lower >= header.data_length_lower) { |
259 | /* Never allow this case to happen */ | 324 | /* Never allow this case to happen */ |
260 | return -1; | 325 | return -1; |
261 | } | 326 | } |
262 | 327 | ||
263 | bwc_feed_avg(session->bwc, length); | 328 | bwc_feed_avg(session->bwc, length); |
264 | 329 | ||
265 | if (net_ntohs(header->data_length_lower) == length - sizeof(struct RTPHeader)) { | 330 | if (header.data_length_lower == length - RTP_HEADER_SIZE) { |
266 | /* The message is sent in single part */ | 331 | /* The message is sent in single part */ |
267 | 332 | ||
268 | /* Only allow messages which have arrived in order; | 333 | /* Only allow messages which have arrived in order; |
269 | * drop late messages | 334 | * drop late messages |
270 | */ | 335 | */ |
271 | if (chloss(session, header)) { | 336 | if (chloss(session, &header)) { |
272 | return 0; | 337 | return 0; |
273 | } | 338 | } |
274 | 339 | ||
275 | /* Message is not late; pick up the latest parameters */ | 340 | /* Message is not late; pick up the latest parameters */ |
276 | session->rsequnum = net_ntohs(header->sequnum); | 341 | session->rsequnum = header.sequnum; |
277 | session->rtimestamp = net_ntohl(header->timestamp); | 342 | session->rtimestamp = header.timestamp; |
278 | 343 | ||
279 | bwc_add_recv(session->bwc, length); | 344 | bwc_add_recv(session->bwc, length); |
280 | 345 | ||
@@ -311,23 +376,23 @@ int handle_rtp_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, | |||
311 | * processing message | 376 | * processing message |
312 | */ | 377 | */ |
313 | 378 | ||
314 | if (session->mp->header.sequnum == net_ntohs(header->sequnum) && | 379 | if (session->mp->header.sequnum == header.sequnum && |
315 | session->mp->header.timestamp == net_ntohl(header->timestamp)) { | 380 | session->mp->header.timestamp == header.timestamp) { |
316 | /* First case */ | 381 | /* First case */ |
317 | 382 | ||
318 | /* Make sure we have enough allocated memory */ | 383 | /* Make sure we have enough allocated memory */ |
319 | if (session->mp->header.data_length_lower - session->mp->len < length - sizeof(struct RTPHeader) || | 384 | if (session->mp->header.data_length_lower - session->mp->len < length - RTP_HEADER_SIZE || |
320 | session->mp->header.data_length_lower <= net_ntohs(header->offset_lower)) { | 385 | session->mp->header.data_length_lower <= header.offset_lower) { |
321 | /* There happened to be some corruption on the stream; | 386 | /* There happened to be some corruption on the stream; |
322 | * continue wihtout this part | 387 | * continue wihtout this part |
323 | */ | 388 | */ |
324 | return 0; | 389 | return 0; |
325 | } | 390 | } |
326 | 391 | ||
327 | memcpy(session->mp->data + net_ntohs(header->offset_lower), data + sizeof(struct RTPHeader), | 392 | memcpy(session->mp->data + header.offset_lower, data + RTP_HEADER_SIZE, |
328 | length - sizeof(struct RTPHeader)); | 393 | length - RTP_HEADER_SIZE); |
329 | 394 | ||
330 | session->mp->len += length - sizeof(struct RTPHeader); | 395 | session->mp->len += length - RTP_HEADER_SIZE; |
331 | 396 | ||
332 | bwc_add_recv(session->bwc, length); | 397 | bwc_add_recv(session->bwc, length); |
333 | 398 | ||
@@ -346,7 +411,7 @@ int handle_rtp_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, | |||
346 | } else { | 411 | } else { |
347 | /* Second case */ | 412 | /* Second case */ |
348 | 413 | ||
349 | if (session->mp->header.timestamp > net_ntohl(header->timestamp)) { | 414 | if (session->mp->header.timestamp > header.timestamp) { |
350 | /* The received message part is from the old message; | 415 | /* The received message part is from the old message; |
351 | * discard it. | 416 | * discard it. |
352 | */ | 417 | */ |
@@ -359,7 +424,7 @@ int handle_rtp_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, | |||
359 | 424 | ||
360 | /* Must account sizes of rtp headers too */ | 425 | /* Must account sizes of rtp headers too */ |
361 | ((session->mp->header.data_length_lower - session->mp->len) / | 426 | ((session->mp->header.data_length_lower - session->mp->len) / |
362 | MAX_CRYPTO_DATA_SIZE) * sizeof(struct RTPHeader)); | 427 | MAX_CRYPTO_DATA_SIZE) * RTP_HEADER_SIZE); |
363 | 428 | ||
364 | /* Push the previous message for processing */ | 429 | /* Push the previous message for processing */ |
365 | if (session->mcb) { | 430 | if (session->mcb) { |
@@ -381,21 +446,21 @@ NEW_MULTIPARTED: | |||
381 | /* Only allow messages which have arrived in order; | 446 | /* Only allow messages which have arrived in order; |
382 | * drop late messages | 447 | * drop late messages |
383 | */ | 448 | */ |
384 | if (chloss(session, header)) { | 449 | if (chloss(session, &header)) { |
385 | return 0; | 450 | return 0; |
386 | } | 451 | } |
387 | 452 | ||
388 | /* Message is not late; pick up the latest parameters */ | 453 | /* Message is not late; pick up the latest parameters */ |
389 | session->rsequnum = net_ntohs(header->sequnum); | 454 | session->rsequnum = header.sequnum; |
390 | session->rtimestamp = net_ntohl(header->timestamp); | 455 | session->rtimestamp = header.timestamp; |
391 | 456 | ||
392 | bwc_add_recv(session->bwc, length); | 457 | bwc_add_recv(session->bwc, length); |
393 | 458 | ||
394 | /* Again, only store message if handler is present | 459 | /* Again, only store message if handler is present |
395 | */ | 460 | */ |
396 | if (session->mcb) { | 461 | if (session->mcb) { |
397 | session->mp = new_message(net_ntohs(header->data_length_lower) + sizeof(struct RTPHeader), data, length); | 462 | session->mp = new_message(header.data_length_lower + RTP_HEADER_SIZE, data, length); |
398 | memmove(session->mp->data + net_ntohs(header->offset_lower), session->mp->data, session->mp->len); | 463 | memmove(session->mp->data + header.offset_lower, session->mp->data, session->mp->len); |
399 | } | 464 | } |
400 | } | 465 | } |
401 | 466 | ||
diff --git a/toxav/rtp.h b/toxav/rtp.h index 03e35498..3f684ee5 100644 --- a/toxav/rtp.h +++ b/toxav/rtp.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright © 2016-2017 The TokTok team. | 2 | * Copyright © 2016-2018 The TokTok team. |
3 | * Copyright © 2013-2015 Tox project. | 3 | * Copyright © 2013-2015 Tox project. |
4 | * | 4 | * |
5 | * This file is part of Tox, the free peer to peer instant messenger. | 5 | * This file is part of Tox, the free peer to peer instant messenger. |
@@ -27,6 +27,15 @@ | |||
27 | 27 | ||
28 | #include <stdbool.h> | 28 | #include <stdbool.h> |
29 | 29 | ||
30 | #ifdef __cplusplus | ||
31 | extern "C" { | ||
32 | #endif | ||
33 | |||
34 | /** | ||
35 | * RTPHeader serialised size in bytes. | ||
36 | */ | ||
37 | #define RTP_HEADER_SIZE 80 | ||
38 | |||
30 | /** | 39 | /** |
31 | * Payload type identifier. Also used as rtp callback prefix. | 40 | * Payload type identifier. Also used as rtp callback prefix. |
32 | */ | 41 | */ |
@@ -53,23 +62,13 @@ enum RTPFlags { | |||
53 | 62 | ||
54 | struct RTPHeader { | 63 | struct RTPHeader { |
55 | /* Standard RTP header */ | 64 | /* Standard RTP header */ |
56 | #ifndef WORDS_BIGENDIAN | 65 | unsigned protocol_version: 2; /* Version has only 2 bits! */ |
57 | uint16_t cc: 4; /* Contributing sources count */ | 66 | unsigned pe: 1; /* Padding */ |
58 | uint16_t xe: 1; /* Extra header */ | 67 | unsigned xe: 1; /* Extra header */ |
59 | uint16_t pe: 1; /* Padding */ | 68 | unsigned cc: 4; /* Contributing sources count */ |
60 | uint16_t protocol_version: 2; /* Version has only 2 bits! */ | 69 | |
61 | 70 | unsigned ma: 1; /* Marker */ | |
62 | uint16_t pt: 7; /* Payload type */ | 71 | unsigned pt: 7; /* Payload type */ |
63 | uint16_t ma: 1; /* Marker */ | ||
64 | #else | ||
65 | uint16_t protocol_version: 2; /* Version has only 2 bits! */ | ||
66 | uint16_t pe: 1; /* Padding */ | ||
67 | uint16_t xe: 1; /* Extra header */ | ||
68 | uint16_t cc: 4; /* Contributing sources count */ | ||
69 | |||
70 | uint16_t ma: 1; /* Marker */ | ||
71 | uint16_t pt: 7; /* Payload type */ | ||
72 | #endif | ||
73 | 72 | ||
74 | uint16_t sequnum; | 73 | uint16_t sequnum; |
75 | uint32_t timestamp; | 74 | uint32_t timestamp; |
@@ -112,20 +111,14 @@ struct RTPHeader { | |||
112 | * Total message length (lower bits). | 111 | * Total message length (lower bits). |
113 | */ | 112 | */ |
114 | uint16_t data_length_lower; | 113 | uint16_t data_length_lower; |
115 | } __attribute__((packed)); | 114 | }; |
116 | |||
117 | /* Check alignment */ | ||
118 | typedef char __fail_if_misaligned_1 [ sizeof(struct RTPHeader) == 80 ? 1 : -1 ]; | ||
119 | 115 | ||
120 | struct RTPMessage { | 116 | struct RTPMessage { |
121 | uint16_t len; | 117 | uint16_t len; |
122 | 118 | ||
123 | struct RTPHeader header; | 119 | struct RTPHeader header; |
124 | uint8_t data[]; | 120 | uint8_t data[]; |
125 | } __attribute__((packed)); | 121 | }; |
126 | |||
127 | /* Check alignment */ | ||
128 | typedef char __fail_if_misaligned_2 [ sizeof(struct RTPMessage) == 82 ? 1 : -1 ]; | ||
129 | 122 | ||
130 | /** | 123 | /** |
131 | * RTP control session. | 124 | * RTP control session. |
@@ -147,6 +140,23 @@ typedef struct { | |||
147 | int (*mcb)(void *, struct RTPMessage *msg); | 140 | int (*mcb)(void *, struct RTPMessage *msg); |
148 | } RTPSession; | 141 | } RTPSession; |
149 | 142 | ||
143 | /** | ||
144 | * Serialise an RTPHeader to bytes to be sent over the network. | ||
145 | * | ||
146 | * @param rdata A byte array of length RTP_HEADER_SIZE. Does not need to be | ||
147 | * initialised. All RTP_HEADER_SIZE bytes will be initialised after a call | ||
148 | * to this function. | ||
149 | * @param header The RTPHeader to serialise. | ||
150 | */ | ||
151 | size_t rtp_header_pack(uint8_t *rdata, const struct RTPHeader *header); | ||
152 | |||
153 | /** | ||
154 | * Deserialise an RTPHeader from bytes received over the network. | ||
155 | * | ||
156 | * @param data A byte array of length RTP_HEADER_SIZE. | ||
157 | * @param header The RTPHeader to write the unpacked values to. | ||
158 | */ | ||
159 | size_t rtp_header_unpack(const uint8_t *data, struct RTPHeader *header); | ||
150 | 160 | ||
151 | RTPSession *rtp_new(int payload_type, Messenger *m, uint32_t friendnumber, | 161 | RTPSession *rtp_new(int payload_type, Messenger *m, uint32_t friendnumber, |
152 | BWController *bwc, void *cs, | 162 | BWController *bwc, void *cs, |
@@ -156,4 +166,8 @@ int rtp_allow_receiving(RTPSession *session); | |||
156 | int rtp_stop_receiving(RTPSession *session); | 166 | int rtp_stop_receiving(RTPSession *session); |
157 | int rtp_send_data(RTPSession *session, const uint8_t *data, uint16_t length, Logger *log); | 167 | int rtp_send_data(RTPSession *session, const uint8_t *data, uint16_t length, Logger *log); |
158 | 168 | ||
169 | #ifdef __cplusplus | ||
170 | } // extern "C" | ||
171 | #endif | ||
172 | |||
159 | #endif /* RTP_H */ | 173 | #endif /* RTP_H */ |
diff --git a/toxav/rtp_test.cpp b/toxav/rtp_test.cpp new file mode 100644 index 00000000..76e369f0 --- /dev/null +++ b/toxav/rtp_test.cpp | |||
@@ -0,0 +1,19 @@ | |||
1 | #include "rtp.h" | ||
2 | |||
3 | #include "../toxcore/crypto_core.h" | ||
4 | |||
5 | #include <gtest/gtest.h> | ||
6 | |||
7 | TEST(Rtp, Deserialisation) { | ||
8 | RTPHeader header; | ||
9 | random_bytes((uint8_t *)&header, sizeof header); | ||
10 | |||
11 | uint8_t rdata[sizeof(RTPHeader)]; | ||
12 | EXPECT_EQ(rtp_header_pack(rdata, &header), RTP_HEADER_SIZE); | ||
13 | |||
14 | RTPHeader unpacked; | ||
15 | EXPECT_EQ(rtp_header_unpack(rdata, &unpacked), RTP_HEADER_SIZE); | ||
16 | |||
17 | EXPECT_EQ(std::string((char const *)&header, sizeof header), | ||
18 | std::string((char const *)&unpacked, sizeof unpacked)); | ||
19 | } | ||