Ejemplo n.º 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
}
Ejemplo n.º 2
0
static void stunc_resp_handler(int err, uint16_t scode, const char *reason,
			       const struct stun_msg *msg, void *arg)
{
	struct ice_candpair *cp = arg;
	struct icem *icem = cp->icem;
	struct stun_attr *attr;

	(void)reason;

#if ICE_TRACE
	icecomp_printf(cp->comp, "Rx %H <--- %H '%u %s'%H\n",
		       icem_cand_print, cp->lcand,
		       icem_cand_print, cp->rcand,
		       scode, reason, print_err, &err);
#endif

	if (err) {
		icem_candpair_failed(cp, err, scode);
		goto out;
	}

	switch (scode) {

	case 0: /* Success case */
		attr = stun_msg_attr(msg, STUN_ATTR_XOR_MAPPED_ADDR);
		if (!attr) {
			DEBUG_WARNING("no XOR-MAPPED-ADDR in response\n");
			icem_candpair_failed(cp, EBADMSG, 0);
			break;
		}

		handle_success(icem, cp, &attr->v.sa);
		break;

	case 487: /* Role Conflict */
		ice_switch_local_role(icem);
		(void)icem_conncheck_send(cp, false, true);
		break;

	default:
		DEBUG_WARNING("{%s.%u} STUN Response: %u %s\n",
			      icem->name, cp->comp->id, scode, reason);
		icem_candpair_failed(cp, err, scode);
		break;
	}

 out:
	pace_next(icem);
}
Ejemplo n.º 3
0
void icem_candpair_set_state(struct candpair *cp, enum candpair_state state)
{
	if (!cp)
		return;

	if (cp->state != state) {
		icecomp_printf(cp->comp,
			       "%5s <---> %5s  FSM:  %10s ===> %-10s\n",
			       ice_cand_type2name(cp->lcand->type),
			       ice_cand_type2name(cp->rcand->type),
			       ice_candpair_state2name(cp->state),
			       ice_candpair_state2name(state));
		cp->state = state;
	}
}
Ejemplo n.º 4
0
Archivo: comp.c Proyecto: soramimi/qSIP
void icem_comp_set_default_rcand(struct icem_comp *comp, struct cand *rcand)
{
	if (!comp)
		return;

	icecomp_printf(comp, "Set default remote candidate: %s:%J\n",
		       ice_cand_type2name(rcand->type), &rcand->addr);

	mem_deref(comp->def_rcand);
	comp->def_rcand = mem_ref(rcand);

	if (comp->turnc) {
		DEBUG_NOTICE("{%s.%u} Default: Add TURN Channel to peer %J\n",
			     comp->icem->name, comp->id, &rcand->addr);

		(void)turnc_add_chan(comp->turnc, &rcand->addr, NULL, NULL);
	}
}
Ejemplo n.º 5
0
Archivo: cand.c Proyecto: Issic47/libre
int icem_rcand_add_prflx(struct cand **rcp, struct icem *icem, uint8_t compid,
			 uint32_t prio, const struct sa *addr)
{
	struct 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   = 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;
}
Ejemplo n.º 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;
}
Ejemplo n.º 7
0
static void triggered_check(struct icem *icem, struct cand *lcand,
			    struct cand *rcand)
{
	struct candpair *cp = NULL;
	int err;

	if (lcand && rcand)
		cp = icem_candpair_find(&icem->checkl, lcand, rcand);

