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/icesdp.c b/src/ice/icesdp.c
new file mode 100644
index 0000000..f05f935
--- /dev/null
+++ b/src/ice/icesdp.c
@@ -0,0 +1,428 @@
+/**
+ * @file icesdp.c SDP Attributes for ICE
+ *
+ * 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_net.h>
+#include <re_stun.h>
+#include <re_ice.h>
+#include "ice.h"
+
+
+#define DEBUG_MODULE "icesdp"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+const char ice_attr_cand[] = "candidate";
+const char ice_attr_remote_cand[] = "remote-candidates";
+const char ice_attr_lite[] = "ice-lite";
+const char ice_attr_ufrag[] = "ice-ufrag";
+const char ice_attr_pwd[] = "ice-pwd";
+const char ice_attr_mismatch[] = "ice-mismatch";
+
+
+static const char rel_addr_str[] = "raddr";
+static const char rel_port_str[] = "rport";
+
+
+/* Encode SDP Attributes */
+
+
+static const char *transp_name(enum ice_transp transp)
+{
+ switch (transp) {
+
+ case ICE_TRANSP_UDP: return "UDP";
+ default: return "???";
+ }
+}
+
+
+static enum ice_transp transp_resolve(const struct pl *transp)
+{
+ if (!pl_strcasecmp(transp, "UDP"))
+ return ICE_TRANSP_UDP;
+
+ return ICE_TRANSP_NONE;
+}
+
+
+/**
+ * Encode SDP candidate attribute
+ *
+ * @param pf Print function
+ * @param cand Candidate to encode
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int ice_cand_encode(struct re_printf *pf, const struct ice_cand *cand)
+{
+ int err;
+
+ err = re_hprintf(pf, "%s %u %s %u %j %u typ %s",
+ cand->foundation, cand->compid,
+ transp_name(cand->transp), cand->prio,
+ &cand->addr, sa_port(&cand->addr),
+ ice_cand_type2name(cand->type));
+
+ if (sa_isset(&cand->rel, SA_ADDR))
+ err |= re_hprintf(pf, " raddr %j", &cand->rel);
+
+ if (sa_isset(&cand->rel, SA_PORT))
+ err |= re_hprintf(pf, " rport %u", sa_port(&cand->rel));
+
+ return err;
+}
+
+
+/**
+ * Check if remote candidates are available
+ *
+ * @param icem ICE Media object
+ *
+ * @return True if available, otherwise false
+ */
+bool ice_remotecands_avail(const struct icem *icem)
+{
+ if (!icem)
+ return false;
+
+ return icem->lrole == ICE_ROLE_CONTROLLING &&
+ icem->state == ICE_CHECKLIST_COMPLETED;
+}
+
+
+/**
+ * Encode the SDP "remote-candidates" Attribute
+ *
+ * @param pf Print function
+ * @param icem ICE Media object
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int ice_remotecands_encode(struct re_printf *pf, const struct icem *icem)
+{
+ struct le *le;
+ int err = 0;
+
+ if (!icem)
+ return EINVAL;
+
+ for (le = icem->rcandl.head; le && !err; le = le->next) {
+
+ const struct ice_cand *rcand = le->data;
+
+ err = re_hprintf(pf, "%s%d %j %u",
+ icem->rcandl.head==le ? "" : " ",
+ rcand->compid,
+ &rcand->addr, sa_port(&rcand->addr));
+ }
+
+ return err;
+}
+
+
+/* Decode SDP Attributes */
+
+
+static int ufrag_decode(struct icem *icem, const char *value)
+{
+ char *ufrag = NULL;
+ int err;
+
+ err = str_dup(&ufrag, value);
+ if (err)
+ return err;
+
+ mem_deref(icem->rufrag);
+ icem->rufrag = mem_ref(ufrag);
+
+ mem_deref(ufrag);
+
+ return 0;
+}
+
+
+static int pwd_decode(struct icem *icem, const char *value)
+{
+ char *pwd = NULL;
+ int err;
+
+ err = str_dup(&pwd, value);
+ if (err)
+ return err;
+
+ mem_deref(icem->rpwd);
+ icem->rpwd = mem_ref(pwd);
+
+ mem_deref(pwd);
+
+ return 0;
+}
+
+
+static int media_ufrag_decode(struct icem *icem, const char *value)
+{
+ icem->rufrag = mem_deref(icem->rufrag);
+
+ return str_dup(&icem->rufrag, value);
+}
+
+
+static int media_pwd_decode(struct icem *icem, const char *value)
+{
+ icem->rpwd = mem_deref(icem->rpwd);
+
+ return str_dup(&icem->rpwd, value);
+}
+
+
+static int cand_decode(struct icem *icem, const char *val)
+{
+ struct pl foundation, compid, transp, prio, addr, port, cand_type;
+ struct pl extra = pl_null;
+ struct sa caddr, rel_addr;
+ char type[8];
+ uint8_t cid;
+ int err;
+
+ sa_init(&rel_addr, AF_INET);
+
+ err = re_regex(val, strlen(val),
+ "[^ ]+ [0-9]+ [^ ]+ [0-9]+ [^ ]+ [0-9]+ typ [a-z]+[^]*",
+ &foundation, &compid, &transp, &prio,
+ &addr, &port, &cand_type, &extra);
+ if (err)
+ return err;
+
+ if (ICE_TRANSP_NONE == transp_resolve(&transp)) {
+ DEBUG_NOTICE("<%s> ignoring candidate with"
+ " unknown transport=%r (%r:%r)\n",
+ icem->name, &transp, &cand_type, &addr);
+ return 0;
+ }
+
+ if (pl_isset(&extra)) {
+
+ struct pl name, value;
+
+ /* Loop through " SP attr SP value" pairs */
+ while (!re_regex(extra.p, extra.l, " [^ ]+ [^ ]+",
+ &name, &value)) {
+
+ pl_advance(&extra, value.p + value.l - extra.p);
+
+ if (0 == pl_strcasecmp(&name, rel_addr_str)) {
+ err = sa_set(&rel_addr, &value,
+ sa_port(&rel_addr));
+ if (err)
+ break;
+ }
+ else if (0 == pl_strcasecmp(&name, rel_port_str)) {
+ sa_set_port(&rel_addr, pl_u32(&value));
+ }
+ }
+ }
+
+ err = sa_set(&caddr, &addr, pl_u32(&port));
+ if (err)
+ return err;
+
+ cid = pl_u32(&compid);
+
+ /* add only if not exist */
+ if (icem_cand_find(&icem->rcandl, cid, &caddr))
+ return 0;
+
+ (void)pl_strcpy(&cand_type, type, sizeof(type));
+
+ return icem_rcand_add(icem, ice_cand_name2type(type), cid,
+ pl_u32(&prio), &caddr, &rel_addr, &foundation);
+}
+
+
+/**
+ * Decode SDP session attributes
+ *
+ * @param icem ICE Media object
+ * @param name Name of the SDP attribute
+ * @param value Value of the SDP attribute (optional)
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int ice_sdp_decode(struct icem *icem, const char *name, const char *value)
+{
+ if (!icem)
+ return EINVAL;
+
+ if (0 == str_casecmp(name, ice_attr_lite)) {
+ if (ICE_MODE_LITE == icem->lmode) {
+ DEBUG_WARNING("we are lite, peer is also lite!\n");
+ return EPROTO;
+ }
+ icem->rmode = ICE_MODE_LITE;
+ icem->lrole = ICE_ROLE_CONTROLLING;
+ }
+ else if (0 == str_casecmp(name, ice_attr_ufrag))
+ return ufrag_decode(icem, value);
+ else if (0 == str_casecmp(name, ice_attr_pwd))
+ return pwd_decode(icem, value);
+
+ return 0;
+}
+
+
+/**
+ * Decode SDP media attributes
+ *
+ * @param icem ICE Media object
+ * @param name Name of the SDP attribute
+ * @param value Value of the SDP attribute (optional)
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int icem_sdp_decode(struct icem *icem, const char *name, const char *value)
+{
+ if (!icem)
+ return EINVAL;
+
+ if (0 == str_casecmp(name, ice_attr_cand))
+ return cand_decode(icem, value);
+ else if (0 == str_casecmp(name, ice_attr_mismatch))
+ icem->mismatch = true;
+ else if (0 == str_casecmp(name, ice_attr_ufrag))
+ return media_ufrag_decode(icem, value);
+ else if (0 == str_casecmp(name, ice_attr_pwd))
+ return media_pwd_decode(icem, value);
+
+ return 0;
+}
+
+
+static const char *ice_tcptype_name(enum ice_tcptype tcptype)
+{
+ switch (tcptype) {
+
+ case ICE_TCP_ACTIVE: return "active";
+ case ICE_TCP_PASSIVE: return "passive";
+ case ICE_TCP_SO: return "so";
+ default: return "???";
+ }
+}
+
+
+static enum ice_tcptype ice_tcptype_resolve(const struct pl *pl)
+{
+ if (0 == pl_strcasecmp(pl, "active")) return ICE_TCP_ACTIVE;
+ if (0 == pl_strcasecmp(pl, "passive")) return ICE_TCP_PASSIVE;
+ if (0 == pl_strcasecmp(pl, "so")) return ICE_TCP_SO;
+
+ return (enum ice_tcptype)-1;
+}
+
+
+int ice_cand_attr_encode(struct re_printf *pf,
+ const struct ice_cand_attr *cand)
+{
+ int err = 0;
+
+ if (!cand)
+ return 0;
+
+ err |= re_hprintf(pf, "%s %u %s %u %j %u typ %s",
+ cand->foundation, cand->compid,
+ net_proto2name(cand->proto), cand->prio,
+ &cand->addr, sa_port(&cand->addr),
+ ice_cand_type2name(cand->type));
+
+ if (sa_isset(&cand->rel_addr, SA_ADDR))
+ err |= re_hprintf(pf, " raddr %j", &cand->rel_addr);
+
+ if (sa_isset(&cand->rel_addr, SA_PORT))
+ err |= re_hprintf(pf, " rport %u", sa_port(&cand->rel_addr));
+
+ if (cand->proto == IPPROTO_TCP) {
+ err |= re_hprintf(pf, " tcptype %s",
+ ice_tcptype_name(cand->tcptype));
+ }
+
+ return err;
+}
+
+
+int ice_cand_attr_decode(struct ice_cand_attr *cand, const char *val)
+{
+ struct pl pl_fnd, pl_compid, pl_transp, pl_prio, pl_addr, pl_port;
+ struct pl pl_type, pl_raddr, pl_rport, pl_opt = PL_INIT;
+ size_t len;
+ char type[8];
+ int err;
+
+ if (!cand || !val)
+ return EINVAL;
+
+ memset(cand, 0, sizeof(*cand));
+
+ len = str_len(val);
+
+ err = re_regex(val, len,
+ "[^ ]+ [0-9]+ [a-z]+ [0-9]+ [^ ]+ [0-9]+ typ [a-z]+"
+ "[^]*",
+ &pl_fnd, &pl_compid, &pl_transp, &pl_prio,
+ &pl_addr, &pl_port, &pl_type, &pl_opt);
+ if (err)
+ return err;
+
+ (void)pl_strcpy(&pl_fnd, cand->foundation, sizeof(cand->foundation));
+
+ if (0 == pl_strcasecmp(&pl_transp, "UDP"))
+ cand->proto = IPPROTO_UDP;
+ else if (0 == pl_strcasecmp(&pl_transp, "TCP"))
+ cand->proto = IPPROTO_TCP;
+ else
+ cand->proto = 0;
+
+ err = sa_set(&cand->addr, &pl_addr, pl_u32(&pl_port));
+ if (err)
+ return err;
+
+ cand->compid = pl_u32(&pl_compid);
+ cand->prio = pl_u32(&pl_prio);
+
+ (void)pl_strcpy(&pl_type, type, sizeof(type));
+
+ cand->type = ice_cand_name2type(type);
+
+ /* optional */
+
+ if (0 == re_regex(pl_opt.p, pl_opt.l, "raddr [^ ]+ rport [0-9]+",
+ &pl_raddr, &pl_rport)) {
+
+ err = sa_set(&cand->rel_addr, &pl_raddr, pl_u32(&pl_rport));
+ if (err)
+ return err;
+ }
+
+ if (cand->proto == IPPROTO_TCP) {
+
+ struct pl tcptype;
+
+ err = re_regex(pl_opt.p, pl_opt.l, "tcptype [^ ]+",
+ &tcptype);
+ if (err)
+ return err;
+
+ cand->tcptype = ice_tcptype_resolve(&tcptype);
+ }
+
+ return 0;
+}