Squashed 'third_party/rawrtc/rew/' content from commit 24c91fd83
Change-Id: Ica2fcc790472ecd5b195d20da982c4e84139cbdd
git-subtree-dir: third_party/rawrtc/rew
git-subtree-split: 24c91fd839b40b11f727c902fa46d20874da33fb
diff --git a/src/trice/candpair.c b/src/trice/candpair.c
new file mode 100644
index 0000000..deb23c4
--- /dev/null
+++ b/src/trice/candpair.c
@@ -0,0 +1,563 @@
+/**
+ * @file candpair.c ICE Candidate Pairs
+ *
+ * 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_udp.h>
+#include <re_stun.h>
+#include <re_ice.h>
+#include <re_trice.h>
+#include "trice.h"
+
+
+#define DEBUG_MODULE "candpair"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+/*
+ * generic routines to operate on "struct ice_candpair"
+ * (for both checkl and validl)
+ */
+
+
+/*
+ * g = controlling agent
+ * d = controlled agent
+
+ pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0)
+
+ */
+static uint64_t ice_calc_pair_prio(uint32_t g, uint32_t d)
+{
+ const uint64_t m = min(g, d);
+ const uint64_t x = max(g, d);
+
+ return (m<<32) + 2*x + (g>d?1:0);
+}
+
+
+static void candpair_destructor(void *arg)
+{
+ struct ice_candpair *cp = arg;
+
+ list_unlink(&cp->le);
+ mem_deref(cp->lcand);
+ mem_deref(cp->rcand);
+ mem_deref(cp->tc);
+
+ mem_deref(cp->conn);
+}
+
+
+static bool sort_handler(struct le *le1, struct le *le2, void *arg)
+{
+ const struct ice_candpair *cp1 = le1->data, *cp2 = le2->data;
+ (void)arg;
+
+ return cp1->pprio >= cp2->pprio;
+}
+
+
+static void candpair_set_pprio(struct ice_candpair *cp, bool controlling)
+{
+ uint32_t g, d;
+
+ if (controlling) {
+ g = cp->lcand->attr.prio;
+ d = cp->rcand->attr.prio;
+ }
+ else {
+ g = cp->rcand->attr.prio;
+ d = cp->lcand->attr.prio;
+ }
+
+ cp->pprio = ice_calc_pair_prio(g, d);
+}
+
+
+/**
+ * Add candidate pair to list, sorted by pair priority (highest is first)
+ */
+static void list_add_sorted(struct list *list, struct ice_candpair *cp)
+{
+ struct le *le;
+
+ /* find our slot */
+ for (le = list_tail(list); le; le = le->prev) {
+ struct ice_candpair *cp0 = le->data;
+
+ if (cp->pprio < cp0->pprio) {
+ list_insert_after(list, le, &cp->le, cp);
+ return;
+ }
+ }
+
+ list_prepend(list, &cp->le, cp);
+}
+
+
+int trice_candpair_alloc(struct ice_candpair **cpp, struct trice *icem,
+ struct ice_lcand *lcand, struct ice_rcand *rcand)
+{
+ struct ice_candpair *cp;
+
+ if (!icem || !lcand || !rcand)
+ return EINVAL;
+
+ if (icem->lrole == ICE_ROLE_UNKNOWN) {
+ DEBUG_WARNING("trice_candpair_alloc: invalid local role!\n");
+ return EINVAL;
+ }
+
+ cp = mem_zalloc(sizeof(*cp), candpair_destructor);
+ if (!cp)
+ return ENOMEM;
+
+ cp->lcand = mem_ref(lcand);
+ cp->rcand = mem_ref(rcand);
+ cp->state = ICE_CANDPAIR_FROZEN;
+
+ candpair_set_pprio(cp, icem->lrole == ICE_ROLE_CONTROLLING);
+
+ list_add_sorted(&icem->checkl, cp);
+
+ if (cpp)
+ *cpp = cp;
+
+ return 0;
+}
+
+
+/** Computing Pair Priority and Ordering Pairs */
+void trice_candpair_prio_order(struct list *lst, bool controlling)
+{
+ struct le *le;
+
+ for (le = list_head(lst); le; le = le->next) {
+ struct ice_candpair *cp = le->data;
+
+ candpair_set_pprio(cp, controlling);
+ }
+
+ list_sort(lst, sort_handler, NULL);
+}
+
+
+void trice_candpair_make_valid(struct trice *icem, struct ice_candpair *pair)
+{
+ if (!icem || !pair)
+ return;
+
+ if (pair->state == ICE_CANDPAIR_FAILED) {
+ DEBUG_WARNING("make_valid: pair already FAILED [%H]\n",
+ trice_candpair_debug, pair);
+ }
+
+ pair->err = 0;
+ pair->scode = 0;
+ pair->valid = true;
+
+ trice_candpair_set_state(pair, ICE_CANDPAIR_SUCCEEDED);
+
+ list_unlink(&pair->le);
+ list_add_sorted(&icem->validl, pair);
+}
+
+
+void trice_candpair_failed(struct ice_candpair *cp, int err, uint16_t scode)
+{
+ if (!cp)
+ return;
+
+ if (cp->state == ICE_CANDPAIR_SUCCEEDED) {
+ DEBUG_WARNING("set_failed(%m): pair already SUCCEEDED [%H]\n",
+ err, trice_candpair_debug, cp);
+ }
+
+ cp->err = err;
+ cp->scode = scode;
+ cp->valid = false;
+
+ cp->conn = mem_deref(cp->conn);
+
+ trice_candpair_set_state(cp, ICE_CANDPAIR_FAILED);
+}
+
+
+void trice_candpair_set_state(struct ice_candpair *pair,
+ enum ice_candpair_state state)
+{
+ if (!pair)
+ return;
+ if (pair->state == state)
+ return;
+
+ if (trice_candpair_iscompleted(pair)) {
+ DEBUG_WARNING("set_state(%s): pair is already completed"
+ " [%H]\n",
+ trice_candpair_state2name(state),
+ trice_candpair_debug, pair);
+ }
+
+#if 0
+ trice_printf(pair->lcand->icem,
+ "%H new state \"%s\"\n",
+ trice_candpair_debug, pair,
+ trice_candpair_state2name(state));
+#endif
+
+ pair->state = state;
+}
+
+
+bool trice_candpair_iscompleted(const struct ice_candpair *cp)
+{
+ if (!cp)
+ return false;
+
+ return cp->state == ICE_CANDPAIR_FAILED ||
+ cp->state == ICE_CANDPAIR_SUCCEEDED;
+}
+
+
+/**
+ * Find the highest-priority candidate-pair in a given list, with
+ * optional match parameters
+ *
+ * @param lst List of candidate pairs
+ * @param lcand Local candidate (optional)
+ * @param rcand Remote candidate (optional)
+ *
+ * @return Matching candidate pair if found, otherwise NULL
+ *
+ * note: assume list is sorted by priority
+ */
+struct ice_candpair *trice_candpair_find(const struct list *lst,
+ const struct ice_lcand *lcand,
+ const struct ice_rcand *rcand)
+{
+ struct le *le;
+
+ for (le = list_head(lst); le; le = le->next) {
+
+ struct ice_candpair *cp = le->data;
+
+ if (!cp->lcand || !cp->rcand) {
+ DEBUG_WARNING("corrupt candpair %p\n", cp);
+ continue;
+ }
+
+ if (lcand && cp->lcand != lcand)
+ continue;
+
+ if (rcand && cp->rcand != rcand)
+ continue;
+
+ return cp;
+ }
+
+ return NULL;
+}
+
+
+/* find the first pair with a given state */
+struct ice_candpair *trice_candpair_find_state(const struct list *lst,
+ enum ice_candpair_state state)
+{
+ struct le *le;
+
+ for (le = list_head(lst); le; le = le->next) {
+
+ struct ice_candpair *cp = le->data;
+
+ if (cp->state != state)
+ continue;
+
+ return cp;
+ }
+
+ return NULL;
+}
+
+
+bool trice_candpair_cmp_fnd(const struct ice_candpair *cp1,
+ const struct ice_candpair *cp2)
+{
+ if (!cp1 || !cp2)
+ return false;
+
+ return 0 == strcmp(cp1->lcand->attr.foundation,
+ cp2->lcand->attr.foundation) &&
+ 0 == strcmp(cp1->rcand->attr.foundation,
+ cp2->rcand->attr.foundation);
+}
+
+
+/* RFC 6544 -- 6.2. Forming the Check Lists
+
+ Local Remote
+ Candidate Candidate
+ ---------------------------
+ tcp-so tcp-so
+ tcp-active tcp-passive
+ tcp-passive tcp-active
+
+ */
+static bool tcptype_match(enum ice_tcptype loc, enum ice_tcptype rem)
+{
+ if (loc == ICE_TCP_SO && rem == ICE_TCP_SO) return true;
+ if (loc == ICE_TCP_ACTIVE && rem == ICE_TCP_PASSIVE) return true;
+ if (loc == ICE_TCP_PASSIVE && rem == ICE_TCP_ACTIVE) return true;
+
+ return false;
+}
+
+
+/* Replace server reflexive candidates by its base */
+static const struct sa *cand_srflx_addr(const struct ice_lcand *cand)
+{
+ if (ICE_CAND_TYPE_SRFLX == cand->attr.type)
+ return &cand->base_addr;
+ else
+ return &cand->attr.addr;
+}
+
+
+static struct ice_candpair *find_same_base_list(const struct list *lst,
+ const struct ice_lcand *lcand,
+ const struct ice_rcand *rcand)
+{
+ struct le *le;
+
+ for (le = list_head(lst); le; le = le->next) {
+
+ struct ice_candpair *cp = le->data;
+
+ if (cp->lcand->attr.compid == lcand->attr.compid
+ &&
+ cp->lcand->attr.proto == lcand->attr.proto
+ &&
+ sa_cmp(cand_srflx_addr(cp->lcand),
+ cand_srflx_addr(lcand), SA_ALL)
+ &&
+ sa_cmp(&cp->rcand->attr.addr,
+ &rcand->attr.addr, SA_ALL)) {
+
+ return cp;
+ }
+ }
+
+ return NULL;
+}
+
+
+/* look in both check-list and valid-list */
+static struct ice_candpair *find_same_base(struct trice *icem,
+ const struct ice_lcand *lcand,
+ const struct ice_rcand *rcand)
+{
+ struct ice_candpair *cp;
+
+ cp = find_same_base_list(&icem->checkl, lcand, rcand);
+ if (cp)
+ return cp;
+
+ cp = find_same_base_list(&icem->validl, lcand, rcand);
+ if (cp)
+ return cp;
+
+ return NULL;
+}
+
+
+/* Pair a local candidate with a remote candidate */
+static int create_pair(struct trice *icem, struct ice_lcand *lcand,
+ struct ice_rcand *rcand)
+{
+ struct ice_candpair *cpx;
+
+ if (lcand->attr.compid != rcand->attr.compid ||
+ lcand->attr.proto != rcand->attr.proto ||
+ sa_af(&lcand->attr.addr) != sa_af(&rcand->attr.addr)) {
+ return 0;
+ }
+
+ /*
+ * IPv6 link-local: only pair with IPv6 link-local addresses
+ * see: RFC5245bis, section 6.1.2.2
+ */
+ if (sa_af(&lcand->attr.addr) == AF_INET6 &&
+ sa_is_linklocal(&lcand->attr.addr) !=
+ sa_is_linklocal(&rcand->attr.addr)) {
+ return 0;
+ }
+
+ /* loopback pairing optimization: only pair with loopback addresses */
+ if (icem->conf.optimize_loopback_pairing &&
+ sa_is_loopback(&lcand->attr.addr) !=
+ sa_is_loopback(&rcand->attr.addr)) {
+ return 0;
+ }
+
+ cpx = find_same_base(icem, lcand, rcand);
+ if (cpx) {
+ trice_printf(icem,
+ "with: pair with same"
+ " base already exist"
+ " (%H)\n",
+ trice_candpair_debug, cpx);
+
+ return 0;
+ }
+
+ if (lcand->attr.proto == IPPROTO_TCP) {
+ if (!tcptype_match(lcand->attr.tcptype,
+ rcand->attr.tcptype))
+ return 0;
+ }
+
+ /* add sorted */
+ return trice_candpair_alloc(NULL, icem, lcand, rcand);
+}
+
+
+/* Pair a candidate with all other candidates of the opposite kind */
+int trice_candpair_with_local(struct trice *icem, struct ice_lcand *lcand)
+{
+ struct list *lst = &icem->rcandl;
+ struct le *le;
+ int err = 0;
+
+ if (icem->lrole == ICE_ROLE_UNKNOWN) {
+ DEBUG_WARNING("trice_candpair_with_local: invalid local role!"
+ "\n");
+ return EINVAL;
+ }
+
+ for (le = list_head(lst); le; le = le->next) {
+
+ struct ice_rcand *rcand = le->data;
+
+ err = create_pair(icem, lcand, rcand);
+ if (err)
+ goto out;
+ }
+
+ out:
+ return err;
+}
+
+
+/* Pair a candidate with all other candidates of the opposite kind */
+int trice_candpair_with_remote(struct trice *icem, struct ice_rcand *rcand)
+{
+ struct list *lst = &icem->lcandl;
+ struct le *le;
+ int err = 0;
+
+ if (icem->lrole == ICE_ROLE_UNKNOWN) {
+ DEBUG_WARNING("trice_candpair_with_remote: invalid local role!"
+ "\n");
+ return EINVAL;
+ }
+
+ for (le = list_head(lst); le; le = le->next) {
+
+ struct ice_lcand *lcand = le->data;
+
+ err = create_pair(icem, lcand, rcand);
+ if (err)
+ goto out;
+ }
+
+ out:
+ return err;
+}
+
+
+int trice_candpair_debug(struct re_printf *pf, const struct ice_candpair *cp)
+{
+ int err;
+
+ if (!cp)
+ return 0;
+
+ err = re_hprintf(pf, "{comp=%u} %10s {%c%c%c%c} %28H <---> %28H",
+ cp->lcand->attr.compid,
+ trice_candpair_state2name(cp->state),
+ cp->valid ? 'V' : ' ',
+ cp->nominated ? 'N' : ' ',
+ cp->estab ? 'E' : ' ',
+ cp->trigged ? 'T' : ' ',
+ trice_cand_print, cp->lcand,
+ trice_cand_print, cp->rcand);
+
+ if (cp->err)
+ err |= re_hprintf(pf, " (%m)", cp->err);
+
+ if (cp->scode)
+ err |= re_hprintf(pf, " [%u]", cp->scode);
+
+ return err;
+}
+
+
+int trice_candpairs_debug(struct re_printf *pf, bool ansi_output,
+ const struct list *list)
+{
+ struct le *le;
+ int err;
+
+ if (!list)
+ return 0;
+
+ err = re_hprintf(pf, " (%u)\n", list_count(list));
+
+ for (le = list->head; le && !err; le = le->next) {
+
+ const struct ice_candpair *cp = le->data;
+ bool ansi = false;
+
+ if (ansi_output) {
+ if (cp->state == ICE_CANDPAIR_SUCCEEDED) {
+ err |= re_hprintf(pf, "\x1b[32m");
+ ansi = true;
+ }
+ else if (cp->err || cp->scode) {
+ err |= re_hprintf(pf, "\x1b[31m");
+ ansi = true;
+ }
+ }
+
+ err |= re_hprintf(pf, " %H\n",
+ trice_candpair_debug, cp);
+
+ if (ansi)
+ err |= re_hprintf(pf, "\x1b[;m");
+ }
+
+ return err;
+}
+
+
+const char *trice_candpair_state2name(enum ice_candpair_state st)
+{
+ switch (st) {
+
+ case ICE_CANDPAIR_FROZEN: return "Frozen";
+ case ICE_CANDPAIR_WAITING: return "Waiting";
+ case ICE_CANDPAIR_INPROGRESS: return "InProgress";
+ case ICE_CANDPAIR_SUCCEEDED: return "Succeeded";
+ case ICE_CANDPAIR_FAILED: return "Failed";
+ default: return "???";
+ }
+}