Imported Upstream version 0.1.17
[platform/upstream/libnice.git] / agent / candidate.c
1 /*
2  * This file is part of the Nice GLib ICE library.
3  *
4  * (C) 2006-2009 Collabora Ltd.
5  *  Contact: Youness Alaoui
6  * (C) 2006-2009 Nokia Corporation. All rights reserved.
7  *  Contact: Kai Vehmanen
8  *
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/
13  *
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
17  * License.
18  *
19  * The Original Code is the Nice GLib ICE library.
20  *
21  * The Initial Developers of the Original Code are Collabora Ltd and Nokia
22  * Corporation. All Rights Reserved.
23  *
24  * Contributors:
25  *   Dafydd Harries, Collabora Ltd.
26  *   Youness Alaoui, Collabora Ltd.
27  *   Kai Vehmanen, Nokia
28  *
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.
38  */
39
40 /*
41  * @file candidate.c
42  * @brief ICE candidate functions
43  */
44
45 #ifdef HAVE_CONFIG_H
46 # include <config.h>
47 #else
48 #define NICEAPI_EXPORT
49 #endif
50
51 #include <string.h>
52
53 #include "agent.h"
54 #include "component.h"
55 #include "interfaces.h"
56
57 G_DEFINE_BOXED_TYPE (NiceCandidate, nice_candidate, nice_candidate_copy,
58     nice_candidate_free);
59
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) */
64
65 NICEAPI_EXPORT NiceCandidate *
66 nice_candidate_new (NiceCandidateType type)
67 {
68   NiceCandidate *candidate;
69
70   candidate = g_slice_new0 (NiceCandidate);
71   candidate->type = type;
72   return candidate;
73 }
74
75
76 NICEAPI_EXPORT void
77 nice_candidate_free (NiceCandidate *candidate)
78 {
79   /* better way of checking if socket is allocated? */
80
81   if (candidate->username)
82     g_free (candidate->username);
83
84   if (candidate->password)
85     g_free (candidate->password);
86
87   if (candidate->turn)
88     turn_server_unref (candidate->turn);
89
90   g_slice_free (NiceCandidate, candidate);
91 }
92
93
94 guint32
95 nice_candidate_jingle_priority (NiceCandidate *candidate)
96 {
97   switch (candidate->type)
98     {
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;
103     default:                                   return 0;
104     }
105 }
106
107 guint32
108 nice_candidate_msn_priority (NiceCandidate *candidate)
109 {
110   switch (candidate->type)
111     {
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;
116     default:                                   return 0;
117     }
118 }
119
120
121 /*
122  * ICE 4.1.2.1. "Recommended Formula" (ID-19):
123  * returns number between 1 and 0x7effffff 
124  */
125 guint32
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)
132   guint component_id)
133 {
134   return (
135       0x1000000 * type_preference +
136       0x100 * local_preference +
137       (0x100 - component_id));
138 }
139
140 static guint16
141 nice_candidate_ice_local_preference_full (guint direction_preference,
142     guint turn_preference, guint other_preference)
143 {
144   /*
145    * bits  0- 5: other_preference (ip local preference)
146    *       6- 8: turn_preference
147    *       9-12: <unused>
148    *      13-15: direction_preference
149    */
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);
153
154   return (direction_preference << 13) +
155       (turn_preference << 6) +
156       other_preference;
157 }
158
159 static guint
160 nice_candidate_ip_local_preference (const NiceCandidate *candidate)
161 {
162   guint preference = 0;
163   gchar ip_string[INET6_ADDRSTRLEN];
164   GList/*<owned gchar*>*/ *ips = NULL;
165   GList/*<unowned gchar*>*/ *iter;
166
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.
172    *
173    * This is required by RFC 5245 Section 4.1.2.1:
174    *   https://tools.ietf.org/html/rfc5245#section-4.1.2.1
175    */
176   if (candidate->type == NICE_CANDIDATE_TYPE_HOST) {
177     nice_address_to_string (&candidate->addr, ip_string);
178   } else {
179     nice_address_to_string (&candidate->base_addr, ip_string);
180   }
181
182   ips = nice_interfaces_get_local_ips (TRUE);
183
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);
188     g_strfreev (tokens);
189     if (match)
190       break;
191     ++preference;
192   }
193
194   g_list_free_full (ips, g_free);
195
196   return preference;
197 }
198
199 static guint16
200 nice_candidate_ice_local_preference (const NiceCandidate *candidate)
201 {
202   guint direction_preference = 0;
203   guint turn_preference = 0;
204
205   switch (candidate->transport)
206     {
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;
211         else
212           direction_preference = 6;
213         break;
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;
218         else
219           direction_preference = 4;
220         break;
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;
225         else
226           direction_preference = 2;
227         break;
228       case NICE_CANDIDATE_TRANSPORT_UDP:
229       default:
230         direction_preference = 1;
231         break;
232     }
233
234   /* Relay candidates are assigned a unique local preference at
235    * creation time.
236    */
237   if (candidate->type == NICE_CANDIDATE_TYPE_RELAYED) {
238     g_assert (candidate->turn);
239     turn_preference = candidate->turn->preference;
240   }
241
242   return nice_candidate_ice_local_preference_full (direction_preference,
243       turn_preference, nice_candidate_ip_local_preference (candidate));
244 }
245
246 static guint16
247 nice_candidate_ms_ice_local_preference_full (guint transport_preference,
248     guint direction_preference, guint turn_preference, guint other_preference)
249 {
250   /*
251    * bits 0- 5: other_preference (ip local preference)
252    *      6- 8: turn_preference
253    *      9-11: direction_preference
254    *     12-15: transport_preference
255    */
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);
260
261   return (transport_preference << 12) +
262       (direction_preference << 9) +
263       (turn_preference << 6) +
264       other_preference;
265 }
266
267 static guint32
268 nice_candidate_ms_ice_local_preference (const NiceCandidate *candidate)
269 {
270   guint transport_preference = 0;
271   guint direction_preference = 0;
272   guint turn_preference = 0;
273
274   switch (candidate->transport)
275     {
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;
280       break;
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;
284       break;
285     case NICE_CANDIDATE_TRANSPORT_UDP:
286     default:
287       transport_preference = NICE_CANDIDATE_TRANSPORT_MS_PREF_UDP;
288       break;
289     }
290
291   /* Relay candidates are assigned a unique local preference at
292    * creation time.
293    */
294   if (candidate->type == NICE_CANDIDATE_TYPE_RELAYED) {
295     g_assert (candidate->turn);
296     turn_preference = candidate->turn->preference;
297   }
298
299   return nice_candidate_ms_ice_local_preference_full(transport_preference,
300       direction_preference, turn_preference,
301       nice_candidate_ip_local_preference (candidate));
302 }
303
304 static guint8
305 nice_candidate_ice_type_preference (const NiceCandidate *candidate,
306     gboolean reliable, gboolean nat_assisted)
307 {
308   guint8 type_preference;
309
310   switch (candidate->type)
311     {
312     case NICE_CANDIDATE_TYPE_HOST:
313       type_preference = NICE_CANDIDATE_TYPE_PREF_HOST;
314       break;
315     case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
316       type_preference = NICE_CANDIDATE_TYPE_PREF_PEER_REFLEXIVE;
317       break;
318     case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
319       if (nat_assisted)
320         type_preference = NICE_CANDIDATE_TYPE_PREF_NAT_ASSISTED;
321       else
322         type_preference = NICE_CANDIDATE_TYPE_PREF_SERVER_REFLEXIVE;
323       break;
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;
327       else
328         type_preference = NICE_CANDIDATE_TYPE_PREF_RELAYED;
329       break;
330     default:
331       type_preference = 0;
332       break;
333     }
334
335   if ((reliable && candidate->transport == NICE_CANDIDATE_TRANSPORT_UDP) ||
336       (!reliable && candidate->transport != NICE_CANDIDATE_TRANSPORT_UDP)) {
337     type_preference = type_preference / 2;
338   }
339
340   return type_preference;
341 }
342
343 guint32
344 nice_candidate_ice_priority (const NiceCandidate *candidate,
345     gboolean reliable, gboolean nat_assisted)
346 {
347   guint8 type_preference;
348   guint16 local_preference;
349
350   type_preference = nice_candidate_ice_type_preference (candidate, reliable,
351       nat_assisted);
352   local_preference = nice_candidate_ice_local_preference (candidate);
353
354   return nice_candidate_ice_priority_full (type_preference, local_preference,
355       candidate->component_id);
356 }
357
358 guint32
359 nice_candidate_ms_ice_priority (const NiceCandidate *candidate,
360     gboolean reliable, gboolean nat_assisted)
361 {
362   guint8 type_preference;
363   guint16 local_preference;
364
365   type_preference = nice_candidate_ice_type_preference (candidate, reliable,
366       nat_assisted);
367   local_preference = nice_candidate_ms_ice_local_preference (candidate);
368
369   return nice_candidate_ice_priority_full (type_preference, local_preference,
370       candidate->component_id);
371 }
372
373 /*
374  * Calculates the pair priority as specified in ICE
375  * sect 5.7.2. "Computing Pair Priority and Ordering Pairs" (ID-19).
376  */
377 guint64
378 nice_candidate_pair_priority (guint32 o_prio, guint32 a_prio)
379 {
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;
385
386   return (one << thirtytwo) * min + 2 * max + (o_prio > a_prio ? 1 : 0);
387 }
388
389 void
390 nice_candidate_pair_priority_to_string (guint64 prio, gchar *string)
391 {
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);
395 }
396
397 /*
398  * Copies a candidate
399  */
400 NICEAPI_EXPORT NiceCandidate *
401 nice_candidate_copy (const NiceCandidate *candidate)
402 {
403   NiceCandidate *copy;
404
405   g_return_val_if_fail (candidate != NULL, NULL);
406
407   copy = nice_candidate_new (candidate->type);
408   memcpy (copy, candidate, sizeof(NiceCandidate));
409
410   copy->turn = NULL;
411   copy->username = g_strdup (copy->username);
412   copy->password = g_strdup (copy->password);
413
414   return copy;
415 }
416
417 NICEAPI_EXPORT gboolean
418 nice_candidate_equal_target (const NiceCandidate *candidate1,
419     const NiceCandidate *candidate2)
420 {
421   g_return_val_if_fail (candidate1 != NULL, FALSE);
422   g_return_val_if_fail (candidate2 != NULL, FALSE);
423
424   return (candidate1->transport == candidate2->transport &&
425       nice_address_equal (&candidate1->addr, &candidate2->addr));
426 }