|
|
@ -28,7 +28,7 @@ |
|
|
|
|
|
|
|
|
#define PAIR_FORMAT STR_FORMAT":"STR_FORMAT":%lu" |
|
|
#define PAIR_FORMAT STR_FORMAT":"STR_FORMAT":%lu" |
|
|
#define PAIR_FMT(p) \ |
|
|
#define PAIR_FMT(p) \ |
|
|
STR_FMT(&(p)->local_address->ice_foundation), \ |
|
|
|
|
|
|
|
|
STR_FMT(&(p)->local_intf->spec->ice_foundation), \ |
|
|
STR_FMT(&(p)->remote_candidate->foundation), \ |
|
|
STR_FMT(&(p)->remote_candidate->foundation), \ |
|
|
(p)->remote_candidate->component_id |
|
|
(p)->remote_candidate->component_id |
|
|
|
|
|
|
|
|
@ -39,7 +39,7 @@ static void __ice_agent_free(void *p); |
|
|
static void create_random_ice_string(struct call *call, str *s, int len); |
|
|
static void create_random_ice_string(struct call *call, str *s, int len); |
|
|
static void __do_ice_checks(struct ice_agent *ag); |
|
|
static void __do_ice_checks(struct ice_agent *ag); |
|
|
static struct ice_candidate_pair *__pair_lookup(struct ice_agent *, struct ice_candidate *cand, |
|
|
static struct ice_candidate_pair *__pair_lookup(struct ice_agent *, struct ice_candidate *cand, |
|
|
struct interface_address *ifa); |
|
|
|
|
|
|
|
|
const struct local_intf *ifa); |
|
|
static void __recalc_pair_prios(struct ice_agent *ag); |
|
|
static void __recalc_pair_prios(struct ice_agent *ag); |
|
|
static void __role_change(struct ice_agent *ag, int new_controlling); |
|
|
static void __role_change(struct ice_agent *ag, int new_controlling); |
|
|
static void __get_complete_components(GQueue *out, struct ice_agent *ag, GTree *t, unsigned int); |
|
|
static void __get_complete_components(GQueue *out, struct ice_agent *ag, GTree *t, unsigned int); |
|
|
@ -88,18 +88,6 @@ enum ice_candidate_type ice_candidate_type(const str *s) { |
|
|
return ICT_UNKNOWN; |
|
|
return ICT_UNKNOWN; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
enum ice_transport ice_transport(const str *s) { |
|
|
|
|
|
if (!str_cmp(s, "udp")) |
|
|
|
|
|
return ITP_UDP; |
|
|
|
|
|
// if (!str_cmp(s, "tcp")) |
|
|
|
|
|
// return ITP_TCP; |
|
|
|
|
|
if (!str_cmp(s, "UDP")) |
|
|
|
|
|
return ITP_UDP; |
|
|
|
|
|
// if (!str_cmp(s, "TCP")) |
|
|
|
|
|
// return ITP_TCP; |
|
|
|
|
|
return ITP_UNKNOWN; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int ice_has_related(enum ice_candidate_type t) { |
|
|
int ice_has_related(enum ice_candidate_type t) { |
|
|
if (t == ICT_HOST) |
|
|
if (t == ICT_HOST) |
|
|
return 0; |
|
|
return 0; |
|
|
@ -109,12 +97,12 @@ int ice_has_related(enum ice_candidate_type t) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static u_int64_t __ice_pair_priority(struct interface_address *ifa, struct ice_candidate *cand, |
|
|
|
|
|
|
|
|
static u_int64_t __ice_pair_priority(const struct local_intf *ifa, struct ice_candidate *cand, |
|
|
int controlling) |
|
|
int controlling) |
|
|
{ |
|
|
{ |
|
|
u_int64_t g, d; |
|
|
u_int64_t g, d; |
|
|
|
|
|
|
|
|
g = ice_priority(ICT_HOST, ifa->preference, cand->component_id); |
|
|
|
|
|
|
|
|
g = ice_priority(ICT_HOST, ifa->unique_id, cand->component_id); |
|
|
d = cand->priority; |
|
|
d = cand->priority; |
|
|
|
|
|
|
|
|
if (!controlling) { |
|
|
if (!controlling) { |
|
|
@ -126,7 +114,7 @@ static u_int64_t __ice_pair_priority(struct interface_address *ifa, struct ice_c |
|
|
return (MIN(g,d) << 32) + (MAX(g,d) << 1) + (g > d ? 1 : 0); |
|
|
return (MIN(g,d) << 32) + (MAX(g,d) << 1) + (g > d ? 1 : 0); |
|
|
} |
|
|
} |
|
|
static void __do_ice_pair_priority(struct ice_candidate_pair *pair) { |
|
|
static void __do_ice_pair_priority(struct ice_candidate_pair *pair) { |
|
|
pair->pair_priority = __ice_pair_priority(pair->local_address, pair->remote_candidate, |
|
|
|
|
|
|
|
|
pair->pair_priority = __ice_pair_priority(pair->local_intf, pair->remote_candidate, |
|
|
AGENT_ISSET(pair->agent, CONTROLLING)); |
|
|
AGENT_ISSET(pair->agent, CONTROLLING)); |
|
|
} |
|
|
} |
|
|
static void __new_stun_transaction(struct ice_candidate_pair *pair) { |
|
|
static void __new_stun_transaction(struct ice_candidate_pair *pair) { |
|
|
@ -144,20 +132,20 @@ static void __all_pairs_list(struct ice_agent *ag) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* agent must be locked */ |
|
|
/* agent must be locked */ |
|
|
static struct ice_candidate_pair *__pair_candidate(struct interface_address *addr, struct ice_agent *ag, |
|
|
|
|
|
struct ice_candidate *cand, struct packet_stream *ps) |
|
|
|
|
|
|
|
|
static struct ice_candidate_pair *__pair_candidate(struct stream_fd *sfd, struct ice_agent *ag, |
|
|
|
|
|
struct ice_candidate *cand) |
|
|
{ |
|
|
{ |
|
|
struct ice_candidate_pair *pair; |
|
|
struct ice_candidate_pair *pair; |
|
|
|
|
|
|
|
|
if (addr->family != family_from_address(&cand->endpoint.ip46)) |
|
|
|
|
|
|
|
|
if (sfd->socket.family != cand->endpoint.address.family) |
|
|
return NULL; |
|
|
return NULL; |
|
|
|
|
|
|
|
|
pair = g_slice_alloc0(sizeof(*pair)); |
|
|
pair = g_slice_alloc0(sizeof(*pair)); |
|
|
|
|
|
|
|
|
pair->agent = ag; |
|
|
pair->agent = ag; |
|
|
pair->remote_candidate = cand; |
|
|
pair->remote_candidate = cand; |
|
|
pair->local_address = addr; |
|
|
|
|
|
pair->packet_stream = ps; |
|
|
|
|
|
|
|
|
pair->local_intf = sfd->local_intf; |
|
|
|
|
|
pair->sfd = sfd; |
|
|
if (cand->component_id != 1) |
|
|
if (cand->component_id != 1) |
|
|
PAIR_SET(pair, FROZEN); |
|
|
PAIR_SET(pair, FROZEN); |
|
|
__do_ice_pair_priority(pair); |
|
|
__do_ice_pair_priority(pair); |
|
|
@ -168,7 +156,8 @@ static struct ice_candidate_pair *__pair_candidate(struct interface_address *add |
|
|
g_tree_insert(ag->all_pairs, pair, pair); |
|
|
g_tree_insert(ag->all_pairs, pair, pair); |
|
|
|
|
|
|
|
|
ilog(LOG_DEBUG, "Created candidate pair "PAIR_FORMAT" between %s and %s, type %s", PAIR_FMT(pair), |
|
|
ilog(LOG_DEBUG, "Created candidate pair "PAIR_FORMAT" between %s and %s, type %s", PAIR_FMT(pair), |
|
|
smart_ntop_buf(&addr->addr), smart_ntop_ep_buf(&cand->endpoint), |
|
|
|
|
|
|
|
|
sockaddr_print_buf(&sfd->socket.local.address), |
|
|
|
|
|
endpoint_print_buf(&cand->endpoint), |
|
|
ice_candidate_type_str(cand->type)); |
|
|
ice_candidate_type_str(cand->type)); |
|
|
|
|
|
|
|
|
return pair; |
|
|
return pair; |
|
|
@ -176,22 +165,21 @@ static struct ice_candidate_pair *__pair_candidate(struct interface_address *add |
|
|
|
|
|
|
|
|
static unsigned int __pair_hash(const void *p) { |
|
|
static unsigned int __pair_hash(const void *p) { |
|
|
const struct ice_candidate_pair *pair = p; |
|
|
const struct ice_candidate_pair *pair = p; |
|
|
return g_direct_hash(pair->local_address) ^ g_direct_hash(pair->remote_candidate); |
|
|
|
|
|
|
|
|
return g_direct_hash(pair->local_intf) ^ g_direct_hash(pair->remote_candidate); |
|
|
} |
|
|
} |
|
|
static int __pair_equal(const void *a, const void *b) { |
|
|
static int __pair_equal(const void *a, const void *b) { |
|
|
const struct ice_candidate_pair *A = a, *B = b; |
|
|
const struct ice_candidate_pair *A = a, *B = b; |
|
|
return A->local_address == B->local_address |
|
|
|
|
|
|
|
|
return A->local_intf == B->local_intf |
|
|
&& A->remote_candidate == B->remote_candidate; |
|
|
&& A->remote_candidate == B->remote_candidate; |
|
|
} |
|
|
} |
|
|
static unsigned int __cand_hash(const void *p) { |
|
|
static unsigned int __cand_hash(const void *p) { |
|
|
const struct ice_candidate *cand = p; |
|
|
const struct ice_candidate *cand = p; |
|
|
return in6_addr_hash(&cand->endpoint.ip46) ^ cand->endpoint.port ^ cand->component_id; |
|
|
|
|
|
|
|
|
return endpoint_hash(&cand->endpoint) ^ cand->component_id; |
|
|
} |
|
|
} |
|
|
static int __cand_equal(const void *a, const void *b) { |
|
|
static int __cand_equal(const void *a, const void *b) { |
|
|
const struct ice_candidate *A = a, *B = b; |
|
|
const struct ice_candidate *A = a, *B = b; |
|
|
return A->endpoint.port == B->endpoint.port |
|
|
|
|
|
&& A->component_id == B->component_id |
|
|
|
|
|
&& in6_addr_eq(&A->endpoint.ip46, &B->endpoint.ip46); |
|
|
|
|
|
|
|
|
return endpoint_eq(&A->endpoint, &B->endpoint) |
|
|
|
|
|
&& A->component_id == B->component_id; |
|
|
} |
|
|
} |
|
|
static unsigned int __found_hash(const void *p) { |
|
|
static unsigned int __found_hash(const void *p) { |
|
|
const struct ice_candidate *cand = p; |
|
|
const struct ice_candidate *cand = p; |
|
|
@ -222,10 +210,10 @@ static int __pair_prio_cmp(const void *a, const void *b) { |
|
|
return -1; |
|
|
return -1; |
|
|
if (A->remote_candidate->component_id > B->remote_candidate->component_id) |
|
|
if (A->remote_candidate->component_id > B->remote_candidate->component_id) |
|
|
return 1; |
|
|
return 1; |
|
|
/* highest local preference first, which is lowest number first */ |
|
|
|
|
|
if (A->local_address->preference < B->local_address->preference) |
|
|
|
|
|
|
|
|
/* highest local preference first, which is lowest unique_id first */ |
|
|
|
|
|
if (A->local_intf->unique_id < B->local_intf->unique_id) |
|
|
return -1; |
|
|
return -1; |
|
|
if (A->local_address->preference > B->local_address->preference) |
|
|
|
|
|
|
|
|
if (A->local_intf->unique_id > B->local_intf->unique_id) |
|
|
return 1; |
|
|
return 1; |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
@ -240,7 +228,7 @@ static void __ice_agent_initialize(struct ice_agent *ag) { |
|
|
ag->foundation_hash = g_hash_table_new(__found_hash, __found_equal); |
|
|
ag->foundation_hash = g_hash_table_new(__found_hash, __found_equal); |
|
|
ag->agent_flags = 0; |
|
|
ag->agent_flags = 0; |
|
|
bf_copy(&ag->agent_flags, ICE_AGENT_CONTROLLING, &media->media_flags, MEDIA_FLAG_ICE_CONTROLLING); |
|
|
bf_copy(&ag->agent_flags, ICE_AGENT_CONTROLLING, &media->media_flags, MEDIA_FLAG_ICE_CONTROLLING); |
|
|
ag->local_interface = media->interface; |
|
|
|
|
|
|
|
|
ag->logical_intf = media->logical_intf; |
|
|
ag->desired_family = media->desired_family; |
|
|
ag->desired_family = media->desired_family; |
|
|
ag->nominated_pairs = g_tree_new(__pair_prio_cmp); |
|
|
ag->nominated_pairs = g_tree_new(__pair_prio_cmp); |
|
|
ag->valid_pairs = g_tree_new(__pair_prio_cmp); |
|
|
ag->valid_pairs = g_tree_new(__pair_prio_cmp); |
|
|
@ -320,6 +308,7 @@ void ice_update(struct ice_agent *ag, struct stream_params *sp) { |
|
|
unsigned int comps; |
|
|
unsigned int comps; |
|
|
struct packet_stream *components[MAX_COMPONENTS], *ps; |
|
|
struct packet_stream *components[MAX_COMPONENTS], *ps; |
|
|
GQueue *candidates; |
|
|
GQueue *candidates; |
|
|
|
|
|
struct stream_fd *sfd; |
|
|
|
|
|
|
|
|
if (!ag) |
|
|
if (!ag) |
|
|
return; |
|
|
return; |
|
|
@ -336,7 +325,7 @@ void ice_update(struct ice_agent *ag, struct stream_params *sp) { |
|
|
__ice_restart(ag); |
|
|
__ice_restart(ag); |
|
|
else if (ag->pwd[0].s && sp->ice_pwd.s && str_cmp_str(&ag->pwd[0], &sp->ice_pwd)) |
|
|
else if (ag->pwd[0].s && sp->ice_pwd.s && str_cmp_str(&ag->pwd[0], &sp->ice_pwd)) |
|
|
__ice_restart(ag); |
|
|
__ice_restart(ag); |
|
|
else if (ag->local_interface != media->interface) |
|
|
|
|
|
|
|
|
else if (ag->logical_intf != media->logical_intf) |
|
|
__ice_restart(ag); |
|
|
__ice_restart(ag); |
|
|
|
|
|
|
|
|
/* update remote info */ |
|
|
/* update remote info */ |
|
|
@ -424,11 +413,13 @@ void ice_update(struct ice_agent *ag, struct stream_params *sp) { |
|
|
pair: |
|
|
pair: |
|
|
if (!ps) |
|
|
if (!ps) |
|
|
continue; |
|
|
continue; |
|
|
for (k = ag->local_interface->list.head; k; k = k->next) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (k = ps->sfds.head; k; k = k->next) { |
|
|
|
|
|
sfd = k->data; |
|
|
/* skip duplicates here also */ |
|
|
/* skip duplicates here also */ |
|
|
if (__pair_lookup(ag, dup, k->data)) |
|
|
|
|
|
|
|
|
if (__pair_lookup(ag, dup, sfd->local_intf)) |
|
|
continue; |
|
|
continue; |
|
|
__pair_candidate(k->data, ag, dup, ps); |
|
|
|
|
|
|
|
|
__pair_candidate(sfd, ag, dup); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -614,8 +605,7 @@ static void __fail_pair(struct ice_candidate_pair *pair) { |
|
|
|
|
|
|
|
|
/* agent must NOT be locked, but call must be locked in R */ |
|
|
/* agent must NOT be locked, but call must be locked in R */ |
|
|
static void __do_ice_check(struct ice_candidate_pair *pair) { |
|
|
static void __do_ice_check(struct ice_candidate_pair *pair) { |
|
|
struct sockaddr_in6 dst; |
|
|
|
|
|
struct packet_stream *ps = pair->packet_stream; |
|
|
|
|
|
|
|
|
struct stream_fd *sfd = pair->sfd; |
|
|
struct ice_agent *ag = pair->agent; |
|
|
struct ice_agent *ag = pair->agent; |
|
|
u_int32_t prio, transact[3]; |
|
|
u_int32_t prio, transact[3]; |
|
|
|
|
|
|
|
|
@ -625,12 +615,7 @@ static void __do_ice_check(struct ice_candidate_pair *pair) { |
|
|
if (!ag->pwd[0].s) |
|
|
if (!ag->pwd[0].s) |
|
|
return; |
|
|
return; |
|
|
|
|
|
|
|
|
ZERO(dst); |
|
|
|
|
|
dst.sin6_port = htons(pair->remote_candidate->endpoint.port); |
|
|
|
|
|
dst.sin6_addr = pair->remote_candidate->endpoint.ip46; |
|
|
|
|
|
dst.sin6_family = AF_INET6; |
|
|
|
|
|
|
|
|
|
|
|
prio = ice_priority(ICT_PRFLX, pair->local_address->preference, |
|
|
|
|
|
|
|
|
prio = ice_priority(ICT_PRFLX, pair->local_intf->unique_id, |
|
|
pair->remote_candidate->component_id); |
|
|
pair->remote_candidate->component_id); |
|
|
|
|
|
|
|
|
mutex_lock(&ag->lock); |
|
|
mutex_lock(&ag->lock); |
|
|
@ -661,12 +646,12 @@ static void __do_ice_check(struct ice_candidate_pair *pair) { |
|
|
|
|
|
|
|
|
ilog(LOG_DEBUG, "Sending %sICE/STUN request for candidate pair "PAIR_FORMAT" from %s to %s", |
|
|
ilog(LOG_DEBUG, "Sending %sICE/STUN request for candidate pair "PAIR_FORMAT" from %s to %s", |
|
|
PAIR_ISSET(pair, TO_USE) ? "nominating " : "", |
|
|
PAIR_ISSET(pair, TO_USE) ? "nominating " : "", |
|
|
PAIR_FMT(pair), smart_ntop_buf(&pair->local_address->addr), |
|
|
|
|
|
smart_ntop_ep_buf(&pair->remote_candidate->endpoint)); |
|
|
|
|
|
|
|
|
PAIR_FMT(pair), sockaddr_print_buf(&pair->local_intf->spec->address.addr), |
|
|
|
|
|
endpoint_print_buf(&pair->remote_candidate->endpoint)); |
|
|
|
|
|
|
|
|
stun_binding_request(&dst, transact, &ag->pwd[0], ag->ufrag, |
|
|
|
|
|
|
|
|
stun_binding_request(&pair->remote_candidate->endpoint, transact, &ag->pwd[0], ag->ufrag, |
|
|
AGENT_ISSET(ag, CONTROLLING), tie_breaker, |
|
|
AGENT_ISSET(ag, CONTROLLING), tie_breaker, |
|
|
prio, &pair->local_address->addr, ps->sfd->fd.fd, |
|
|
|
|
|
|
|
|
prio, &sfd->socket, |
|
|
PAIR_ISSET(pair, TO_USE)); |
|
|
PAIR_ISSET(pair, TO_USE)); |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
@ -721,7 +706,7 @@ static void __nominate_pairs(struct ice_agent *ag) { |
|
|
static void __do_ice_checks(struct ice_agent *ag) { |
|
|
static void __do_ice_checks(struct ice_agent *ag) { |
|
|
GList *l; |
|
|
GList *l; |
|
|
struct ice_candidate_pair *pair, *highest = NULL, *frozen = NULL, *valid; |
|
|
struct ice_candidate_pair *pair, *highest = NULL, *frozen = NULL, *valid; |
|
|
struct packet_stream *ps; |
|
|
|
|
|
|
|
|
struct stream_fd *sfd; |
|
|
GQueue retransmits = G_QUEUE_INIT; |
|
|
GQueue retransmits = G_QUEUE_INIT; |
|
|
struct timeval next_run = {0,0}; |
|
|
struct timeval next_run = {0,0}; |
|
|
int have_more = 0; |
|
|
int have_more = 0; |
|
|
@ -761,8 +746,8 @@ static void __do_ice_checks(struct ice_agent *ag) { |
|
|
pair = l->data; |
|
|
pair = l->data; |
|
|
|
|
|
|
|
|
/* skip dead streams */ |
|
|
/* skip dead streams */ |
|
|
ps = pair->packet_stream; |
|
|
|
|
|
if (!ps || !ps->sfd) |
|
|
|
|
|
|
|
|
sfd = pair->sfd; |
|
|
|
|
|
if (!sfd || !sfd->stream || !sfd->stream->selected_sfd) |
|
|
continue; |
|
|
continue; |
|
|
if (PAIR_ISSET(pair, FAILED)) |
|
|
if (PAIR_ISSET(pair, FAILED)) |
|
|
continue; |
|
|
continue; |
|
|
@ -835,13 +820,12 @@ static void __agent_shutdown(struct ice_agent *ag) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* agent must be locked for these */ |
|
|
/* agent must be locked for these */ |
|
|
static struct ice_candidate *__cand_lookup(struct ice_agent *ag, const struct sockaddr_in6 *sin, |
|
|
|
|
|
|
|
|
static struct ice_candidate *__cand_lookup(struct ice_agent *ag, const endpoint_t *sin, |
|
|
unsigned int component) |
|
|
unsigned int component) |
|
|
{ |
|
|
{ |
|
|
struct ice_candidate d; |
|
|
struct ice_candidate d; |
|
|
|
|
|
|
|
|
d.endpoint.port = ntohs(sin->sin6_port); |
|
|
|
|
|
d.endpoint.ip46 = sin->sin6_addr; |
|
|
|
|
|
|
|
|
d.endpoint = *sin; |
|
|
d.component_id = component; |
|
|
d.component_id = component; |
|
|
return g_hash_table_lookup(ag->candidate_hash, &d); |
|
|
return g_hash_table_lookup(ag->candidate_hash, &d); |
|
|
} |
|
|
} |
|
|
@ -855,11 +839,11 @@ static struct ice_candidate *__foundation_lookup(struct ice_agent *ag, const str |
|
|
return g_hash_table_lookup(ag->foundation_hash, &d); |
|
|
return g_hash_table_lookup(ag->foundation_hash, &d); |
|
|
} |
|
|
} |
|
|
static struct ice_candidate_pair *__pair_lookup(struct ice_agent *ag, struct ice_candidate *cand, |
|
|
static struct ice_candidate_pair *__pair_lookup(struct ice_agent *ag, struct ice_candidate *cand, |
|
|
struct interface_address *ifa) |
|
|
|
|
|
|
|
|
const struct local_intf *ifa) |
|
|
{ |
|
|
{ |
|
|
struct ice_candidate_pair p; |
|
|
struct ice_candidate_pair p; |
|
|
|
|
|
|
|
|
p.local_address = ifa; |
|
|
|
|
|
|
|
|
p.local_intf = ifa; |
|
|
p.remote_candidate = cand; |
|
|
p.remote_candidate = cand; |
|
|
return g_hash_table_lookup(ag->pair_hash, &p); |
|
|
return g_hash_table_lookup(ag->pair_hash, &p); |
|
|
} |
|
|
} |
|
|
@ -868,29 +852,25 @@ static void __cand_ice_foundation(struct call *call, struct ice_candidate *cand) |
|
|
char buf[64]; |
|
|
char buf[64]; |
|
|
int len; |
|
|
int len; |
|
|
|
|
|
|
|
|
len = sprintf(buf, "%lx%lx%lx%lx%x%x", |
|
|
|
|
|
(long unsigned) cand->endpoint.ip46.s6_addr32[0], |
|
|
|
|
|
(long unsigned) cand->endpoint.ip46.s6_addr32[1], |
|
|
|
|
|
(long unsigned) cand->endpoint.ip46.s6_addr32[2], |
|
|
|
|
|
(long unsigned) cand->endpoint.ip46.s6_addr32[3], |
|
|
|
|
|
cand->type, cand->transport); |
|
|
|
|
|
|
|
|
len = sprintf(buf, "%x%x%x", endpoint_hash(&cand->endpoint), |
|
|
|
|
|
cand->type, g_direct_hash(cand->transport)); |
|
|
call_str_cpy_len(call, &cand->foundation, buf, len); |
|
|
call_str_cpy_len(call, &cand->foundation, buf, len); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* agent must be locked */ |
|
|
/* 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) |
|
|
|
|
|
|
|
|
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 *cand, *old_cand; |
|
|
struct ice_candidate_pair *pair; |
|
|
struct ice_candidate_pair *pair; |
|
|
struct call *call = ag->call; |
|
|
struct call *call = ag->call; |
|
|
|
|
|
struct packet_stream *ps = sfd->stream; |
|
|
|
|
|
|
|
|
cand = g_slice_alloc0(sizeof(*cand)); |
|
|
cand = g_slice_alloc0(sizeof(*cand)); |
|
|
cand->component_id = ps->component; |
|
|
cand->component_id = ps->component; |
|
|
cand->transport = ITP_UDP; |
|
|
|
|
|
|
|
|
cand->transport = sfd->local_intf->spec->address.type; // XXX add socket type into socket_t? |
|
|
cand->priority = priority; |
|
|
cand->priority = priority; |
|
|
cand->endpoint.ip46 = src->sin6_addr; |
|
|
|
|
|
cand->endpoint.port = ntohs(src->sin6_port); |
|
|
|
|
|
|
|
|
cand->endpoint = *src; |
|
|
cand->type = ICT_PRFLX; |
|
|
cand->type = ICT_PRFLX; |
|
|
__cand_ice_foundation(call, cand); |
|
|
__cand_ice_foundation(call, cand); |
|
|
|
|
|
|
|
|
@ -900,7 +880,7 @@ static struct ice_candidate_pair *__learned_candidate(struct ice_agent *ag, stru |
|
|
* address, but from different ports. we cannot distinguish such candidates and |
|
|
* address, but from different ports. we cannot distinguish such candidates and |
|
|
* will drop the one with the lower priority */ |
|
|
* will drop the one with the lower priority */ |
|
|
g_slice_free1(sizeof(*cand), cand); |
|
|
g_slice_free1(sizeof(*cand), cand); |
|
|
pair = __pair_lookup(ag, old_cand, ifa); |
|
|
|
|
|
|
|
|
pair = __pair_lookup(ag, old_cand, sfd->local_intf); |
|
|
if (pair) |
|
|
if (pair) |
|
|
goto out; /* nothing to do */ |
|
|
goto out; /* nothing to do */ |
|
|
cand = old_cand; |
|
|
cand = old_cand; |
|
|
@ -912,7 +892,7 @@ static struct ice_candidate_pair *__learned_candidate(struct ice_agent *ag, stru |
|
|
g_hash_table_insert(ag->foundation_hash, cand, cand); |
|
|
g_hash_table_insert(ag->foundation_hash, cand, cand); |
|
|
|
|
|
|
|
|
pair: |
|
|
pair: |
|
|
pair = __pair_candidate(ifa, ag, cand, ps); |
|
|
|
|
|
|
|
|
pair = __pair_candidate(sfd, ag, cand); |
|
|
PAIR_SET(pair, LEARNED); |
|
|
PAIR_SET(pair, LEARNED); |
|
|
__all_pairs_list(ag); |
|
|
__all_pairs_list(ag); |
|
|
|
|
|
|
|
|
@ -1005,7 +985,7 @@ static void __get_complete_components(GQueue *out, struct ice_agent *ag, GTree * |
|
|
cand = __foundation_lookup(ag, &pair1->remote_candidate->foundation, i); |
|
|
cand = __foundation_lookup(ag, &pair1->remote_candidate->foundation, i); |
|
|
if (!cand) |
|
|
if (!cand) |
|
|
goto next_foundation; |
|
|
goto next_foundation; |
|
|
pairX = __pair_lookup(ag, cand, pair1->local_address); |
|
|
|
|
|
|
|
|
pairX = __pair_lookup(ag, cand, pair1->local_intf); |
|
|
if (!pairX) |
|
|
if (!pairX) |
|
|
goto next_foundation; |
|
|
goto next_foundation; |
|
|
if (!bf_isset(&pairX->pair_flags, flag)) |
|
|
if (!bf_isset(&pairX->pair_flags, flag)) |
|
|
@ -1029,10 +1009,11 @@ found: |
|
|
static int __check_valid(struct ice_agent *ag) { |
|
|
static int __check_valid(struct ice_agent *ag) { |
|
|
struct call_media *media = ag->media; |
|
|
struct call_media *media = ag->media; |
|
|
struct packet_stream *ps; |
|
|
struct packet_stream *ps; |
|
|
GList *l, *k; |
|
|
|
|
|
|
|
|
GList *l, *k, *m; |
|
|
GQueue all_compos; |
|
|
GQueue all_compos; |
|
|
struct ice_candidate_pair *pair; |
|
|
struct ice_candidate_pair *pair; |
|
|
struct interface_address *ifa; |
|
|
|
|
|
|
|
|
// const struct local_intf *ifa; |
|
|
|
|
|
struct stream_fd *sfd; |
|
|
|
|
|
|
|
|
if (!ag) { |
|
|
if (!ag) { |
|
|
ilog(LOG_ERR, "ice ag is NULL"); |
|
|
ilog(LOG_ERR, "ice ag is NULL"); |
|
|
@ -1050,12 +1031,6 @@ static int __check_valid(struct ice_agent *ag) { |
|
|
ilog(LOG_DEBUG, "ICE completed, using pair "PAIR_FORMAT, PAIR_FMT(pair)); |
|
|
ilog(LOG_DEBUG, "ICE completed, using pair "PAIR_FORMAT, PAIR_FMT(pair)); |
|
|
AGENT_SET(ag, COMPLETED); |
|
|
AGENT_SET(ag, COMPLETED); |
|
|
|
|
|
|
|
|
ifa = g_atomic_pointer_get(&media->local_address); |
|
|
|
|
|
if (ifa != pair->local_address |
|
|
|
|
|
&& g_atomic_pointer_compare_and_exchange(&media->local_address, ifa, |
|
|
|
|
|
pair->local_address)) |
|
|
|
|
|
ilog(LOG_INFO, "ICE negotiated: local interface %s", smart_ntop_buf(&pair->local_address->addr)); |
|
|
|
|
|
|
|
|
|
|
|
for (l = media->streams.head, k = all_compos.head; l && k; l = l->next, k = k->next) { |
|
|
for (l = media->streams.head, k = all_compos.head; l && k; l = l->next, k = k->next) { |
|
|
ps = l->data; |
|
|
ps = l->data; |
|
|
pair = k->data; |
|
|
pair = k->data; |
|
|
@ -1063,10 +1038,20 @@ static int __check_valid(struct ice_agent *ag) { |
|
|
mutex_lock(&ps->out_lock); |
|
|
mutex_lock(&ps->out_lock); |
|
|
if (memcmp(&ps->endpoint, &pair->remote_candidate->endpoint, sizeof(ps->endpoint))) { |
|
|
if (memcmp(&ps->endpoint, &pair->remote_candidate->endpoint, sizeof(ps->endpoint))) { |
|
|
ilog(LOG_INFO, "ICE negotiated: peer for component %u is %s", ps->component, |
|
|
ilog(LOG_INFO, "ICE negotiated: peer for component %u is %s", ps->component, |
|
|
smart_ntop_ep_buf(&pair->remote_candidate->endpoint)); |
|
|
|
|
|
|
|
|
endpoint_print_buf(&pair->remote_candidate->endpoint)); |
|
|
ps->endpoint = pair->remote_candidate->endpoint; |
|
|
ps->endpoint = pair->remote_candidate->endpoint; |
|
|
} |
|
|
} |
|
|
mutex_unlock(&ps->out_lock); |
|
|
mutex_unlock(&ps->out_lock); |
|
|
|
|
|
|
|
|
|
|
|
for (m = ps->sfds.head; m; m = m->next) { |
|
|
|
|
|
sfd = m->data; |
|
|
|
|
|
if (sfd->local_intf != pair->local_intf) |
|
|
|
|
|
continue; |
|
|
|
|
|
ps->selected_sfd = sfd; |
|
|
|
|
|
if (ps->component == 1) |
|
|
|
|
|
ilog(LOG_INFO, "ICE negotiated: local interface %s", |
|
|
|
|
|
sockaddr_print_buf(&pair->local_intf->spec->address.addr)); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
call_media_unkernelize(media); |
|
|
call_media_unkernelize(media); |
|
|
@ -1083,18 +1068,19 @@ static int __check_valid(struct ice_agent *ag) { |
|
|
* -1 = generic error, process packet as normal |
|
|
* -1 = generic error, process packet as normal |
|
|
* -2 = role conflict |
|
|
* -2 = role conflict |
|
|
*/ |
|
|
*/ |
|
|
int ice_request(struct packet_stream *ps, struct sockaddr_in6 *src, struct in6_addr *dst, |
|
|
|
|
|
|
|
|
int ice_request(struct stream_fd *sfd, const endpoint_t *src, |
|
|
struct stun_attrs *attrs) |
|
|
struct stun_attrs *attrs) |
|
|
{ |
|
|
{ |
|
|
|
|
|
struct packet_stream *ps = sfd->stream; |
|
|
struct call_media *media = ps->media; |
|
|
struct call_media *media = ps->media; |
|
|
struct ice_agent *ag; |
|
|
struct ice_agent *ag; |
|
|
struct interface_address *ifa; |
|
|
|
|
|
const char *err; |
|
|
const char *err; |
|
|
struct ice_candidate *cand; |
|
|
struct ice_candidate *cand; |
|
|
struct ice_candidate_pair *pair; |
|
|
struct ice_candidate_pair *pair; |
|
|
int ret; |
|
|
int ret; |
|
|
|
|
|
|
|
|
__DBG("received ICE request from %s on %s", smart_ntop_port_buf(src), smart_ntop_buf(dst)); |
|
|
|
|
|
|
|
|
__DBG("received ICE request from %s on %s", endpoint_print_buf(src), |
|
|
|
|
|
endpoint_print_buf(&sfd->socket.local)); |
|
|
|
|
|
|
|
|
ag = media->ice_agent; |
|
|
ag = media->ice_agent; |
|
|
if (!ag) |
|
|
if (!ag) |
|
|
@ -1102,20 +1088,15 @@ int ice_request(struct packet_stream *ps, struct sockaddr_in6 *src, struct in6_a |
|
|
|
|
|
|
|
|
atomic64_set(&ag->last_activity, poller_now); |
|
|
atomic64_set(&ag->last_activity, poller_now); |
|
|
|
|
|
|
|
|
ifa = get_interface_from_address(ag->local_interface, dst); |
|
|
|
|
|
err = "ICE/STUN binding request received on unknown local interface address"; |
|
|
|
|
|
if (!ifa) |
|
|
|
|
|
goto err; |
|
|
|
|
|
|
|
|
|
|
|
/* determine candidate pair */ |
|
|
/* determine candidate pair */ |
|
|
mutex_lock(&ag->lock); |
|
|
mutex_lock(&ag->lock); |
|
|
|
|
|
|
|
|
cand = __cand_lookup(ag, src, ps->component); |
|
|
cand = __cand_lookup(ag, src, ps->component); |
|
|
|
|
|
|
|
|
if (!cand) |
|
|
if (!cand) |
|
|
pair = __learned_candidate(ag, ps, src, ifa, attrs->priority); |
|
|
|
|
|
|
|
|
pair = __learned_candidate(ag, sfd, src, attrs->priority); |
|
|
else |
|
|
else |
|
|
pair = __pair_lookup(ag, cand, ifa); |
|
|
|
|
|
|
|
|
pair = __pair_lookup(ag, cand, sfd->local_intf); |
|
|
|
|
|
|
|
|
err = "Failed to determine ICE candidate from STUN request"; |
|
|
err = "Failed to determine ICE candidate from STUN request"; |
|
|
if (!pair) |
|
|
if (!pair) |
|
|
@ -1167,8 +1148,8 @@ int ice_request(struct packet_stream *ps, struct sockaddr_in6 *src, struct in6_a |
|
|
|
|
|
|
|
|
err_unlock: |
|
|
err_unlock: |
|
|
mutex_unlock(&ag->lock); |
|
|
mutex_unlock(&ag->lock); |
|
|
err: |
|
|
|
|
|
ilog(LOG_NOTICE, "%s (from %s on interface %s)", err, smart_ntop_port_buf(src), smart_ntop_buf(dst)); |
|
|
|
|
|
|
|
|
ilog(LOG_NOTICE, "%s (from %s on interface %s)", err, endpoint_print_buf(src), |
|
|
|
|
|
endpoint_print_buf(&sfd->socket.local)); |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -1192,19 +1173,21 @@ static int __check_succeeded_complete(struct ice_agent *ag) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* call is locked in R */ |
|
|
/* call is locked in R */ |
|
|
int ice_response(struct packet_stream *ps, struct sockaddr_in6 *src, struct in6_addr *dst, |
|
|
|
|
|
|
|
|
int ice_response(struct stream_fd *sfd, const endpoint_t *src, |
|
|
struct stun_attrs *attrs, u_int32_t transaction[3]) |
|
|
struct stun_attrs *attrs, u_int32_t transaction[3]) |
|
|
{ |
|
|
{ |
|
|
struct ice_candidate_pair *pair, *opair; |
|
|
struct ice_candidate_pair *pair, *opair; |
|
|
struct ice_agent *ag; |
|
|
struct ice_agent *ag; |
|
|
|
|
|
struct packet_stream *ps = sfd->stream; |
|
|
struct call_media *media = ps->media; |
|
|
struct call_media *media = ps->media; |
|
|
const char *err; |
|
|
const char *err; |
|
|
unsigned int component; |
|
|
unsigned int component; |
|
|
struct ice_candidate *cand; |
|
|
struct ice_candidate *cand; |
|
|
struct interface_address *ifa; |
|
|
|
|
|
|
|
|
const struct local_intf *ifa; |
|
|
int ret, was_ctl; |
|
|
int ret, was_ctl; |
|
|
|
|
|
|
|
|
__DBG("received ICE response from %s on %s", smart_ntop_port_buf(src), smart_ntop_buf(dst)); |
|
|
|
|
|
|
|
|
__DBG("received ICE response from %s on %s", endpoint_print_buf(src), |
|
|
|
|
|
endpoint_print_buf(&sfd->socket.local)); |
|
|
|
|
|
|
|
|
ag = media->ice_agent; |
|
|
ag = media->ice_agent; |
|
|
if (!ag) |
|
|
if (!ag) |
|
|
@ -1222,24 +1205,20 @@ int ice_response(struct packet_stream *ps, struct sockaddr_in6 *src, struct in6_ |
|
|
|
|
|
|
|
|
mutex_unlock(&ag->lock); |
|
|
mutex_unlock(&ag->lock); |
|
|
|
|
|
|
|
|
ifa = pair->local_address; |
|
|
|
|
|
|
|
|
ifa = pair->local_intf; |
|
|
|
|
|
|
|
|
ilog(LOG_DEBUG, "Received ICE/STUN response code %u for candidate pair "PAIR_FORMAT" from %s to %s", |
|
|
ilog(LOG_DEBUG, "Received ICE/STUN response code %u for candidate pair "PAIR_FORMAT" from %s to %s", |
|
|
attrs->error_code, PAIR_FMT(pair), |
|
|
attrs->error_code, PAIR_FMT(pair), |
|
|
smart_ntop_ep_buf(&pair->remote_candidate->endpoint), |
|
|
|
|
|
smart_ntop_buf(&ifa->addr)); |
|
|
|
|
|
|
|
|
endpoint_print_buf(&pair->remote_candidate->endpoint), |
|
|
|
|
|
sockaddr_print_buf(&ifa->spec->address.addr)); |
|
|
|
|
|
|
|
|
/* verify endpoints */ |
|
|
/* verify endpoints */ |
|
|
err = "ICE/STUN response received, but source address didn't match remote candidate address"; |
|
|
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) |
|
|
|
|
|
|
|
|
if (!endpoint_eq(src, &pair->remote_candidate->endpoint)) |
|
|
goto err; |
|
|
goto err; |
|
|
|
|
|
|
|
|
err = "ICE/STUN response received, but destination address didn't match local interface address"; |
|
|
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) |
|
|
|
|
|
|
|
|
if (pair->sfd != sfd) |
|
|
goto err; |
|
|
goto err; |
|
|
|
|
|
|
|
|
PAIR_CLEAR(pair, IN_PROGRESS); |
|
|
PAIR_CLEAR(pair, IN_PROGRESS); |
|
|
@ -1321,7 +1300,7 @@ err_unlock: |
|
|
err: |
|
|
err: |
|
|
if (err) |
|
|
if (err) |
|
|
ilog(LOG_NOTICE, "%s (from %s on interface %s)", |
|
|
ilog(LOG_NOTICE, "%s (from %s on interface %s)", |
|
|
err, smart_ntop_port_buf(src), smart_ntop_buf(dst)); |
|
|
|
|
|
|
|
|
err, endpoint_print_buf(src), endpoint_print_buf(&sfd->socket.local)); |
|
|
|
|
|
|
|
|
if (pair && attrs->error_code) |
|
|
if (pair && attrs->error_code) |
|
|
__fail_pair(pair); |
|
|
__fail_pair(pair); |
|
|
@ -1402,9 +1381,9 @@ static void create_random_ice_string(struct call *call, str *s, int len) { |
|
|
call_str_cpy_len(call, s, buf, len); |
|
|
call_str_cpy_len(call, s, buf, len); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void ice_foundation(struct interface_address *ifa) { |
|
|
|
|
|
random_ice_string(ifa->foundation_buf, sizeof(ifa->foundation_buf)); |
|
|
|
|
|
str_init_len(&ifa->ice_foundation, ifa->foundation_buf, sizeof(ifa->foundation_buf)); |
|
|
|
|
|
|
|
|
void ice_foundation(str *s) { |
|
|
|
|
|
str_init_len(s, malloc(ICE_FOUNDATION_LENGTH), ICE_FOUNDATION_LENGTH); |
|
|
|
|
|
random_ice_string(s->s, ICE_FOUNDATION_LENGTH); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void ice_remote_candidates(GQueue *out, struct ice_agent *ag) { |
|
|
void ice_remote_candidates(GQueue *out, struct ice_agent *ag) { |
|
|
|