Imported Upstream version 0.1.17
[platform/upstream/libnice.git] / agent / discovery.c
1 /*
2  * This file is part of the Nice GLib ICE library.
3  *
4  * (C) 2008-2009 Collabora Ltd.
5  *  Contact: Youness Alaoui
6  * (C) 2007-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  *   Youness Alaoui, Collabora Ltd.
26  *   Kai Vehmanen, Nokia
27  *
28  * Alternatively, the contents of this file may be used under the terms of the
29  * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
30  * case the provisions of LGPL are applicable instead of those above. If you
31  * wish to allow use of your version of this file only under the terms of the
32  * LGPL and not to allow others to use your version of this file under the
33  * MPL, indicate your decision by deleting the provisions above and replace
34  * them with the notice and other provisions required by the LGPL. If you do
35  * not delete the provisions above, a recipient may use your version of this
36  * file under either the MPL or the LGPL.
37  */
38
39 /*
40  * @file discovery.c
41  * @brief ICE candidate discovery functions
42  */
43
44 #ifdef HAVE_CONFIG_H
45 # include <config.h>
46 #endif
47
48 #include <glib.h>
49
50 #include <stdlib.h>
51 #include <string.h>
52 #include <errno.h>
53
54 #include "debug.h"
55
56 #include "agent.h"
57 #include "agent-priv.h"
58 #include "component.h"
59 #include "discovery.h"
60 #include "stun/usages/bind.h"
61 #include "stun/usages/turn.h"
62 #include "socket.h"
63
64 /*
65  * Frees the CandidateDiscovery structure pointed to
66  * by 'user data'. Compatible with g_slist_free_full().
67  */
68 static void discovery_free_item (CandidateDiscovery *cand)
69 {
70   if (cand->turn)
71     turn_server_unref (cand->turn);
72
73   g_slice_free (CandidateDiscovery, cand);
74 }
75
76 /*
77  * Frees all discovery related resources for the agent.
78  */
79 void discovery_free (NiceAgent *agent)
80 {
81   g_slist_free_full (agent->discovery_list,
82       (GDestroyNotify) discovery_free_item);
83   agent->discovery_list = NULL;
84   agent->discovery_unsched_items = 0;
85
86   if (agent->discovery_timer_source != NULL) {
87     g_source_destroy (agent->discovery_timer_source);
88     g_source_unref (agent->discovery_timer_source);
89     agent->discovery_timer_source = NULL;
90   }
91 }
92
93 /*
94  * Prunes the list of discovery processes for items related
95  * to stream 'stream_id'.
96  *
97  * @return TRUE on success, FALSE on a fatal error
98  */
99 void discovery_prune_stream (NiceAgent *agent, guint stream_id)
100 {
101   GSList *i;
102
103   for (i = agent->discovery_list; i ; ) {
104     CandidateDiscovery *cand = i->data;
105     GSList *next = i->next;
106
107     if (cand->stream_id == stream_id) {
108       agent->discovery_list = g_slist_remove (agent->discovery_list, cand);
109       discovery_free_item (cand);
110     }
111     i = next;
112   }
113
114   if (agent->discovery_list == NULL) {
115     /* noone using the timer anymore, clean it up */
116     discovery_free (agent);
117   }
118 }
119
120 /*
121  * Prunes the list of discovery processes for items related
122  * to socket @sock.
123  *
124  * @return TRUE on success, FALSE on a fatal error
125  */
126 void discovery_prune_socket (NiceAgent *agent, NiceSocket *sock)
127 {
128   GSList *i;
129
130   for (i = agent->discovery_list; i ; ) {
131     CandidateDiscovery *discovery = i->data;
132     GSList *next = i->next;
133
134     if (discovery->nicesock == sock) {
135       agent->discovery_list = g_slist_remove (agent->discovery_list, discovery);
136       discovery_free_item (discovery);
137     }
138     i = next;
139   }
140
141   if (agent->discovery_list == NULL) {
142     /* noone using the timer anymore, clean it up */
143     discovery_free (agent);
144   }
145 }
146
147 /*
148  * Frees a CandidateRefresh and calls destroy callback if it has been set.
149  */
150 void refresh_free (NiceAgent *agent, CandidateRefresh *cand)
151 {
152   nice_debug ("Agent %p : Freeing candidate refresh %p", agent, cand);
153
154   agent->refresh_list = g_slist_remove (agent->refresh_list, cand);
155
156   if (cand->timer_source != NULL) {
157     g_source_destroy (cand->timer_source);
158     g_clear_pointer (&cand->timer_source, g_source_unref);
159   }
160
161   if (cand->tick_source) {
162     g_source_destroy (cand->tick_source);
163     g_clear_pointer (&cand->tick_source, g_source_unref);
164   }
165
166   if (cand->destroy_source) {
167     g_source_destroy (cand->destroy_source);
168     g_source_unref (cand->destroy_source);
169   }
170
171   if (cand->destroy_cb) {
172     cand->destroy_cb (cand->destroy_cb_data);
173   }
174
175   g_slice_free (CandidateRefresh, cand);
176 }
177
178 static gboolean on_refresh_remove_timeout (NiceAgent *agent,
179     CandidateRefresh *cand)
180 {
181   switch (stun_timer_refresh (&cand->timer)) {
182     case STUN_USAGE_TIMER_RETURN_TIMEOUT:
183       {
184         StunTransactionId id;
185
186         nice_debug ("Agent %p : TURN deallocate for refresh %p timed out",
187             agent, cand);
188
189         stun_message_id (&cand->stun_message, id);
190         stun_agent_forget_transaction (&cand->stun_agent, id);
191
192         refresh_free (agent, cand);
193         break;
194       }
195     case STUN_USAGE_TIMER_RETURN_RETRANSMIT:
196       nice_debug ("Agent %p : Retransmitting TURN deallocate for refresh %p",
197           agent, cand);
198
199       agent_socket_send (cand->nicesock, &cand->server,
200           stun_message_length (&cand->stun_message), (gchar *)cand->stun_buffer);
201
202       G_GNUC_FALLTHROUGH;
203     case STUN_USAGE_TIMER_RETURN_SUCCESS:
204       agent_timeout_add_with_context (agent, &cand->tick_source,
205           "TURN deallocate retransmission", stun_timer_remainder (&cand->timer),
206           (NiceTimeoutLockedCallback) on_refresh_remove_timeout, cand);
207       break;
208     default:
209       break;
210   }
211
212   return G_SOURCE_REMOVE;
213 }
214
215 /*
216  * Closes the port associated with the candidate refresh on the TURN server by
217  * sending a refresh request that has zero lifetime. After a response is
218  * received or the request times out, 'cand' gets freed and 'cb' is called.
219  */
220 static gboolean refresh_remove_async (NiceAgent *agent, gpointer pointer)
221 {
222   uint8_t *username;
223   gsize username_len;
224   uint8_t *password;
225   gsize password_len;
226   size_t buffer_len = 0;
227   CandidateRefresh *cand = (CandidateRefresh *) pointer;
228   StunUsageTurnCompatibility turn_compat = agent_to_turn_compatibility (agent);
229
230   nice_debug ("Agent %p : Sending request to remove TURN allocation "
231       "for refresh %p", agent, cand);
232
233   if (cand->timer_source != NULL) {
234     g_source_destroy (cand->timer_source);
235     g_source_unref (cand->timer_source);
236     cand->timer_source = NULL;
237   }
238
239   g_source_destroy (cand->destroy_source);
240   g_source_unref (cand->destroy_source);
241   cand->destroy_source = NULL;
242
243   username = (uint8_t *)cand->candidate->turn->username;
244   username_len = (size_t) strlen (cand->candidate->turn->username);
245   password = (uint8_t *)cand->candidate->turn->password;
246   password_len = (size_t) strlen (cand->candidate->turn->password);
247
248   if (turn_compat == STUN_USAGE_TURN_COMPATIBILITY_MSN ||
249       turn_compat == STUN_USAGE_TURN_COMPATIBILITY_OC2007) {
250     username = cand->candidate->turn->decoded_username;
251     password = cand->candidate->turn->decoded_password;
252     username_len = cand->candidate->turn->decoded_username_len;
253     password_len = cand->candidate->turn->decoded_password_len;
254   }
255
256   buffer_len = stun_usage_turn_create_refresh (&cand->stun_agent,
257       &cand->stun_message,  cand->stun_buffer, sizeof(cand->stun_buffer),
258       cand->stun_resp_msg.buffer == NULL ? NULL : &cand->stun_resp_msg, 0,
259       username, username_len,
260       password, password_len,
261       agent_to_turn_compatibility (agent));
262
263   if (buffer_len > 0) {
264     agent_socket_send (cand->nicesock, &cand->server, buffer_len,
265         (gchar *)cand->stun_buffer);
266
267     stun_timer_start (&cand->timer, agent->stun_initial_timeout,
268         agent->stun_max_retransmissions);
269
270     agent_timeout_add_with_context (agent, &cand->tick_source,
271         "TURN deallocate retransmission", stun_timer_remainder (&cand->timer),
272         (NiceTimeoutLockedCallback) on_refresh_remove_timeout, cand);
273   }
274   return G_SOURCE_REMOVE;
275 }
276
277 typedef struct {
278   NiceAgent *agent;
279   gpointer user_data;
280   guint items_to_free;
281   NiceTimeoutLockedCallback cb;
282 } RefreshPruneAsyncData;
283
284 static void on_refresh_removed (RefreshPruneAsyncData *data)
285 {
286   if (data->items_to_free == 0 || --(data->items_to_free) == 0) {
287     GSource *timeout_source = NULL;
288     agent_timeout_add_with_context (data->agent, &timeout_source,
289         "Async refresh prune", 0, data->cb, data->user_data);
290
291     g_source_unref (timeout_source);
292     g_free (data);
293   }
294 }
295
296 static void refresh_prune_async (NiceAgent *agent, GSList *refreshes,
297   NiceTimeoutLockedCallback function, gpointer user_data)
298 {
299   RefreshPruneAsyncData *data = g_new0 (RefreshPruneAsyncData, 1);
300   GSList *it;
301   guint timeout = 0;
302
303   data->agent = agent;
304   data->user_data = user_data;
305   data->cb = function;
306
307   for (it = refreshes; it; it = it->next) {
308     CandidateRefresh *cand = it->data;
309
310     if (cand->disposing)
311       continue;
312
313     timeout += agent->timer_ta;
314     cand->disposing = TRUE;
315     cand->destroy_cb = (GDestroyNotify) on_refresh_removed;
316     cand->destroy_cb_data = data;
317
318     agent_timeout_add_with_context(agent, &cand->destroy_source,
319         "TURN refresh remove async", timeout, refresh_remove_async, cand);
320
321     ++data->items_to_free;
322   }
323
324   if (data->items_to_free == 0) {
325     /* Stream doesn't have any refreshes to remove. Invoke our callback once to
326      * schedule client's callback function. */
327     on_refresh_removed (data);
328   }
329 }
330
331 void refresh_prune_agent_async (NiceAgent *agent,
332     NiceTimeoutLockedCallback function, gpointer user_data)
333 {
334   refresh_prune_async (agent, agent->refresh_list, function, user_data);
335 }
336
337 /*
338  * Removes the candidate refreshes related to 'stream' and asynchronously
339  * closes the associated port allocations on TURN server. Invokes 'function'
340  * when the process finishes.
341  */
342 void refresh_prune_stream_async (NiceAgent *agent, NiceStream *stream,
343     NiceTimeoutLockedCallback function)
344 {
345   GSList *refreshes = NULL;
346   GSList *i;
347
348   for (i = agent->refresh_list; i ; i = i->next) {
349     CandidateRefresh *cand = i->data;
350
351     /* Don't free the candidate refresh to the currently selected local candidate
352      * unless the whole pair is being destroyed.
353      */
354     if (cand->stream_id == stream->id) {
355       refreshes = g_slist_append (refreshes, cand);
356     }
357   }
358
359   refresh_prune_async (agent, refreshes, function, stream);
360   g_slist_free (refreshes);
361 }
362
363 /*
364  * Removes the candidate refreshes related to 'candidate'. The function does not
365  * close any associated port allocations on TURN server. Its purpose is in
366  * situations when an error is detected in socket communication that prevents
367  * sending more requests to the server.
368  */
369 void refresh_prune_candidate (NiceAgent *agent, NiceCandidate *candidate)
370 {
371   GSList *i;
372
373   for (i = agent->refresh_list; i;) {
374     GSList *next = i->next;
375     CandidateRefresh *refresh = i->data;
376
377     if (refresh->candidate == candidate) {
378       refresh_free(agent, refresh);
379     }
380
381     i = next;
382   }
383 }
384
385 /*
386  * Removes the candidate refreshes related to 'candidate' and asynchronously
387  * closes the associated port allocations on TURN server. Invokes 'function'
388  * when the process finishes.
389  */
390 void refresh_prune_candidate_async (NiceAgent *agent, NiceCandidate *candidate,
391     NiceTimeoutLockedCallback function)
392 {
393   GSList *refreshes = NULL;
394   GSList *i;
395
396   for (i = agent->refresh_list; i; i = i->next) {
397     CandidateRefresh *refresh = i->data;
398
399     if (refresh->candidate == candidate) {
400       refreshes = g_slist_append (refreshes, refresh);
401     }
402   }
403
404   refresh_prune_async (agent, refreshes, function, candidate);
405   g_slist_free (refreshes);
406 }
407
408 /*
409  * Adds a new local candidate. Implements the candidate pruning
410  * defined in ICE spec section 4.1.3 "Eliminating Redundant
411  * Candidates" (ID-19).
412  */
413 static gboolean priv_add_local_candidate_pruned (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *candidate)
414 {
415   GSList *i;
416
417   g_assert (candidate != NULL);
418
419   for (i = component->local_candidates; i ; i = i->next) {
420     NiceCandidate *c = i->data;
421
422     if (nice_address_equal (&c->base_addr, &candidate->base_addr) &&
423         nice_address_equal (&c->addr, &candidate->addr) &&
424         c->transport == candidate->transport) {
425       nice_debug ("Candidate %p (component-id %u) redundant, ignoring.", candidate, component->id);
426       return FALSE;
427     }
428   }
429
430   component->local_candidates = g_slist_append (component->local_candidates,
431       candidate);
432   conn_check_add_for_local_candidate(agent, stream_id, component, candidate);
433
434   return TRUE;
435 }
436
437 static guint priv_highest_remote_foundation (NiceComponent *component)
438 {
439   GSList *i;
440   guint highest = 1;
441   gchar foundation[NICE_CANDIDATE_MAX_FOUNDATION];
442
443   for (highest = 1;; highest++) {
444     gboolean taken = FALSE;
445
446     g_snprintf (foundation, NICE_CANDIDATE_MAX_FOUNDATION, "remote%u",
447         highest);
448     for (i = component->remote_candidates; i; i = i->next) {
449       NiceCandidate *cand = i->data;
450       if (strncmp (foundation, cand->foundation,
451               NICE_CANDIDATE_MAX_FOUNDATION) == 0) {
452         taken = TRUE;
453         break;
454       }
455     }
456     if (!taken)
457       return highest;
458   }
459
460   g_return_val_if_reached (highest);
461 }
462
463 /* From RFC 5245 section 4.1.3:
464  *
465  *   for reflexive and relayed candidates, the STUN or TURN servers
466  *   used to obtain them have the same IP address.
467  */
468 static gboolean
469 priv_compare_turn_servers (TurnServer *turn1, TurnServer *turn2)
470 {
471   if (turn1 == turn2)
472     return TRUE;
473   if (turn1 == NULL || turn2 == NULL)
474     return FALSE;
475
476   return nice_address_equal_no_port (&turn1->server, &turn2->server);
477 }
478
479 /*
480  * Assings a foundation to the candidate.
481  *
482  * Implements the mechanism described in ICE sect
483  * 4.1.1.3 "Computing Foundations" (ID-19).
484  */
485 static void priv_assign_foundation (NiceAgent *agent, NiceCandidate *candidate)
486 {
487   GSList *i, *j, *k;
488
489   for (i = agent->streams; i; i = i->next) {
490     NiceStream *stream = i->data;
491     for (j = stream->components; j; j = j->next) {
492       NiceComponent *component = j->data;
493       for (k = component->local_candidates; k; k = k->next) {
494         NiceCandidate *n = k->data;
495
496         /* note: candidate must not on the local candidate list */
497         g_assert (candidate != n);
498
499         if (candidate->type == n->type &&
500             candidate->transport == n->transport &&
501             nice_address_equal_no_port (&candidate->base_addr, &n->base_addr) &&
502             (candidate->type != NICE_CANDIDATE_TYPE_RELAYED ||
503                 priv_compare_turn_servers (candidate->turn, n->turn)) &&
504             !(agent->compatibility == NICE_COMPATIBILITY_GOOGLE &&
505                 n->type == NICE_CANDIDATE_TYPE_RELAYED)) {
506           /* note: currently only one STUN server per stream at a
507            *       time is supported, so there is no need to check
508            *       for candidates that would otherwise share the
509            *       foundation, but have different STUN servers */
510           g_strlcpy (candidate->foundation, n->foundation,
511               NICE_CANDIDATE_MAX_FOUNDATION);
512           if (n->username) {
513             g_free (candidate->username);
514             candidate->username = g_strdup (n->username);
515           }
516           if (n->password) {
517             g_free (candidate->password);
518             candidate->password = g_strdup (n->password);
519           }
520           return;
521         }
522       }
523     }
524   }
525
526   g_snprintf (candidate->foundation, NICE_CANDIDATE_MAX_FOUNDATION,
527       "%u", agent->next_candidate_id++);
528 }
529
530 static void priv_assign_remote_foundation (NiceAgent *agent, NiceCandidate *candidate)
531 {
532   GSList *i, *j, *k;
533   guint next_remote_id;
534   NiceComponent *component = NULL;
535
536   for (i = agent->streams; i; i = i->next) {
537     NiceStream *stream = i->data;
538     for (j = stream->components; j; j = j->next) {
539       NiceComponent *c = j->data;
540
541       if (c->id == candidate->component_id)
542         component = c;
543
544       for (k = c->remote_candidates; k; k = k->next) {
545         NiceCandidate *n = k->data;
546
547         /* note: candidate must not on the remote candidate list */
548         g_assert (candidate != n);
549
550         if (candidate->type == n->type &&
551             candidate->transport == n->transport &&
552             candidate->stream_id == n->stream_id &&
553             nice_address_equal_no_port (&candidate->addr, &n->addr)) {
554           /* note: No need to check for STUN/TURN servers, as these candidate
555            * will always be peer reflexive, never relayed or serve reflexive.
556            */
557           g_strlcpy (candidate->foundation, n->foundation,
558               NICE_CANDIDATE_MAX_FOUNDATION);
559           if (n->username) {
560             g_free (candidate->username);
561             candidate->username = g_strdup (n->username);
562           }
563           if (n->password) {
564             g_free (candidate->password);
565             candidate->password = g_strdup (n->password);
566           }
567           return;
568         }
569       }
570     }
571   }
572
573   if (component) {
574     next_remote_id = priv_highest_remote_foundation (component);
575     g_snprintf (candidate->foundation, NICE_CANDIDATE_MAX_FOUNDATION,
576         "remote%u", next_remote_id);
577   }
578 }
579
580
581 static
582 void priv_generate_candidate_credentials (NiceAgent *agent,
583     NiceCandidate *candidate)
584 {
585
586   if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
587       agent->compatibility == NICE_COMPATIBILITY_OC2007) {
588     guchar username[32];
589     guchar password[16];
590
591     g_free (candidate->username);
592     g_free (candidate->password);
593
594     nice_rng_generate_bytes (agent->rng, 32, (gchar *)username);
595     nice_rng_generate_bytes (agent->rng, 16, (gchar *)password);
596
597     candidate->username = g_base64_encode (username, 32);
598     candidate->password = g_base64_encode (password, 16);
599
600   } else if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
601     gchar username[16];
602
603     g_free (candidate->username);
604     g_free (candidate->password);
605     candidate->password = NULL;
606
607     nice_rng_generate_bytes_print (agent->rng, 16, (gchar *)username);
608
609     candidate->username = g_strndup (username, 16);
610   }
611
612
613 }
614
615 static gboolean
616 priv_local_host_candidate_duplicate_port (NiceAgent *agent,
617   NiceCandidate *candidate)
618 {
619   GSList *i, *j, *k;
620
621   if (candidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE)
622     return FALSE;
623
624   for (i = agent->streams; i; i = i->next) {
625     NiceStream *stream = i->data;
626
627     for (j = stream->components; j; j = j->next) {
628       NiceComponent *component = j->data;
629
630       for (k = component->local_candidates; k; k = k->next) {
631         NiceCandidate *c = k->data;
632
633         if (candidate->transport == c->transport &&
634             nice_address_ip_version (&candidate->addr) ==
635             nice_address_ip_version (&c->addr) &&
636             nice_address_get_port (&candidate->addr) ==
637             nice_address_get_port (&c->addr))
638           return TRUE;
639       }
640     }
641   }
642   return FALSE;
643 }
644
645 /*
646  * Creates a local host candidate for 'component_id' of stream
647  * 'stream_id'.
648  *
649  * @return pointer to the created candidate, or NULL on error
650  */
651 HostCandidateResult discovery_add_local_host_candidate (
652   NiceAgent *agent,
653   guint stream_id,
654   guint component_id,
655   NiceAddress *address,
656   NiceCandidateTransport transport,
657   NiceCandidate **outcandidate)
658 {
659   NiceCandidate *candidate;
660   NiceComponent *component;
661   NiceStream *stream;
662   NiceSocket *nicesock = NULL;
663   HostCandidateResult res = HOST_CANDIDATE_FAILED;
664
665   if (!agent_find_component (agent, stream_id, component_id, &stream, &component))
666     return res;
667
668   candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_HOST);
669   candidate->transport = transport;
670   candidate->stream_id = stream_id;
671   candidate->component_id = component_id;
672   candidate->addr = *address;
673   candidate->base_addr = *address;
674   if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
675     candidate->priority = nice_candidate_jingle_priority (candidate);
676   } else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
677              agent->compatibility == NICE_COMPATIBILITY_OC2007)  {
678     candidate->priority = nice_candidate_msn_priority (candidate);
679   } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
680     candidate->priority =  nice_candidate_ms_ice_priority (candidate,
681         agent->reliable, FALSE);
682   } else {
683     candidate->priority = nice_candidate_ice_priority (candidate,
684         agent->reliable, FALSE);
685   }
686
687   priv_generate_candidate_credentials (agent, candidate);
688   priv_assign_foundation (agent, candidate);
689
690   /* note: candidate username and password are left NULL as stream
691      level ufrag/password are used */
692   if (transport == NICE_CANDIDATE_TRANSPORT_UDP) {
693     nicesock = nice_udp_bsd_socket_new (address);
694   } else if (transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE) {
695     nicesock = nice_tcp_active_socket_new (agent->main_context, address);
696   } else if (transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE) {
697     nicesock = nice_tcp_passive_socket_new (agent->main_context, address);
698   } else {
699     /* TODO: Add TCP-SO */
700   }
701   if (!nicesock) {
702     res = HOST_CANDIDATE_CANT_CREATE_SOCKET;
703     goto errors;
704   }
705
706   candidate->sockptr = nicesock;
707   candidate->addr = nicesock->addr;
708   candidate->base_addr = nicesock->addr;
709
710   if (priv_local_host_candidate_duplicate_port (agent, candidate)) {
711     res = HOST_CANDIDATE_DUPLICATE_PORT;
712     goto errors;
713   }
714
715   if (!priv_add_local_candidate_pruned (agent, stream_id, component,
716           candidate)) {
717     res = HOST_CANDIDATE_REDUNDANT;
718     goto errors;
719   }
720
721   _priv_set_socket_tos (agent, nicesock, stream->tos);
722   nice_component_attach_socket (component, nicesock);
723
724   *outcandidate = candidate;
725
726   return HOST_CANDIDATE_SUCCESS;
727
728 errors:
729   nice_candidate_free (candidate);
730   if (nicesock)
731     nice_socket_free (nicesock);
732   return res;
733 }
734
735 /*
736  * Creates a server reflexive candidate for 'component_id' of stream
737  * 'stream_id'.
738  *
739  * @return pointer to the created candidate, or NULL on error
740  */
741 NiceCandidate*
742 discovery_add_server_reflexive_candidate (
743   NiceAgent *agent,
744   guint stream_id,
745   guint component_id,
746   NiceAddress *address,
747   NiceCandidateTransport transport,
748   NiceSocket *base_socket,
749   gboolean nat_assisted)
750 {
751   NiceCandidate *candidate;
752   NiceComponent *component;
753   NiceStream *stream;
754   gboolean result = FALSE;
755
756   if (!agent_find_component (agent, stream_id, component_id, &stream, &component))
757     return NULL;
758
759   candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE);
760   candidate->transport = transport;
761   candidate->stream_id = stream_id;
762   candidate->component_id = component_id;
763   candidate->addr = *address;
764
765   /* step: link to the base candidate+socket */
766   candidate->sockptr = base_socket;
767   candidate->base_addr = base_socket->addr;
768
769   if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
770     candidate->priority = nice_candidate_jingle_priority (candidate);
771   } else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
772              agent->compatibility == NICE_COMPATIBILITY_OC2007)  {
773     candidate->priority = nice_candidate_msn_priority (candidate);
774   } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
775     candidate->priority =  nice_candidate_ms_ice_priority (candidate,
776         agent->reliable, nat_assisted);
777   } else {
778     candidate->priority =  nice_candidate_ice_priority (candidate,
779         agent->reliable, nat_assisted);
780   }
781
782   priv_generate_candidate_credentials (agent, candidate);
783   priv_assign_foundation (agent, candidate);
784
785   result = priv_add_local_candidate_pruned (agent, stream_id, component, candidate);
786   if (result) {
787     agent_signal_new_candidate (agent, candidate);
788   }
789   else {
790     /* error: duplicate candidate */
791     nice_candidate_free (candidate), candidate = NULL;
792   }
793
794   return candidate;
795 }
796
797 /*
798  * Creates a server reflexive candidate for 'component_id' of stream
799  * 'stream_id' for each TCP_PASSIVE and TCP_ACTIVE candidates for each
800  * base address.
801  *
802  * @return pointer to the created candidate, or NULL on error
803  */
804 void
805 discovery_discover_tcp_server_reflexive_candidates (
806   NiceAgent *agent,
807   guint stream_id,
808   guint component_id,
809   NiceAddress *address,
810   NiceSocket *base_socket)
811 {
812   NiceComponent *component;
813   NiceStream *stream;
814   NiceAddress base_addr = base_socket->addr;
815   GSList *i;
816
817   if (!agent_find_component (agent, stream_id, component_id, &stream, &component))
818     return;
819
820   nice_address_set_port (&base_addr, 0);
821   for (i = component->local_candidates; i; i = i ->next) {
822     NiceCandidate *c = i->data;
823     NiceAddress caddr;
824
825     caddr = c->addr;
826     nice_address_set_port (&caddr, 0);
827     if (agent->force_relay == FALSE &&
828         c->transport != NICE_CANDIDATE_TRANSPORT_UDP &&
829         c->type == NICE_CANDIDATE_TYPE_HOST &&
830         nice_address_equal (&base_addr, &caddr)) {
831       nice_address_set_port (address, nice_address_get_port (&c->addr));
832       discovery_add_server_reflexive_candidate (
833           agent,
834           stream_id,
835           component_id,
836           address,
837           c->transport,
838           c->sockptr,
839           FALSE);
840     }
841   }
842 }
843
844 /*
845  * Creates a server reflexive candidate for 'component_id' of stream
846  * 'stream_id'.
847  *
848  * @return pointer to the created candidate, or NULL on error
849  */
850 NiceCandidate*
851 discovery_add_relay_candidate (
852   NiceAgent *agent,
853   guint stream_id,
854   guint component_id,
855   NiceAddress *address,
856   NiceCandidateTransport transport,
857   NiceSocket *base_socket,
858   TurnServer *turn)
859 {
860   NiceCandidate *candidate;
861   NiceComponent *component;
862   NiceStream *stream;
863   NiceSocket *relay_socket = NULL;
864
865   if (!agent_find_component (agent, stream_id, component_id, &stream, &component))
866     return NULL;
867
868   candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_RELAYED);
869   candidate->transport = transport;
870   candidate->stream_id = stream_id;
871   candidate->component_id = component_id;
872   candidate->addr = *address;
873   candidate->turn = turn_server_ref (turn);
874
875   /* step: link to the base candidate+socket */
876   relay_socket = nice_udp_turn_socket_new (agent->main_context, address,
877       base_socket, &turn->server,
878       turn->username, turn->password,
879       agent_to_turn_socket_compatibility (agent));
880   if (!relay_socket)
881     goto errors;
882
883   candidate->sockptr = relay_socket;
884   candidate->base_addr = base_socket->addr;
885
886   if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
887     candidate->priority = nice_candidate_jingle_priority (candidate);
888   } else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
889              agent->compatibility == NICE_COMPATIBILITY_OC2007)  {
890     candidate->priority = nice_candidate_msn_priority (candidate);
891   } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
892     candidate->priority =  nice_candidate_ms_ice_priority (candidate,
893         agent->reliable, FALSE);
894   } else {
895     candidate->priority =  nice_candidate_ice_priority (candidate,
896         agent->reliable, FALSE);
897   }
898
899   priv_generate_candidate_credentials (agent, candidate);
900
901   /* Google uses the turn username as the candidate username */
902   if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
903     g_free (candidate->username);
904     candidate->username = g_strdup (turn->username);
905   }
906
907   priv_assign_foundation (agent, candidate);
908
909   if (!priv_add_local_candidate_pruned (agent, stream_id, component, candidate))
910     goto errors;
911
912   nice_component_attach_socket (component, relay_socket);
913   agent_signal_new_candidate (agent, candidate);
914
915   return candidate;
916
917 errors:
918   nice_candidate_free (candidate);
919   if (relay_socket)
920     nice_socket_free (relay_socket);
921   return NULL;
922 }
923
924 /*
925  * Creates a peer reflexive candidate for 'component_id' of stream
926  * 'stream_id'.
927  *
928  * @return pointer to the created candidate, or NULL on error
929  */
930 NiceCandidate*
931 discovery_add_peer_reflexive_candidate (
932   NiceAgent *agent,
933   guint stream_id,
934   guint component_id,
935   guint32 priority,
936   NiceAddress *address,
937   NiceSocket *base_socket,
938   NiceCandidate *local,
939   NiceCandidate *remote)
940 {
941   NiceCandidate *candidate;
942   NiceComponent *component;
943   NiceStream *stream;
944   gboolean result;
945
946   if (!agent_find_component (agent, stream_id, component_id, &stream, &component))
947     return NULL;
948
949   candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_PEER_REFLEXIVE);
950   if (local)
951     candidate->transport = local->transport;
952   else if (remote)
953     candidate->transport = conn_check_match_transport (remote->transport);
954   else {
955     if (base_socket->type == NICE_SOCKET_TYPE_UDP_BSD ||
956         base_socket->type == NICE_SOCKET_TYPE_UDP_TURN)
957       candidate->transport = NICE_CANDIDATE_TRANSPORT_UDP;
958     else
959       candidate->transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
960   }
961   candidate->stream_id = stream_id;
962   candidate->component_id = component_id;
963   candidate->addr = *address;
964   candidate->sockptr = base_socket;
965   candidate->base_addr = base_socket->addr;
966   /* We don't ensure priority uniqueness in this case, since the
967    * discovered candidate receives the same priority than its
968    * parent pair, by design, RFC 5245, sect 7.1.3.2.1.
969    * Discovering Peer Reflexive Candidates (the priority from the
970    * STUN Request)
971    */
972   candidate->priority = priority;
973   priv_assign_foundation (agent, candidate);
974
975   if ((agent->compatibility == NICE_COMPATIBILITY_MSN ||
976        agent->compatibility == NICE_COMPATIBILITY_OC2007) &&
977       remote && local) {
978     guchar *new_username = NULL;
979     guchar *decoded_local = NULL;
980     guchar *decoded_remote = NULL;
981     gsize local_size;
982     gsize remote_size;
983     g_free(candidate->username);
984     g_free(candidate->password);
985
986     decoded_local = g_base64_decode (local->username, &local_size);
987     decoded_remote = g_base64_decode (remote->username, &remote_size);
988
989     new_username = g_new0(guchar, local_size + remote_size);
990     memcpy(new_username, decoded_local, local_size);
991     memcpy(new_username + local_size, decoded_remote, remote_size);
992
993     candidate->username = g_base64_encode (new_username, local_size + remote_size);
994     g_free(new_username);
995     g_free(decoded_local);
996     g_free(decoded_remote);
997
998     candidate->password = g_strdup(local->password);
999   } else if (local) {
1000     g_free(candidate->username);
1001     g_free(candidate->password);
1002
1003     candidate->username = g_strdup(local->username);
1004     candidate->password = g_strdup(local->password);
1005   }
1006
1007   result = priv_add_local_candidate_pruned (agent, stream_id, component, candidate);
1008   if (result != TRUE) {
1009     /* error: memory allocation, or duplicate candidate */
1010     nice_candidate_free (candidate), candidate = NULL;
1011   }
1012
1013   return candidate;
1014 }
1015
1016
1017 /*
1018  * Adds a new peer reflexive candidate to the list of known
1019  * remote candidates. The candidate is however not paired with
1020  * existing local candidates.
1021  *
1022  * See ICE sect 7.2.1.3 "Learning Peer Reflexive Candidates" (ID-19).
1023  *
1024  * @return pointer to the created candidate, or NULL on error
1025  */
1026 NiceCandidate *discovery_learn_remote_peer_reflexive_candidate (
1027   NiceAgent *agent,
1028   NiceStream *stream,
1029   NiceComponent *component,
1030   guint32 priority,
1031   const NiceAddress *remote_address,
1032   NiceSocket *nicesock,
1033   NiceCandidate *local,
1034   NiceCandidate *remote)
1035 {
1036   NiceCandidate *candidate;
1037
1038   candidate = nice_candidate_new (NICE_CANDIDATE_TYPE_PEER_REFLEXIVE);
1039
1040   candidate->addr = *remote_address;
1041   candidate->base_addr = *remote_address;
1042   if (remote)
1043     candidate->transport = remote->transport;
1044   else if (local)
1045     candidate->transport = conn_check_match_transport (local->transport);
1046   else {
1047     if (nicesock->type == NICE_SOCKET_TYPE_UDP_BSD ||
1048         nicesock->type == NICE_SOCKET_TYPE_UDP_TURN)
1049       candidate->transport = NICE_CANDIDATE_TRANSPORT_UDP;
1050     else
1051       candidate->transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE;
1052   }
1053   candidate->sockptr = nicesock;
1054   candidate->stream_id = stream->id;
1055   candidate->component_id = component->id;
1056
1057   /* if the check didn't contain the PRIORITY attribute, then the priority will
1058    * be 0, which is invalid... */
1059   if (priority != 0) {
1060     candidate->priority = priority;
1061   } else if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
1062     candidate->priority = nice_candidate_jingle_priority (candidate);
1063   } else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
1064              agent->compatibility == NICE_COMPATIBILITY_OC2007)  {
1065     candidate->priority = nice_candidate_msn_priority (candidate);
1066   } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
1067     candidate->priority =  nice_candidate_ms_ice_priority (candidate,
1068         agent->reliable, FALSE);
1069   } else {
1070     candidate->priority = nice_candidate_ice_priority (candidate,
1071         agent->reliable, FALSE);
1072   }
1073
1074   priv_assign_remote_foundation (agent, candidate);
1075
1076   if ((agent->compatibility == NICE_COMPATIBILITY_MSN ||
1077        agent->compatibility == NICE_COMPATIBILITY_OC2007) &&
1078       remote && local) {
1079     guchar *new_username = NULL;
1080     guchar *decoded_local = NULL;
1081     guchar *decoded_remote = NULL;
1082     gsize local_size;
1083     gsize remote_size;
1084     g_free(candidate->username);
1085     g_free (candidate->password);
1086
1087     decoded_local = g_base64_decode (local->username, &local_size);
1088     decoded_remote = g_base64_decode (remote->username, &remote_size);
1089
1090     new_username = g_new0(guchar, local_size + remote_size);
1091     memcpy(new_username, decoded_remote, remote_size);
1092     memcpy(new_username + remote_size, decoded_local, local_size);
1093
1094     candidate->username = g_base64_encode (new_username, local_size + remote_size);
1095     g_free(new_username);
1096     g_free(decoded_local);
1097     g_free(decoded_remote);
1098
1099     candidate->password = g_strdup(remote->password);
1100   } else if (remote) {
1101     g_free (candidate->username);
1102     g_free (candidate->password);
1103     candidate->username = g_strdup(remote->username);
1104     candidate->password = g_strdup(remote->password);
1105   }
1106
1107   /* note: candidate username and password are left NULL as stream 
1108      level ufrag/password are used */
1109
1110   component->remote_candidates = g_slist_append (component->remote_candidates,
1111       candidate);
1112
1113   agent_signal_new_remote_candidate (agent, candidate);
1114
1115   return candidate;
1116 }
1117
1118 /* 
1119  * Timer callback that handles scheduling new candidate discovery
1120  * processes (paced by the Ta timer), and handles running of the 
1121  * existing discovery processes.
1122  *
1123  * This function is designed for the g_timeout_add() interface.
1124  *
1125  * @return will return FALSE when no more pending timers.
1126  */
1127 static gboolean priv_discovery_tick_unlocked (NiceAgent *agent)
1128 {
1129   CandidateDiscovery *cand;
1130   GSList *i;
1131   int not_done = 0; /* note: track whether to continue timer */
1132   int need_pacing = 0;
1133   size_t buffer_len = 0;
1134
1135   {
1136     static int tick_counter = 0;
1137     if (tick_counter++ % 50 == 0)
1138       nice_debug ("Agent %p : discovery tick #%d with list %p (1)", agent, tick_counter, agent->discovery_list);
1139   }
1140
1141   for (i = agent->discovery_list; i ; i = i->next) {
1142     cand = i->data;
1143
1144     if (cand->pending != TRUE) {
1145       cand->pending = TRUE;
1146
1147       if (agent->discovery_unsched_items)
1148         --agent->discovery_unsched_items;
1149
1150       if (nice_debug_is_enabled ()) {
1151         gchar tmpbuf[INET6_ADDRSTRLEN];
1152         nice_address_to_string (&cand->server, tmpbuf);
1153         nice_debug ("Agent %p : discovery - scheduling cand type %u addr %s.",
1154             agent, cand->type, tmpbuf);
1155       }
1156       if (nice_address_is_valid (&cand->server) &&
1157           (cand->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE ||
1158               cand->type == NICE_CANDIDATE_TYPE_RELAYED)) {
1159         NiceComponent *component;
1160
1161         if (agent_find_component (agent, cand->stream_id,
1162                 cand->component_id, NULL, &component) &&
1163             (component->state == NICE_COMPONENT_STATE_DISCONNECTED ||
1164                 component->state == NICE_COMPONENT_STATE_FAILED))
1165           agent_signal_component_state_change (agent,
1166                                                cand->stream_id,
1167                                                cand->component_id,
1168                                                NICE_COMPONENT_STATE_GATHERING);
1169
1170         if (cand->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE) {
1171           buffer_len = stun_usage_bind_create (&cand->stun_agent,
1172               &cand->stun_message, cand->stun_buffer, sizeof(cand->stun_buffer));
1173         } else if (cand->type == NICE_CANDIDATE_TYPE_RELAYED) {
1174           uint8_t *username = (uint8_t *)cand->turn->username;
1175           gsize username_len = strlen (cand->turn->username);
1176           uint8_t *password = (uint8_t *)cand->turn->password;
1177           gsize password_len = strlen (cand->turn->password);
1178           StunUsageTurnCompatibility turn_compat =
1179               agent_to_turn_compatibility (agent);
1180
1181           if (turn_compat == STUN_USAGE_TURN_COMPATIBILITY_MSN ||
1182               turn_compat == STUN_USAGE_TURN_COMPATIBILITY_OC2007) {
1183             username = cand->turn->decoded_username;
1184             password = cand->turn->decoded_password;
1185             username_len = cand->turn->decoded_username_len;
1186             password_len = cand->turn->decoded_password_len;
1187           }
1188
1189           buffer_len = stun_usage_turn_create (&cand->stun_agent,
1190               &cand->stun_message,  cand->stun_buffer, sizeof(cand->stun_buffer),
1191               cand->stun_resp_msg.buffer == NULL ? NULL : &cand->stun_resp_msg,
1192               STUN_USAGE_TURN_REQUEST_PORT_NORMAL,
1193               -1, -1,
1194               username, username_len,
1195               password, password_len,
1196               turn_compat);
1197         }
1198
1199         if (buffer_len > 0 &&
1200             agent_socket_send (cand->nicesock, &cand->server, buffer_len,
1201                 (gchar *)cand->stun_buffer) >= 0) {
1202           /* case: success, start waiting for the result */
1203           if (nice_socket_is_reliable (cand->nicesock)) {
1204             stun_timer_start_reliable (&cand->timer, agent->stun_reliable_timeout);
1205           } else {
1206             stun_timer_start (&cand->timer,
1207                 agent->stun_initial_timeout,
1208                 agent->stun_max_retransmissions);
1209           }
1210
1211           cand->next_tick = g_get_monotonic_time ();
1212           ++need_pacing;
1213         } else {
1214           /* case: error in starting discovery, start the next discovery */
1215           nice_debug ("Agent %p : Error starting discovery, skipping the item.",
1216               agent);
1217           cand->done = TRUE;
1218           cand->stun_message.buffer = NULL;
1219           cand->stun_message.buffer_len = 0;
1220           continue;
1221         }
1222       }
1223       else
1224         /* allocate relayed candidates */
1225         g_assert_not_reached ();
1226
1227       ++not_done; /* note: new discovery scheduled */
1228     }
1229
1230     if (need_pacing)
1231       break;
1232
1233     if (cand->done != TRUE) {
1234       gint64 now = g_get_monotonic_time ();
1235
1236       if (cand->stun_message.buffer == NULL) {
1237         nice_debug ("Agent %p : STUN discovery was cancelled, marking discovery done.", agent);
1238         cand->done = TRUE;
1239       }
1240       else if (now >= cand->next_tick) {
1241         switch (stun_timer_refresh (&cand->timer)) {
1242           case STUN_USAGE_TIMER_RETURN_TIMEOUT:
1243             {
1244               /* Time out */
1245               /* case: error, abort processing */
1246               StunTransactionId id;
1247
1248               stun_message_id (&cand->stun_message, id);
1249               stun_agent_forget_transaction (&cand->stun_agent, id);
1250
1251               cand->done = TRUE;
1252               cand->stun_message.buffer = NULL;
1253               cand->stun_message.buffer_len = 0;
1254               nice_debug ("Agent %p : bind discovery timed out, aborting discovery item.", agent);
1255               break;
1256             }
1257           case STUN_USAGE_TIMER_RETURN_RETRANSMIT:
1258             {
1259               /* case: not ready complete, so schedule next timeout */
1260               unsigned int timeout = stun_timer_remainder (&cand->timer);
1261
1262               stun_debug ("STUN transaction retransmitted (timeout %dms).",
1263                   timeout);
1264
1265               /* retransmit */
1266               agent_socket_send (cand->nicesock, &cand->server,
1267                   stun_message_length (&cand->stun_message),
1268                   (gchar *)cand->stun_buffer);
1269
1270               /* note: convert from milli to microseconds for g_time_val_add() */
1271               cand->next_tick = now + (timeout * 1000);
1272
1273               ++not_done; /* note: retry later */
1274               ++need_pacing;
1275               break;
1276             }
1277           case STUN_USAGE_TIMER_RETURN_SUCCESS:
1278             {
1279               unsigned int timeout = stun_timer_remainder (&cand->timer);
1280
1281               cand->next_tick = now + (timeout * 1000);
1282
1283               ++not_done; /* note: retry later */
1284               break;
1285             }
1286           default:
1287             /* Nothing to do. */
1288             break;
1289         }
1290
1291       } else {
1292         ++not_done; /* note: discovery not expired yet */
1293       }
1294     }
1295
1296     if (need_pacing)
1297       break;
1298   }
1299
1300   if (not_done == 0) {
1301     nice_debug ("Agent %p : Candidate gathering FINISHED, stopping discovery timer.", agent);
1302
1303     discovery_free (agent);
1304
1305     agent_gathering_done (agent);
1306
1307     /* note: no pending timers, return FALSE to stop timer */
1308     return FALSE;
1309   }
1310
1311   return TRUE;
1312 }
1313
1314 static gboolean priv_discovery_tick_agent_locked (NiceAgent *agent,
1315     gpointer pointer)
1316 {
1317   gboolean ret;
1318
1319   ret = priv_discovery_tick_unlocked (agent);
1320   if (ret == FALSE) {
1321     if (agent->discovery_timer_source != NULL) {
1322       g_source_destroy (agent->discovery_timer_source);
1323       g_source_unref (agent->discovery_timer_source);
1324       agent->discovery_timer_source = NULL;
1325     }
1326   }
1327
1328   return ret;
1329 }
1330
1331 /*
1332  * Initiates the candidate discovery process by starting
1333  * the necessary timers.
1334  *
1335  * @pre agent->discovery_list != NULL  // unsched discovery items available
1336  */
1337 void discovery_schedule (NiceAgent *agent)
1338 {
1339   g_assert (agent->discovery_list != NULL);
1340
1341   if (agent->discovery_unsched_items > 0) {
1342
1343     if (agent->discovery_timer_source == NULL) {
1344       /* step: run first iteration immediately */
1345       gboolean res = priv_discovery_tick_unlocked (agent);
1346       if (res == TRUE) {
1347         agent_timeout_add_with_context (agent, &agent->discovery_timer_source,
1348             "Candidate discovery tick", agent->timer_ta,
1349             priv_discovery_tick_agent_locked, NULL);
1350       }
1351     }
1352   }
1353 }