Пример #1
0
static void handle_success(struct icem *icem, struct ice_candpair *cp,
			   const struct sa *laddr)
{
	if (!icem_cand_find(&icem->lcandl, cp->lcand->compid, laddr)) {

		int err;

		icecomp_printf(cp->comp, "adding local PRFLX Candidate: %J\n",
			       laddr);

		err = icem_lcand_add(icem, cp->lcand,
				     ICE_CAND_TYPE_PRFLX, laddr);
		if (err) {
			DEBUG_WARNING("failed to add PRFLX: %m\n", err);
		}
	}

	cp = construct_valid_pair(icem, cp, laddr, &cp->rcand->addr);
	if (!cp) {
		DEBUG_WARNING("{%s} no valid candidate pair for %J\n",
			      icem->name, laddr);
		return;
	}

	icem_candpair_make_valid(cp);
	icem_comp_set_selected(cp->comp, cp);

	cp->nominated = true;

#if 0
	/* stop conncheck now -- conclude */
	icem_conncheck_stop(icem, 0);
#endif
}
Пример #2
0
static void stun_resp_handler(int err, uint16_t scode, const char *reason,
			      const struct stun_msg *msg, void *arg)
{
	struct icem_comp *comp = arg;
	struct icem *icem = comp->icem;
	struct stun_attr *attr;
	struct cand *lcand;

	--icem->nstun;

	if (err || scode > 0) {
		DEBUG_WARNING("{%s.%u} STUN Request failed: %m\n",
			      icem->name, comp->id, err);
		goto out;
	}

	lcand = icem_cand_find(&icem->lcandl, comp->id, NULL);
	if (!lcand)
		goto out;

	attr = stun_msg_attr(msg, STUN_ATTR_XOR_MAPPED_ADDR);
	if (!attr)
		attr = stun_msg_attr(msg, STUN_ATTR_MAPPED_ADDR);
	if (!attr) {
		DEBUG_WARNING("no Mapped Address in Response\n");
		err = EPROTO;
		goto out;
	}

	err = icem_lcand_add(icem, lcand->base, CAND_TYPE_SRFLX, &attr->v.sa);

 out:
	call_gather_handler(err, icem, scode, reason);
}
Пример #3
0
/*
 * 7.2.2.  Additional Procedures for Lite Implementations
 */
static int handle_stun_lite(struct icem *icem,
                            struct icem_comp *comp, const struct sa *src,
                            bool use_cand)
{
    struct cand *lcand, *rcand;
    struct candpair *cp;
    int err;

    if (!use_cand)
        return 0;

    rcand = icem_cand_find(&icem->rcandl, comp->id, src);
    if (!rcand) {
        DEBUG_WARNING("lite: could not find remote candidate\n");
        return 0;
    }

    /* find the local host candidate with the same component */
    lcand = icem_cand_find(&icem->lcandl, comp->id, NULL);
    if (!lcand) {
        DEBUG_WARNING("lite: could not find local candidate\n");
        return 0;
    }

    /* search validlist for existing candpair's */
    if (icem_candpair_find(&icem->validl, lcand, rcand))
        return 0;

    err = icem_candpair_alloc(&cp, icem, lcand, rcand);
    if (err) {
        DEBUG_WARNING("lite: failed to created candidate pair\n");
        return err;
    }

    icem_candpair_make_valid(cp);
    cp->nominated = true;

    return 0;
}
Пример #4
0
static void turnc_handler(int err, uint16_t scode, const char *reason,
			  const struct sa *relay, const struct sa *mapped,
			  const struct stun_msg *msg, void *arg)
{
	struct icem_comp *comp = arg;
	struct icem *icem = comp->icem;
	struct cand *lcand;
	(void)msg;

	--icem->nstun;

	/* TURN failed, so we destroy the client */
	if (err || scode) {
		comp->turnc = mem_deref(comp->turnc);
	}

	if (err) {
		DEBUG_WARNING("{%s.%u} TURN Client error: %m\n",
			      icem->name, comp->id, err);
		goto out;
	}

	if (scode) {
		DEBUG_WARNING("{%s.%u} TURN Client error: %u %s\n",
			      icem->name, comp->id, scode, reason);
		err = send_binding_request(icem, comp);
		if (err)
			goto out;
		return;
	}

	lcand = icem_cand_find(&icem->lcandl, comp->id, NULL);
	if (!lcand)
		goto out;

	if (!sa_cmp(relay, &lcand->base->addr, SA_ALL)) {
		err = icem_lcand_add(icem, lcand->base,
				     CAND_TYPE_RELAY, relay);
	}

	if (mapped) {
		err |= icem_lcand_add(icem, lcand->base,
				      CAND_TYPE_SRFLX, mapped);
	}
	else {
		err |= send_binding_request(icem, comp);
	}

 out:
	call_gather_handler(err, icem, scode, reason);
}
Пример #5
0
/**
 * Verifying ICE Support and set default remote candidate
 *
 * @param icem   ICE Media
 * @param compid Component ID
 * @param raddr  Address of default remote candidate
 *
 * @return True if ICE is supported, otherwise false
 */
