| /** |
| * @file sdes.c RTCP Source Description |
| * |
| * Copyright (C) 2010 Creytiv.com |
| */ |
| #include <string.h> |
| #include <re_types.h> |
| #include <re_fmt.h> |
| #include <re_mem.h> |
| #include <re_mbuf.h> |
| #include <re_list.h> |
| #include <re_sa.h> |
| #include <re_rtp.h> |
| #include "rtcp.h" |
| |
| |
| #define DEBUG_MODULE "rtcp_sdes" |
| #define DEBUG_LEVEL 5 |
| #include <re_dbg.h> |
| |
| |
| enum { |
| RTCP_SDES_MIN_SIZE = 1, |
| }; |
| |
| |
| /** |
| * Encode one SDES chunk into mbuffer |
| * |
| * @param mb Buffer to encode into |
| * @param src First SSRC/CSRC |
| * @param itemc Number of SDES items to encode |
| * |
| * @return 0 if success, otherwise errorcode |
| */ |
| int rtcp_sdes_encode(struct mbuf *mb, uint32_t src, uint32_t itemc, ...) |
| { |
| va_list ap; |
| size_t start; |
| int err = 0; |
| |
| if (!mb || !itemc) |
| return EINVAL; |
| |
| va_start(ap, itemc); |
| |
| start = mb->pos; |
| err = mbuf_write_u32(mb, htonl(src)); |
| |
| /* add all SDES items */ |
| while (itemc-- && !err) { |
| const uint8_t type = va_arg(ap, int); |
| const char *v = va_arg(ap, const char *); |
| size_t len; |
| if (!v) |
| continue; |
| |
| len = strlen(v); /* note: max 255 chars */ |
| if (len > 255) { |
| err = EINVAL; |
| goto out; |
| } |
| |
| err = mbuf_write_u8(mb, type); |
| err |= mbuf_write_u8(mb, len & 0xff); |
| err |= mbuf_write_mem(mb, (uint8_t *)v, len); |
| } |
| |
| /* END padding */ |
| err |= mbuf_write_u8(mb, RTCP_SDES_END); |
| while ((mb->pos - start) & 0x3) |
| err |= mbuf_write_u8(mb, RTCP_SDES_END); |
| |
| out: |
| va_end(ap); |
| |
| return err; |
| } |
| |
| |
| /** |
| * Decode SDES items from a buffer |
| * |
| * @param mb Buffer to decode from |
| * @param sdes RTCP SDES to decode into |
| * |
| * @return 0 if success, otherwise errorcode |
| */ |
| int rtcp_sdes_decode(struct mbuf *mb, struct rtcp_sdes *sdes) |
| { |
| size_t start; |
| |
| if (!sdes) |
| return EINVAL; |
| if (mbuf_get_left(mb) < RTCP_SRC_SIZE) |
| return EBADMSG; |
| |
| start = mb->pos; |
| sdes->src = ntohl(mbuf_read_u32(mb)); |
| |
| /* Decode all SDES items */ |
| while (mbuf_get_left(mb) >= RTCP_SDES_MIN_SIZE) { |
| uint8_t type; |
| struct rtcp_sdes_item *item; |
| |
| type = mbuf_read_u8(mb); |
| if (type == RTCP_SDES_END) |
| break; |
| |
| if (mbuf_get_left(mb) < 1) |
| return EBADMSG; |
| |
| if (!sdes->itemv) { |
| sdes->itemv = mem_alloc(sizeof(*sdes->itemv), NULL); |
| if (!sdes->itemv) |
| return ENOMEM; |
| } |
| else { |
| const size_t sz = (sdes->n + 1) * sizeof(*sdes->itemv); |
| struct rtcp_sdes_item *itemv; |
| |
| itemv = mem_realloc(sdes->itemv, sz); |
| if (!itemv) |
| return ENOMEM; |
| |
| sdes->itemv = itemv; |
| } |
| |
| item = &sdes->itemv[sdes->n]; |
| |
| item->type = (enum rtcp_sdes_type)type; |
| item->length = mbuf_read_u8(mb); |
| if (mbuf_get_left(mb) < item->length) |
| return EBADMSG; |
| item->data = mem_alloc(item->length, NULL); |
| if (!item->data) |
| return ENOMEM; |
| (void)mbuf_read_mem(mb, (uint8_t *)item->data, item->length); |
| |
| sdes->n++; |
| } |
| |
| /* slurp padding */ |
| while ((mb->pos - start) & 0x3 && mbuf_get_left(mb)) |
| ++mb->pos; |
| |
| return 0; |
| } |