NiceCandidate * nice_component_set_selected_remote_candidate (NiceComponent *component, NiceAgent *agent, NiceCandidate *candidate) { NiceCandidate *local = NULL; NiceCandidate *remote = NULL; guint64 priority = 0; GSList *item = NULL; g_assert (candidate != NULL); for (item = component->local_candidates; item; item = g_slist_next (item)) { NiceCandidate *tmp = item->data; guint64 tmp_prio = 0; if (tmp->transport != conn_check_match_transport(candidate->transport) || tmp->addr.s.addr.sa_family != candidate->addr.s.addr.sa_family || tmp->type != NICE_CANDIDATE_TYPE_HOST) continue; tmp_prio = agent_candidate_pair_priority (agent, tmp, candidate); if (tmp_prio > priority) { priority = tmp_prio; local = tmp; } } if (local == NULL) return NULL; remote = nice_component_find_remote_candidate (component, &candidate->addr, candidate->transport); if (!remote) { remote = nice_candidate_copy (candidate); component->remote_candidates = g_slist_append (component->remote_candidates, remote); agent_signal_new_remote_candidate (agent, remote); } nice_component_clear_selected_pair (component); component->selected_pair.local = local; component->selected_pair.remote = remote; component->selected_pair.priority = priority; return local; }
/* * Adds a new peer reflexive candidate to the list of known * remote candidates. The candidate is however not paired with * existing local candidates. * * See ICE sect 7.2.1.3 "Learning Peer Reflexive Candidates" (ID-19). * * @return pointer to the created candidate, or NULL on error */ NiceCandidate *discovery_learn_remote_peer_reflexive_candidate ( NiceAgent *agent, NiceStream *stream, NiceComponent *component, guint32 priority, const NiceAddress *remote_address, NiceSocket *nicesock, NiceCandidate *local, NiceCandidate *remote) { NiceCandidate *candidate; candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_PEER_REFLEXIVE); candidate->addr = *remote_address; candidate->base_addr = *remote_address; if (remote) candidate->transport = remote->transport; else if (local) candidate->transport = conn_check_match_transport (local->transport); else { if (nicesock->type == NICE_SOCKET_TYPE_UDP_BSD || nicesock->type == NICE_SOCKET_TYPE_UDP_TURN) candidate->transport = NICE_CANDIDATE_TRANSPORT_UDP; else candidate->transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE; } candidate->sockptr = nicesock; candidate->stream_id = stream->id; candidate->component_id = component->id; /* if the check didn't contain the PRIORITY attribute, then the priority will * be 0, which is invalid... */ if (priority != 0) { candidate->priority = priority; } else if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) { candidate->priority = nice_candidate_jingle_priority (candidate); } else if (agent->compatibility == NICE_COMPATIBILITY_MSN || agent->compatibility == NICE_COMPATIBILITY_OC2007) { candidate->priority = nice_candidate_msn_priority (candidate); } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) { candidate->priority = nice_candidate_ms_ice_priority (candidate, agent->reliable, FALSE); } else { candidate->priority = nice_candidate_ice_priority (candidate, agent->reliable, FALSE); } priv_assign_remote_foundation (agent, candidate); if ((agent->compatibility == NICE_COMPATIBILITY_MSN || agent->compatibility == NICE_COMPATIBILITY_OC2007) && remote && local) { guchar *new_username = NULL; guchar *decoded_local = NULL; guchar *decoded_remote = NULL; gsize local_size; gsize remote_size; g_free(candidate->username); g_free (candidate->password); decoded_local = g_base64_decode (local->username, &local_size); decoded_remote = g_base64_decode (remote->username, &remote_size); new_username = g_new0(guchar, local_size + remote_size); memcpy(new_username, decoded_remote, remote_size); memcpy(new_username + remote_size, decoded_local, local_size); candidate->username = g_base64_encode (new_username, local_size + remote_size); g_free(new_username); g_free(decoded_local); g_free(decoded_remote); candidate->password = g_strdup(remote->password); } else if (remote) { g_free (candidate->username); g_free (candidate->password); candidate->username = g_strdup(remote->username); candidate->password = g_strdup(remote->password); } /* note: candidate username and password are left NULL as stream level ufrag/password are used */ component->remote_candidates = g_slist_append (component->remote_candidates, candidate); agent_signal_new_remote_candidate (agent, candidate); return candidate; }
/* * Creates a peer reflexive candidate for 'component_id' of stream * 'stream_id'. * * @return pointer to the created candidate, or NULL on error */ NiceCandidate* discovery_add_peer_reflexive_candidate ( NiceAgent *agent, guint stream_id, guint component_id, NiceAddress *address, NiceSocket *base_socket, NiceCandidate *local, NiceCandidate *remote) { NiceCandidate *candidate; NiceComponent *component; NiceStream *stream; gboolean result; if (!agent_find_component (agent, stream_id, component_id, &stream, &component)) return NULL; candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_PEER_REFLEXIVE); if (local) candidate->transport = local->transport; else if (remote) candidate->transport = conn_check_match_transport (remote->transport); else { if (base_socket->type == NICE_SOCKET_TYPE_UDP_BSD || base_socket->type == NICE_SOCKET_TYPE_UDP_TURN) candidate->transport = NICE_CANDIDATE_TRANSPORT_UDP; else candidate->transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE; } candidate->stream_id = stream_id; candidate->component_id = component_id; candidate->addr = *address; candidate->sockptr = base_socket; candidate->base_addr = base_socket->addr; if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) { candidate->priority = nice_candidate_jingle_priority (candidate); } else if (agent->compatibility == NICE_COMPATIBILITY_MSN || agent->compatibility == NICE_COMPATIBILITY_OC2007) { candidate->priority = nice_candidate_msn_priority (candidate); } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) { candidate->priority = nice_candidate_ms_ice_priority (candidate, agent->reliable, FALSE); } else { candidate->priority = nice_candidate_ice_priority (candidate, agent->reliable, FALSE); } candidate->priority = ensure_unique_priority (component, candidate->priority); priv_assign_foundation (agent, candidate); if ((agent->compatibility == NICE_COMPATIBILITY_MSN || agent->compatibility == NICE_COMPATIBILITY_OC2007) && remote && local) { guchar *new_username = NULL; guchar *decoded_local = NULL; guchar *decoded_remote = NULL; gsize local_size; gsize remote_size; g_free(candidate->username); g_free(candidate->password); decoded_local = g_base64_decode (local->username, &local_size); decoded_remote = g_base64_decode (remote->username, &remote_size); new_username = g_new0(guchar, local_size + remote_size); memcpy(new_username, decoded_local, local_size); memcpy(new_username + local_size, decoded_remote, remote_size); candidate->username = g_base64_encode (new_username, local_size + remote_size); g_free(new_username); g_free(decoded_local); g_free(decoded_remote); candidate->password = g_strdup(local->password); } else if (local) { g_free(candidate->username); g_free(candidate->password); candidate->username = g_strdup(local->username); candidate->password = g_strdup(local->password); } result = priv_add_local_candidate_pruned (agent, stream_id, component, candidate); if (result != TRUE) { /* error: memory allocation, or duplicate candidate */ nice_candidate_free (candidate), candidate = NULL; } return candidate; }