bool icem_verify_support(struct icem *icem, unsigned compid,
			 const struct sa *raddr)
{
	struct ice_cand *rcand;
	bool match;

	if (!icem)
		return false;

	rcand = icem_cand_find(&icem->rcandl, compid, raddr);
	match = rcand != NULL;

	if (!match)
		icem->mismatch = true;

	if (rcand) {
		icem_comp_set_default_rcand(icem_comp_find(icem, compid),
					    rcand);
	}

	return match;
}
Пример #6
0
static int handle_stun(struct ice *ice, struct icem *icem,
		       struct icem_comp *comp, const struct sa *src,
		       uint32_t prio, bool use_cand, bool tunnel)
{
	struct cand *lcand = NULL, *rcand;
	struct candpair *cp = NULL;
	int err;

	rcand = icem_cand_find(&icem->rcandl, comp->id, src);
	if (!rcand) {
		err = icem_rcand_add_prflx(&rcand, icem, comp->id, prio, src);
		if (err)
			return err;
	}

	cp = icem_candpair_find_rcand(icem, rcand);
	if (cp)
		lcand = cp->lcand;
	else
		lcand = icem_lcand_find_checklist(icem, comp->id);

	if (!lcand) {
		DEBUG_WARNING("{%s.%u} no local candidate"
			      " (checklist=%u) (src=%J)\n",
			      icem->name, comp->id,
			      list_count(&icem->checkl), src);
		return 0;
	}

	if (ICE_MODE_FULL == ice->lmode)
		triggered_check(icem, lcand, rcand);

	if (!cp) {
		cp = icem_candpair_find_rcand(icem, rcand);
		if (!cp) {
			DEBUG_WARNING("{%s.%u} candidate pair not found:"
				      " source=%J\n",
				      icem->name, comp->id, src);
			return 0;
		}
	}

#if ICE_TRACE
	icecomp_printf(comp, "Rx Binding Request from %J via %s"
		       " (candpair=%s) %s\n",
		       src, tunnel ? "Tunnel" : "Socket",
		       cp ? ice_candpair_state2name(cp->state) : "n/a",
		       use_cand ? "[USE]" : "");
#else
	(void)tunnel;
#endif

	/* 7.2.1.5.  Updating the Nominated Flag */
	if (use_cand) {
		if (ice->lrole == ROLE_CONTROLLED) {
			if (cp->state == CANDPAIR_SUCCEEDED) {
				cp->nominated = true;

				icecomp_printf(comp, "setting NOMINATED"
					       " flag on candpair [%H]\n",
					       icem_candpair_debug, cp);
			}
		}

		/* Cancel conncheck. Choose Selected Pair */
		icem_candpair_make_valid(cp);

		if (ice->conf.nom == ICE_NOMINATION_REGULAR) {
			icem_candpair_cancel(cp);
			icem_comp_set_selected(comp, cp);
		}
	}

	return 0;
}
Пример #7
0
/**
 * Constructing a Valid Pair
 *
 * @return The valid pair
 */
static struct ice_candpair *construct_valid_pair(struct icem *icem,
					     struct ice_candpair *cp,
					     const struct sa *mapped,
					     const struct sa *dest)
{
	struct ice_cand *lcand, *rcand;
	struct ice_candpair *cp2;
	int err;

	lcand = icem_cand_find(&icem->lcandl, cp->lcand->compid, mapped);
	rcand = icem_cand_find(&icem->rcandl, cp->rcand->compid, dest);

	if (!lcand) {
		DEBUG_WARNING("no such local candidate: %J\n", mapped);
		return NULL;
	}
	if (!rcand) {
		DEBUG_WARNING("no such remote candidate: %J\n", dest);
		return NULL;
	}

	/* New candidate? -- implicit success */
	if (lcand != cp->lcand || rcand != cp->rcand) {

		if (lcand != cp->lcand) {
			icecomp_printf(cp->comp,
				       "New local candidate for mapped %J\n",
				       mapped);
		}
		if (rcand != cp->rcand) {
			icecomp_printf(cp->comp,
				       "New remote candidate for dest %J\n",
				       dest);
		}

		/* The original candidate pair is set to 'Failed' because
		 * the implicitly discovered pair is 'better'.
		 * This happens for UAs behind NAT where the original
		 * pair is of type 'host' and the implicit pair is 'srflx'
		 */

		icem_candpair_make_valid(cp);

		cp2 = icem_candpair_find(&icem->validl, lcand, rcand);
		if (cp2)
			return cp2;

		err = icem_candpair_clone(&cp2, cp, lcand, rcand);
		if (err)
			return NULL;

		icem_candpair_make_valid(cp2);
		/*icem_candpair_failed(cp, EINTR, 0);*/

		return cp2;
	}
	else {
		/* Add to VALID LIST, the pair that generated the check */
		icem_candpair_make_valid(cp);

		return cp;
	}
}
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);
}