blob: cd4880d2d5d6042571bbd65c0a3ca730b72cb485 [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file pkt.c RTCP Packet handling
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6#include <string.h>
7#include <re_types.h>
8#include <re_fmt.h>
9#include <re_mem.h>
10#include <re_mbuf.h>
11#include <re_list.h>
12#include <re_sys.h>
13#include <re_sa.h>
14#include <re_rtp.h>
15#include "rtcp.h"
16
17
18#define DEBUG_MODULE "rtcp_pkt"
19#define DEBUG_LEVEL 5
20#include <re_dbg.h>
21
22
23static void rtcp_destructor(void *data)
24{
25 struct rtcp_msg *msg = data;
26 size_t i, j;
27
28 switch (msg->hdr.pt) {
29
30 case RTCP_SR:
31 mem_deref(msg->r.sr.rrv);
32 break;
33
34 case RTCP_RR:
35 mem_deref(msg->r.rr.rrv);
36 break;
37
38 case RTCP_SDES:
39 if (!msg->r.sdesv)
40 break;
41
42 for (i=0; i<msg->hdr.count; i++) {
43 struct rtcp_sdes *sdes = &msg->r.sdesv[i];
44
45 for (j=0; j<sdes->n; j++) {
46
47 mem_deref(sdes->itemv[j].data);
48 }
49 mem_deref(sdes->itemv);
50 }
51 mem_deref(msg->r.sdesv);
52 break;
53
54 case RTCP_BYE:
55 mem_deref(msg->r.bye.srcv);
56 mem_deref(msg->r.bye.reason);
57 break;
58
59 case RTCP_APP:
60 mem_deref(msg->r.app.data);
61 break;
62
63 case RTCP_RTPFB:
64 case RTCP_PSFB:
65 mem_deref(msg->r.fb.fci.p);
66 break;
67
68 default:
69 /* nothing allocated */
70 break;
71 }
72}
73
74
75/**
76 * Encode the RTCP Header
77 *
78 * @param mb Buffer to encode into
79 * @param count Number of sub-elemements
80 * @param type RTCP Packet type
81 * @param length Packet length in words
82 *
83 * @return 0 for success, otherwise errorcode
84 */
85int rtcp_hdr_encode(struct mbuf *mb, uint8_t count, enum rtcp_type type,
86 uint16_t length)
87{
88 int err;
89
90 if (!mb)
91 return EINVAL;
92
93 err = mbuf_write_u8(mb, RTCP_VERSION<<6 | count);
94 err |= mbuf_write_u8(mb, type);
95 err |= mbuf_write_u16(mb, htons(length));
96
97 return err;
98}
99
100
101/**
102 * Decode the RTCP Header
103 *
104 * @param mb Buffer to decode from
105 * @param hdr RTCP Header to decode into
106 *
107 * @return 0 for success, otherwise errorcode
108 */
109int rtcp_hdr_decode(struct mbuf *mb, struct rtcp_hdr *hdr)
110{
111 uint8_t b;
112
113 if (!hdr)
114 return EINVAL;
115 if (mbuf_get_left(mb) < RTCP_HDR_SIZE)
116 return EBADMSG;
117
118 b = mbuf_read_u8(mb);
119 hdr->pt = mbuf_read_u8(mb);
120 hdr->length = ntohs(mbuf_read_u16(mb));
121
122 hdr->version = (b >> 6) & 0x3;
123 hdr->p = (b >> 5) & 0x1;
124 hdr->count = (b >> 0) & 0x1f;
125
126 return 0;
127}
128
129
130int rtcp_vencode(struct mbuf *mb, enum rtcp_type type, uint32_t count,
131 va_list ap)
132{
133 size_t i, pos;
134 uint16_t len;
135 const uint8_t *data;
136 size_t data_len;
137 const uint32_t *srcv;
138 const char *reason;
139 rtcp_encode_h *ench;
140 void *arg;
141 int err = 0;
142
143 if (!mb)
144 return EINVAL;
145
146 pos = mb->pos;
147
148 /* Skip header - encoded last */
149 mb->pos = mb->end = (mb->pos + RTCP_HDR_SIZE);
150
151 switch (type) {
152
153 case RTCP_SR:
154 for (i=0; i<6; i++)
155 err |= mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t)));
156 ench = va_arg(ap, rtcp_encode_h *);
157 arg = va_arg(ap, void *);
158 if (ench)
159 err |= ench(mb, arg);
160 break;
161
162 case RTCP_RR:
163 err = mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t)));
164 ench = va_arg(ap, rtcp_encode_h *);
165 arg = va_arg(ap, void *);
166 if (ench)
167 err |= ench(mb, arg);
168 break;
169
170 case RTCP_SDES:
171 ench = va_arg(ap, rtcp_encode_h *);
172 arg = va_arg(ap, void *);
173 if (ench)
174 err |= ench(mb, arg);
175 break;
176
177 case RTCP_BYE:
178 srcv = va_arg(ap, uint32_t *);
179 reason = va_arg(ap, char *);
180 for (i=0; i<count && !err; i++) {
181 err = mbuf_write_u32(mb, htonl(srcv[i]));
182 }
183 if (reason) {
184 err |= mbuf_write_u8(mb, strlen(reason));
185 err |= mbuf_write_str(mb, reason);
186 }
187 break;
188
189 case RTCP_APP:
190 err = mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t)));
191 err |= mbuf_write_mem(mb, va_arg(ap, uint8_t *), 4);
192 data = va_arg(ap, const uint8_t *);
193 data_len = va_arg(ap, size_t);
194 if (data) {
195 if (data_len % 4) {
196 DEBUG_WARNING("not a multiple of 32bits\n");
197 return EBADMSG;
198 }
199 err |= mbuf_write_mem(mb, data, data_len);
200 }
201 break;
202
203 case RTCP_FIR:
204 err = mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t)));
205 break;
206
207 case RTCP_NACK:
208 err = mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t)));
209 err |= mbuf_write_u16(mb, htons(va_arg(ap, uint32_t)));
210 err |= mbuf_write_u16(mb, htons(va_arg(ap, uint32_t)));
211 break;
212
213 case RTCP_RTPFB:
214 case RTCP_PSFB:
215 err = mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t)));
216 err |= mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t)));
217 ench = va_arg(ap, rtcp_encode_h *);
218 arg = va_arg(ap, void *);
219 if (ench)
220 err |= ench(mb, arg);
221 break;
222
223 default:
224 return EINVAL;
225 }
226 if (err)
227 return err;
228
229 /* padding to 32 bits */
230 while ((mb->end - pos) & 0x3)
231 err |= mbuf_write_u8(mb, 0x00);
232 if (err)
233 return err;
234
235 /* Encode RTCP Header */
236 mb->pos = pos;
237 len = (mb->end - pos - RTCP_HDR_SIZE)/sizeof(uint32_t);
238 err = rtcp_hdr_encode(mb, count, type, len);
239 if (err)
240 return err;
241
242 mb->pos = mb->end;
243
244 return 0;
245}
246
247
248/**
249 * Encode an RTCP Packet into a buffer
250 *
251 * @param mb Buffer to encode into
252 * @param type RTCP Packet type
253 * @param count Packet-specific count
254 *
255 * @return 0 for success, otherwise errorcode
256 */
257int rtcp_encode(struct mbuf *mb, enum rtcp_type type, uint32_t count, ...)
258{
259 va_list ap;
260 int err;
261
262 va_start(ap, count);
263 err = rtcp_vencode(mb, type, count, ap);
264 va_end(ap);
265
266 return err;
267}
268
269
270/**
271 * Decode one RTCP message from a buffer
272 *
273 * @param msgp Pointer to allocated RTCP Message
274 * @param mb Buffer to decode from
275 *
276 * @return 0 for success, otherwise errorcode
277 */
278int rtcp_decode(struct rtcp_msg **msgp, struct mbuf *mb)
279{
280 struct rtcp_msg *msg = NULL;
281 size_t start, i, sz, count, rem;
282 int err;
283
284 if (!msgp)
285 return EINVAL;
286 if (mbuf_get_left(mb) < RTCP_HDR_SIZE)
287 return EBADMSG;
288
289 msg = mem_zalloc(sizeof(*msg), rtcp_destructor);
290 if (!msg)
291 return ENOMEM;
292
293 start = mb->pos;
294
295 /* decode and check header */
296 err = rtcp_hdr_decode(mb, &msg->hdr);
297 if (err)
298 goto out;
299
300 if (msg->hdr.version != RTCP_VERSION)
301 goto badmsg;
302
303 /* check length and remaining */
304 rem = msg->hdr.length * sizeof(uint32_t);
305 if (mbuf_get_left(mb) < rem)
306 goto badmsg;
307
308 count = msg->hdr.count;
309
310 switch (msg->hdr.pt) {
311
312 case RTCP_SR:
313 if (mbuf_get_left(mb) < (RTCP_SRC_SIZE + RTCP_SR_SIZE))
314 goto badmsg;
315 msg->r.sr.ssrc = ntohl(mbuf_read_u32(mb));
316 msg->r.sr.ntp_sec = ntohl(mbuf_read_u32(mb));
317 msg->r.sr.ntp_frac = ntohl(mbuf_read_u32(mb));
318 msg->r.sr.rtp_ts = ntohl(mbuf_read_u32(mb));
319 msg->r.sr.psent = ntohl(mbuf_read_u32(mb));
320 msg->r.sr.osent = ntohl(mbuf_read_u32(mb));
321
322 err = rtcp_rr_alloc(&msg->r.sr.rrv, count);
323 if (err)
324 goto out;
325 for (i=0; i<count && !err; i++)
326 err = rtcp_rr_decode(mb, &msg->r.sr.rrv[i]);
327 break;
328
329 case RTCP_RR:
330 if (mbuf_get_left(mb) < RTCP_SRC_SIZE)
331 goto badmsg;
332 msg->r.rr.ssrc = ntohl(mbuf_read_u32(mb));
333
334 err = rtcp_rr_alloc(&msg->r.rr.rrv, count);
335 if (err)
336 goto out;
337 for (i=0; i<count && !err; i++)
338 err = rtcp_rr_decode(mb, &msg->r.rr.rrv[i]);
339 break;
340
341 case RTCP_SDES:
342 if (count == 0)
343 break;
344
345 sz = count * sizeof(*msg->r.sdesv);
346 msg->r.sdesv = mem_zalloc(sz, NULL);
347 if (!msg->r.sdesv) {
348 err = ENOMEM;
349 goto out;
350 }
351
352 for (i=0; i<msg->hdr.count && !err; i++)
353 err = rtcp_sdes_decode(mb, &msg->r.sdesv[i]);
354 break;
355
356 case RTCP_BYE:
357 sz = count * sizeof(*msg->r.bye.srcv);
358 msg->r.bye.srcv = mem_alloc(sz, NULL);
359 if (!msg->r.bye.srcv) {
360 err = ENOMEM;
361 goto out;
362 }
363 if (mbuf_get_left(mb) < sz)
364 goto badmsg;
365 for (i=0; i<count; i++)
366 msg->r.bye.srcv[i] = ntohl(mbuf_read_u32(mb));
367
368 /* decode reason (optional) */
369 if (rem > count*sizeof(uint32_t)) {
370 const size_t len = mbuf_read_u8(mb);
371 if (mbuf_get_left(mb) < len)
372 goto badmsg;
373
374 err = mbuf_strdup(mb, &msg->r.bye.reason, len);
375 }
376 break;
377
378 case RTCP_APP:
379 if (mbuf_get_left(mb) < RTCP_APP_SIZE)
380 goto badmsg;
381 msg->r.app.src = ntohl(mbuf_read_u32(mb));
382 (void)mbuf_read_mem(mb, (uint8_t *)msg->r.app.name,
383 sizeof(msg->r.app.name));
384 if (rem > RTCP_APP_SIZE) {
385 msg->r.app.data_len = rem - RTCP_APP_SIZE;
386 msg->r.app.data = mem_alloc(msg->r.app.data_len, NULL);
387 if (!msg->r.app.data) {
388 err = ENOMEM;
389 goto out;
390 }
391 if (mbuf_get_left(mb) < msg->r.app.data_len)
392 goto badmsg;
393 (void)mbuf_read_mem(mb, msg->r.app.data,
394 msg->r.app.data_len);
395 }
396 break;
397
398 case RTCP_FIR:
399 if (mbuf_get_left(mb) < RTCP_FIR_SIZE)
400 goto badmsg;
401 msg->r.fir.ssrc = ntohl(mbuf_read_u32(mb));
402 break;
403
404 case RTCP_NACK:
405 if (mbuf_get_left(mb) < RTCP_NACK_SIZE)
406 goto badmsg;
407 msg->r.nack.ssrc = ntohl(mbuf_read_u32(mb));
408 msg->r.nack.fsn = ntohs(mbuf_read_u16(mb));
409 msg->r.nack.blp = ntohs(mbuf_read_u16(mb));
410 break;
411
412 case RTCP_RTPFB:
413 if (mbuf_get_left(mb) < RTCP_FB_SIZE)
414 goto badmsg;
415
416 if (msg->hdr.length < 2)
417 goto badmsg;
418
419 msg->r.fb.ssrc_packet = ntohl(mbuf_read_u32(mb));
420 msg->r.fb.ssrc_media = ntohl(mbuf_read_u32(mb));
421 msg->r.fb.n = msg->hdr.length - 2;
422
423 err = rtcp_rtpfb_decode(mb, msg);
424 break;
425
426 case RTCP_PSFB:
427 if (mbuf_get_left(mb) < RTCP_FB_SIZE)
428 goto badmsg;
429
430 if (msg->hdr.length < 2)
431 goto badmsg;
432
433 msg->r.fb.ssrc_packet = ntohl(mbuf_read_u32(mb));
434 msg->r.fb.ssrc_media = ntohl(mbuf_read_u32(mb));
435 msg->r.fb.n = msg->hdr.length - 2;
436
437 err = rtcp_psfb_decode(mb, msg);
438 break;
439
440 default:
441 /* unknown message type */
442 mbuf_advance(mb, rem);
443 break;
444 }
445 if (err)
446 goto out;
447
448 /* slurp padding */
449 while ((mb->pos - start) & 0x3 && mbuf_get_left(mb))
450 ++mb->pos;
451
452 out:
453 if (err)
454 mem_deref(msg);
455 else
456 *msgp = msg;
457
458 return err;
459
460 badmsg:
461 mem_deref(msg);
462 return EBADMSG;
463}