Exemplo n.º 1
0
/* agent must be locked */
static struct ice_candidate_pair *__learned_candidate(struct ice_agent *ag, struct packet_stream *ps,
		struct sockaddr_in6 *src, struct interface_address *ifa, unsigned long priority)
{
	struct ice_candidate *cand, *old_cand;
	struct ice_candidate_pair *pair;
	struct call *call = ag->call;

	cand = g_slice_alloc0(sizeof(*cand));
	cand->component_id = ps->component;
	cand->transport = ITP_UDP;
	cand->priority = priority;
	cand->endpoint.ip46 = src->sin6_addr;
	cand->endpoint.port = ntohs(src->sin6_port);
	cand->type = ICT_PRFLX;
	__cand_ice_foundation(call, cand);

	old_cand = __foundation_lookup(ag, &cand->foundation, ps->component);
	if (old_cand && old_cand->priority > priority) {
		/* this is possible if two distinct requests are received from the same NAT IP
		 * address, but from different ports. we cannot distinguish such candidates and
		 * will drop the one with the lower priority */
		g_slice_free1(sizeof(*cand), cand);
		pair = __pair_lookup(ag, old_cand, ifa);
		if (pair)
			goto out; /* nothing to do */
		cand = old_cand;
		goto pair;
	}

	g_queue_push_tail(&ag->remote_candidates, cand);
	g_hash_table_insert(ag->candidate_hash, cand, cand);
	g_hash_table_insert(ag->foundation_hash, cand, cand);

pair:
	pair = __pair_candidate(ifa, ag, cand, ps);
	PAIR_SET(pair, LEARNED);
	__all_pairs_list(ag);

out:
	return pair;
}
Exemplo n.º 2
0
/* agent must be locked */
static struct ice_candidate_pair *__learned_candidate(struct ice_agent *ag, struct stream_fd *sfd,
		const endpoint_t *src, unsigned long priority)
{
	struct ice_candidate *cand, *old_cand;
	struct ice_candidate_pair *pair;
	struct call *call = ag->call;
	struct packet_stream *ps = sfd->stream;

	cand = g_slice_alloc0(sizeof(*cand));
	cand->component_id = ps->component;
	cand->transport = sfd->local_intf->spec->local_address.type; // XXX add socket type into socket_t?
	cand->priority = priority;
	cand->endpoint = *src;
	cand->type = ICT_PRFLX;
	__cand_ice_foundation(call, cand);

	old_cand = __foundation_lookup(ag, &cand->foundation, ps->component);
	if (old_cand && old_cand->priority > priority) {
		/* this is possible if two distinct requests are received from the same NAT IP
		 * address, but from different ports. we cannot distinguish such candidates and
		 * will drop the one with the lower priority */
		g_slice_free1(sizeof(*cand), cand);
		pair = __pair_lookup(ag, old_cand, sfd->local_intf);
		if (pair)
			goto out; /* nothing to do */
		cand = old_cand;
		goto pair;
	}

	g_queue_push_tail(&ag->remote_candidates, cand);
	g_hash_table_insert(ag->candidate_hash, cand, cand);
	g_hash_table_insert(ag->foundation_hash, cand, cand);

pair:
	pair = __pair_candidate(sfd, ag, cand);
	PAIR_SET(pair, LEARNED);
	__all_pairs_list(ag);

out:
	return pair;
}
Exemplo n.º 3
0
/* initializes "out" */
static void __get_complete_components(GQueue *out, struct ice_agent *ag, GTree *t, unsigned int flag) {
	GQueue compo1 = G_QUEUE_INIT;
	GList *l;
	struct ice_candidate_pair *pair1, *pairX;
	struct ice_candidate *cand;
	unsigned int i;

	__get_pairs_by_component(&compo1, t, 1);

	g_queue_init(out);

	for (l = compo1.head; l; l = l->next) {
		pair1 = l->data;

		g_queue_clear(out);
		g_queue_push_tail(out, pair1);

		for (i = 2; i <= ag->active_components; i++) {
			cand = __foundation_lookup(ag, &pair1->remote_candidate->foundation, i);
			if (!cand)
				goto next_foundation;
			pairX = __pair_lookup(ag, cand, pair1->local_address);
			if (!pairX)
				goto next_foundation;
			if (!bf_isset(&pairX->pair_flags, flag))
				goto next_foundation;
			g_queue_push_tail(out, pairX);
		}
		goto found;

next_foundation:
		;
	}

	/* nothing found */
	g_queue_clear(out);

found:
	g_queue_clear(&compo1);
}
Exemplo n.º 4
0
/* call is locked in R */
int ice_response(struct packet_stream *ps, struct sockaddr_in6 *src, struct in6_addr *dst,
		struct stun_attrs *attrs, u_int32_t transaction[3])
{
	struct ice_candidate_pair *pair, *opair;
	struct ice_agent *ag;
	struct call_media *media = ps->media;
	const char *err;
	unsigned int component;
	struct ice_candidate *cand;
	struct interface_address *ifa;
	int ret, was_ctl;

