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/ice/cand.c b/src/ice/cand.c
new file mode 100644
index 0000000..5d4ee05
--- /dev/null
+++ b/src/ice/cand.c
@@ -0,0 +1,322 @@
+/**
+ * @file cand.c  ICE Candidates
+ *
+ * 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_tmr.h>
+#include <re_sa.h>
+#include <re_sys.h>
+#include <re_stun.h>
+#include <re_turn.h>
+#include <re_ice.h>
+#include "ice.h"
+
+
+#define DEBUG_MODULE "icecand"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+static void cand_destructor(void *arg)
+{
+	struct ice_cand *cand = arg;
+
+	list_unlink(&cand->le);
+	mem_deref(cand->foundation);
+	mem_deref(cand->ifname);
+
+	if (cand != cand->base)
+		mem_deref(cand->base);
+}
+
+
+/** Foundation is a hash of IP address and candidate type */
+static int compute_foundation(struct ice_cand *cand)
+{
+	uint32_t v;
+
+	v  = sa_hash(&cand->addr, SA_ADDR);
+	v ^= cand->type;
+
+	return re_sdprintf(&cand->foundation, "%08x", v);
+}
+
+
+static int cand_alloc(struct ice_cand **candp, struct icem *icem,
+		      enum ice_cand_type type, unsigned compid,
+		      uint32_t prio, const char *ifname,
+		      enum ice_transp transp, const struct sa *addr)
+{
+	struct ice_cand *cand;
+	int err;
+
+	if (!icem)
+		return EINVAL;
+
+	cand = mem_zalloc(sizeof(*cand), cand_destructor);
+	if (!cand)
+		return ENOMEM;
+
+	list_append(&icem->lcandl, &cand->le, cand);
+
+	cand->type   = type;
+	cand->compid = compid;
+	cand->prio   = prio;
+	cand->transp = transp;
+
+	sa_cpy(&cand->addr, addr);
+
+	err = compute_foundation(cand);
+
+	if (ifname)
+		err |= str_dup(&cand->ifname, ifname);
+
+	if (err)
+		mem_deref(cand);
+	else if (candp)
+		*candp = cand;
+
+	return err;
+}
+
+
+int icem_lcand_add_base(struct icem *icem, unsigned compid, uint16_t lprio,
+			const char *ifname, enum ice_transp transp,
+			const struct sa *addr)
+{
+	struct icem_comp *comp;
+	struct ice_cand *cand;
+	int err;
+
+	comp = icem_comp_find(icem, compid);
+	if (!comp)
+		return ENOENT;
+
+	err = cand_alloc(&cand, icem, ICE_CAND_TYPE_HOST, compid,
+			 ice_cand_calc_prio(ICE_CAND_TYPE_HOST, lprio, compid),
+			 ifname, transp, addr);
+	if (err)
+		return err;
+
+	/* the base is itself */
+	cand->base = cand;
+
+	sa_set_port(&cand->addr, comp->lport);
+
+	return 0;
+}
+
+
+int icem_lcand_add(struct icem *icem, struct ice_cand *base,
+		   enum ice_cand_type type,
+		   const struct sa *addr)
+{
+	struct ice_cand *cand;
+	int err;
+
+	if (!base)
+		return EINVAL;
+
+	err = cand_alloc(&cand, icem, type, base->compid,
+			 ice_cand_calc_prio(type, 0, base->compid),
+			 base->ifname, base->transp, addr);
+	if (err)
+		return err;
+
+	cand->base = mem_ref(base);
+	sa_cpy(&cand->rel, &base->addr);
+
+	return 0;
+}
+
+
+int icem_rcand_add(struct icem *icem, enum ice_cand_type type, unsigned compid,
+		   uint32_t prio, const struct sa *addr,
+		   const struct sa *rel_addr, const struct pl *foundation)
+{
+	struct ice_cand *rcand;
+	int err;
+
+	if (!icem || !foundation)
+		return EINVAL;
+
+	rcand = mem_zalloc(sizeof(*rcand), cand_destructor);
+	if (!rcand)
+		return ENOMEM;
+
+	list_append(&icem->rcandl, &rcand->le, rcand);
+
+	rcand->type   = type;
+	rcand->compid = compid;
+	rcand->prio   = prio;
+
+	sa_cpy(&rcand->addr, addr);
+	sa_cpy(&rcand->rel, rel_addr);
+
+	err = pl_strdup(&rcand->foundation, foundation);
+
+	if (err)
+		mem_deref(rcand);
+
+	return err;
+}
+
+
+int icem_rcand_add_prflx(struct ice_cand **rcp, struct icem *icem,
+			 unsigned compid, uint32_t prio,
+			 const struct sa *addr)
+{
+	struct ice_cand *rcand;
+	int err;
+
+	if (!icem || !addr)
+		return EINVAL;
+
+	rcand = mem_zalloc(sizeof(*rcand), cand_destructor);
+	if (!rcand)
+		return ENOMEM;
+
+	list_append(&icem->rcandl, &rcand->le, rcand);
+
+	rcand->type   = ICE_CAND_TYPE_PRFLX;
+	rcand->compid = compid;
+	rcand->prio   = prio;
+	rcand->addr   = *addr;
+
+	err = re_sdprintf(&rcand->foundation, "%08x", rand_u32());
+	if (err)
+		goto out;
+
+	icecomp_printf(icem_comp_find(icem, compid),
+		       "added PeerReflexive remote candidate"
+		       " with priority %u (%J)\n", prio, addr);
+
+ out:
+	if (err)
+		mem_deref(rcand);
+	else if (rcp)
+		*rcp = rcand;
+
+	return err;
+}
+
+
+struct ice_cand *icem_cand_find(const struct list *lst, unsigned compid,
+				const struct sa *addr)
+{
+	struct le *le;
+
+	for (le = list_head(lst); le; le = le->next) {
+
+		struct ice_cand *cand = le->data;
+
+		if (compid && cand->compid != compid)
+			continue;
+
+		if (addr && !sa_cmp(&cand->addr, addr, SA_ALL))
+			continue;
+
+		return cand;
+	}
+
+	return NULL;
+}
+
+
+/**
+ * Find the highest priority LCAND on the check-list of type HOST/RELAY
+ *
+ * @param icem    ICE Media object
+ * @param compid  Component ID
+ *
+ * @return Local candidate if found, otherwise NULL
+ */
+struct ice_cand *icem_lcand_find_checklist(const struct icem *icem,
+					   unsigned compid)
+{
+	struct le *le;
+
+	for (le = icem->checkl.head; le; le = le->next) {
+		struct ice_candpair *cp = le->data;
+
+		if (cp->lcand->compid != compid)
+			continue;
+
+		switch (cp->lcand->type) {
+
+		case ICE_CAND_TYPE_HOST:
+		case ICE_CAND_TYPE_RELAY:
+			return cp->lcand;
+
+		default:
+			break;
+		}
+	}
+
+	return NULL;
+}
+
+
+struct ice_cand *icem_lcand_base(struct ice_cand *lcand)
+{
+	return lcand ? lcand->base : NULL;
+}
+
+
+const struct sa *icem_lcand_addr(const struct ice_cand *cand)
+{
+	return cand ? &cand->addr : NULL;
+}
+
+
+int icem_cands_debug(struct re_printf *pf, const struct list *lst)
+{
+	struct le *le;
+	int err;
+
+	err = re_hprintf(pf, " (%u)\n", list_count(lst));
+
+	for (le = list_head(lst); le && !err; le = le->next) {
+
+		const struct ice_cand *cand = le->data;
+
+		err |= re_hprintf(pf, "  {%u} fnd=%-2s prio=%08x %24H",
+				  cand->compid, cand->foundation, cand->prio,
+				  icem_cand_print, cand);
+
+		if (sa_isset(&cand->rel, SA_ADDR))
+			err |= re_hprintf(pf, " (rel-addr=%J)", &cand->rel);
+
+		err |= re_hprintf(pf, "\n");
+	}
+
+	return err;
+}
+
+
+int icem_cand_print(struct re_printf *pf, const struct ice_cand *cand)
+{
+	int err = 0;
+
+	if (!cand)
+		return 0;
+
+	if (cand->ifname)
+		err |= re_hprintf(pf, "%s:", cand->ifname);
+
+	err |= re_hprintf(pf, "%s:%J",
+			  ice_cand_type2name(cand->type), &cand->addr);
+
+	return err;
+}
+
+enum ice_cand_type icem_cand_type(const struct ice_cand *cand)
+{
+	return cand ? cand->type : (enum ice_cand_type)-1;
+}