/** * @file sdes.c RTCP Source Description * * Copyright (C) 2010 Creytiv.com */ #include #include #include #include #include #include #include #include #include "rtcp.h" #define DEBUG_MODULE "rtcp_sdes" #define DEBUG_LEVEL 5 #include 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; }