2 * This file is part of the Nice GLib ICE library.
4 * (C) 2006-2009 Collabora Ltd.
5 * Contact: Youness Alaoui
6 * (C) 2006-2009 Nokia Corporation. All rights reserved.
7 * Contact: Kai Vehmanen
9 * The contents of this file are subject to the Mozilla Public License Version
10 * 1.1 (the "License"); you may not use this file except in compliance with
11 * the License. You may obtain a copy of the License at
12 * http://www.mozilla.org/MPL/
14 * Software distributed under the License is distributed on an "AS IS" basis,
15 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
16 * for the specific language governing rights and limitations under the
19 * The Original Code is the Nice GLib ICE library.
21 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
22 * Corporation. All Rights Reserved.
25 * Dafydd Harries, Collabora Ltd.
26 * Youness Alaoui, Collabora Ltd.
29 * Alternatively, the contents of this file may be used under the terms of the
30 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
31 * case the provisions of LGPL are applicable instead of those above. If you
32 * wish to allow use of your version of this file only under the terms of the
33 * LGPL and not to allow others to use your version of this file under the
34 * MPL, indicate your decision by deleting the provisions above and replace
35 * them with the notice and other provisions required by the LGPL. If you do
36 * not delete the provisions above, a recipient may use your version of this
37 * file under either the MPL or the LGPL.
42 * @brief ICE candidate functions
48 #define NICEAPI_EXPORT
54 #include "component.h"
55 #include "interfaces.h"
57 G_DEFINE_BOXED_TYPE (NiceCandidate, nice_candidate, nice_candidate_copy,
60 /* (ICE 4.1.1 "Gathering Candidates") ""Every candidate is a transport
61 * address. It also has a type and a base. Three types are defined and
62 * gathered by this specification - host candidates, server reflexive
63 * candidates, and relayed candidates."" (ID-19) */
65 NICEAPI_EXPORT NiceCandidate *
66 nice_candidate_new (NiceCandidateType type)
68 NiceCandidate *candidate;
70 candidate = g_slice_new0 (NiceCandidate);
71 candidate->type = type;
77 nice_candidate_free (NiceCandidate *candidate)
79 /* better way of checking if socket is allocated? */
81 if (candidate->username)
82 g_free (candidate->username);
84 if (candidate->password)
85 g_free (candidate->password);
88 turn_server_unref (candidate->turn);
90 g_slice_free (NiceCandidate, candidate);
95 nice_candidate_jingle_priority (NiceCandidate *candidate)
97 switch (candidate->type)
99 case NICE_CANDIDATE_TYPE_HOST: return 1000;
100 case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE: return 900;
101 case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE: return 900;
102 case NICE_CANDIDATE_TYPE_RELAYED: return 500;
108 nice_candidate_msn_priority (NiceCandidate *candidate)
110 switch (candidate->type)
112 case NICE_CANDIDATE_TYPE_HOST: return 830;
113 case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE: return 550;
114 case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE: return 550;
115 case NICE_CANDIDATE_TYPE_RELAYED: return 450;
122 * ICE 4.1.2.1. "Recommended Formula" (ID-19):
123 * returns number between 1 and 0x7effffff
126 nice_candidate_ice_priority_full (
127 // must be ∈ (0, 126) (max 2^7 - 2)
128 guint type_preference,
129 // must be ∈ (0, 65535) (max 2^16 - 1)
130 guint local_preference,
131 // must be ∈ (0, 255) (max 2 ^ 8 - 1)
135 0x1000000 * type_preference +
136 0x100 * local_preference +
137 (0x100 - component_id));
141 nice_candidate_ice_local_preference_full (guint direction_preference,
142 guint turn_preference, guint other_preference)
145 * bits 0- 5: other_preference (ip local preference)
146 * 6- 8: turn_preference
148 * 13-15: direction_preference
150 g_assert_cmpuint (other_preference, <, NICE_CANDIDATE_MAX_LOCAL_ADDRESSES);
151 g_assert_cmpuint (turn_preference, <, NICE_CANDIDATE_MAX_TURN_SERVERS);
152 g_assert_cmpuint (direction_preference, <, 8);
154 return (direction_preference << 13) +
155 (turn_preference << 6) +
160 nice_candidate_ip_local_preference (const NiceCandidate *candidate)
162 guint preference = 0;
163 gchar ip_string[INET6_ADDRSTRLEN];
164 GList/*<owned gchar*>*/ *ips = NULL;
165 GList/*<unowned gchar*>*/ *iter;
167 /* Ensure otherwise identical host candidates with only different IP addresses
168 * (multihomed host) get assigned different priorities. Position of the IP in
169 * the list obtained from nice_interfaces_get_local_ips() serves here as the
170 * distinguishing value of other_preference. Reflexive and relayed candidates
171 * are likewise differentiated by their base address.
173 * This is required by RFC 5245 Section 4.1.2.1:
174 * https://tools.ietf.org/html/rfc5245#section-4.1.2.1
176 if (candidate->type == NICE_CANDIDATE_TYPE_HOST) {
177 nice_address_to_string (&candidate->addr, ip_string);
179 nice_address_to_string (&candidate->base_addr, ip_string);
182 ips = nice_interfaces_get_local_ips (TRUE);
184 for (iter = ips; iter; iter = g_list_next (iter)) {
185 /* Strip the IPv6 link-local scope string */
186 gchar **tokens = g_strsplit (iter->data, "%", 2);
187 gboolean match = (g_strcmp0 (ip_string, tokens[0]) == 0);
194 g_list_free_full (ips, g_free);
200 nice_candidate_ice_local_preference (const NiceCandidate *candidate)
202 guint direction_preference = 0;
203 guint turn_preference = 0;
205 switch (candidate->transport)
207 case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
208 if (candidate->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE ||
209 candidate->type == NICE_CANDIDATE_TYPE_HOST)
210 direction_preference = 4;
212 direction_preference = 6;
214 case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
215 if (candidate->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE ||
216 candidate->type == NICE_CANDIDATE_TYPE_HOST)
217 direction_preference = 2;
219 direction_preference = 4;
221 case NICE_CANDIDATE_TRANSPORT_TCP_SO:
222 if (candidate->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE ||
223 candidate->type == NICE_CANDIDATE_TYPE_HOST)
224 direction_preference = 6;
226 direction_preference = 2;
228 case NICE_CANDIDATE_TRANSPORT_UDP:
230 direction_preference = 1;
234 /* Relay candidates are assigned a unique local preference at
237 if (candidate->type == NICE_CANDIDATE_TYPE_RELAYED) {
238 g_assert (candidate->turn);
239 turn_preference = candidate->turn->preference;
242 return nice_candidate_ice_local_preference_full (direction_preference,
243 turn_preference, nice_candidate_ip_local_preference (candidate));
247 nice_candidate_ms_ice_local_preference_full (guint transport_preference,
248 guint direction_preference, guint turn_preference, guint other_preference)
251 * bits 0- 5: other_preference (ip local preference)
252 * 6- 8: turn_preference
253 * 9-11: direction_preference
254 * 12-15: transport_preference
256 g_assert_cmpuint (other_preference, <, NICE_CANDIDATE_MAX_LOCAL_ADDRESSES);
257 g_assert_cmpuint (turn_preference, <, NICE_CANDIDATE_MAX_TURN_SERVERS);
258 g_assert_cmpuint (direction_preference, <, 8);
259 g_assert_cmpuint (transport_preference, <, 16);
261 return (transport_preference << 12) +
262 (direction_preference << 9) +
263 (turn_preference << 6) +
268 nice_candidate_ms_ice_local_preference (const NiceCandidate *candidate)
270 guint transport_preference = 0;
271 guint direction_preference = 0;
272 guint turn_preference = 0;
274 switch (candidate->transport)
276 case NICE_CANDIDATE_TRANSPORT_TCP_SO:
277 case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
278 transport_preference = NICE_CANDIDATE_TRANSPORT_MS_PREF_TCP;
279 direction_preference = NICE_CANDIDATE_DIRECTION_MS_PREF_ACTIVE;
281 case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
282 transport_preference = NICE_CANDIDATE_TRANSPORT_MS_PREF_TCP;
283 direction_preference = NICE_CANDIDATE_DIRECTION_MS_PREF_PASSIVE;
285 case NICE_CANDIDATE_TRANSPORT_UDP:
287 transport_preference = NICE_CANDIDATE_TRANSPORT_MS_PREF_UDP;
291 /* Relay candidates are assigned a unique local preference at
294 if (candidate->type == NICE_CANDIDATE_TYPE_RELAYED) {
295 g_assert (candidate->turn);
296 turn_preference = candidate->turn->preference;
299 return nice_candidate_ms_ice_local_preference_full(transport_preference,
300 direction_preference, turn_preference,
301 nice_candidate_ip_local_preference (candidate));
305 nice_candidate_ice_type_preference (const NiceCandidate *candidate,
306 gboolean reliable, gboolean nat_assisted)
308 guint8 type_preference;
310 switch (candidate->type)
312 case NICE_CANDIDATE_TYPE_HOST:
313 type_preference = NICE_CANDIDATE_TYPE_PREF_HOST;
315 case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
316 type_preference = NICE_CANDIDATE_TYPE_PREF_PEER_REFLEXIVE;
318 case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
320 type_preference = NICE_CANDIDATE_TYPE_PREF_NAT_ASSISTED;
322 type_preference = NICE_CANDIDATE_TYPE_PREF_SERVER_REFLEXIVE;
324 case NICE_CANDIDATE_TYPE_RELAYED:
325 if (candidate->turn->type == NICE_RELAY_TYPE_TURN_UDP)
326 type_preference = NICE_CANDIDATE_TYPE_PREF_RELAYED_UDP;
328 type_preference = NICE_CANDIDATE_TYPE_PREF_RELAYED;
335 if ((reliable && candidate->transport == NICE_CANDIDATE_TRANSPORT_UDP) ||
336 (!reliable && candidate->transport != NICE_CANDIDATE_TRANSPORT_UDP)) {
337 type_preference = type_preference / 2;
340 return type_preference;
344 nice_candidate_ice_priority (const NiceCandidate *candidate,
345 gboolean reliable, gboolean nat_assisted)
347 guint8 type_preference;
348 guint16 local_preference;
350 type_preference = nice_candidate_ice_type_preference (candidate, reliable,
352 local_preference = nice_candidate_ice_local_preference (candidate);
354 return nice_candidate_ice_priority_full (type_preference, local_preference,
355 candidate->component_id);
359 nice_candidate_ms_ice_priority (const NiceCandidate *candidate,
360 gboolean reliable, gboolean nat_assisted)
362 guint8 type_preference;
363 guint16 local_preference;
365 type_preference = nice_candidate_ice_type_preference (candidate, reliable,
367 local_preference = nice_candidate_ms_ice_local_preference (candidate);
369 return nice_candidate_ice_priority_full (type_preference, local_preference,
370 candidate->component_id);
374 * Calculates the pair priority as specified in ICE
375 * sect 5.7.2. "Computing Pair Priority and Ordering Pairs" (ID-19).
378 nice_candidate_pair_priority (guint32 o_prio, guint32 a_prio)
380 guint32 max = o_prio > a_prio ? o_prio : a_prio;
381 guint32 min = o_prio < a_prio ? o_prio : a_prio;
382 /* These two constants are here explictly to make some version of GCC happy */
383 const guint64 one = 1;
384 const guint64 thirtytwo = 32;
386 return (one << thirtytwo) * min + 2 * max + (o_prio > a_prio ? 1 : 0);
390 nice_candidate_pair_priority_to_string (guint64 prio, gchar *string)
392 g_snprintf (string, NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE,
393 "%08" G_GINT64_MODIFIER "x:%08" G_GINT64_MODIFIER "x:%" G_GUINT64_FORMAT,
394 prio >> 32, (prio >> 1) & 0x7fffffff, prio & 1);
400 NICEAPI_EXPORT NiceCandidate *
401 nice_candidate_copy (const NiceCandidate *candidate)
405 g_return_val_if_fail (candidate != NULL, NULL);
407 copy = nice_candidate_new (candidate->type);
408 memcpy (copy, candidate, sizeof(NiceCandidate));
411 copy->username = g_strdup (copy->username);
412 copy->password = g_strdup (copy->password);
417 NICEAPI_EXPORT gboolean
418 nice_candidate_equal_target (const NiceCandidate *candidate1,
419 const NiceCandidate *candidate2)
421 g_return_val_if_fail (candidate1 != NULL, FALSE);
422 g_return_val_if_fail (candidate2 != NULL, FALSE);
424 return (candidate1->transport == candidate2->transport &&
425 nice_address_equal (&candidate1->addr, &candidate2->addr));