	if (cp) {
		icecomp_printf(cp->comp,
			       "triggered_check: found CandidatePair on"
			       " checklist in state: %H\n",
			       icem_candpair_debug, cp);

		switch (cp->state) {

#if 0
			/* TODO: I am not sure why we should cancel the
			 *       pending Connectivity check here. this
			 *       can lead to a deadlock situation where
			 *       both agents are stuck on sending
			 *       triggered checks on the same candidate pair
			 */
		case CANDPAIR_INPROGRESS:
			icem_candpair_cancel(cp);
			/*@fallthrough@*/
#endif

		case CANDPAIR_FAILED:
			icem_candpair_set_state(cp, CANDPAIR_WAITING);
			/*@fallthrough@*/

		case CANDPAIR_FROZEN:
		case CANDPAIR_WAITING:
			err = icem_conncheck_send(cp, false, true);
			if (err) {
				DEBUG_WARNING("triggered check failed\n");
			}
			break;

		case CANDPAIR_SUCCEEDED:
		default:
			break;
		}
	}
	else {

#if 0
		err = icem_candpair_alloc(&cp, icem, lcand, rcand);
		if (err) {
			DEBUG_WARNING("failed to allocate candpair:"
				      " lcand=%p rcand=%p (%m)\n",
				      lcand, rcand, err);
			return;
		}

		icem_candpair_prio_order(&icem->checkl);

		icem_candpair_set_state(cp, CANDPAIR_WAITING);

		(void)icem_conncheck_send(cp, false, true);
#endif

	}
}
Ejemplo n.º 8
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;
	}
}
Ejemplo n.º 9
0
int icem_conncheck_send(struct ice_candpair *cp, bool use_cand, bool trigged)
{
	struct ice_cand *lcand = cp->lcand;
	struct icem *icem = cp->icem;
	char username_buf[64];
	size_t presz = 0;
	uint32_t prio_prflx;
	uint16_t ctrl_attr;
	int err = 0;

	icem_candpair_set_state(cp, ICE_CANDPAIR_INPROGRESS);

	(void)re_snprintf(username_buf, sizeof(username_buf),
			  "%s:%s", icem->rufrag, icem->lufrag);

	/* PRIORITY and USE-CANDIDATE */
	prio_prflx = ice_cand_calc_prio(ICE_CAND_TYPE_PRFLX, 0, lcand->compid);

	switch (icem->lrole) {

	case ICE_ROLE_CONTROLLING:
		ctrl_attr = STUN_ATTR_CONTROLLING;

		if (icem->conf.nom == ICE_NOMINATION_AGGRESSIVE)
			use_cand = true;
		break;

	case ICE_ROLE_CONTROLLED:
		ctrl_attr = STUN_ATTR_CONTROLLED;
		break;

	default:
		return EINVAL;
	}

#if ICE_TRACE
	icecomp_printf(cp->comp, "Tx %H ---> %H (%s) %s %s\n",
		       icem_cand_print, cp->lcand, icem_cand_print, cp->rcand,
		       ice_candpair_state2name(cp->state),
		       use_cand ? "[USE]" : "",
		       trigged ? "[Trigged]" : "");
#else
	(void)trigged;
#endif

	/* A connectivity check MUST utilize the STUN short term credential
	   mechanism. */

	/* The password is equal to the password provided by the peer */
	if (!icem->rpwd) {
		DEBUG_WARNING("no remote password!\n");
	}

	if (cp->ct_conn) {
		DEBUG_WARNING("send_req: CONNCHECK already Pending!\n");
		return EBUSY;
	}

	switch (lcand->type) {

	case ICE_CAND_TYPE_RELAY:
		/* Creating Permissions for Relayed Candidates */
		err = turnc_add_chan(cp->comp->turnc, &cp->rcand->addr,
				     NULL, NULL);
		if (err) {
			DEBUG_WARNING("add channel: %m\n", err);
			break;
		}
		presz = 4;
		/*@fallthrough@*/

	case ICE_CAND_TYPE_HOST:
	case ICE_CAND_TYPE_SRFLX:
	case ICE_CAND_TYPE_PRFLX:
		cp->ct_conn = mem_deref(cp->ct_conn);
		err = stun_request(&cp->ct_conn, icem->stun, icem->proto,
				   cp->comp->sock, &cp->rcand->addr, presz,
				   STUN_METHOD_BINDING,
				   (uint8_t *)icem->rpwd, str_len(icem->rpwd),
				   true, stunc_resp_handler, cp,
				   4,
				   STUN_ATTR_USERNAME, username_buf,
				   STUN_ATTR_PRIORITY, &prio_prflx,
				   ctrl_attr, &icem->tiebrk,
				   STUN_ATTR_USE_CAND,
				   use_cand ? &use_cand : 0);
		break;

	default:
		DEBUG_WARNING("unknown candidate type %d\n", lcand->type);
		err = EINVAL;
		break;
	}

	return err;
}