Squashed 'third_party/rawrtc/re/' content from commit f3163ce8b

Change-Id: I6a235e6ac0f03269d951026f9d195da05c40fdab
git-subtree-dir: third_party/rawrtc/re
git-subtree-split: f3163ce8b526a13b35ef71ce4dd6f43585064d8a
diff --git a/src/rtp/pkt.c b/src/rtp/pkt.c
new file mode 100644
index 0000000..cd4880d
--- /dev/null
+++ b/src/rtp/pkt.c
@@ -0,0 +1,463 @@
+/**
+ * @file pkt.c  RTCP Packet handling
+ *
+ * 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_sys.h>
+#include <re_sa.h>
+#include <re_rtp.h>
+#include "rtcp.h"
+
+
+#define DEBUG_MODULE "rtcp_pkt"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+static void rtcp_destructor(void *data)
+{
+	struct rtcp_msg *msg = data;
+	size_t i, j;
+
+	switch (msg->hdr.pt) {
+
+	case RTCP_SR:
+		mem_deref(msg->r.sr.rrv);
+		break;
+
+	case RTCP_RR:
+		mem_deref(msg->r.rr.rrv);
+		break;
+
+	case RTCP_SDES:
+		if (!msg->r.sdesv)
+			break;
+
+		for (i=0; i<msg->hdr.count; i++) {
+			struct rtcp_sdes *sdes = &msg->r.sdesv[i];
+
+			for (j=0; j<sdes->n; j++) {
+
+				mem_deref(sdes->itemv[j].data);
+			}
+			mem_deref(sdes->itemv);
+		}
+		mem_deref(msg->r.sdesv);
+		break;
+
+	case RTCP_BYE:
+		mem_deref(msg->r.bye.srcv);
+		mem_deref(msg->r.bye.reason);
+		break;
+
+	case RTCP_APP:
+		mem_deref(msg->r.app.data);
+		break;
+
+	case RTCP_RTPFB:
+	case RTCP_PSFB:
+		mem_deref(msg->r.fb.fci.p);
+		break;
+
+	default:
+		/* nothing allocated */
+		break;
+	}
+}
+
+
+/**
+ * Encode the RTCP Header
+ *
+ * @param mb     Buffer to encode into
+ * @param count  Number of sub-elemements
+ * @param type   RTCP Packet type
+ * @param length Packet length in words
+ *
+ * @return 0 for success, otherwise errorcode
+ */
+int rtcp_hdr_encode(struct mbuf *mb, uint8_t count, enum rtcp_type type,
+		    uint16_t length)
+{
+	int err;
+
+	if (!mb)
+		return EINVAL;
+
+	err  = mbuf_write_u8(mb, RTCP_VERSION<<6 | count);
+	err |= mbuf_write_u8(mb, type);
+	err |= mbuf_write_u16(mb, htons(length));
+
+	return err;
+}
+
+
+/**
+ * Decode the RTCP Header
+ *
+ * @param mb  Buffer to decode from
+ * @param hdr RTCP Header to decode into
+ *
+ * @return 0 for success, otherwise errorcode
+ */
+int rtcp_hdr_decode(struct mbuf *mb, struct rtcp_hdr *hdr)
+{
+	uint8_t b;
+
+	if (!hdr)
+		return EINVAL;
+	if (mbuf_get_left(mb) < RTCP_HDR_SIZE)
+		return EBADMSG;
+
+	b = mbuf_read_u8(mb);
+	hdr->pt = mbuf_read_u8(mb);
+	hdr->length = ntohs(mbuf_read_u16(mb));
+
+	hdr->version = (b >> 6) & 0x3;
+	hdr->p       = (b >> 5) & 0x1;
+	hdr->count   = (b >> 0) & 0x1f;
+
+	return 0;
+}
+
+
+int rtcp_vencode(struct mbuf *mb, enum rtcp_type type, uint32_t count,
+		 va_list ap)
+{
+	size_t i, pos;
+	uint16_t len;
+	const uint8_t *data;
+	size_t data_len;
+	const uint32_t *srcv;
+	const char *reason;
+	rtcp_encode_h *ench;
+	void *arg;
+	int err = 0;
+
+	if (!mb)
+		return EINVAL;
+
+	pos = mb->pos;
+
+	/* Skip header - encoded last */
+	mb->pos = mb->end = (mb->pos + RTCP_HDR_SIZE);
+
+	switch (type) {
+
+	case RTCP_SR:
+		for (i=0; i<6; i++)
+			err |= mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t)));
+		ench = va_arg(ap, rtcp_encode_h *);
+		arg = va_arg(ap, void *);
+		if (ench)
+			err |= ench(mb, arg);
+		break;
+
+	case RTCP_RR:
+		err = mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t)));
+		ench = va_arg(ap, rtcp_encode_h *);
+		arg = va_arg(ap, void *);
+		if (ench)
+			err |= ench(mb, arg);
+		break;
+
+	case RTCP_SDES:
+		ench = va_arg(ap, rtcp_encode_h *);
+		arg = va_arg(ap, void *);
+		if (ench)
+			err |= ench(mb, arg);
+		break;
+
+	case RTCP_BYE:
+		srcv   = va_arg(ap, uint32_t *);
+		reason = va_arg(ap, char *);
+		for (i=0; i<count && !err; i++) {
+			err = mbuf_write_u32(mb, htonl(srcv[i]));
+		}
+		if (reason) {
+			err |= mbuf_write_u8(mb, strlen(reason));
+			err |= mbuf_write_str(mb, reason);
+		}
+		break;
+
+	case RTCP_APP:
+		err  = mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t)));
+		err |= mbuf_write_mem(mb, va_arg(ap, uint8_t *), 4);
+		data = va_arg(ap, const uint8_t *);
+		data_len = va_arg(ap, size_t);
+		if (data) {
+			if (data_len % 4) {
+				DEBUG_WARNING("not a multiple of 32bits\n");
+				return EBADMSG;
+			}
+			err |= mbuf_write_mem(mb, data, data_len);
+		}
+		break;
+
+	case RTCP_FIR:
+		err  = mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t)));
+		break;
+
+	case RTCP_NACK:
+		err  = mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t)));
+		err |= mbuf_write_u16(mb, htons(va_arg(ap, uint32_t)));
+		err |= mbuf_write_u16(mb, htons(va_arg(ap, uint32_t)));
+		break;
+
+	case RTCP_RTPFB:
+	case RTCP_PSFB:
+		err  = mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t)));
+		err |= mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t)));
+		ench = va_arg(ap, rtcp_encode_h *);
+		arg = va_arg(ap, void *);
+		if (ench)
+			err |= ench(mb, arg);
+		break;
+
+	default:
+		return EINVAL;
+	}
+	if (err)
+		return err;
+
+	/* padding to 32 bits */
+	while ((mb->end - pos) & 0x3)
+		err |= mbuf_write_u8(mb, 0x00);
+	if (err)
+		return err;
+
+	/* Encode RTCP Header */
+	mb->pos = pos;
+	len = (mb->end - pos - RTCP_HDR_SIZE)/sizeof(uint32_t);
+	err = rtcp_hdr_encode(mb, count, type, len);
+	if (err)
+		return err;
+
+	mb->pos = mb->end;
+
+	return 0;
+}
+
+
+/**
+ * Encode an RTCP Packet into a buffer
+ *
+ * @param mb    Buffer to encode into
+ * @param type  RTCP Packet type
+ * @param count Packet-specific count
+ *
+ * @return 0 for success, otherwise errorcode
+ */
+int rtcp_encode(struct mbuf *mb, enum rtcp_type type, uint32_t count, ...)
+{
+	va_list ap;
+	int err;
+
+	va_start(ap, count);
+	err = rtcp_vencode(mb, type, count, ap);
+	va_end(ap);
+
+	return err;
+}
+
+
+/**
+ * Decode one RTCP message from a buffer
+ *
+ * @param msgp Pointer to allocated RTCP Message
+ * @param mb   Buffer to decode from
+ *
+ * @return 0 for success, otherwise errorcode
+ */
+int rtcp_decode(struct rtcp_msg **msgp, struct mbuf *mb)
+{
+	struct rtcp_msg *msg = NULL;
+	size_t start, i, sz, count, rem;
+	int err;
+
+	if (!msgp)
+		return EINVAL;
+	if (mbuf_get_left(mb) < RTCP_HDR_SIZE)
+		return EBADMSG;
+
+	msg = mem_zalloc(sizeof(*msg), rtcp_destructor);
+	if (!msg)
+		return ENOMEM;
+
+	start = mb->pos;
+
+	/* decode and check header */
+	err = rtcp_hdr_decode(mb, &msg->hdr);
+	if (err)
+		goto out;
+
+	if (msg->hdr.version != RTCP_VERSION)
+		goto badmsg;
+
+	/* check length and remaining */
+	rem = msg->hdr.length * sizeof(uint32_t);
+	if (mbuf_get_left(mb) < rem)
+		goto badmsg;
+
+	count = msg->hdr.count;
+
+	switch (msg->hdr.pt) {
+
+	case RTCP_SR:
+		if (mbuf_get_left(mb) < (RTCP_SRC_SIZE + RTCP_SR_SIZE))
+			goto badmsg;
+		msg->r.sr.ssrc     = ntohl(mbuf_read_u32(mb));
+		msg->r.sr.ntp_sec  = ntohl(mbuf_read_u32(mb));
+		msg->r.sr.ntp_frac = ntohl(mbuf_read_u32(mb));
+		msg->r.sr.rtp_ts   = ntohl(mbuf_read_u32(mb));
+		msg->r.sr.psent    = ntohl(mbuf_read_u32(mb));
+		msg->r.sr.osent    = ntohl(mbuf_read_u32(mb));
+
+		err = rtcp_rr_alloc(&msg->r.sr.rrv, count);
+		if (err)
+			goto out;
+		for (i=0; i<count && !err; i++)
+			err = rtcp_rr_decode(mb, &msg->r.sr.rrv[i]);
+		break;
+
+	case RTCP_RR:
+		if (mbuf_get_left(mb) < RTCP_SRC_SIZE)
+			goto badmsg;
+		msg->r.rr.ssrc = ntohl(mbuf_read_u32(mb));
+
+		err = rtcp_rr_alloc(&msg->r.rr.rrv, count);
+		if (err)
+			goto out;
+		for (i=0; i<count && !err; i++)
+			err = rtcp_rr_decode(mb, &msg->r.rr.rrv[i]);
+		break;
+
+	case RTCP_SDES:
+		if (count == 0)
+			break;
+
+		sz = count * sizeof(*msg->r.sdesv);
+		msg->r.sdesv = mem_zalloc(sz, NULL);
+		if (!msg->r.sdesv) {
+			err = ENOMEM;
+			goto out;
+		}
+
+		for (i=0; i<msg->hdr.count && !err; i++)
+			err = rtcp_sdes_decode(mb, &msg->r.sdesv[i]);
+		break;
+
+	case RTCP_BYE:
+		sz = count * sizeof(*msg->r.bye.srcv);
+		msg->r.bye.srcv = mem_alloc(sz, NULL);
+		if (!msg->r.bye.srcv) {
+			err = ENOMEM;
+			goto out;
+		}
+		if (mbuf_get_left(mb) < sz)
+			goto badmsg;
+		for (i=0; i<count; i++)
+			msg->r.bye.srcv[i] = ntohl(mbuf_read_u32(mb));
+
+		/* decode reason (optional) */
+		if (rem > count*sizeof(uint32_t)) {
+			const size_t len = mbuf_read_u8(mb);
+			if (mbuf_get_left(mb) < len)
+				goto badmsg;
+
+			err = mbuf_strdup(mb, &msg->r.bye.reason, len);
+		}
+		break;
+
+	case RTCP_APP:
+		if (mbuf_get_left(mb) < RTCP_APP_SIZE)
+			goto badmsg;
+		msg->r.app.src = ntohl(mbuf_read_u32(mb));
+		(void)mbuf_read_mem(mb, (uint8_t *)msg->r.app.name,
+				    sizeof(msg->r.app.name));
+		if (rem > RTCP_APP_SIZE) {
+			msg->r.app.data_len = rem - RTCP_APP_SIZE;
+			msg->r.app.data = mem_alloc(msg->r.app.data_len, NULL);
+			if (!msg->r.app.data) {
+				err = ENOMEM;
+				goto out;
+			}
+			if (mbuf_get_left(mb) < msg->r.app.data_len)
+				goto badmsg;
+			(void)mbuf_read_mem(mb, msg->r.app.data,
+					    msg->r.app.data_len);
+		}
+		break;
+
+	case RTCP_FIR:
+		if (mbuf_get_left(mb) < RTCP_FIR_SIZE)
+			goto badmsg;
+		msg->r.fir.ssrc = ntohl(mbuf_read_u32(mb));
+		break;
+
+	case RTCP_NACK:
+		if (mbuf_get_left(mb) < RTCP_NACK_SIZE)
+			goto badmsg;
+		msg->r.nack.ssrc = ntohl(mbuf_read_u32(mb));
+		msg->r.nack.fsn  = ntohs(mbuf_read_u16(mb));
+		msg->r.nack.blp  = ntohs(mbuf_read_u16(mb));
+		break;
+
+	case RTCP_RTPFB:
+		if (mbuf_get_left(mb) < RTCP_FB_SIZE)
+			goto badmsg;
+
+		if (msg->hdr.length < 2)
+			goto badmsg;
+
+		msg->r.fb.ssrc_packet = ntohl(mbuf_read_u32(mb));
+		msg->r.fb.ssrc_media = ntohl(mbuf_read_u32(mb));
+		msg->r.fb.n = msg->hdr.length - 2;
+
+		err = rtcp_rtpfb_decode(mb, msg);
+		break;
+
+	case RTCP_PSFB:
+		if (mbuf_get_left(mb) < RTCP_FB_SIZE)
+			goto badmsg;
+
+		if (msg->hdr.length < 2)
+			goto badmsg;
+
+		msg->r.fb.ssrc_packet = ntohl(mbuf_read_u32(mb));
+		msg->r.fb.ssrc_media = ntohl(mbuf_read_u32(mb));
+		msg->r.fb.n = msg->hdr.length - 2;
+
+		err = rtcp_psfb_decode(mb, msg);
+		break;
+
+	default:
+		/* unknown message type */
+		mbuf_advance(mb, rem);
+		break;
+	}
+	if (err)
+		goto out;
+
+	/* slurp padding */
+	while ((mb->pos - start) & 0x3 && mbuf_get_left(mb))
+		++mb->pos;
+
+ out:
+	if (err)
+		mem_deref(msg);
+	else
+		*msgp = msg;
+
+	return err;
+
+ badmsg:
+	mem_deref(msg);
+	return EBADMSG;
+}