	__DBG("received ICE response from %s on %s", smart_ntop_port_buf(src), smart_ntop_buf(dst));

	ag = media->ice_agent;
	if (!ag)
		return -1;

	atomic64_set(&ag->last_activity, poller_now);

	mutex_lock(&ag->lock);

	pair = g_hash_table_lookup(ag->transaction_hash, transaction);
	err = "ICE/STUN response with unknown transaction received";
	if (!pair)
		goto err_unlock;
	was_ctl = pair->was_controlling;

	mutex_unlock(&ag->lock);

	ifa = pair->local_address;

	ilog(LOG_DEBUG, "Received ICE/STUN response code %u for candidate pair "PAIR_FORMAT" from %s to %s",
			attrs->error_code, PAIR_FMT(pair),
			smart_ntop_ep_buf(&pair->remote_candidate->endpoint),
			smart_ntop_buf(&ifa->addr));

	/* verify endpoints */
	err = "ICE/STUN response received, but source address didn't match remote candidate address";
	if (memcmp(&src->sin6_addr, &pair->remote_candidate->endpoint.ip46, sizeof(src->sin6_addr)))
		goto err;
	if (ntohs(src->sin6_port) != pair->remote_candidate->endpoint.port)
		goto err;

	err = "ICE/STUN response received, but destination address didn't match local interface address";
	if (memcmp(dst, &ifa->addr, sizeof(*dst)))
		goto err;
	if (pair->packet_stream != ps)
		goto err;

	PAIR_CLEAR(pair, IN_PROGRESS);
	ret = 0;

	/* handle all errors */
	if (attrs->error_code) {
		err = "ICE/STUN error received";
		if (attrs->error_code != 487)
			goto err;
		__role_change(ag, !was_ctl);
		__trigger_check(pair);
		goto out;
	}

	/* we don't discover peer reflexive here (RFC 5245 7.1.3.2.1) as we don't expect to be behind NAT */
	/* we also skip parts of 7.1.3.2.2 as we don't do server reflexive */

	mutex_lock(&ag->lock);

	/* check if we're in the final (controlling) phase */
	if (pair->was_nominated && PAIR_CLEAR(pair, TO_USE)) {
		ilog(LOG_DEBUG, "Setting nominated ICE candidate pair "PAIR_FORMAT" as valid", PAIR_FMT(pair));
		PAIR_SET(pair, VALID);
		g_tree_insert(ag->valid_pairs, pair, pair);
		ret = __check_valid(ag);
		goto out_unlock;
	}

	if (PAIR_SET(pair, SUCCEEDED))
		goto out_unlock;

	ilog(LOG_DEBUG, "Setting ICE candidate pair "PAIR_FORMAT" as succeeded", PAIR_FMT(pair));
	g_tree_insert(ag->succeeded_pairs, pair, pair);

	if (!ag->start_nominating.tv_sec) {
		if (__check_succeeded_complete(ag)) {
			ag->start_nominating = g_now;
			timeval_add_usec(&ag->start_nominating, 100000);
			__agent_schedule_abs(ag, &ag->start_nominating);
		}
	}

	/* now unfreeze all other pairs from the same foundation */
	for (component = 1; component <= MAX_COMPONENTS; component++) {
		if (component == ps->component)
			continue;
		cand = __foundation_lookup(ag, &pair->remote_candidate->foundation, component);
		if (!cand)
			continue;
		opair = __pair_lookup(ag, cand, ifa);
		if (!opair)
			continue;

		if (PAIR_ISSET(opair, FAILED))
			continue;
		if (!PAIR_CLEAR(opair, FROZEN))
			continue;

		ilog(LOG_DEBUG, "Unfreezing related ICE pair "PAIR_FORMAT, PAIR_FMT(opair));
	}

	/* if this was previously nominated by the peer, it's now valid */
	if (PAIR_ISSET(pair, NOMINATED)) {
		PAIR_SET(pair, VALID);
		g_tree_insert(ag->valid_pairs, pair, pair);

		if (!AGENT_ISSET(ag, CONTROLLING))
			ret = __check_valid(ag);
	}

out_unlock:
	mutex_unlock(&ag->lock);
out:
	return ret;

err_unlock:
	mutex_unlock(&ag->lock);
err:
	if (err)
		ilog(LOG_NOTICE, "%s (from %s on interface %s)",
				err, smart_ntop_port_buf(src), smart_ntop_buf(dst));

	if (pair && attrs->error_code)
		__fail_pair(pair);

	return 0;
}