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;
+}