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  *   Kai Vehmanen, Nokia
26  *   Youness Alaoui, Collabora Ltd.
27  *   Dafydd Harries, Collabora Ltd.
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 conncheck.c
42  * @brief ICE connectivity checks
43  */
44 
45 #ifdef HAVE_CONFIG_H
46 # include <config.h>
47 #endif
48 
49 #include <errno.h>
50 #include <string.h>
51 
52 #include <glib.h>
53 
54 #include "debug.h"
55 
56 #include "agent.h"
57 #include "agent-priv.h"
58 #include "conncheck.h"
59 #include "discovery.h"
60 #include "stun/stun5389.h"
61 #include "stun/usages/ice.h"
62 #include "stun/usages/bind.h"
63 #include "stun/usages/turn.h"
64 
65 static void priv_update_check_list_failed_components (NiceAgent *agent, NiceStream *stream);
66 static guint priv_prune_pending_checks (NiceAgent *agent, NiceStream *stream, NiceComponent *component);
67 static gboolean priv_schedule_triggered_check (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceSocket *local_socket, NiceCandidate *remote_cand);
68 static void priv_mark_pair_nominated (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceCandidate *localcand, NiceCandidate *remotecand);
69 static size_t priv_create_username (NiceAgent *agent, NiceStream *stream,
70     guint component_id, NiceCandidate *remote, NiceCandidate *local,
71     uint8_t *dest, guint dest_len, gboolean inbound);
72 static size_t priv_get_password (NiceAgent *agent, NiceStream *stream,
73     NiceCandidate *remote, uint8_t **password);
74 static void candidate_check_pair_fail (NiceStream *stream,
75     NiceAgent *agent, CandidateCheckPair *p);
76 static void candidate_check_pair_free (NiceAgent *agent,
77     CandidateCheckPair *pair);
78 static CandidateCheckPair *priv_conn_check_add_for_candidate_pair_matched (
79     NiceAgent *agent, guint stream_id, NiceComponent *component,
80     NiceCandidate *local, NiceCandidate *remote, NiceCheckState initial_state);
81 static gboolean priv_conn_keepalive_tick_agent_locked (NiceAgent *agent,
82     gpointer pointer);
83 
priv_timer_remainder(gint64 timer,gint64 now)84 static gint64 priv_timer_remainder (gint64 timer, gint64 now)
85 {
86   if (now >= timer)
87     return 0;
88 
89   return (timer - now) / 1000;
90 }
91 
92 static gchar
priv_state_to_gchar(NiceCheckState state)93 priv_state_to_gchar (NiceCheckState state)
94 {
95   switch (state) {
96     case NICE_CHECK_WAITING:
97       return 'W';
98     case NICE_CHECK_IN_PROGRESS:
99       return 'I';
100     case NICE_CHECK_SUCCEEDED:
101       return 'S';
102     case NICE_CHECK_FAILED:
103       return 'F';
104     case NICE_CHECK_FROZEN:
105       return 'Z';
106     case NICE_CHECK_DISCOVERED:
107       return 'D';
108     default:
109       g_assert_not_reached ();
110   }
111 }
112 
113 static const gchar *
priv_state_to_string(NiceCheckState state)114 priv_state_to_string (NiceCheckState state)
115 {
116   switch (state) {
117     case NICE_CHECK_WAITING:
118       return "WAITING";
119     case NICE_CHECK_IN_PROGRESS:
120       return "IN_PROGRESS";
121     case NICE_CHECK_SUCCEEDED:
122       return "SUCCEEDED";
123     case NICE_CHECK_FAILED:
124       return "FAILED";
125     case NICE_CHECK_FROZEN:
126       return "FROZEN";
127     case NICE_CHECK_DISCOVERED:
128       return "DISCOVERED";
129     default:
130       g_assert_not_reached ();
131   }
132 }
133 
134 #define SET_PAIR_STATE( a, p, s ) G_STMT_START{\
135   g_assert (p); \
136   p->state = s; \
137   nice_debug ("Agent %p : pair %p state %s (%s)", \
138       a, p, priv_state_to_string (s), G_STRFUNC); \
139 }G_STMT_END
140 
141 static const gchar *
priv_ice_return_to_string(StunUsageIceReturn ice_return)142 priv_ice_return_to_string (StunUsageIceReturn ice_return)
143 {
144   switch (ice_return) {
145     case STUN_USAGE_ICE_RETURN_SUCCESS:
146       return "success";
147     case STUN_USAGE_ICE_RETURN_ERROR:
148       return "error";
149     case STUN_USAGE_ICE_RETURN_INVALID:
150       return "invalid";
151     case STUN_USAGE_ICE_RETURN_ROLE_CONFLICT:
152       return "role conflict";
153     case STUN_USAGE_ICE_RETURN_INVALID_REQUEST:
154       return "invalid request";
155     case STUN_USAGE_ICE_RETURN_INVALID_METHOD:
156       return "invalid method";
157     case STUN_USAGE_ICE_RETURN_MEMORY_ERROR:
158       return "memory error";
159     case STUN_USAGE_ICE_RETURN_INVALID_ADDRESS:
160       return "invalid address";
161     case STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS:
162       return "no mapped address";
163     default:
164       g_assert_not_reached ();
165   }
166 }
167 
168 static const gchar *
priv_socket_type_to_string(NiceSocketType type)169 priv_socket_type_to_string (NiceSocketType type)
170 {
171   switch (type) {
172     case NICE_SOCKET_TYPE_UDP_BSD:
173       return "udp";
174     case NICE_SOCKET_TYPE_TCP_BSD:
175       return "tcp";
176     case NICE_SOCKET_TYPE_PSEUDOSSL:
177       return "ssl";
178     case NICE_SOCKET_TYPE_HTTP:
179       return "http";
180     case NICE_SOCKET_TYPE_SOCKS5:
181       return "socks";
182     case NICE_SOCKET_TYPE_UDP_TURN:
183       return "udp-turn";
184     case NICE_SOCKET_TYPE_UDP_TURN_OVER_TCP:
185       return "tcp-turn";
186     case NICE_SOCKET_TYPE_TCP_ACTIVE:
187       return "tcp-act";
188     case NICE_SOCKET_TYPE_TCP_PASSIVE:
189       return "tcp-pass";
190     case NICE_SOCKET_TYPE_TCP_SO:
191       return "tcp-so";
192     default:
193       g_assert_not_reached ();
194   }
195 }
196 
197 /*
198  * Dump the component list of incoming checks
199  */
200 static void
print_component_incoming_checks(NiceAgent * agent,NiceStream * stream,NiceComponent * component)201 print_component_incoming_checks (NiceAgent *agent, NiceStream *stream,
202   NiceComponent *component)
203 {
204   GList *i;
205 
206   for (i = component->incoming_checks.head; i; i = i->next) {
207     IncomingCheck *icheck = i->data;
208     gchar tmpbuf1[INET6_ADDRSTRLEN] = {0};
209     gchar tmpbuf2[INET6_ADDRSTRLEN] = {0};
210 
211     nice_address_to_string (&icheck->local_socket->addr, tmpbuf1);
212     nice_address_to_string (&icheck->from, tmpbuf2);
213     nice_debug ("Agent %p : *** sc=%d/%d : icheck %p : "
214       "sock %s [%s]:%u > [%s]:%u",
215       agent, stream->id, component->id, icheck,
216       priv_socket_type_to_string (icheck->local_socket->type),
217       tmpbuf1, nice_address_get_port (&icheck->local_socket->addr),
218       tmpbuf2, nice_address_get_port (&icheck->from));
219   }
220 }
221 
222 /*
223  * Dump the conncheck lists of the agent
224  */
225 static void
priv_print_conn_check_lists(NiceAgent * agent,const gchar * where,const gchar * detail)226 priv_print_conn_check_lists (NiceAgent *agent, const gchar *where, const gchar *detail)
227 {
228   GSList *i, *k, *l;
229   guint j, m;
230   gint64 now;
231 
232   if (!nice_debug_is_verbose ())
233     return;
234 
235   now = g_get_monotonic_time ();
236 
237 #define PRIORITY_LEN 32
238 
239   nice_debug ("Agent %p : *** conncheck list DUMP (called from %s%s)",
240       agent, where, detail ? detail : "");
241   nice_debug ("Agent %p : *** agent nomination mode %s, %s",
242       agent, agent->nomination_mode == NICE_NOMINATION_MODE_AGGRESSIVE ?
243       "aggressive" : "regular",
244       agent->controlling_mode ? "controlling" : "controlled");
245   for (i = agent->streams; i ; i = i->next) {
246     NiceStream *stream = i->data;
247     for (j = 1; j <= stream->n_components; j++) {
248       NiceComponent *component;
249       for (k = stream->conncheck_list; k ; k = k->next) {
250         CandidateCheckPair *pair = k->data;
251         if (pair->component_id == j) {
252           gchar local_addr[INET6_ADDRSTRLEN];
253           gchar remote_addr[INET6_ADDRSTRLEN];
254           gchar priority[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE];
255 
256           nice_address_to_string (&pair->local->addr, local_addr);
257           nice_address_to_string (&pair->remote->addr, remote_addr);
258           nice_candidate_pair_priority_to_string (pair->priority, priority);
259 
260           nice_debug ("Agent %p : *** sc=%d/%d : pair %p : "
261               "f=%s t=%s:%s sock=%s "
262               "%s:[%s]:%u > %s:[%s]:%u prio=%s/%08x state=%c%s%s%s%s",
263               agent, pair->stream_id, pair->component_id, pair,
264               pair->foundation,
265               nice_candidate_type_to_string (pair->local->type),
266               nice_candidate_type_to_string (pair->remote->type),
267               priv_socket_type_to_string (pair->sockptr->type),
268               nice_candidate_transport_to_string (pair->local->transport),
269               local_addr, nice_address_get_port (&pair->local->addr),
270               nice_candidate_transport_to_string (pair->remote->transport),
271               remote_addr, nice_address_get_port (&pair->remote->addr),
272               priority, pair->stun_priority,
273               priv_state_to_gchar (pair->state),
274               pair->valid ? "V" : "",
275               pair->nominated ? "N" : "",
276               pair->use_candidate_on_next_check ? "C" : "",
277               g_slist_find (agent->triggered_check_queue, pair) ? "T" : "");
278 
279           for (l = pair->stun_transactions, m = 0; l; l = l->next, m++) {
280             StunTransaction *stun = l->data;
281             nice_debug ("Agent %p : *** sc=%d/%d : pair %p :   "
282                 "stun#=%d timer=%d/%d %" G_GINT64_FORMAT "/%dms buf=%p %s",
283                 agent, pair->stream_id, pair->component_id, pair, m,
284                 stun->timer.retransmissions, stun->timer.max_retransmissions,
285                 stun->timer.delay - priv_timer_remainder (stun->next_tick, now),
286                 stun->timer.delay,
287                 stun->message.buffer,
288                 (m == 0 && pair->retransmit) ? "(R)" : "");
289           }
290         }
291       }
292       if (agent_find_component (agent, stream->id, j, NULL, &component))
293         print_component_incoming_checks (agent, stream, component);
294     }
295   }
296 }
297 
298 /* Add the pair to the triggered checks list, if not already present
299  */
300 static void
priv_add_pair_to_triggered_check_queue(NiceAgent * agent,CandidateCheckPair * pair)301 priv_add_pair_to_triggered_check_queue (NiceAgent *agent, CandidateCheckPair *pair)
302 {
303   g_assert (pair);
304 
305   if (agent->triggered_check_queue == NULL ||
306       g_slist_find (agent->triggered_check_queue, pair) == NULL)
307     agent->triggered_check_queue = g_slist_append (agent->triggered_check_queue, pair);
308 }
309 
310 /* Remove the pair from the triggered checks list
311  */
312 static void
priv_remove_pair_from_triggered_check_queue(NiceAgent * agent,CandidateCheckPair * pair)313 priv_remove_pair_from_triggered_check_queue (NiceAgent *agent, CandidateCheckPair *pair)
314 {
315   g_assert (pair);
316   agent->triggered_check_queue = g_slist_remove (agent->triggered_check_queue, pair);
317 }
318 
319 /* Get the pair from the triggered checks list
320  */
321 static CandidateCheckPair *
priv_get_pair_from_triggered_check_queue(NiceAgent * agent)322 priv_get_pair_from_triggered_check_queue (NiceAgent *agent)
323 {
324   CandidateCheckPair *pair = NULL;
325 
326   if (agent->triggered_check_queue) {
327     pair = (CandidateCheckPair *)agent->triggered_check_queue->data;
328     priv_remove_pair_from_triggered_check_queue (agent, pair);
329   }
330   return pair;
331 }
332 
333 /*
334  * Finds the next connectivity check in WAITING state.
335  */
priv_conn_check_find_next_waiting(GSList * conn_check_list)336 static CandidateCheckPair *priv_conn_check_find_next_waiting (GSList *conn_check_list)
337 {
338   GSList *i;
339 
340   /* note: list is sorted in priority order to first waiting check has
341    *       the highest priority */
342   for (i = conn_check_list; i ; i = i->next) {
343     CandidateCheckPair *p = i->data;
344     if (p->state == NICE_CHECK_WAITING)
345       return p;
346   }
347 
348   return NULL;
349 }
350 
351 /*
352  * Initiates a new connectivity check for a ICE candidate pair.
353  *
354  * @return TRUE on success, FALSE on error
355  */
356 static gboolean
priv_conn_check_initiate(NiceAgent * agent,CandidateCheckPair * pair)357 priv_conn_check_initiate (NiceAgent *agent, CandidateCheckPair *pair)
358 {
359   SET_PAIR_STATE (agent, pair, NICE_CHECK_IN_PROGRESS);
360   if (conn_check_send (agent, pair)) {
361     NiceStream *stream;
362     NiceComponent *component;
363 
364     if (!agent_find_component (agent, pair->stream_id, pair->component_id,
365         &stream, &component)) {
366       nice_debug ("Could not find stream or component in conn_check_initiate");
367       SET_PAIR_STATE (agent, pair, NICE_CHECK_FAILED);
368       return FALSE;
369     }
370     candidate_check_pair_fail (stream, agent, pair);
371     conn_check_update_check_list_state_for_ready (agent, stream, component);
372     return FALSE;
373   }
374   return TRUE;
375 }
376 
377 /*
378  * Unfreezes the next connectivity check in the list. Follows the
379  * algorithm defined in sect 6.1.2.6 (Computing Candidate Pair States)
380  * and sect 6.1.4.2 (Performing Connectivity Checks) of the ICE spec
381  * (RFC8445)
382  *
383  * Note that this algorithm is slightly simplified compared to previous
384  * version of the spec (RFC5245), and this new version is now
385  * idempotent.
386  *
387  * @return TRUE on success, and FALSE if no frozen candidates were found.
388  */
389 static gboolean
priv_conn_check_unfreeze_next(NiceAgent * agent)390 priv_conn_check_unfreeze_next (NiceAgent *agent)
391 {
392   GSList *i, *j;
393   GSList *foundation_list = NULL;
394   gboolean result = FALSE;
395 
396   /* While a pair in state waiting exists, we do nothing */
397   for (i = agent->streams; i ; i = i->next) {
398     NiceStream *s = i->data;
399     for (j = s->conncheck_list; j ; j = j->next) {
400       CandidateCheckPair *p = j->data;
401 
402       if (p->state == NICE_CHECK_WAITING)
403         return TRUE;
404     }
405   }
406 
407   /* When there are no more pairs in waiting state, we unfreeze some
408    * pairs, so that we get a single waiting pair per foundation.
409    */
410   for (i = agent->streams; i ; i = i->next) {
411     NiceStream *s = i->data;
412     for (j = s->conncheck_list; j ; j = j->next) {
413       CandidateCheckPair *p = j->data;
414 
415       if (g_slist_find_custom (foundation_list, p->foundation,
416           (GCompareFunc)strcmp))
417         continue;
418 
419       if (p->state == NICE_CHECK_FROZEN) {
420         nice_debug ("Agent %p : Pair %p with s/c-id %u/%u (%s) unfrozen.",
421             agent, p, p->stream_id, p->component_id, p->foundation);
422         SET_PAIR_STATE (agent, p, NICE_CHECK_WAITING);
423         foundation_list = g_slist_prepend (foundation_list, p->foundation);
424         result = TRUE;
425       }
426     }
427   }
428   g_slist_free (foundation_list);
429 
430   /* We dump the conncheck list when something interesting happened, ie
431    * when we unfroze some pairs.
432    */
433   if (result)
434     priv_print_conn_check_lists (agent, G_STRFUNC, NULL);
435 
436   return result;
437 }
438 
439 /*
440  * Unfreezes the related connectivity check in the list after
441  * check 'success_check' has successfully completed.
442  *
443  * See sect 7.2.5.3.3 (Updating Candidate Pair States) of ICE spec (RFC8445).
444  *
445  * Note that this algorithm is slightly simplified compared to previous
446  * version of the spec (RFC5245)
447  *
448  * @param agent context
449  * @param pair a pair, whose connectivity check has just succeeded
450  *
451  */
452 void
conn_check_unfreeze_related(NiceAgent * agent,CandidateCheckPair * pair)453 conn_check_unfreeze_related (NiceAgent *agent, CandidateCheckPair *pair)
454 {
455   GSList *i, *j;
456   gboolean result = FALSE;
457 
458   g_assert (pair);
459   g_assert (pair->state == NICE_CHECK_SUCCEEDED);
460 
461   for (i = agent->streams; i ; i = i->next) {
462     NiceStream *s = i->data;
463     for (j = s->conncheck_list; j ; j = j->next) {
464       CandidateCheckPair *p = j->data;
465 
466       /* The states for all other Frozen candidates pairs in all
467        * checklists with the same foundation is set to waiting
468        */
469       if (p->state == NICE_CHECK_FROZEN &&
470           strncmp (p->foundation, pair->foundation,
471               NICE_CANDIDATE_PAIR_MAX_FOUNDATION) == 0) {
472         nice_debug ("Agent %p : Unfreezing check %p "
473             "(after successful check %p).", agent, p, pair);
474         SET_PAIR_STATE (agent, p, NICE_CHECK_WAITING);
475         result = TRUE;
476       }
477     }
478   }
479   /* We dump the conncheck list when something interesting happened, ie
480    * when we unfroze some pairs.
481    */
482   if (result)
483     priv_print_conn_check_lists (agent, G_STRFUNC, NULL);
484 }
485 
486 /*
487  * Unfreezes this connectivity check if its foundation is the same than
488  * the foundation of an already succeeded pair.
489  *
490  * See sect 7.2.5.3.3 (Updating Candidate Pair States) of ICE spec (RFC8445).
491  *
492  * @param agent context
493  * @param pair a pair, whose state is frozen
494  *
495  */
496 static void
priv_conn_check_unfreeze_maybe(NiceAgent * agent,CandidateCheckPair * pair)497 priv_conn_check_unfreeze_maybe (NiceAgent *agent, CandidateCheckPair *pair)
498 {
499   GSList *i, *j;
500   gboolean result = FALSE;
501 
502   g_assert (pair);
503   g_assert (pair->state == NICE_CHECK_FROZEN);
504 
505   for (i = agent->streams; i ; i = i->next) {
506     NiceStream *s = i->data;
507     for (j = s->conncheck_list; j ; j = j->next) {
508       CandidateCheckPair *p = j->data;
509 
510       if (p->state == NICE_CHECK_SUCCEEDED &&
511           strncmp (p->foundation, pair->foundation,
512               NICE_CANDIDATE_PAIR_MAX_FOUNDATION) == 0) {
513         nice_debug ("Agent %p : Unfreezing check %p "
514             "(after successful check %p).", agent, pair, p);
515         SET_PAIR_STATE (agent, pair, NICE_CHECK_WAITING);
516         result = TRUE;
517       }
518     }
519   }
520   /* We dump the conncheck list when something interesting happened, ie
521    * when we unfroze some pairs.
522    */
523   if (result)
524     priv_print_conn_check_lists (agent, G_STRFUNC, NULL);
525 }
526 
527 guint
conn_check_stun_transactions_count(NiceAgent * agent)528 conn_check_stun_transactions_count (NiceAgent *agent)
529 {
530   GSList *i, *j;
531   guint count = 0;
532 
533   for (i = agent->streams; i ; i = i->next) {
534     NiceStream *s = i->data;
535     for (j = s->conncheck_list; j ; j = j->next) {
536       CandidateCheckPair *p = j->data;
537 
538       if (p->stun_transactions)
539         count += g_slist_length (p->stun_transactions);
540     }
541   }
542   return count;
543 }
544 
545 /*
546  * Create a new STUN transaction and add it to the list
547  * of ongoing stun transactions of a pair.
548  *
549  * @pair the pair the new stun transaction should be added to.
550  * @return the created stun transaction.
551  */
552 static StunTransaction *
priv_add_stun_transaction(CandidateCheckPair * pair)553 priv_add_stun_transaction (CandidateCheckPair *pair)
554 {
555   StunTransaction *stun = g_slice_new0 (StunTransaction);
556   pair->stun_transactions = g_slist_prepend (pair->stun_transactions, stun);
557   pair->retransmit = TRUE;
558   return stun;
559 }
560 
561 /*
562  * Forget a STUN transaction.
563  *
564  * @data the stun transaction to be forgotten.
565  * @user_data the component contained the concerned stun agent.
566  */
567 static void
priv_forget_stun_transaction(gpointer data,gpointer user_data)568 priv_forget_stun_transaction (gpointer data, gpointer user_data)
569 {
570   StunTransaction *stun = data;
571   NiceComponent *component = user_data;
572   StunTransactionId id;
573 
574   if (stun->message.buffer != NULL) {
575     stun_message_id (&stun->message, id);
576     stun_agent_forget_transaction (&component->stun_agent, id);
577   }
578 }
579 
580 static void
priv_free_stun_transaction(gpointer data)581 priv_free_stun_transaction (gpointer data)
582 {
583   g_slice_free (StunTransaction, data);
584 }
585 
586 /*
587  * Remove a STUN transaction from a pair, and forget it
588  * from the related component stun agent.
589  *
590  * @pair the pair the stun transaction should be removed from.
591  * @stun the stun transaction to be removed.
592  * @component the component containing the stun agent used to
593  * forget the stun transaction.
594  */
595 static void
priv_remove_stun_transaction(CandidateCheckPair * pair,StunTransaction * stun,NiceComponent * component)596 priv_remove_stun_transaction (CandidateCheckPair *pair,
597   StunTransaction *stun, NiceComponent *component)
598 {
599   priv_forget_stun_transaction (stun, component);
600   pair->stun_transactions = g_slist_remove (pair->stun_transactions, stun);
601   priv_free_stun_transaction (stun);
602   if (pair->stun_transactions == NULL)
603     pair->retransmit = FALSE;
604 }
605 
606 /*
607  * Remove all STUN transactions from a pair, and forget them
608  * from the related component stun agent.
609  *
610  * @pair the pair the stun list should be cleared.
611  * @component the component containing the stun agent used to
612  * forget the stun transactions.
613  */
614 static void
priv_free_all_stun_transactions(CandidateCheckPair * pair,NiceComponent * component)615 priv_free_all_stun_transactions (CandidateCheckPair *pair,
616   NiceComponent *component)
617 {
618   if (component)
619     g_slist_foreach (pair->stun_transactions, priv_forget_stun_transaction, component);
620   g_slist_free_full (pair->stun_transactions, priv_free_stun_transaction);
621   pair->stun_transactions = NULL;
622   pair->retransmit = FALSE;
623 }
624 
625 static void
candidate_check_pair_fail(NiceStream * stream,NiceAgent * agent,CandidateCheckPair * p)626 candidate_check_pair_fail (NiceStream *stream, NiceAgent *agent, CandidateCheckPair *p)
627 {
628   NiceComponent *component;
629 
630   component = nice_stream_find_component_by_id (stream, p->component_id);
631   SET_PAIR_STATE (agent, p, NICE_CHECK_FAILED);
632   priv_free_all_stun_transactions (p, component);
633 }
634 
635 /*
636  * Helper function for connectivity check timer callback that
637  * runs through the stream specific part of the state machine.
638  *
639  * @param agent context pointer
640  * @param stream which stream (of the agent)
641  * @return will return TRUE if a new stun request has been sent
642  */
643 static gboolean
priv_conn_check_tick_stream(NiceAgent * agent,NiceStream * stream)644 priv_conn_check_tick_stream (NiceAgent *agent, NiceStream *stream)
645 {
646   gboolean pair_failed = FALSE;
647   GSList *i, *j;
648   unsigned int timeout;
649   gint64 now;
650 
651   now = g_get_monotonic_time ();
652 
653   /* step: process ongoing STUN transactions */
654   for (i = stream->conncheck_list; i ; i = i->next) {
655     CandidateCheckPair *p = i->data;
656     gchar tmpbuf1[INET6_ADDRSTRLEN], tmpbuf2[INET6_ADDRSTRLEN];
657     NiceComponent *component;
658     guint index = 0, remaining = 0;
659 
660     if (p->stun_transactions == NULL)
661       continue;
662 
663     if (!agent_find_component (agent, p->stream_id, p->component_id,
664         NULL, &component))
665       continue;
666 
667     j = p->stun_transactions;
668     while (j) {
669       StunTransaction *stun = j->data;
670       GSList *next = j->next;
671 
672       if (now < stun->next_tick)
673         remaining++;
674       else
675         switch (stun_timer_refresh (&stun->timer)) {
676           case STUN_USAGE_TIMER_RETURN_TIMEOUT:
677 timer_return_timeout:
678             priv_remove_stun_transaction (p, stun, component);
679             break;
680           case STUN_USAGE_TIMER_RETURN_RETRANSMIT:
681             /* case: retransmission stopped, due to the nomination of
682              * a pair with a higher priority than this in-progress pair,
683              * ICE spec, sect 8.1.2 "Updating States", item 2.2
684              */
685             if (!p->retransmit || index > 0)
686               goto timer_return_timeout;
687 
688             /* case: not ready, so schedule a new timeout */
689             timeout = stun_timer_remainder (&stun->timer);
690 
691             nice_debug ("Agent %p :STUN transaction retransmitted on pair %p "
692                 "(timer=%d/%d %d/%dms).",
693                 agent, p,
694                 stun->timer.retransmissions, stun->timer.max_retransmissions,
695                 stun->timer.delay - timeout, stun->timer.delay);
696 
697             agent_socket_send (p->sockptr, &p->remote->addr,
698                 stun_message_length (&stun->message),
699                 (gchar *)stun->buffer);
700 
701             /* note: convert from milli to microseconds for g_time_val_add() */
702             stun->next_tick = now + timeout * 1000;
703 
704             return TRUE;
705           case STUN_USAGE_TIMER_RETURN_SUCCESS:
706             timeout = stun_timer_remainder (&stun->timer);
707             /* note: convert from milli to microseconds for g_time_val_add() */
708             stun->next_tick = now + timeout * 1000;
709             remaining++;
710             break;
711           default:
712             g_assert_not_reached();
713             break;
714         }
715       j = next;
716       index++;
717     }
718 
719     if (remaining == 0) {
720       nice_address_to_string (&p->local->addr, tmpbuf1);
721       nice_address_to_string (&p->remote->addr, tmpbuf2);
722       nice_debug ("Agent %p : Retransmissions failed, giving up on pair %p",
723           agent, p);
724       nice_debug ("Agent %p : Failed pair is [%s]:%u --> [%s]:%u", agent,
725           tmpbuf1, nice_address_get_port (&p->local->addr),
726           tmpbuf2, nice_address_get_port (&p->remote->addr));
727       candidate_check_pair_fail (stream, agent, p);
728       pair_failed = TRUE;
729 
730       /* perform a check if a transition state from connected to
731        * ready can be performed. This may happen here, when the last
732        * in-progress pair has expired its retransmission count
733        * in priv_conn_check_tick_stream(), which is a condition to
734        * make the transition connected to ready.
735        */
736       conn_check_update_check_list_state_for_ready (agent, stream, component);
737     }
738   }
739 
740   if (pair_failed)
741     priv_print_conn_check_lists (agent, G_STRFUNC, ", retransmission failed");
742 
743   return FALSE;
744 }
745 
746 static gboolean
priv_conn_check_ordinary_check(NiceAgent * agent,NiceStream * stream)747 priv_conn_check_ordinary_check (NiceAgent *agent, NiceStream *stream)
748 {
749   CandidateCheckPair *pair;
750   gboolean stun_sent = FALSE;
751 
752   /* step: perform an ordinary check, sec 6.1.4.2 point 3. (Performing
753    * Connectivity Checks) of ICE spec (RFC8445)
754    * note: This code is executed when the triggered checks list is
755    * empty, and when no STUN message has been sent (pacing constraint)
756    */
757   pair = priv_conn_check_find_next_waiting (stream->conncheck_list);
758   if (pair == NULL) {
759     /* step: there is no candidate in waiting state, try to unfreeze
760      * some pairs and retry, sect 6.1.4.2 point 2. (Performing Connectivity
761      * Checks) of ICE spec (RFC8445)
762      */
763     priv_conn_check_unfreeze_next (agent);
764     pair = priv_conn_check_find_next_waiting (stream->conncheck_list);
765   }
766 
767   if (pair) {
768     stun_sent = priv_conn_check_initiate (agent, pair);
769     priv_print_conn_check_lists (agent, G_STRFUNC,
770         ", initiated an ordinary connection check");
771   }
772   return stun_sent;
773 }
774 
775 static gboolean
priv_conn_check_triggered_check(NiceAgent * agent,NiceStream * stream)776 priv_conn_check_triggered_check (NiceAgent *agent, NiceStream *stream)
777 {
778   CandidateCheckPair *pair;
779   gboolean stun_sent = FALSE;
780 
781   /* step: perform a test from the triggered checks list,
782    * sect 6.1.4.2 point 1. (Performing Connectivity Checks) of ICE
783    * spec (RFC8445)
784    */
785   pair = priv_get_pair_from_triggered_check_queue (agent);
786 
787   if (pair) {
788     stun_sent = priv_conn_check_initiate (agent, pair);
789     priv_print_conn_check_lists (agent, G_STRFUNC,
790         ", initiated a connection check from triggered check list");
791   }
792   return stun_sent;
793 }
794 
795 
796 static gboolean
priv_conn_check_tick_stream_nominate(NiceAgent * agent,NiceStream * stream)797 priv_conn_check_tick_stream_nominate (NiceAgent *agent, NiceStream *stream)
798 {
799   gboolean keep_timer_going = FALSE;
800   /* s_xxx counters are stream-wide */
801   guint s_inprogress = 0;
802   guint s_succeeded = 0;
803   guint s_discovered = 0;
804   guint s_nominated = 0;
805   guint s_waiting_for_nomination = 0;
806   guint s_valid = 0;
807   guint s_frozen = 0;
808   guint s_waiting = 0;
809   CandidateCheckPair *other_stream_pair = NULL;
810   GSList *i, *j;
811 
812   /* Search for a nominated pair (or selected to be nominated pair)
813    * from another stream.
814    */
815   for (i = agent->streams; i ; i = i->next) {
816     NiceStream *s = i->data;
817     if (s->id == stream->id)
818       continue;
819     for (j = s->conncheck_list; j ; j = j->next) {
820       CandidateCheckPair *p = j->data;
821       if (p->nominated || (p->use_candidate_on_next_check &&
822           p->state != NICE_CHECK_FAILED)) {
823         other_stream_pair = p;
824         break;
825       }
826     }
827     if (other_stream_pair)
828       break;
829   }
830 
831   /* we compute some stream-wide counter values */
832   for (i = stream->conncheck_list; i ; i = i->next) {
833     CandidateCheckPair *p = i->data;
834     if (p->state == NICE_CHECK_FROZEN)
835       s_frozen++;
836     else if (p->state == NICE_CHECK_IN_PROGRESS)
837       s_inprogress++;
838     else if (p->state == NICE_CHECK_WAITING)
839       s_waiting++;
840     else if (p->state == NICE_CHECK_SUCCEEDED)
841       s_succeeded++;
842     else if (p->state == NICE_CHECK_DISCOVERED)
843       s_discovered++;
844     if (p->valid)
845       s_valid++;
846 
847     if ((p->state == NICE_CHECK_SUCCEEDED || p->state == NICE_CHECK_DISCOVERED)
848         && p->nominated)
849       s_nominated++;
850     else if ((p->state == NICE_CHECK_SUCCEEDED ||
851             p->state == NICE_CHECK_DISCOVERED) && !p->nominated)
852       s_waiting_for_nomination++;
853   }
854 
855   /* note: keep the timer going as long as there is work to be done */
856   if (s_inprogress)
857     keep_timer_going = TRUE;
858 
859   if (s_nominated < stream->n_components &&
860       s_waiting_for_nomination) {
861     if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) {
862       if (agent->nomination_mode == NICE_NOMINATION_MODE_REGULAR &&
863           agent->controlling_mode) {
864 #define NICE_MIN_NUMBER_OF_VALID_PAIRS 2
865         /* ICE 8.1.1.1 Regular nomination
866          * we choose to nominate the valid pair of a component if
867          * - there is no pair left frozen, waiting or in-progress, or
868          * - if there are at least two valid pairs, or
869          * - if there is at least one valid pair of type HOST-HOST
870          *
871          * This is the "stopping criterion" described in 8.1.1.1, and is
872          * a "local optimization" between accumulating more valid pairs,
873          * and limiting the time spent waiting for in-progress connections
874          * checks until they finally fail.
875          */
876         for (i = stream->components; i; i = i->next) {
877           NiceComponent *component = i->data;
878           CandidateCheckPair *other_component_pair = NULL;
879           CandidateCheckPair *this_component_pair = NULL;
880           NiceCandidate *lcand1 = NULL;
881           NiceCandidate *rcand1 = NULL;
882           NiceCandidate *lcand2, *rcand2;
883           gboolean already_done = FALSE;
884           gboolean found_other_component_pair = FALSE;
885           gboolean found_other_stream_pair = FALSE;
886           gboolean first_nomination = FALSE;
887           gboolean stopping_criterion;
888           /* p_xxx counters are component-wide */
889           guint p_valid = 0;
890           guint p_frozen = 0;
891           guint p_waiting = 0;
892           guint p_inprogress = 0;
893           guint p_host_host_valid = 0;
894 
895           /* we compute some component-wide counter values */
896           for (j = stream->conncheck_list; j ; j = j->next) {
897             CandidateCheckPair *p = j->data;
898             if (p->component_id == component->id) {
899               /* verify that the choice of the pair to be nominated
900                * has not already been done
901                */
902               if (p->use_candidate_on_next_check)
903                 already_done = TRUE;
904               if (p->state == NICE_CHECK_FROZEN)
905                 p_frozen++;
906               else if (p->state == NICE_CHECK_WAITING)
907                 p_waiting++;
908               else if (p->state == NICE_CHECK_IN_PROGRESS)
909                 p_inprogress++;
910               if (p->valid)
911                 p_valid++;
912               if (p->valid &&
913                   p->local->type == NICE_CANDIDATE_TYPE_HOST &&
914                   p->remote->type == NICE_CANDIDATE_TYPE_HOST)
915                 p_host_host_valid++;
916             }
917           }
918 
919           if (already_done)
920             continue;
921 
922           /* Search for a nominated pair (or selected to be nominated pair)
923            * from another component of this stream.
924            */
925           for (j = stream->conncheck_list; j ; j = j->next) {
926             CandidateCheckPair *p = j->data;
927             if (p->component_id == component->id)
928               continue;
929             if (p->nominated || (p->use_candidate_on_next_check &&
930                 p->state != NICE_CHECK_FAILED)) {
931               other_component_pair = p;
932               break;
933             }
934           }
935 
936           if (other_stream_pair == NULL && other_component_pair == NULL)
937             first_nomination = TRUE;
938 
939           /* We choose a pair to be nominated in the list of valid
940            * pairs.
941            *
942            * this pair will be the one with the highest priority,
943            * when we don't have other nominated pairs in other
944            * components and in other streams
945            *
946            * this pair will be a pair compatible with another nominated
947            * pair from another component if we found one.
948            *
949            * else this pair will be a pair compatible with another
950            * nominated pair from another stream if we found one.
951            *
952            */
953           for (j = stream->conncheck_list; j ; j = j->next) {
954             CandidateCheckPair *p = j->data;
955             /* note: highest priority item selected (list always sorted) */
956             if (p->component_id == component->id &&
957                 !p->nominated &&
958                 !p->use_candidate_on_next_check &&
959                 p->valid) {
960               /* According a ICE spec, sect 8.1.1.1.  "Regular
961                * Nomination", we enqueue the check that produced this
962                * valid pair. When this pair has been discovered, we want
963                * to test its parent pair instead.
964                */
965               if (p->succeeded_pair != NULL) {
966                 g_assert_cmpint (p->state, ==, NICE_CHECK_DISCOVERED);
967                 p = p->succeeded_pair;
968               }
969               g_assert_cmpint (p->state, ==, NICE_CHECK_SUCCEEDED);
970 
971               if (this_component_pair == NULL)
972                 /* highest priority pair */
973                 this_component_pair = p;
974 
975               lcand1 = p->local;
976               rcand1 = p->remote;
977 
978               if (first_nomination)
979                 /* use the highest priority pair */
980                 break;
981 
982               if (other_component_pair) {
983                 lcand2 = other_component_pair->local;
984                 rcand2 = other_component_pair->remote;
985               }
986               if (other_component_pair &&
987                   lcand1->transport == lcand2->transport &&
988                   nice_address_equal_no_port (&lcand1->addr, &lcand2->addr) &&
989                   nice_address_equal_no_port (&rcand1->addr, &rcand2->addr)) {
990                 /* else continue the research with lower priority
991                  * pairs, compatible with a nominated pair of
992                  * another component
993                  */
994                 this_component_pair = p;
995                 found_other_component_pair = TRUE;
996                 break;
997               }
998 
999               if (other_stream_pair) {
1000                 lcand2 = other_stream_pair->local;
1001                 rcand2 = other_stream_pair->remote;
1002               }
1003               if (other_stream_pair &&
1004                   other_component_pair == NULL &&
1005                   lcand1->transport == lcand2->transport &&
1006                   nice_address_equal_no_port (&lcand1->addr, &lcand2->addr) &&
1007                   nice_address_equal_no_port (&rcand1->addr, &rcand2->addr)) {
1008                 /* else continue the research with lower priority
1009                  * pairs, compatible with a nominated pair of
1010                  * another stream
1011                  */
1012                 this_component_pair = p;
1013                 found_other_stream_pair = TRUE;
1014                 break;
1015               }
1016             }
1017           }
1018 
1019           /* No valid pair for this component */
1020           if (this_component_pair == NULL)
1021             continue;
1022 
1023           /* The stopping criterion tries to select a set of pairs of
1024            * the same kind (transport/type) for all components of a
1025            * stream, and for all streams, when possible (see last
1026            * paragraph).
1027            *
1028            * When no stream has nominated a pair yet, we apply the
1029            * following criterion :
1030            *   - stop if we have a valid host-host pair
1031            *   - or stop if we have at least "some* (2 in the current
1032            *     implementation) valid pairs, and select the best one
1033            *   - or stop if the conncheck cannot evolve more
1034            *
1035            * Else when the stream has a nominated pair in another
1036            * component we apply this criterion:
1037            *   - stop if we have a valid pair of the same kind than this
1038            *     other nominated pair.
1039            *   - or stop if the conncheck cannot evolve more
1040            *
1041            * Else when another stream has a nominated pair we apply the
1042            * following criterion:
1043            *   - stop if we have a valid pair of the same kind than the
1044            *     other nominated pair.
1045            *   - or stop if the conncheck cannot evolve more
1046            *
1047            * When no further evolution of the conncheck is possible, we
1048            * prefer to select the best valid pair we have, *even* if it
1049            * is not compatible with the transport of another stream of
1050            * component. We think it's still a better choice than marking
1051            * this component 'failed'.
1052            */
1053           stopping_criterion = FALSE;
1054           if (first_nomination && p_host_host_valid > 0) {
1055             stopping_criterion = TRUE;
1056             nice_debug ("Agent %p : stopping criterion: "
1057                 "valid host-host pair", agent);
1058           } else if (first_nomination &&
1059               p_valid >= NICE_MIN_NUMBER_OF_VALID_PAIRS) {
1060             stopping_criterion = TRUE;
1061             nice_debug ("Agent %p : stopping criterion: "
1062                 "*some* valid pairs", agent);
1063           } else if (found_other_component_pair) {
1064             stopping_criterion = TRUE;
1065             nice_debug ("Agent %p : stopping criterion: "
1066                 "matching pair in another component", agent);
1067           } else if (found_other_stream_pair) {
1068             stopping_criterion = TRUE;
1069             nice_debug ("Agent %p : stopping criterion: "
1070                 "matching pair in another stream", agent);
1071           } else if (p_waiting == 0 && p_inprogress == 0 && p_frozen == 0) {
1072             stopping_criterion = TRUE;
1073             nice_debug ("Agent %p : stopping criterion: "
1074                 "no more pairs to check", agent);
1075           }
1076 
1077           if (!stopping_criterion)
1078             continue;
1079 
1080           /* when the stopping criterion is reached, we add the
1081            * selected pair for this component to the triggered checks
1082            * list
1083            */
1084           nice_debug ("Agent %p : restarting check of %s:%s pair %p with "
1085               "USE-CANDIDATE attrib (regular nomination) for "
1086               "stream %d component %d", agent,
1087               nice_candidate_transport_to_string (
1088                   this_component_pair->local->transport),
1089               nice_candidate_transport_to_string (
1090                   this_component_pair->remote->transport),
1091               this_component_pair, stream->id, component->id);
1092           this_component_pair->use_candidate_on_next_check = TRUE;
1093           priv_add_pair_to_triggered_check_queue (agent, this_component_pair);
1094           keep_timer_going = TRUE;
1095         }
1096       }
1097     } else if (agent->controlling_mode) {
1098       for (i = stream->components; i; i = i->next) {
1099         NiceComponent *component = i->data;
1100 
1101 	for (j = stream->conncheck_list; j ; j = j->next) {
1102 	  CandidateCheckPair *p = j->data;
1103 	  /* note: highest priority item selected (list always sorted) */
1104 	  if (p->component_id == component->id &&
1105               (p->state == NICE_CHECK_SUCCEEDED ||
1106                p->state == NICE_CHECK_DISCOVERED)) {
1107 	    nice_debug ("Agent %p : restarting check of pair %p as the "
1108                 "nominated pair.", agent, p);
1109 	    p->nominated = TRUE;
1110             conn_check_update_selected_pair (agent, component, p);
1111             priv_add_pair_to_triggered_check_queue (agent, p);
1112             keep_timer_going = TRUE;
1113 	    break; /* move to the next component */
1114 	  }
1115 	}
1116       }
1117     }
1118   }
1119   if (stream->tick_counter++ % 50 == 0)
1120     nice_debug ("Agent %p : stream %u: timer tick #%u: %u frozen, "
1121         "%u in-progress, %u waiting, %u succeeded, %u discovered, "
1122         "%u nominated, %u waiting-for-nom, %u valid",
1123         agent, stream->id, stream->tick_counter,
1124         s_frozen, s_inprogress, s_waiting, s_succeeded, s_discovered,
1125         s_nominated, s_waiting_for_nomination, s_valid);
1126 
1127   return keep_timer_going;
1128 
1129 }
1130 
1131 static void
conn_check_stop(NiceAgent * agent)1132 conn_check_stop (NiceAgent *agent)
1133 {
1134   if (agent->conncheck_timer_source == NULL)
1135     return;
1136 
1137   g_source_destroy (agent->conncheck_timer_source);
1138   g_source_unref (agent->conncheck_timer_source);
1139   agent->conncheck_timer_source = NULL;
1140   agent->conncheck_ongoing_idle_delay = 0;
1141 }
1142 
1143 
1144 /*
1145  * Timer callback that handles initiating and managing connectivity
1146  * checks (paced by the Ta timer).
1147  *
1148  * This function is designed for the g_timeout_add() interface.
1149  *
1150  * @return will return FALSE when no more pending timers.
1151  */
priv_conn_check_tick_agent_locked(NiceAgent * agent,gpointer user_data)1152 static gboolean priv_conn_check_tick_agent_locked (NiceAgent *agent,
1153     gpointer user_data)
1154 {
1155   gboolean keep_timer_going = FALSE;
1156   gboolean stun_sent = FALSE;
1157   GSList *i;
1158 
1159   /* step: process triggered checks
1160    * these steps are ordered by priority, since a single stun request
1161    * is sent per callback, we process the important steps first.
1162    *
1163    * perform a single stun request per timer callback,
1164    * to respect stun pacing
1165    */
1166   for (i = agent->streams; i && !stun_sent; i = i->next) {
1167     NiceStream *stream = i->data;
1168 
1169     stun_sent = priv_conn_check_triggered_check (agent, stream);
1170   }
1171 
1172   /* step: process ongoing STUN transactions */
1173   for (i = agent->streams; i && !stun_sent; i = i->next) {
1174     NiceStream *stream = i->data;
1175 
1176     stun_sent = priv_conn_check_tick_stream (agent, stream);
1177   }
1178 
1179   /* step: process ordinary checks */
1180   for (i = agent->streams; i && !stun_sent; i = i->next) {
1181     NiceStream *stream = i->data;
1182 
1183     stun_sent = priv_conn_check_ordinary_check (agent, stream);
1184   }
1185 
1186   if (stun_sent)
1187     keep_timer_going = TRUE;
1188 
1189   /* step: try to nominate a pair
1190    */
1191   for (i = agent->streams; i; i = i->next) {
1192     NiceStream *stream = i->data;
1193 
1194     if (priv_conn_check_tick_stream_nominate (agent, stream))
1195       keep_timer_going = TRUE;
1196   }
1197 
1198   /* note: we provide a grace period before declaring a component as
1199    * failed. Components marked connected, and then ready follow another
1200    * code path, and are not concerned by this grace period.
1201    */
1202   if (!keep_timer_going && agent->conncheck_ongoing_idle_delay == 0)
1203     nice_debug ("Agent %p : waiting %d msecs before checking "
1204         "for failed components.", agent, agent->idle_timeout);
1205 
1206   if (keep_timer_going)
1207     agent->conncheck_ongoing_idle_delay = 0;
1208   else
1209     agent->conncheck_ongoing_idle_delay += agent->timer_ta;
1210 
1211   /* step: stop timer if no work left */
1212   if (!keep_timer_going &&
1213       agent->conncheck_ongoing_idle_delay >= agent->idle_timeout) {
1214     nice_debug ("Agent %p : checking for failed components now.", agent);
1215     for (i = agent->streams; i; i = i->next) {
1216       NiceStream *stream = i->data;
1217       priv_update_check_list_failed_components (agent, stream);
1218     }
1219 
1220     nice_debug ("Agent %p : %s: stopping conncheck timer", agent, G_STRFUNC);
1221     priv_print_conn_check_lists (agent, G_STRFUNC,
1222         ", conncheck timer stopped");
1223 
1224     /* Stopping the timer so destroy the source.. this will allow
1225        the timer to be reset if we get a set_remote_candidates after this
1226        point */
1227     conn_check_stop (agent);
1228 
1229     /* XXX: what to signal, is all processing now really done? */
1230     nice_debug ("Agent %p : changing conncheck state to COMPLETED.", agent);
1231     return FALSE;
1232   }
1233 
1234   return TRUE;
1235 }
1236 
priv_conn_keepalive_retransmissions_tick_agent_locked(NiceAgent * agent,gpointer pointer)1237 static gboolean priv_conn_keepalive_retransmissions_tick_agent_locked (
1238     NiceAgent *agent, gpointer pointer)
1239 {
1240   CandidatePair *pair = (CandidatePair *) pointer;
1241 
1242   g_source_destroy (pair->keepalive.tick_source);
1243   g_source_unref (pair->keepalive.tick_source);
1244   pair->keepalive.tick_source = NULL;
1245 
1246   switch (stun_timer_refresh (&pair->keepalive.timer)) {
1247     case STUN_USAGE_TIMER_RETURN_TIMEOUT:
1248       {
1249         /* Time out */
1250         StunTransactionId id;
1251         NiceComponent *component;
1252 
1253         if (!agent_find_component (agent,
1254                 pair->keepalive.stream_id, pair->keepalive.component_id,
1255                 NULL, &component)) {
1256           nice_debug ("Could not find stream or component in"
1257               " priv_conn_keepalive_retransmissions_tick");
1258           return FALSE;
1259         }
1260 
1261         stun_message_id (&pair->keepalive.stun_message, id);
1262         stun_agent_forget_transaction (&component->stun_agent, id);
1263         pair->keepalive.stun_message.buffer = NULL;
1264 
1265         if (agent->media_after_tick) {
1266           nice_debug ("Agent %p : Keepalive conncheck timed out!! "
1267               "but media was received. Suspecting keepalive lost because of "
1268               "network bottleneck", agent);
1269         } else {
1270           nice_debug ("Agent %p : Keepalive conncheck timed out!! "
1271               "peer probably lost connection", agent);
1272           agent_signal_component_state_change (agent,
1273               pair->keepalive.stream_id, pair->keepalive.component_id,
1274               NICE_COMPONENT_STATE_FAILED);
1275         }
1276         break;
1277       }
1278     case STUN_USAGE_TIMER_RETURN_RETRANSMIT:
1279       /* Retransmit */
1280       agent_socket_send (pair->local->sockptr, &pair->remote->c.addr,
1281           stun_message_length (&pair->keepalive.stun_message),
1282           (gchar *)pair->keepalive.stun_buffer);
1283 
1284       nice_debug ("Agent %p : Retransmitting keepalive conncheck",
1285           agent);
1286 
1287       G_GNUC_FALLTHROUGH;
1288     case STUN_USAGE_TIMER_RETURN_SUCCESS:
1289       agent_timeout_add_with_context (agent,
1290           &pair->keepalive.tick_source,
1291           "Pair keepalive", stun_timer_remainder (&pair->keepalive.timer),
1292           priv_conn_keepalive_retransmissions_tick_agent_locked, pair);
1293       break;
1294     default:
1295       g_assert_not_reached();
1296       break;
1297   }
1298 
1299   return FALSE;
1300 }
1301 
peer_reflexive_candidate_priority(NiceAgent * agent,NiceCandidate * local_candidate)1302 static guint32 peer_reflexive_candidate_priority (NiceAgent *agent,
1303     NiceCandidate *local_candidate)
1304 {
1305   NiceCandidate *candidate_priority =
1306       nice_candidate_new (NICE_CANDIDATE_TYPE_PEER_REFLEXIVE);
1307   guint32 priority;
1308 
1309   candidate_priority->transport = local_candidate->transport;
1310   candidate_priority->component_id = local_candidate->component_id;
1311   candidate_priority->base_addr = local_candidate->addr;
1312   if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
1313     priority = nice_candidate_jingle_priority (candidate_priority);
1314   } else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
1315              agent->compatibility == NICE_COMPATIBILITY_OC2007) {
1316     priority = nice_candidate_msn_priority (candidate_priority);
1317   } else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
1318     priority = nice_candidate_ms_ice_priority (candidate_priority,
1319         agent->reliable, FALSE);
1320   } else {
1321     priority = nice_candidate_ice_priority (candidate_priority,
1322         agent->reliable, FALSE);
1323   }
1324   nice_candidate_free (candidate_priority);
1325 
1326   return priority;
1327 }
1328 
1329 /* Returns the priority of a local candidate of type peer-reflexive that
1330  * would be learned as a consequence of a check from this local
1331  * candidate. See RFC 5245, section 7.1.2.1. "PRIORITY and USE-CANDIDATE".
1332  * RFC 5245 is more explanatory than RFC 8445 on this detail.
1333  *
1334  * Apply to local candidates of type host only, because candidates of type
1335  * relay are supposed to have a public IP address, that wont generate
1336  * a peer-reflexive address. Server-reflexive candidates are not
1337  * concerned too, because no STUN request is sent with a local candidate
1338  * of this type.
1339  */
stun_request_priority(NiceAgent * agent,NiceCandidate * local_candidate)1340 static guint32 stun_request_priority (NiceAgent *agent,
1341     NiceCandidate *local_candidate)
1342 {
1343   if (local_candidate->type == NICE_CANDIDATE_TYPE_HOST)
1344     return peer_reflexive_candidate_priority (agent, local_candidate);
1345   else
1346     return local_candidate->priority;
1347 }
1348 
ms_ice2_legacy_conncheck_send(StunMessage * msg,NiceSocket * sock,const NiceAddress * remote_addr)1349 static void ms_ice2_legacy_conncheck_send(StunMessage *msg, NiceSocket *sock,
1350     const NiceAddress *remote_addr)
1351 {
1352   uint32_t *fingerprint_attr;
1353   uint32_t fingerprint_orig;
1354   uint16_t fingerprint_len;
1355   size_t buffer_len;
1356 
1357   if (msg->agent->ms_ice2_send_legacy_connchecks == FALSE) {
1358     return;
1359   }
1360 
1361   fingerprint_attr = (uint32_t *)stun_message_find (msg,
1362       STUN_ATTRIBUTE_FINGERPRINT, &fingerprint_len);
1363 
1364   if (fingerprint_attr == NULL) {
1365     nice_debug ("FINGERPRINT not found.");
1366     return;
1367   }
1368 
1369   if (fingerprint_len != sizeof (fingerprint_orig)) {
1370     nice_debug ("Unexpected FINGERPRINT length %u.", fingerprint_len);
1371     return;
1372   }
1373 
1374   memcpy (&fingerprint_orig, fingerprint_attr, sizeof (fingerprint_orig));
1375 
1376   buffer_len = stun_message_length (msg);
1377 
1378   *fingerprint_attr = stun_fingerprint (msg->buffer, buffer_len, TRUE);
1379 
1380   agent_socket_send (sock, remote_addr, buffer_len, (gchar *)msg->buffer);
1381 
1382   memcpy (fingerprint_attr, &fingerprint_orig, sizeof (fingerprint_orig));
1383 }
1384 
1385 /*
1386  * Timer callback that handles initiating and managing connectivity
1387  * checks (paced by the Ta timer).
1388  *
1389  * This function is designed for the g_timeout_add() interface.
1390  *
1391  * @return will return FALSE when no more pending timers.
1392  */
priv_conn_keepalive_tick_unlocked(NiceAgent * agent)1393 static gboolean priv_conn_keepalive_tick_unlocked (NiceAgent *agent)
1394 {
1395   GSList *i, *j, *k;
1396   int errors = 0;
1397   size_t buf_len = 0;
1398   guint64 now;
1399   guint64 min_next_tick;
1400   guint64 next_timer_tick;
1401 
1402   now = g_get_monotonic_time ();
1403   min_next_tick = now + 1000 * NICE_AGENT_TIMER_TR_DEFAULT;
1404 
1405   /* case 1: session established and media flowing
1406    *         (ref ICE sect 11 "Keepalives" RFC-8445)
1407    * TODO: keepalives should be send only when no packet has been sent
1408    * on that pair in the last Tr seconds, and not unconditionally.
1409    */
1410   for (i = agent->streams; i; i = i->next) {
1411 
1412     NiceStream *stream = i->data;
1413     for (j = stream->components; j; j = j->next) {
1414       NiceComponent *component = j->data;
1415       if (component->selected_pair.local != NULL) {
1416 	CandidatePair *p = &component->selected_pair;
1417 
1418         /* Disable keepalive checks on TCP candidates unless explicitly enabled */
1419         if (p->local->c.transport != NICE_CANDIDATE_TRANSPORT_UDP &&
1420             !agent->keepalive_conncheck)
1421           continue;
1422 
1423         if (p->keepalive.next_tick) {
1424           if (p->keepalive.next_tick < min_next_tick)
1425             min_next_tick = p->keepalive.next_tick;
1426           if (now < p->keepalive.next_tick)
1427             continue;
1428         }
1429 
1430         if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE ||
1431             agent->keepalive_conncheck) {
1432           uint8_t uname[NICE_STREAM_MAX_UNAME];
1433           size_t uname_len =
1434               priv_create_username (agent, agent_find_stream (agent, stream->id),
1435                   component->id, (NiceCandidate *) p->remote,
1436                   (NiceCandidate *) p->local, uname, sizeof (uname), FALSE);
1437           uint8_t *password = NULL;
1438           size_t password_len = priv_get_password (agent,
1439               agent_find_stream (agent, stream->id),
1440               (NiceCandidate *) p->remote, &password);
1441 
1442           if (p->keepalive.stun_message.buffer != NULL) {
1443             nice_debug ("Agent %p: Keepalive for s%u:c%u still"
1444                 " retransmitting, not restarting", agent, stream->id,
1445                 component->id);
1446             continue;
1447           }
1448 
1449           if (nice_debug_is_enabled ()) {
1450             gchar tmpbuf[INET6_ADDRSTRLEN];
1451             nice_address_to_string (&p->remote->c.addr, tmpbuf);
1452             nice_debug ("Agent %p : Keepalive STUN-CC REQ to '%s:%u', "
1453                 "(c-id:%u), username='%.*s' (%" G_GSIZE_FORMAT "), "
1454                 "password='%.*s' (%" G_GSIZE_FORMAT "), priority=%08x.",
1455                 agent, tmpbuf, nice_address_get_port (&p->remote->c.addr),
1456                 component->id, (int) uname_len, uname, uname_len,
1457                 (int) password_len, password, password_len,
1458                 p->stun_priority);
1459           }
1460           if (uname_len > 0) {
1461             buf_len = stun_usage_ice_conncheck_create (&component->stun_agent,
1462                 &p->keepalive.stun_message, p->keepalive.stun_buffer,
1463                 sizeof(p->keepalive.stun_buffer),
1464                 uname, uname_len, password, password_len,
1465                 agent->controlling_mode, agent->controlling_mode,
1466                 p->stun_priority,
1467                 agent->tie_breaker,
1468                 NULL,
1469                 agent_to_ice_compatibility (agent));
1470 
1471             nice_debug ("Agent %p: conncheck created %zd - %p",
1472                 agent, buf_len, p->keepalive.stun_message.buffer);
1473 
1474             if (buf_len > 0) {
1475               stun_timer_start (&p->keepalive.timer,
1476                   agent->stun_initial_timeout,
1477                   agent->stun_max_retransmissions);
1478 
1479               agent->media_after_tick = FALSE;
1480 
1481               /* send the conncheck */
1482               agent_socket_send (p->local->sockptr, &p->remote->c.addr,
1483                   buf_len, (gchar *)p->keepalive.stun_buffer);
1484 
1485               p->keepalive.stream_id = stream->id;
1486               p->keepalive.component_id = component->id;
1487               p->keepalive.next_tick = now + 1000 * NICE_AGENT_TIMER_TR_DEFAULT;
1488 
1489               agent_timeout_add_with_context (agent,
1490                   &p->keepalive.tick_source, "Pair keepalive",
1491                   stun_timer_remainder (&p->keepalive.timer),
1492                   priv_conn_keepalive_retransmissions_tick_agent_locked, p);
1493 
1494               next_timer_tick = now + agent->timer_ta * 1000;
1495               goto done;
1496             } else {
1497               ++errors;
1498             }
1499           }
1500         } else {
1501           buf_len = stun_usage_bind_keepalive (&component->stun_agent,
1502               &p->keepalive.stun_message, p->keepalive.stun_buffer,
1503               sizeof(p->keepalive.stun_buffer));
1504 
1505           if (buf_len > 0) {
1506             agent_socket_send (p->local->sockptr, &p->remote->c.addr, buf_len,
1507                 (gchar *)p->keepalive.stun_buffer);
1508 
1509             p->keepalive.next_tick = now + 1000 * NICE_AGENT_TIMER_TR_DEFAULT;
1510 
1511             if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
1512               ms_ice2_legacy_conncheck_send (&p->keepalive.stun_message,
1513                   p->local->sockptr, &p->remote->c.addr);
1514             }
1515 
1516             if (nice_debug_is_enabled ()) {
1517               gchar tmpbuf[INET6_ADDRSTRLEN];
1518               nice_address_to_string (&p->local->c.base_addr, tmpbuf);
1519               nice_debug ("Agent %p : resending STUN to keep the "
1520                   "selected base address %s:%u alive in s%d/c%d.", agent,
1521                   tmpbuf, nice_address_get_port (&p->local->c.base_addr),
1522                   stream->id, component->id);
1523             }
1524 
1525             next_timer_tick = now + agent->timer_ta * 1000;
1526             goto done;
1527           } else {
1528             ++errors;
1529           }
1530         }
1531       }
1532     }
1533   }
1534 
1535   /* case 2: connectivity establishment ongoing
1536    *         (ref ICE sect 5.1.1.4 "Keeping Candidates Alive" RFC-8445)
1537    */
1538   for (i = agent->streams; i; i = i->next) {
1539     NiceStream *stream = i->data;
1540     for (j = stream->components; j; j = j->next) {
1541       NiceComponent *component = j->data;
1542       if (component->state < NICE_COMPONENT_STATE_CONNECTED &&
1543           agent->stun_server_ip) {
1544         NiceAddress stun_server;
1545         if (nice_address_set_from_string (&stun_server, agent->stun_server_ip)) {
1546           StunAgent stun_agent;
1547           uint8_t stun_buffer[STUN_MAX_MESSAGE_SIZE_IPV6];
1548           StunMessage stun_message;
1549           size_t buffer_len = 0;
1550 
1551           nice_address_set_port (&stun_server, agent->stun_server_port);
1552 
1553           nice_agent_init_stun_agent (agent, &stun_agent);
1554 
1555           buffer_len = stun_usage_bind_create (&stun_agent,
1556               &stun_message, stun_buffer, sizeof(stun_buffer));
1557 
1558           for (k = component->local_candidates; k; k = k->next) {
1559             NiceCandidateImpl *candidate = (NiceCandidateImpl *) k->data;
1560             if (candidate->c.type == NICE_CANDIDATE_TYPE_HOST &&
1561                 candidate->c.transport == NICE_CANDIDATE_TRANSPORT_UDP &&
1562                 nice_address_ip_version (&candidate->c.addr) ==
1563                 nice_address_ip_version (&stun_server)) {
1564 
1565               if (candidate->keepalive_next_tick) {
1566                 if (candidate->keepalive_next_tick < min_next_tick)
1567                   min_next_tick = candidate->keepalive_next_tick;
1568                 if (now < candidate->keepalive_next_tick)
1569                 continue;
1570               }
1571 
1572               /* send the conncheck */
1573               if (nice_debug_is_enabled ()) {
1574                 gchar tmpbuf[INET6_ADDRSTRLEN];
1575                 nice_address_to_string (&candidate->c.addr, tmpbuf);
1576                 nice_debug ("Agent %p : resending STUN to keep the local "
1577                     "candidate %s:%u alive in s%d/c%d.", agent,
1578                     tmpbuf, nice_address_get_port (&candidate->c.addr),
1579                     stream->id, component->id);
1580               }
1581               agent_socket_send (candidate->sockptr, &stun_server,
1582                   buffer_len, (gchar *)stun_buffer);
1583               candidate->keepalive_next_tick = now +
1584                   1000 * NICE_AGENT_TIMER_TR_DEFAULT;
1585               next_timer_tick = now + agent->timer_ta * 1000;
1586               goto done;
1587             }
1588           }
1589         }
1590       }
1591     }
1592   }
1593 
1594   next_timer_tick = min_next_tick;
1595 
1596   done:
1597   if (errors) {
1598     nice_debug ("Agent %p : %s: stopping keepalive timer", agent, G_STRFUNC);
1599     return FALSE;
1600   }
1601 
1602   if (agent->keepalive_timer_source) {
1603     g_source_destroy (agent->keepalive_timer_source);
1604     g_source_unref (agent->keepalive_timer_source);
1605     agent->keepalive_timer_source = NULL;
1606   }
1607   agent_timeout_add_with_context (agent, &agent->keepalive_timer_source,
1608       "Connectivity keepalive timeout", (next_timer_tick - now)/ 1000,
1609       priv_conn_keepalive_tick_agent_locked, NULL);
1610   return TRUE;
1611 }
1612 
priv_conn_keepalive_tick_agent_locked(NiceAgent * agent,gpointer pointer)1613 static gboolean priv_conn_keepalive_tick_agent_locked (NiceAgent *agent,
1614     gpointer pointer)
1615 {
1616   gboolean ret;
1617 
1618   ret = priv_conn_keepalive_tick_unlocked (agent);
1619   if (ret == FALSE) {
1620     if (agent->keepalive_timer_source) {
1621       g_source_destroy (agent->keepalive_timer_source);
1622       g_source_unref (agent->keepalive_timer_source);
1623       agent->keepalive_timer_source = NULL;
1624     }
1625   }
1626 
1627   return ret;
1628 }
1629 
1630 
priv_turn_allocate_refresh_retransmissions_tick_agent_locked(NiceAgent * agent,gpointer pointer)1631 static gboolean priv_turn_allocate_refresh_retransmissions_tick_agent_locked (
1632     NiceAgent *agent, gpointer pointer)
1633 {
1634   CandidateRefresh *cand = (CandidateRefresh *) pointer;
1635 
1636   g_source_destroy (cand->tick_source);
1637   g_source_unref (cand->tick_source);
1638   cand->tick_source = NULL;
1639 
1640   switch (stun_timer_refresh (&cand->timer)) {
1641     case STUN_USAGE_TIMER_RETURN_TIMEOUT:
1642       {
1643         /* Time out */
1644         StunTransactionId id;
1645 
1646         stun_message_id (&cand->stun_message, id);
1647         stun_agent_forget_transaction (&cand->stun_agent, id);
1648 
1649         refresh_free (agent, cand);
1650         break;
1651       }
1652     case STUN_USAGE_TIMER_RETURN_RETRANSMIT:
1653       /* Retransmit */
1654       agent_socket_send (cand->nicesock, &cand->server,
1655           stun_message_length (&cand->stun_message), (gchar *)cand->stun_buffer);
1656 
1657       G_GNUC_FALLTHROUGH;
1658     case STUN_USAGE_TIMER_RETURN_SUCCESS:
1659       agent_timeout_add_with_context (agent, &cand->tick_source,
1660           "Candidate TURN refresh", stun_timer_remainder (&cand->timer),
1661           priv_turn_allocate_refresh_retransmissions_tick_agent_locked, cand);
1662       break;
1663     default:
1664       /* Nothing to do. */
1665       break;
1666   }
1667 
1668   return G_SOURCE_REMOVE;
1669 }
1670 
priv_turn_allocate_refresh_tick_unlocked(NiceAgent * agent,CandidateRefresh * cand)1671 static void priv_turn_allocate_refresh_tick_unlocked (NiceAgent *agent,
1672     CandidateRefresh *cand)
1673 {
1674   uint8_t *username;
1675   gsize username_len;
1676   uint8_t *password;
1677   gsize password_len;
1678   size_t buffer_len = 0;
1679   StunUsageTurnCompatibility turn_compat =
1680       agent_to_turn_compatibility (agent);
1681 
1682   username = (uint8_t *)cand->candidate->turn->username;
1683   username_len = (size_t) strlen (cand->candidate->turn->username);
1684   password = (uint8_t *)cand->candidate->turn->password;
1685   password_len = (size_t) strlen (cand->candidate->turn->password);
1686 
1687   if (turn_compat == STUN_USAGE_TURN_COMPATIBILITY_MSN ||
1688       turn_compat == STUN_USAGE_TURN_COMPATIBILITY_OC2007) {
1689     username = cand->candidate->turn->decoded_username;
1690     password = cand->candidate->turn->decoded_password;
1691     username_len = cand->candidate->turn->decoded_username_len;
1692     password_len = cand->candidate->turn->decoded_password_len;
1693   }
1694 
1695   buffer_len = stun_usage_turn_create_refresh (&cand->stun_agent,
1696       &cand->stun_message,  cand->stun_buffer, sizeof(cand->stun_buffer),
1697       cand->stun_resp_msg.buffer == NULL ? NULL : &cand->stun_resp_msg, -1,
1698       username, username_len,
1699       password, password_len,
1700       turn_compat);
1701 
1702   nice_debug ("Agent %p : Sending allocate Refresh %zd", agent,
1703       buffer_len);
1704 
1705   if (cand->tick_source != NULL) {
1706     g_source_destroy (cand->tick_source);
1707     g_source_unref (cand->tick_source);
1708     cand->tick_source = NULL;
1709   }
1710 
1711   if (buffer_len > 0) {
1712     stun_timer_start (&cand->timer,
1713         agent->stun_initial_timeout,
1714         agent->stun_max_retransmissions);
1715 
1716     /* send the refresh */
1717     agent_socket_send (cand->nicesock, &cand->server,
1718         buffer_len, (gchar *)cand->stun_buffer);
1719 
1720     agent_timeout_add_with_context (agent, &cand->tick_source,
1721         "Candidate TURN refresh", stun_timer_remainder (&cand->timer),
1722         priv_turn_allocate_refresh_retransmissions_tick_agent_locked, cand);
1723   }
1724 
1725 }
1726 
1727 
1728 /*
1729  * Timer callback that handles refreshing TURN allocations
1730  *
1731  * This function is designed for the g_timeout_add() interface.
1732  *
1733  * @return will return FALSE when no more pending timers.
1734  */
priv_turn_allocate_refresh_tick_agent_locked(NiceAgent * agent,gpointer pointer)1735 static gboolean priv_turn_allocate_refresh_tick_agent_locked (NiceAgent *agent,
1736     gpointer pointer)
1737 {
1738   CandidateRefresh *cand = (CandidateRefresh *) pointer;
1739 
1740   priv_turn_allocate_refresh_tick_unlocked (agent, cand);
1741 
1742   return G_SOURCE_REMOVE;
1743 }
1744 
1745 
1746 /*
1747  * Initiates the next pending connectivity check.
1748  */
conn_check_schedule_next(NiceAgent * agent)1749 void conn_check_schedule_next (NiceAgent *agent)
1750 {
1751   if (agent->discovery_unsched_items > 0)
1752     nice_debug ("Agent %p : WARN: starting conn checks before local candidate gathering is finished.", agent);
1753 
1754   /* step: schedule timer if not running yet */
1755   if (agent->conncheck_timer_source == NULL) {
1756     agent_timeout_add_with_context (agent, &agent->conncheck_timer_source,
1757         "Connectivity check schedule", agent->timer_ta,
1758         priv_conn_check_tick_agent_locked, NULL);
1759   }
1760 
1761   /* step: also start the keepalive timer */
1762   if (agent->keepalive_timer_source == NULL) {
1763     agent_timeout_add_with_context (agent, &agent->keepalive_timer_source,
1764         "Connectivity keepalive timeout", agent->timer_ta,
1765         priv_conn_keepalive_tick_agent_locked, NULL);
1766   }
1767 }
1768 
1769 /*
1770  * Compares two connectivity check items. Checkpairs are sorted
1771  * in descending priority order, with highest priority item at
1772  * the start of the list.
1773  */
conn_check_compare(const CandidateCheckPair * a,const CandidateCheckPair * b)1774 gint conn_check_compare (const CandidateCheckPair *a, const CandidateCheckPair *b)
1775 {
1776   if (a->priority > b->priority)
1777     return -1;
1778   else if (a->priority < b->priority)
1779     return 1;
1780   return 0;
1781 }
1782 
1783 /* Find a transport compatible with a given socket.
1784  *
1785  * Returns TRUE when a matching transport can be guessed from
1786  * the type of the socket in an unambiguous way.
1787  */
1788 static gboolean
nice_socket_has_compatible_transport(NiceSocket * socket,NiceCandidateTransport * transport)1789 nice_socket_has_compatible_transport (NiceSocket *socket,
1790     NiceCandidateTransport *transport)
1791 {
1792   gboolean found = TRUE;
1793 
1794   g_assert (socket);
1795   g_assert (transport);
1796 
1797   switch (socket->type) {
1798     case NICE_SOCKET_TYPE_TCP_BSD:
1799       if (nice_tcp_bsd_socket_get_passive_parent (socket))
1800         *transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
1801       else
1802         *transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE;
1803       break;
1804     case NICE_SOCKET_TYPE_TCP_PASSIVE:
1805       *transport = NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
1806       break;
1807     case NICE_SOCKET_TYPE_TCP_ACTIVE:
1808       *transport = NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE;
1809       break;
1810     case NICE_SOCKET_TYPE_UDP_BSD:
1811       *transport = NICE_CANDIDATE_TRANSPORT_UDP;
1812       break;
1813     default:
1814       found = FALSE;
1815   }
1816 
1817   return found;
1818 }
1819 
1820 /* Test if a local socket and a local candidate are compatible. This
1821  * function does supplementary tests when the address and port are not
1822  * sufficient to give a unique candidate. We try to avoid comparing
1823  * directly the sockptr value, when possible, to rely on objective
1824  * properties of the candidate and the socket instead, and we also
1825  * choose to ignore the conncheck list for the same reason.
1826  */
1827 static gboolean
local_candidate_and_socket_compatible(NiceAgent * agent,NiceCandidate * lcand,NiceSocket * socket)1828 local_candidate_and_socket_compatible (NiceAgent *agent,
1829     NiceCandidate *lcand, NiceSocket *socket)
1830 {
1831   gboolean ret = TRUE;
1832   NiceCandidateTransport transport;
1833   NiceCandidateImpl *lc = (NiceCandidateImpl *) lcand;
1834 
1835   g_assert (socket);
1836   g_assert (lcand);
1837 
1838   if (nice_socket_has_compatible_transport (socket, &transport)) {
1839     ret = (lcand->transport == transport);
1840     /* tcp-active discovered peer-reflexive local candidate, where
1841      * socket is the tcp connect related socket */
1842     if (ret && transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE &&
1843         nice_address_get_port (&lcand->addr) > 0)
1844       ret = (lc->sockptr == socket);
1845   } else if (socket->type == NICE_SOCKET_TYPE_UDP_TURN)
1846     /* Socket of type udp-turn will match a unique local candidate
1847      * by its sockptr value. An an udp-turn socket doesn't carry enough
1848      * information when base socket is udp-turn-over-tcp to disambiguate
1849      * between a tcp-act and a tcp-pass local candidate.
1850      */
1851     ret = (lc->sockptr == socket);
1852 
1853   return ret;
1854 }
1855 
1856 /* Test if a local socket and a remote candidate are compatible.
1857  * This function is very close to its local candidate counterpart,
1858  * the difference is that we also use information from the local
1859  * candidate we may have identified previously. This is needed
1860  * to disambiguate the transport of the candidate with a socket
1861  * of type udp-turn.
1862  *
1863  */
1864 static gboolean
remote_candidate_and_socket_compatible(NiceAgent * agent,NiceCandidate * lcand,NiceCandidate * rcand,NiceSocket * socket)1865 remote_candidate_and_socket_compatible (NiceAgent *agent,
1866     NiceCandidate *lcand, NiceCandidate *rcand, NiceSocket *socket)
1867 {
1868   gboolean ret = TRUE;
1869   NiceCandidateTransport transport;
1870 
1871   g_assert (socket);
1872   g_assert (rcand);
1873 
1874   if (nice_socket_has_compatible_transport (socket, &transport))
1875     ret = (conn_check_match_transport (rcand->transport) == transport);
1876 
1877   /* This supplementary test with the local candidate is needed with
1878    * socket of type udp-turn, the type doesn't allow to disambiguate
1879    * between a tcp-pass and a tcp-act remote candidate
1880    */
1881   if (lcand && ret)
1882     ret = (conn_check_match_transport (lcand->transport) == rcand->transport);
1883 
1884   return ret;
1885 }
1886 
1887 void
conn_check_remote_candidates_set(NiceAgent * agent,NiceStream * stream,NiceComponent * component)1888 conn_check_remote_candidates_set(NiceAgent *agent, NiceStream *stream,
1889     NiceComponent *component)
1890 {
1891   GList *i;
1892   GSList *j;
1893   NiceCandidate *lcand = NULL, *rcand = NULL;
1894 
1895   nice_debug ("Agent %p : conn_check_remote_candidates_set %u %u",
1896     agent, stream->id, component->id);
1897 
1898   if (stream->remote_ufrag[0] == 0)
1899     return;
1900 
1901   if (component->incoming_checks.head)
1902     nice_debug ("Agent %p : credentials have been set, "
1903       "we can process incoming checks", agent);
1904 
1905   for (i = component->incoming_checks.head; i;) {
1906     IncomingCheck *icheck = i->data;
1907     GList *i_next = i->next;
1908 
1909     nice_debug ("Agent %p : replaying icheck=%p (sock=%p)",
1910         agent, icheck, icheck->local_socket);
1911 
1912     /* sect 7.2.1.3., "Learning Peer Reflexive Candidates", has to
1913      * be handled separately */
1914     for (j = component->local_candidates; j; j = j->next) {
1915       NiceCandidate *cand = j->data;
1916       NiceAddress *addr;
1917 
1918       if (cand->type == NICE_CANDIDATE_TYPE_RELAYED)
1919         addr = &cand->addr;
1920       else
1921         addr = &cand->base_addr;
1922 
1923       if (nice_address_equal (&icheck->local_socket->addr, addr) &&
1924           local_candidate_and_socket_compatible (agent, cand,
1925           icheck->local_socket)) {
1926         lcand = cand;
1927         break;
1928       }
1929     }
1930 
1931     if (lcand == NULL) {
1932       for (j = component->local_candidates; j; j = j->next) {
1933         NiceCandidate *cand = j->data;
1934         NiceAddress *addr = &cand->base_addr;
1935 
1936         /* tcp-active (not peer-reflexive discovered) local candidate, where
1937          * socket is the tcp connect related socket */
1938         if (nice_address_equal_no_port (&icheck->local_socket->addr, addr) &&
1939             nice_address_get_port (&cand->addr) == 0 &&
1940             cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE &&
1941             local_candidate_and_socket_compatible (agent, cand,
1942             icheck->local_socket)) {
1943           lcand = cand;
1944           break;
1945         }
1946       }
1947     }
1948 
1949     g_assert (lcand != NULL);
1950 
1951     for (j = component->remote_candidates; j; j = j->next) {
1952       NiceCandidate *cand = j->data;
1953       if (nice_address_equal (&cand->addr, &icheck->from) &&
1954           remote_candidate_and_socket_compatible (agent, lcand, cand,
1955           icheck->local_socket)) {
1956         rcand = cand;
1957         break;
1958       }
1959     }
1960 
1961     if (lcand->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE) {
1962       CandidateCheckPair *pair = NULL;
1963 
1964       for (j = stream->conncheck_list; j; j = j->next) {
1965         CandidateCheckPair *p = j->data;
1966         if (lcand == p->local && rcand == p->remote) {
1967           pair = p;
1968           break;
1969         }
1970       }
1971       if (pair == NULL)
1972         priv_conn_check_add_for_candidate_pair_matched (agent,
1973             stream->id, component, lcand, rcand, NICE_CHECK_WAITING);
1974     }
1975 
1976     priv_schedule_triggered_check (agent, stream, component,
1977         icheck->local_socket, rcand);
1978     if (icheck->use_candidate)
1979       priv_mark_pair_nominated (agent, stream, component, lcand, rcand);
1980 
1981     if (icheck->username)
1982       g_free (icheck->username);
1983     g_slice_free (IncomingCheck, icheck);
1984     g_queue_delete_link (&component->incoming_checks, i);
1985     i = i_next;
1986   }
1987 }
1988 
1989 /*
1990  * Handle any processing steps for connectivity checks after
1991  * remote credentials have been set. This function handles
1992  * the special case where answerer has sent us connectivity
1993  * checks before the answer (containing credentials information),
1994  * reaches us. The special case is documented in RFC 5245 sect 7.2.
1995  * ).
1996  */
conn_check_remote_credentials_set(NiceAgent * agent,NiceStream * stream)1997 void conn_check_remote_credentials_set(NiceAgent *agent, NiceStream *stream)
1998 {
1999   GSList *j;
2000 
2001   for (j = stream->components; j ; j = j->next) {
2002     NiceComponent *component = j->data;
2003 
2004     conn_check_remote_candidates_set(agent, stream, component);
2005   }
2006 }
2007 
2008 /*
2009  * Enforces the upper limit for connectivity checks by dropping
2010  * lower-priority pairs as described RFC 8445 section 6.1.2.5. See also
2011  * conn_check_add_for_candidate().
2012  * Returns TRUE if the pair in argument is one of the deleted pairs.
2013  */
priv_limit_conn_check_list_size(NiceAgent * agent,NiceStream * stream,CandidateCheckPair * pair)2014 static gboolean priv_limit_conn_check_list_size (NiceAgent *agent,
2015     NiceStream *stream, CandidateCheckPair *pair)
2016 {
2017   guint valid = 0;
2018   guint cancelled = 0;
2019   gboolean deleted = FALSE;
2020   GSList *item = stream->conncheck_list;
2021 
2022   while (item) {
2023     CandidateCheckPair *p = item->data;
2024     GSList *next = item->next;
2025 
2026     valid++;
2027     /* We remove lower-priority pairs, but only the ones that can be
2028      * safely discarded without breaking an ongoing conncheck process.
2029      * This only includes pairs that are in the frozen state (those
2030      * initially added when remote candidates are received) or in failed
2031      * state. Pairs in any other state play a role in the conncheck, and
2032      * there removal may lead to a failing conncheck that would succeed
2033      * otherwise.
2034      *
2035      * We also remove failed pairs from the list unconditionally.
2036      */
2037     if ((valid > agent->max_conn_checks && p->state == NICE_CHECK_FROZEN) ||
2038         p->state == NICE_CHECK_FAILED) {
2039       if (p == pair)
2040         deleted = TRUE;
2041       nice_debug ("Agent %p : pair %p removed.", agent, p);
2042       candidate_check_pair_free (agent, p);
2043       stream->conncheck_list = g_slist_delete_link (stream->conncheck_list,
2044           item);
2045       cancelled++;
2046     }
2047     item = next;
2048   }
2049 
2050   if (cancelled > 0)
2051     nice_debug ("Agent %p : Pruned %d pairs. "
2052         "Conncheck list has %d elements left. "
2053         "Maximum connchecks allowed : %d", agent, cancelled,
2054         valid - cancelled, agent->max_conn_checks);
2055 
2056   return deleted;
2057 }
2058 
2059 /*
2060  * Changes the selected pair for the component if 'pair'
2061  * has higher priority than the currently selected pair. See
2062  * RFC 8445 sect 8.1.1. "Nominating Pairs"
2063  */
2064 void
conn_check_update_selected_pair(NiceAgent * agent,NiceComponent * component,CandidateCheckPair * pair)2065 conn_check_update_selected_pair (NiceAgent *agent, NiceComponent *component,
2066     CandidateCheckPair *pair)
2067 {
2068   CandidatePair cpair = { 0, };
2069 
2070   g_assert (component);
2071   g_assert (pair);
2072   /* pair is expected to have the nominated flag */
2073   g_assert (pair->nominated);
2074   if (pair->priority > component->selected_pair.priority) {
2075     gchar priority[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE];
2076     nice_candidate_pair_priority_to_string (pair->priority, priority);
2077     nice_debug ("Agent %p : changing SELECTED PAIR for component %u: %s:%s "
2078         "(prio:%s).", agent, component->id,
2079         pair->local->foundation, pair->remote->foundation, priority);
2080 
2081     cpair.local = (NiceCandidateImpl *) pair->local;
2082     cpair.remote = (NiceCandidateImpl *) pair->remote;
2083     cpair.priority = pair->priority;
2084     cpair.stun_priority = pair->stun_priority;
2085 
2086     nice_component_update_selected_pair (agent, component, &cpair);
2087 
2088     priv_conn_keepalive_tick_unlocked (agent);
2089 
2090     agent_signal_new_selected_pair (agent, pair->stream_id, component->id,
2091         pair->local, pair->remote);
2092   }
2093 }
2094 
2095 /*
2096  * Updates the check list state.
2097  *
2098  * Implements parts of the algorithm described in
2099  * ICE sect 8.1.2. "Updating States" (RFC 5245): if for any
2100  * component, all checks have been completed and have
2101  * failed to produce a nominated pair, mark that component's
2102  * state to NICE_CHECK_FAILED.
2103  *
2104  * Sends a component state changesignal via 'agent'.
2105  */
priv_update_check_list_failed_components(NiceAgent * agent,NiceStream * stream)2106 static void priv_update_check_list_failed_components (NiceAgent *agent, NiceStream *stream)
2107 {
2108   GSList *i;
2109   gboolean completed;
2110   guint nominated;
2111   /* note: emitting a signal might cause the client
2112    *       to remove the stream, thus the component count
2113    *       must be fetched before entering the loop*/
2114   guint c, components = stream->n_components;
2115 
2116   if (stream->conncheck_list == NULL)
2117     return;
2118 
2119   for (i = agent->discovery_list; i; i = i->next) {
2120     CandidateDiscovery *d = i->data;
2121 
2122     /* There is still discovery ogoing for this stream,
2123      * so don't fail any of it's candidates.
2124      */
2125     if (d->stream_id == stream->id && !d->done)
2126       return;
2127   }
2128   if (agent->discovery_list != NULL)
2129     return;
2130 
2131   /* note: iterate the conncheck list for each component separately */
2132   for (c = 0; c < components; c++) {
2133     NiceComponent *component = NULL;
2134     if (!agent_find_component (agent, stream->id, c+1, NULL, &component))
2135       continue;
2136 
2137     nominated = 0;
2138     completed = TRUE;
2139     for (i = stream->conncheck_list; i; i = i->next) {
2140       CandidateCheckPair *p = i->data;
2141 
2142       g_assert_cmpuint (p->stream_id, ==, stream->id);
2143 
2144       if (p->component_id == (c + 1)) {
2145         if (p->nominated)
2146           ++nominated;
2147 	if (p->state != NICE_CHECK_FAILED &&
2148             p->state != NICE_CHECK_SUCCEEDED &&
2149             p->state != NICE_CHECK_DISCOVERED)
2150 	  completed = FALSE;
2151       }
2152     }
2153 
2154     /* note: all pairs are either failed or succeeded, and the component
2155      * has not produced a nominated pair.
2156      * Set the component to FAILED only if it actually had remote candidates
2157      * that failed.. */
2158     if (completed && nominated == 0 &&
2159         component != NULL && component->remote_candidates != NULL)
2160       agent_signal_component_state_change (agent,
2161 					   stream->id,
2162 					   (c + 1), /* component-id */
2163 					   NICE_COMPONENT_STATE_FAILED);
2164   }
2165 }
2166 
2167 /*
2168  * Updates the check list state for a stream component.
2169  *
2170  * Implements the algorithm described in ICE sect 8.1.2
2171  * "Updating States" (ID-19) as it applies to checks of
2172  * a certain component. If there are any nominated pairs,
2173  * ICE processing may be concluded, and component state is
2174  * changed to READY.
2175  *
2176  * Sends a component state changesignal via 'agent'.
2177  */
conn_check_update_check_list_state_for_ready(NiceAgent * agent,NiceStream * stream,NiceComponent * component)2178 void conn_check_update_check_list_state_for_ready (NiceAgent *agent,
2179     NiceStream *stream, NiceComponent *component)
2180 {
2181   GSList *i;
2182   guint valid = 0, nominated = 0;
2183 
2184   g_assert (component);
2185 
2186   /* step: search for at least one nominated pair */
2187   for (i = stream->conncheck_list; i; i = i->next) {
2188     CandidateCheckPair *p = i->data;
2189     if (p->component_id == component->id) {
2190       if (p->valid) {
2191 	++valid;
2192 	if (p->nominated == TRUE) {
2193           ++nominated;
2194 	}
2195       }
2196     }
2197   }
2198 
2199   if (nominated > 0) {
2200     /* Only go to READY if no checks are left in progress. If there are
2201      * any that are kept, then this function will be called again when the
2202      * conncheck tick timer finishes them all */
2203     if (priv_prune_pending_checks (agent, stream, component) == 0) {
2204       /* Continue through the states to give client code a nice
2205        * logical progression. See http://phabricator.freedesktop.org/D218 for
2206        * discussion. */
2207       if (component->state < NICE_COMPONENT_STATE_CONNECTING ||
2208           component->state == NICE_COMPONENT_STATE_FAILED)
2209         agent_signal_component_state_change (agent, stream->id, component->id,
2210             NICE_COMPONENT_STATE_CONNECTING);
2211       if (component->state < NICE_COMPONENT_STATE_CONNECTED)
2212         agent_signal_component_state_change (agent, stream->id, component->id,
2213             NICE_COMPONENT_STATE_CONNECTED);
2214       agent_signal_component_state_change (agent, stream->id,
2215           component->id, NICE_COMPONENT_STATE_READY);
2216     }
2217   }
2218   nice_debug ("Agent %p : conn.check list status: %u nominated, %u valid, c-id %u.", agent, nominated, valid, component->id);
2219 }
2220 
2221 /*
2222  * The remote party has signalled that the candidate pair
2223  * described by 'component' and 'remotecand' is nominated
2224  * for use.
2225  */
priv_mark_pair_nominated(NiceAgent * agent,NiceStream * stream,NiceComponent * component,NiceCandidate * localcand,NiceCandidate * remotecand)2226 static void priv_mark_pair_nominated (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceCandidate *localcand, NiceCandidate *remotecand)
2227 {
2228   GSList *i;
2229 
2230   g_assert (component);
2231 
2232   if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent) &&
2233       agent->controlling_mode)
2234     return;
2235 
2236   /* step: search for at least one nominated pair */
2237   for (i = stream->conncheck_list; i; i = i->next) {
2238     CandidateCheckPair *pair = i->data;
2239     if (pair->local == localcand && pair->remote == remotecand) {
2240       /* ICE, 7.2.1.5. Updating the Nominated Flag */
2241       /* note: TCP candidates typically produce peer reflexive
2242        * candidate, generating a "discovered" pair that can be
2243        * nominated.
2244        */
2245       if (pair->state == NICE_CHECK_SUCCEEDED &&
2246           pair->discovered_pair != NULL) {
2247         pair = pair->discovered_pair;
2248         g_assert_cmpint (pair->state, ==, NICE_CHECK_DISCOVERED);
2249       }
2250 
2251       /* If the received Binding request triggered a new check to be
2252        * enqueued in the triggered-check queue (Section 7.3.1.4), once
2253        * the check is sent and if it generates a successful response,
2254        * and generates a valid pair, the agent sets the nominated flag
2255        * of the pair to true
2256        */
2257       if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) {
2258         if (g_slist_find (agent->triggered_check_queue, pair) ||
2259             pair->state == NICE_CHECK_IN_PROGRESS) {
2260 
2261         /* This pair is not always in the triggered check list, for
2262          * example if it is in-progress with a lower priority than an
2263          * already nominated pair.  Is that case, it is not rescheduled
2264          * for a connection check, see function
2265          * priv_schedule_triggered_check(), case NICE_CHECK_IN_PROGRESS.
2266          */
2267         pair->mark_nominated_on_response_arrival = TRUE;
2268         nice_debug ("Agent %p : pair %p (%s) is %s, "
2269             "will be nominated on response receipt.",
2270             agent, pair, pair->foundation,
2271             priv_state_to_string (pair->state));
2272         }
2273       }
2274 
2275       if (pair->valid ||
2276           !NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) {
2277         nice_debug ("Agent %p : marking pair %p (%s) as nominated",
2278             agent, pair, pair->foundation);
2279         pair->nominated = TRUE;
2280       }
2281 
2282       if (pair->valid) {
2283         /* Do not step down to CONNECTED if we're already at state READY*/
2284         if (component->state == NICE_COMPONENT_STATE_FAILED)
2285           agent_signal_component_state_change (agent,
2286               stream->id, component->id, NICE_COMPONENT_STATE_CONNECTING);
2287         conn_check_update_selected_pair (agent, component, pair);
2288         if (component->state == NICE_COMPONENT_STATE_CONNECTING)
2289           /* step: notify the client of a new component state (must be done
2290            *       before the possible check list state update step */
2291           agent_signal_component_state_change (agent,
2292               stream->id, component->id, NICE_COMPONENT_STATE_CONNECTED);
2293       }
2294 
2295       if (pair->nominated)
2296         conn_check_update_check_list_state_for_ready (agent, stream, component);
2297     }
2298   }
2299 }
2300 
2301 /*
2302  * Creates a new connectivity check pair and adds it to
2303  * the agent's list of checks.
2304  */
priv_add_new_check_pair(NiceAgent * agent,guint stream_id,NiceComponent * component,NiceCandidateImpl * local,NiceCandidateImpl * remote,NiceCheckState initial_state)2305 static CandidateCheckPair *priv_add_new_check_pair (NiceAgent *agent,
2306     guint stream_id, NiceComponent *component, NiceCandidateImpl *local,
2307     NiceCandidateImpl *remote, NiceCheckState initial_state)
2308 {
2309   NiceStream *stream;
2310   CandidateCheckPair *pair;
2311   guint64 priority;
2312 
2313   g_assert (local != NULL);
2314   g_assert (remote != NULL);
2315 
2316   priority = agent_candidate_pair_priority (agent, (NiceCandidate *) local,
2317       (NiceCandidate *) remote);
2318 
2319   if (component->selected_pair.priority &&
2320       priority < component->selected_pair.priority) {
2321     gchar prio1[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE];
2322     gchar prio2[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE];
2323 
2324     nice_candidate_pair_priority_to_string (priority, prio1);
2325     nice_candidate_pair_priority_to_string (component->selected_pair.priority,
2326         prio2);
2327     nice_debug ("Agent %p : do not create a pair that would have a priority "
2328         "%s lower than selected pair priority %s.", agent, prio1, prio2);
2329     return NULL;
2330   }
2331 
2332   stream = agent_find_stream (agent, stream_id);
2333   pair = g_slice_new0 (CandidateCheckPair);
2334 
2335   pair->stream_id = stream_id;
2336   pair->component_id = component->id;
2337   pair->local = (NiceCandidate *) local;
2338   pair->remote = (NiceCandidate *) remote;
2339   /* note: we use the remote sockptr only in the case
2340    * of TCP transport
2341    */
2342   if (local->c.transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE &&
2343       remote->c.type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE)
2344     pair->sockptr = remote->sockptr;
2345   else
2346     pair->sockptr = local->sockptr;
2347   g_snprintf (pair->foundation, NICE_CANDIDATE_PAIR_MAX_FOUNDATION, "%s:%s",
2348       local->c.foundation, remote->c.foundation);
2349 
2350   pair->priority = agent_candidate_pair_priority (agent,
2351       (NiceCandidate *) local, (NiceCandidate *) remote);
2352   nice_debug ("Agent %p : creating a new pair", agent);
2353   SET_PAIR_STATE (agent, pair, initial_state);
2354   {
2355       gchar tmpbuf1[INET6_ADDRSTRLEN];
2356       gchar tmpbuf2[INET6_ADDRSTRLEN];
2357       nice_address_to_string (&pair->local->addr, tmpbuf1);
2358       nice_address_to_string (&pair->remote->addr, tmpbuf2);
2359       nice_debug ("Agent %p : new pair %p : [%s]:%u --> [%s]:%u", agent, pair,
2360           tmpbuf1, nice_address_get_port (&pair->local->addr),
2361           tmpbuf2, nice_address_get_port (&pair->remote->addr));
2362   }
2363   pair->stun_priority = stun_request_priority (agent, (NiceCandidate *) local);
2364 
2365   stream->conncheck_list = g_slist_insert_sorted (stream->conncheck_list, pair,
2366       (GCompareFunc)conn_check_compare);
2367 
2368   nice_debug ("Agent %p : added a new pair %p with foundation '%s' and "
2369       "transport %s:%s to stream %u component %u",
2370       agent, pair, pair->foundation,
2371       nice_candidate_transport_to_string (pair->local->transport),
2372       nice_candidate_transport_to_string (pair->remote->transport),
2373       stream_id, component->id);
2374 
2375   if (initial_state == NICE_CHECK_FROZEN)
2376     priv_conn_check_unfreeze_maybe (agent, pair);
2377 
2378   /* implement the hard upper limit for number of
2379      checks (see sect 5.7.3 ICE ID-19): */
2380   if (agent->compatibility == NICE_COMPATIBILITY_RFC5245) {
2381     if (priv_limit_conn_check_list_size (agent, stream, pair))
2382       return NULL;
2383   }
2384 
2385   return pair;
2386 }
2387 
2388 NiceCandidateTransport
conn_check_match_transport(NiceCandidateTransport transport)2389 conn_check_match_transport (NiceCandidateTransport transport)
2390 {
2391   switch (transport) {
2392     case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
2393       return NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
2394       break;
2395     case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
2396       return NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE;
2397       break;
2398     case NICE_CANDIDATE_TRANSPORT_TCP_SO:
2399     case NICE_CANDIDATE_TRANSPORT_UDP:
2400     default:
2401       return transport;
2402       break;
2403   }
2404 }
2405 
priv_conn_check_add_for_candidate_pair_matched(NiceAgent * agent,guint stream_id,NiceComponent * component,NiceCandidate * local,NiceCandidate * remote,NiceCheckState initial_state)2406 static CandidateCheckPair *priv_conn_check_add_for_candidate_pair_matched (
2407     NiceAgent *agent, guint stream_id, NiceComponent *component,
2408      NiceCandidate *local, NiceCandidate *remote, NiceCheckState initial_state)
2409 {
2410   CandidateCheckPair *pair;
2411 
2412   pair = priv_add_new_check_pair (agent, stream_id, component,
2413       (NiceCandidateImpl *) local, (NiceCandidateImpl *) remote, initial_state);
2414   if (pair) {
2415     if (component->state == NICE_COMPONENT_STATE_CONNECTED ||
2416         component->state == NICE_COMPONENT_STATE_READY) {
2417       agent_signal_component_state_change (agent,
2418           stream_id,
2419           component->id,
2420           NICE_COMPONENT_STATE_CONNECTED);
2421     } else {
2422       agent_signal_component_state_change (agent,
2423           stream_id,
2424           component->id,
2425           NICE_COMPONENT_STATE_CONNECTING);
2426     }
2427   }
2428 
2429   return pair;
2430 }
2431 
conn_check_add_for_candidate_pair(NiceAgent * agent,guint stream_id,NiceComponent * component,NiceCandidate * local,NiceCandidate * remote)2432 gboolean conn_check_add_for_candidate_pair (NiceAgent *agent,
2433     guint stream_id, NiceComponent *component, NiceCandidate *local,
2434     NiceCandidate *remote)
2435 {
2436   gboolean ret = FALSE;
2437 
2438   g_assert (local != NULL);
2439   g_assert (remote != NULL);
2440 
2441   /* note: do not create pairs where the local candidate is a srv-reflexive
2442    * or peer-reflexive (ICE 6.1.2.4. "Pruning the pairs" RFC 8445)
2443    */
2444   if ((agent->compatibility == NICE_COMPATIBILITY_RFC5245 ||
2445       agent->compatibility == NICE_COMPATIBILITY_WLM2009 ||
2446       agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
2447       (local->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE ||
2448       local->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE)) {
2449     return FALSE;
2450   }
2451 
2452   /* note: do not create pairs where local candidate has TCP passive transport
2453    *       (ice-tcp-13 6.2. "Forming the Check Lists") */
2454   if (local->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE) {
2455     return FALSE;
2456   }
2457 
2458   /* note: match pairs only if transport and address family are the same */
2459   if (local->transport == conn_check_match_transport (remote->transport) &&
2460      local->addr.s.addr.sa_family == remote->addr.s.addr.sa_family) {
2461     if (priv_conn_check_add_for_candidate_pair_matched (agent, stream_id,
2462         component, local, remote, NICE_CHECK_FROZEN))
2463       ret = TRUE;
2464   }
2465 
2466   return ret;
2467 }
2468 
2469 /*
2470  * Forms new candidate pairs by matching the new remote candidate
2471  * 'remote_cand' with all existing local candidates of 'component'.
2472  * Implements the logic described in ICE sect 5.7.1. "Forming Candidate
2473  * Pairs" (ID-19).
2474  *
2475  * @param agent context
2476  * @param component pointer to the component
2477  * @param remote remote candidate to match with
2478  *
2479  * @return number of checks added, negative on fatal errors
2480  */
conn_check_add_for_candidate(NiceAgent * agent,guint stream_id,NiceComponent * component,NiceCandidate * remote)2481 int conn_check_add_for_candidate (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *remote)
2482 {
2483   GSList *i;
2484   int added = 0;
2485   int ret = 0;
2486 
2487   g_assert (remote != NULL);
2488 
2489   /* note: according to 7.2.1.3, "Learning Peer Reflexive Candidates",
2490    * the agent does not pair this candidate with any local candidates.
2491    */
2492   if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent) &&
2493       remote->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE)
2494   {
2495     return added;
2496   }
2497 
2498   for (i = component->local_candidates; i ; i = i->next) {
2499     NiceCandidate *local = i->data;
2500 
2501     if (agent->force_relay && local->type != NICE_CANDIDATE_TYPE_RELAYED)
2502         continue;
2503 
2504     ret = conn_check_add_for_candidate_pair (agent, stream_id, component, local, remote);
2505 
2506     if (ret) {
2507       ++added;
2508     }
2509   }
2510 
2511   return added;
2512 }
2513 
2514 /*
2515  * Forms new candidate pairs by matching the new local candidate
2516  * 'local_cand' with all existing remote candidates of 'component'.
2517  *
2518  * @param agent context
2519  * @param component pointer to the component
2520  * @param local local candidate to match with
2521  *
2522  * @return number of checks added, negative on fatal errors
2523  */
conn_check_add_for_local_candidate(NiceAgent * agent,guint stream_id,NiceComponent * component,NiceCandidate * local)2524 int conn_check_add_for_local_candidate (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidate *local)
2525 {
2526   GSList *i;
2527   int added = 0;
2528   int ret = 0;
2529 
2530   g_assert (local != NULL);
2531 
2532   /*
2533    * note: according to 7.1.3.2.1 "Discovering Peer Reflexive
2534    * Candidates", the peer reflexive candidate is not paired
2535    * with other remote candidates
2536    */
2537 
2538   if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent) &&
2539       local->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE)
2540   {
2541     return added;
2542   }
2543 
2544   for (i = component->remote_candidates; i ; i = i->next) {
2545 
2546     NiceCandidate *remote = i->data;
2547     ret = conn_check_add_for_candidate_pair (agent, stream_id, component, local, remote);
2548 
2549     if (ret) {
2550       ++added;
2551     }
2552   }
2553 
2554   return added;
2555 }
2556 
2557 /*
2558  * Frees the CandidateCheckPair structure pointer to
2559  * by 'user data'. Compatible with GDestroyNotify.
2560  */
candidate_check_pair_free(NiceAgent * agent,CandidateCheckPair * pair)2561 static void candidate_check_pair_free (NiceAgent *agent,
2562     CandidateCheckPair *pair)
2563 {
2564   priv_remove_pair_from_triggered_check_queue (agent, pair);
2565   priv_free_all_stun_transactions (pair, NULL);
2566   g_slice_free (CandidateCheckPair, pair);
2567 }
2568 
2569 /*
2570  * Frees all resources of all connectivity checks.
2571  */
conn_check_free(NiceAgent * agent)2572 void conn_check_free (NiceAgent *agent)
2573 {
2574   GSList *i;
2575   for (i = agent->streams; i; i = i->next) {
2576     NiceStream *stream = i->data;
2577 
2578     if (stream->conncheck_list) {
2579       GSList *item;
2580 
2581       nice_debug ("Agent %p, freeing conncheck_list of stream %p", agent,
2582           stream);
2583       for (item = stream->conncheck_list; item; item = item->next)
2584         candidate_check_pair_free (agent, item->data);
2585       g_slist_free (stream->conncheck_list);
2586       stream->conncheck_list = NULL;
2587     }
2588   }
2589 
2590   conn_check_stop (agent);
2591 }
2592 
2593 /*
2594  * Prunes the list of connectivity checks for items related
2595  * to stream 'stream_id'.
2596  *
2597  * @return TRUE on success, FALSE on a fatal error
2598  */
conn_check_prune_stream(NiceAgent * agent,NiceStream * stream)2599 void conn_check_prune_stream (NiceAgent *agent, NiceStream *stream)
2600 {
2601   GSList *i;
2602   gboolean keep_going = FALSE;
2603 
2604   if (stream->conncheck_list) {
2605     GSList *item;
2606 
2607     nice_debug ("Agent %p, freeing conncheck_list of stream %p", agent, stream);
2608 
2609     for (item = stream->conncheck_list; item; item = item->next)
2610       candidate_check_pair_free (agent, item->data);
2611     g_slist_free (stream->conncheck_list);
2612     stream->conncheck_list = NULL;
2613   }
2614 
2615   for (i = agent->streams; i; i = i->next) {
2616     NiceStream *s = i->data;
2617     if (s->conncheck_list) {
2618       keep_going = TRUE;
2619       break;
2620     }
2621   }
2622 
2623   if (!keep_going)
2624     conn_check_stop (agent);
2625 }
2626 
2627 /*
2628  * Fills 'dest' with a username string for use in an outbound connectivity
2629  * checks. No more than 'dest_len' characters (including terminating
2630  * NULL) is ever written to the 'dest'.
2631  */
2632 static
priv_gen_username(NiceAgent * agent,guint component_id,gchar * remote,gchar * local,uint8_t * dest,guint dest_len)2633 size_t priv_gen_username (NiceAgent *agent, guint component_id,
2634     gchar *remote, gchar *local, uint8_t *dest, guint dest_len)
2635 {
2636   guint len = 0;
2637   gsize remote_len = strlen (remote);
2638   gsize local_len = strlen (local);
2639 
2640   if (remote_len > 0 && local_len > 0) {
2641     if (agent->compatibility == NICE_COMPATIBILITY_RFC5245 &&
2642         dest_len >= remote_len + local_len + 1) {
2643       memcpy (dest, remote, remote_len);
2644       len += remote_len;
2645       memcpy (dest + len, ":", 1);
2646       len++;
2647       memcpy (dest + len, local, local_len);
2648       len += local_len;
2649     } else if ((agent->compatibility == NICE_COMPATIBILITY_WLM2009 ||
2650         agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
2651         dest_len >= remote_len + local_len + 4 ) {
2652       memcpy (dest, remote, remote_len);
2653       len += remote_len;
2654       memcpy (dest + len, ":", 1);
2655       len++;
2656       memcpy (dest + len, local, local_len);
2657       len += local_len;
2658       if (len % 4 != 0) {
2659         memset (dest + len, 0, 4 - (len % 4));
2660         len += 4 - (len % 4);
2661       }
2662     } else if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE &&
2663         dest_len >= remote_len + local_len) {
2664       memcpy (dest, remote, remote_len);
2665       len += remote_len;
2666       memcpy (dest + len, local, local_len);
2667       len += local_len;
2668     } else if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
2669 	       agent->compatibility == NICE_COMPATIBILITY_OC2007) {
2670       gchar component_str[10];
2671       guchar *local_decoded = NULL;
2672       guchar *remote_decoded = NULL;
2673       gsize local_decoded_len;
2674       gsize remote_decoded_len;
2675       gsize total_len;
2676       int padding;
2677 
2678       g_snprintf (component_str, sizeof(component_str), "%d", component_id);
2679       local_decoded = g_base64_decode (local, &local_decoded_len);
2680       remote_decoded = g_base64_decode (remote, &remote_decoded_len);
2681 
2682       total_len = remote_decoded_len + local_decoded_len + 3 + 2*strlen (component_str);
2683       padding = 4 - (total_len % 4);
2684 
2685       if (dest_len >= total_len + padding) {
2686         guchar pad_char[1] = {0};
2687         int i;
2688 
2689         memcpy (dest, remote_decoded, remote_decoded_len);
2690         len += remote_decoded_len;
2691         memcpy (dest + len, ":", 1);
2692         len++;
2693         memcpy (dest + len, component_str, strlen (component_str));
2694         len += strlen (component_str);
2695 
2696         memcpy (dest + len, ":", 1);
2697         len++;
2698 
2699         memcpy (dest + len, local_decoded, local_decoded_len);
2700         len += local_decoded_len;
2701         memcpy (dest + len, ":", 1);
2702         len++;
2703         memcpy (dest + len, component_str, strlen (component_str));;
2704         len += strlen (component_str);
2705 
2706         for (i = 0; i < padding; i++) {
2707           memcpy (dest + len, pad_char, 1);
2708           len++;
2709         }
2710 
2711       }
2712 
2713       g_free (local_decoded);
2714       g_free (remote_decoded);
2715     }
2716   }
2717 
2718   return len;
2719 }
2720 
2721 /*
2722  * Fills 'dest' with a username string for use in an outbound connectivity
2723  * checks. No more than 'dest_len' characters (including terminating
2724  * NULL) is ever written to the 'dest'.
2725  */
2726 static
priv_create_username(NiceAgent * agent,NiceStream * stream,guint component_id,NiceCandidate * remote,NiceCandidate * local,uint8_t * dest,guint dest_len,gboolean inbound)2727 size_t priv_create_username (NiceAgent *agent, NiceStream *stream,
2728     guint component_id, NiceCandidate *remote, NiceCandidate *local,
2729     uint8_t *dest, guint dest_len, gboolean inbound)
2730 {
2731   gchar *local_username = NULL;
2732   gchar *remote_username = NULL;
2733 
2734 
2735   if (remote && remote->username) {
2736     remote_username = remote->username;
2737   }
2738 
2739   if (local && local->username) {
2740     local_username = local->username;
2741   }
2742 
2743   if (stream) {
2744     if (remote_username == NULL) {
2745       remote_username = stream->remote_ufrag;
2746     }
2747     if (local_username == NULL) {
2748       local_username = stream->local_ufrag;
2749     }
2750   }
2751 
2752   if (local_username && remote_username) {
2753     if (inbound) {
2754       return priv_gen_username (agent, component_id,
2755           local_username, remote_username, dest, dest_len);
2756     } else {
2757       return priv_gen_username (agent, component_id,
2758           remote_username, local_username, dest, dest_len);
2759     }
2760   }
2761 
2762   return 0;
2763 }
2764 
2765 /*
2766  * Returns a password string for use in an outbound connectivity
2767  * check.
2768  */
2769 static
priv_get_password(NiceAgent * agent,NiceStream * stream,NiceCandidate * remote,uint8_t ** password)2770 size_t priv_get_password (NiceAgent *agent, NiceStream *stream,
2771     NiceCandidate *remote, uint8_t **password)
2772 {
2773   if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE)
2774     return 0;
2775 
2776   if (remote && remote->password) {
2777     *password = (uint8_t *)remote->password;
2778     return strlen (remote->password);
2779   }
2780 
2781   if (stream) {
2782     *password = (uint8_t *)stream->remote_password;
2783     return strlen (stream->remote_password);
2784   }
2785 
2786   return 0;
2787 }
2788 
2789 /* Implement the computation specific in RFC 8445 section 14 */
2790 
priv_compute_conncheck_timer(NiceAgent * agent,NiceStream * stream)2791 static unsigned int priv_compute_conncheck_timer (NiceAgent *agent, NiceStream *stream)
2792 {
2793   GSList *i, *j;
2794   guint waiting_and_in_progress = 0;
2795   unsigned int rto = 0;
2796 
2797   /* we can compute precisely the number of pairs in-progress or
2798    * waiting for all streams, instead of limiting the value to one
2799    * stream, and multiplying it by the number of active streams.
2800    * Since RFC8445, this number of waiting and in-progress pairs
2801    * if maxed by the number of different foundations in the conncheck
2802    * list.
2803    */
2804   for (i = agent->streams; i ; i = i->next) {
2805     NiceStream *s = i->data;
2806     for (j = s->conncheck_list; j ; j = j->next) {
2807       CandidateCheckPair *p = j->data;
2808       if (p->state == NICE_CHECK_IN_PROGRESS ||
2809           p->state == NICE_CHECK_WAITING)
2810         waiting_and_in_progress++;
2811     }
2812   }
2813 
2814   rto = agent->timer_ta  * waiting_and_in_progress;
2815 
2816   nice_debug ("Agent %p : timer set to %dms, "
2817     "waiting+in_progress=%d", agent, MAX (rto, STUN_TIMER_DEFAULT_TIMEOUT),
2818     waiting_and_in_progress);
2819   return MAX (rto, STUN_TIMER_DEFAULT_TIMEOUT);
2820 }
2821 
2822 /*
2823  * Sends a connectivity check over candidate pair 'pair'.
2824  *
2825  * @return zero on success, non-zero on error
2826  */
conn_check_send(NiceAgent * agent,CandidateCheckPair * pair)2827 int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
2828 {
2829 
2830   /* note: following information is supplied:
2831    *  - username (for USERNAME attribute)
2832    *  - password (for MESSAGE-INTEGRITY)
2833    *  - priority (for PRIORITY)
2834    *  - ICE-CONTROLLED/ICE-CONTROLLING (for role conflicts)
2835    *  - USE-CANDIDATE (if sent by the controlling agent)
2836    */
2837 
2838   uint8_t uname[NICE_STREAM_MAX_UNAME];
2839   NiceStream *stream;
2840   NiceComponent *component;
2841   gsize uname_len;
2842   uint8_t *password = NULL;
2843   gsize password_len;
2844   bool controlling = agent->controlling_mode;
2845  /* XXX: add API to support different nomination modes: */
2846   bool cand_use = controlling;
2847   size_t buffer_len;
2848   unsigned int timeout;
2849   StunTransaction *stun;
2850 
2851   if (!agent_find_component (agent, pair->stream_id, pair->component_id,
2852           &stream, &component))
2853     return -1;
2854 
2855   uname_len = priv_create_username (agent, stream, pair->component_id,
2856       pair->remote, pair->local, uname, sizeof (uname), FALSE);
2857   password_len = priv_get_password (agent, stream, pair->remote, &password);
2858 
2859   if (password != NULL &&
2860       (agent->compatibility == NICE_COMPATIBILITY_MSN ||
2861        agent->compatibility == NICE_COMPATIBILITY_OC2007)) {
2862     password = g_base64_decode ((gchar *) password, &password_len);
2863   }
2864 
2865   if (nice_debug_is_enabled ()) {
2866     gchar tmpbuf1[INET6_ADDRSTRLEN];
2867     gchar tmpbuf2[INET6_ADDRSTRLEN];
2868     nice_address_to_string (&pair->local->addr, tmpbuf1);
2869     nice_address_to_string (&pair->remote->addr, tmpbuf2);
2870     nice_debug ("Agent %p : STUN-CC REQ [%s]:%u --> [%s]:%u, socket=%u, "
2871         "pair=%p (c-id:%u), tie=%llu, username='%.*s' (%" G_GSIZE_FORMAT "), "
2872         "password='%.*s' (%" G_GSIZE_FORMAT "), prio=%08x, %s.", agent,
2873 	     tmpbuf1, nice_address_get_port (&pair->local->addr),
2874 	     tmpbuf2, nice_address_get_port (&pair->remote->addr),
2875              pair->sockptr->fileno ? g_socket_get_fd(pair->sockptr->fileno) : -1,
2876 	     pair, pair->component_id,
2877 	     (unsigned long long)agent->tie_breaker,
2878         (int) uname_len, uname, uname_len,
2879         (int) password_len, password, password_len,
2880         pair->stun_priority,
2881         controlling ? "controlling" : "controlled");
2882   }
2883 
2884   if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) {
2885     switch (agent->nomination_mode) {
2886       case NICE_NOMINATION_MODE_REGULAR:
2887         /* We are doing regular nomination, so we set the use-candidate
2888          * attrib, when the controlling agent decided which valid pair to
2889          * resend with this flag in priv_conn_check_tick_stream()
2890          */
2891         cand_use = pair->use_candidate_on_next_check;
2892         nice_debug ("Agent %p : %s: set cand_use=%d "
2893             "(regular nomination).", agent, G_STRFUNC, cand_use);
2894         break;
2895       case NICE_NOMINATION_MODE_AGGRESSIVE:
2896         /* We are doing aggressive nomination, we set the use-candidate
2897          * attrib in every check we send, when we are the controlling
2898          * agent, RFC 5245, 8.1.1.2
2899          */
2900         cand_use = controlling;
2901         nice_debug ("Agent %p : %s: set cand_use=%d "
2902             "(aggressive nomination).", agent, G_STRFUNC, cand_use);
2903         break;
2904       default:
2905         /* Nothing to do. */
2906         break;
2907     }
2908   } else if (cand_use)
2909     pair->nominated = controlling;
2910 
2911   if (uname_len == 0) {
2912     nice_debug ("Agent %p: no credentials found, cancelling conncheck", agent);
2913     return -1;
2914   }
2915 
2916   stun = priv_add_stun_transaction (pair);
2917 
2918   buffer_len = stun_usage_ice_conncheck_create (&component->stun_agent,
2919       &stun->message, stun->buffer, sizeof(stun->buffer),
2920       uname, uname_len, password, password_len,
2921       cand_use, controlling, pair->stun_priority,
2922       agent->tie_breaker,
2923       pair->local->foundation,
2924       agent_to_ice_compatibility (agent));
2925 
2926   nice_debug ("Agent %p: conncheck created %zd - %p", agent, buffer_len,
2927       stun->message.buffer);
2928 
2929   if (agent->compatibility == NICE_COMPATIBILITY_MSN ||
2930       agent->compatibility == NICE_COMPATIBILITY_OC2007) {
2931     g_free (password);
2932   }
2933 
2934   if (buffer_len == 0) {
2935     nice_debug ("Agent %p: buffer is empty, cancelling conncheck", agent);
2936     priv_remove_stun_transaction (pair, stun, component);
2937     return -1;
2938   }
2939 
2940   if (nice_socket_is_reliable(pair->sockptr)) {
2941     timeout = agent->stun_reliable_timeout;
2942     stun_timer_start_reliable(&stun->timer, timeout);
2943   } else {
2944     timeout = priv_compute_conncheck_timer (agent, stream);
2945     stun_timer_start (&stun->timer, timeout, agent->stun_max_retransmissions);
2946   }
2947 
2948   stun->next_tick = g_get_monotonic_time () + timeout * 1000;
2949 
2950   /* TCP-ACTIVE candidate must create a new socket before sending
2951    * by connecting to the peer. The new socket is stored in the candidate
2952    * check pair, until we discover a new local peer reflexive */
2953   if (pair->sockptr->fileno == NULL &&
2954       pair->sockptr->type != NICE_SOCKET_TYPE_UDP_TURN &&
2955       pair->local->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE) {
2956     NiceStream *stream2 = NULL;
2957     NiceComponent *component2 = NULL;
2958     NiceSocket *new_socket;
2959 
2960     if (agent_find_component (agent, pair->stream_id, pair->component_id,
2961             &stream2, &component2)) {
2962       new_socket = nice_tcp_active_socket_connect (pair->sockptr,
2963           &pair->remote->addr);
2964       if (new_socket) {
2965         nice_debug ("Agent %p: add to tcp-act socket %p a new "
2966             "tcp connect socket %p on pair %p in s/c %d/%d",
2967             agent, pair->sockptr, new_socket, pair, stream->id, component->id);
2968         pair->sockptr = new_socket;
2969         _priv_set_socket_tos (agent, pair->sockptr, stream2->tos);
2970 
2971         nice_socket_set_writable_callback (pair->sockptr, _tcp_sock_is_writable,
2972             component2);
2973 
2974         nice_component_attach_socket (component2, new_socket);
2975       }
2976     }
2977   }
2978   /* send the conncheck */
2979   agent_socket_send (pair->sockptr, &pair->remote->addr,
2980       buffer_len, (gchar *)stun->buffer);
2981 
2982   if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2)
2983     ms_ice2_legacy_conncheck_send (&stun->message, pair->sockptr,
2984         &pair->remote->addr);
2985 
2986   return 0;
2987 }
2988 
2989 /*
2990  * Implemented the pruning steps described in ICE sect 8.1.2
2991  * "Updating States" (ID-19) after a pair has been nominated.
2992  *
2993  * @see conn_check_update_check_list_state_failed_components()
2994  */
priv_prune_pending_checks(NiceAgent * agent,NiceStream * stream,NiceComponent * component)2995 static guint priv_prune_pending_checks (NiceAgent *agent, NiceStream *stream, NiceComponent *component)
2996 {
2997   GSList *i;
2998   guint64 priority;
2999   guint in_progress = 0;
3000   guint triggered_check = 0;
3001   gchar prio[NICE_CANDIDATE_PAIR_PRIORITY_MAX_SIZE];
3002 
3003   nice_debug ("Agent %p: Pruning pending checks for s%d/c%d",
3004       agent, stream->id, component->id);
3005 
3006   /* Called when we have at least one selected pair */
3007   priority = component->selected_pair.priority;
3008   g_assert (priority > 0);
3009 
3010   nice_candidate_pair_priority_to_string (priority, prio);
3011   nice_debug ("Agent %p : selected pair priority is %s", agent, prio);
3012 
3013   i = stream->conncheck_list;
3014   while (i) {
3015     CandidateCheckPair *p = i->data;
3016     GSList *next = i->next;
3017 
3018     if (p->component_id != component->id) {
3019       i = next;
3020       continue;
3021     }
3022 
3023     /* We do not remove a pair from the conncheck list if it is also in
3024      * the triggered check queue.  This is not what suggests the ICE
3025      * spec, but it proved to be more robust in the aggressive
3026      * nomination scenario, precisely because these pairs may have the
3027      * use-candidate flag set, and the peer agent may already have
3028      * selected such one.
3029      */
3030     if (g_slist_find (agent->triggered_check_queue, p) &&
3031         p->state != NICE_CHECK_IN_PROGRESS) {
3032       if (p->priority < priority) {
3033         nice_debug ("Agent %p : pair %p removed.", agent, p);
3034         candidate_check_pair_free (agent, p);
3035         stream->conncheck_list = g_slist_delete_link(stream->conncheck_list, i);
3036       } else
3037         triggered_check++;
3038     }
3039 
3040     /* step: cancel all FROZEN and WAITING pairs for the component */
3041     else if (p->state == NICE_CHECK_FROZEN || p->state == NICE_CHECK_WAITING) {
3042       nice_debug ("Agent %p : pair %p removed.", agent, p);
3043       candidate_check_pair_free (agent, p);
3044       stream->conncheck_list = g_slist_delete_link(stream->conncheck_list, i);
3045     }
3046 
3047     /* note: a SHOULD level req. in ICE 8.1.2. "Updating States" (ID-19) */
3048     else if (p->state == NICE_CHECK_IN_PROGRESS) {
3049       if (p->priority < priority) {
3050         priv_remove_pair_from_triggered_check_queue (agent, p);
3051         if (p->retransmit) {
3052           p->retransmit = FALSE;
3053           nice_debug ("Agent %p : pair %p will not be retransmitted.",
3054               agent, p);
3055         }
3056       } else {
3057         /* We must keep the higher priority pairs running because if a udp
3058          * packet was lost, we might end up using a bad candidate */
3059         nice_candidate_pair_priority_to_string (p->priority, prio);
3060         nice_debug ("Agent %p : pair %p kept IN_PROGRESS because priority "
3061             "%s is higher than priority of best nominated pair.", agent, p, prio);
3062         /* We may also have to enable the retransmit flag of pairs with
3063          * a higher priority than the first nominated pair
3064          */
3065         if (!p->retransmit && p->stun_transactions) {
3066           p->retransmit = TRUE;
3067           nice_debug ("Agent %p : pair %p will be retransmitted.", agent, p);
3068         }
3069         in_progress++;
3070       }
3071     }
3072     i = next;
3073   }
3074 
3075   return in_progress + triggered_check;
3076 }
3077 
3078 /*
3079  * Schedules a triggered check after a successfully inbound
3080  * connectivity check. Implements ICE sect 7.2.1.4 "Triggered Checks" (ID-19).
3081  *
3082  * @param agent self pointer
3083  * @param component the check is related to
3084  * @param local_socket socket from which the inbound check was received
3085  * @param remote_cand remote candidate from which the inbound check was sent
3086  */
priv_schedule_triggered_check(NiceAgent * agent,NiceStream * stream,NiceComponent * component,NiceSocket * local_socket,NiceCandidate * remote_cand)3087 static gboolean priv_schedule_triggered_check (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceSocket *local_socket, NiceCandidate *remote_cand)
3088 {
3089   GSList *i;
3090   NiceCandidate *local = NULL;
3091   CandidateCheckPair *p;
3092 
3093   g_assert (remote_cand != NULL);
3094 
3095   nice_debug ("Agent %p : scheduling triggered check with socket=%p "
3096       "and remote cand=%p.", agent, local_socket, remote_cand);
3097 
3098   for (i = stream->conncheck_list; i ; i = i->next) {
3099       p = i->data;
3100       if (p->component_id == component->id &&
3101 	  p->remote == remote_cand &&
3102           p->sockptr == local_socket) {
3103         /* If we match with a peer-reflexive discovered pair, we
3104          * use the parent succeeded pair instead */
3105 
3106         if (p->succeeded_pair != NULL) {
3107           g_assert_cmpint (p->state, ==, NICE_CHECK_DISCOVERED);
3108           p = p->succeeded_pair;
3109         }
3110 
3111 	nice_debug ("Agent %p : Found a matching pair %p (%s) (%s) ...",
3112             agent, p, p->foundation, priv_state_to_string (p->state));
3113 
3114 	switch (p->state) {
3115           case NICE_CHECK_WAITING:
3116 	  case NICE_CHECK_FROZEN:
3117             nice_debug ("Agent %p : pair %p added for a triggered check.",
3118                 agent, p);
3119             priv_add_pair_to_triggered_check_queue (agent, p);
3120             break;
3121           case NICE_CHECK_IN_PROGRESS:
3122             /* note: according to ICE SPEC sect 7.2.1.4 "Triggered Checks"
3123              * we cancel the in-progress transaction, and after the
3124              * retransmission timeout, we create a new connectivity check
3125              * for that pair.  The controlling role of this new check may
3126              * be different from the role of this cancelled check.
3127              *
3128              * When another pair, with a higher priority is already
3129              * nominated, so there's no reason to recheck this pair,
3130              * since it can in no way replace the nominated one.
3131              */
3132             if (p->priority > component->selected_pair.priority) {
3133               nice_debug ("Agent %p : pair %p added for a triggered check.",
3134                   agent, p);
3135               priv_add_pair_to_triggered_check_queue (agent, p);
3136             }
3137             break;
3138           case NICE_CHECK_FAILED:
3139             if (p->priority > component->selected_pair.priority) {
3140                 nice_debug ("Agent %p : pair %p added for a triggered check.",
3141                     agent, p);
3142                 priv_add_pair_to_triggered_check_queue (agent, p);
3143                 /* If the component for this pair is in failed state, move it
3144                  * back to connecting, and reinitiate the timers
3145                  */
3146                 if (component->state == NICE_COMPONENT_STATE_FAILED) {
3147                   agent_signal_component_state_change (agent, stream->id,
3148                       component->id, NICE_COMPONENT_STATE_CONNECTING);
3149                   conn_check_schedule_next (agent);
3150                 /* If the component if in ready state, move it back to
3151                  * connected as this failed pair with a higher priority
3152                  * than the nominated pair requires to pursue the
3153                  * conncheck
3154                  */
3155                 } else if (component->state == NICE_COMPONENT_STATE_READY) {
3156                   agent_signal_component_state_change (agent, stream->id,
3157                       component->id, NICE_COMPONENT_STATE_CONNECTED);
3158                   conn_check_schedule_next (agent);
3159                 }
3160             }
3161             break;
3162 	  case NICE_CHECK_SUCCEEDED:
3163             nice_debug ("Agent %p : nothing to do for pair %p.", agent, p);
3164             break;
3165           default:
3166             break;
3167         }
3168 
3169 	/* note: the spec says the we SHOULD retransmit in-progress
3170 	 *       checks immediately, but we won't do that now */
3171 
3172 	return TRUE;
3173       }
3174   }
3175 
3176   for (i = component->local_candidates; i ; i = i->next) {
3177       NiceCandidateImpl *lc = i->data;
3178       local = i->data;
3179       if (lc->sockptr == local_socket)
3180         break;
3181   }
3182 
3183   if (i) {
3184     nice_debug ("Agent %p : Adding a triggered check to conn.check list (local=%p).", agent, local);
3185     p = priv_conn_check_add_for_candidate_pair_matched (agent, stream->id,
3186         component, local, remote_cand, NICE_CHECK_WAITING);
3187     if (p)
3188       priv_add_pair_to_triggered_check_queue (agent, p);
3189     return TRUE;
3190   }
3191   else {
3192     nice_debug ("Agent %p : Didn't find a matching pair for triggered check (remote-cand=%p).", agent, remote_cand);
3193     return FALSE;
3194   }
3195 }
3196 
3197 
3198 /*
3199  * Sends a reply to an successfully received STUN connectivity
3200  * check request. Implements parts of the ICE spec section 7.2 (STUN
3201  * Server Procedures).
3202  *
3203  * @param agent context pointer
3204  * @param stream which stream (of the agent)
3205  * @param component which component (of the stream)
3206  * @param rcand remote candidate from which the request came, if NULL,
3207  *        the response is sent immediately but no other processing is done
3208  * @param toaddr address to which reply is sent
3209  * @param socket the socket over which the request came
3210  * @param rbuf_len length of STUN message to send
3211  * @param msg the STUN message to send
3212  * @param use_candidate whether the request had USE_CANDIDATE attribute
3213  *
3214  * @pre (rcand == NULL || nice_address_equal(rcand->addr, toaddr) == TRUE)
3215  */
priv_reply_to_conn_check(NiceAgent * agent,NiceStream * stream,NiceComponent * component,NiceCandidate * lcand,NiceCandidate * rcand,const NiceAddress * toaddr,NiceSocket * sockptr,size_t rbuf_len,StunMessage * msg,gboolean use_candidate)3216 static void priv_reply_to_conn_check (NiceAgent *agent, NiceStream *stream,
3217     NiceComponent *component, NiceCandidate *lcand, NiceCandidate *rcand,
3218     const NiceAddress *toaddr, NiceSocket *sockptr, size_t rbuf_len,
3219     StunMessage *msg, gboolean use_candidate)
3220 {
3221   g_assert (rcand == NULL || nice_address_equal(&rcand->addr, toaddr) == TRUE);
3222 
3223   if (nice_debug_is_enabled ()) {
3224     gchar tmpbuf[INET6_ADDRSTRLEN];
3225     nice_address_to_string (toaddr, tmpbuf);
3226     nice_debug ("Agent %p : STUN-CC RESP to '%s:%u', socket=%u, len=%u, cand=%p (c-id:%u), use-cand=%d.", agent,
3227 	     tmpbuf,
3228 	     nice_address_get_port (toaddr),
3229              sockptr->fileno ? g_socket_get_fd(sockptr->fileno) : -1,
3230 	     (unsigned)rbuf_len,
3231 	     rcand, component->id,
3232 	     (int)use_candidate);
3233   }
3234 
3235   agent_socket_send (sockptr, toaddr, rbuf_len, (const gchar*)msg->buffer);
3236   if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
3237     ms_ice2_legacy_conncheck_send(msg, sockptr, toaddr);
3238   }
3239 
3240   /* We react to this stun request when we have the remote credentials.
3241    * When credentials are not yet known, this request is stored
3242    * in incoming_checks for later processing when returning from this
3243    * function.
3244    */
3245   if (rcand && stream->remote_ufrag[0]) {
3246     priv_schedule_triggered_check (agent, stream, component, sockptr, rcand);
3247     if (use_candidate)
3248       priv_mark_pair_nominated (agent, stream, component, lcand, rcand);
3249   }
3250 }
3251 
3252 /*
3253  * Stores information of an incoming STUN connectivity check
3254  * for later use. This is only needed when a check is received
3255  * before we get information about the remote candidates (via
3256  * SDP or other signaling means).
3257  *
3258  * @return non-zero on error, zero on success
3259  */
priv_store_pending_check(NiceAgent * agent,NiceComponent * component,const NiceAddress * from,NiceSocket * sockptr,uint8_t * username,uint16_t username_len,uint32_t priority,gboolean use_candidate)3260 static int priv_store_pending_check (NiceAgent *agent, NiceComponent *component,
3261     const NiceAddress *from, NiceSocket *sockptr, uint8_t *username,
3262     uint16_t username_len, uint32_t priority, gboolean use_candidate)
3263 {
3264   IncomingCheck *icheck;
3265   nice_debug ("Agent %p : Storing pending check.", agent);
3266 
3267   if (g_queue_get_length (&component->incoming_checks) >=
3268       NICE_AGENT_MAX_REMOTE_CANDIDATES) {
3269     nice_debug ("Agent %p : WARN: unable to store information for early incoming check.", agent);
3270     return -1;
3271   }
3272 
3273   icheck = g_slice_new0 (IncomingCheck);
3274   g_queue_push_tail (&component->incoming_checks, icheck);
3275   icheck->from = *from;
3276   icheck->local_socket = sockptr;
3277   icheck->priority = priority;
3278   icheck->use_candidate = use_candidate;
3279   icheck->username_len = username_len;
3280   icheck->username = NULL;
3281   if (username_len > 0)
3282     icheck->username = g_memdup (username, username_len);
3283 
3284   return 0;
3285 }
3286 
3287 /*
3288  * Adds a new pair, discovered from an incoming STUN response, to
3289  * the connectivity check list.
3290  *
3291  * @return created pair, or NULL on fatal (memory allocation) errors
3292  */
priv_add_peer_reflexive_pair(NiceAgent * agent,guint stream_id,NiceComponent * component,NiceCandidateImpl * local_cand,CandidateCheckPair * parent_pair)3293 static CandidateCheckPair *priv_add_peer_reflexive_pair (NiceAgent *agent, guint stream_id, NiceComponent *component, NiceCandidateImpl *local_cand, CandidateCheckPair *parent_pair)
3294 {
3295   CandidateCheckPair *pair = g_slice_new0 (CandidateCheckPair);
3296   NiceStream *stream = agent_find_stream (agent, stream_id);
3297 
3298   pair->stream_id = stream_id;
3299   pair->component_id = component->id;;
3300   pair->local = (NiceCandidate *) local_cand;
3301   pair->remote = parent_pair->remote;
3302   pair->sockptr = local_cand->sockptr;
3303   parent_pair->discovered_pair = pair;
3304   pair->succeeded_pair = parent_pair;
3305   nice_debug ("Agent %p : creating a new pair", agent);
3306   SET_PAIR_STATE (agent, pair, NICE_CHECK_DISCOVERED);
3307   {
3308       gchar tmpbuf1[INET6_ADDRSTRLEN];
3309       gchar tmpbuf2[INET6_ADDRSTRLEN];
3310       nice_address_to_string (&pair->local->addr, tmpbuf1);
3311       nice_address_to_string (&pair->remote->addr, tmpbuf2);
3312       nice_debug ("Agent %p : new pair %p : [%s]:%u --> [%s]:%u", agent, pair,
3313           tmpbuf1, nice_address_get_port (&pair->local->addr),
3314           tmpbuf2, nice_address_get_port (&pair->remote->addr));
3315   }
3316   g_snprintf (pair->foundation, NICE_CANDIDATE_PAIR_MAX_FOUNDATION, "%s:%s",
3317       local_cand->c.foundation, parent_pair->remote->foundation);
3318 
3319   if (agent->controlling_mode == TRUE)
3320     pair->priority = nice_candidate_pair_priority (pair->local->priority,
3321         pair->remote->priority);
3322   else
3323     pair->priority = nice_candidate_pair_priority (pair->remote->priority,
3324         pair->local->priority);
3325   pair->nominated = parent_pair->nominated;
3326   /* the peer-reflexive priority used in stun request is copied from
3327    * the parent succeeded pair. This value is not required for discovered
3328    * pair, that won't emit stun requests themselves, but may be used when
3329    * such pair becomes the selected pair, and when keepalive stun are emitted,
3330    * using the sockptr and stun_priority values from the succeeded pair.
3331    */
3332   pair->stun_priority = parent_pair->stun_priority;
3333   nice_debug ("Agent %p : added a new peer-discovered pair %p with "
3334       "foundation '%s' and transport %s:%s to stream %u component %u",
3335       agent, pair, pair->foundation,
3336       nice_candidate_transport_to_string (pair->local->transport),
3337       nice_candidate_transport_to_string (pair->remote->transport),
3338       stream_id, component->id);
3339 
3340   stream->conncheck_list = g_slist_insert_sorted (stream->conncheck_list, pair,
3341       (GCompareFunc)conn_check_compare);
3342 
3343   return pair;
3344 }
3345 
3346 /*
3347  * Recalculates priorities of all candidate pairs. This
3348  * is required after a conflict in ICE roles.
3349  */
recalculate_pair_priorities(NiceAgent * agent)3350 void recalculate_pair_priorities (NiceAgent *agent)
3351 {
3352   GSList *i, *j;
3353 
3354   for (i = agent->streams; i; i = i->next) {
3355     NiceStream *stream = i->data;
3356     for (j = stream->conncheck_list; j; j = j->next) {
3357       CandidateCheckPair *p = j->data;
3358       p->priority = agent_candidate_pair_priority (agent, p->local, p->remote);
3359     }
3360     stream->conncheck_list = g_slist_sort (stream->conncheck_list,
3361         (GCompareFunc)conn_check_compare);
3362   }
3363 }
3364 
3365 /*
3366  * Change the agent role if different from 'control'. Can be
3367  * initiated both by handling of incoming connectivity checks,
3368  * and by processing the responses to checks sent by us.
3369  */
priv_check_for_role_conflict(NiceAgent * agent,gboolean control)3370 static void priv_check_for_role_conflict (NiceAgent *agent, gboolean control)
3371 {
3372   /* role conflict, change mode; wait for a new conn. check */
3373   if (control != agent->controlling_mode) {
3374     nice_debug ("Agent %p : Role conflict, changing agent role to \"%s\".",
3375         agent, control ? "controlling" : "controlled");
3376     agent->controlling_mode = control;
3377     /* the pair priorities depend on the roles, so recalculation
3378      * is needed */
3379     recalculate_pair_priorities (agent);
3380   }
3381   else
3382     nice_debug ("Agent %p : Role conflict, staying with role \"%s\".",
3383         agent, control ? "controlling" : "controlled");
3384 }
3385 
3386 /*
3387  * Checks whether the mapped address in connectivity check response
3388  * matches any of the known local candidates. If not, apply the
3389  * mechanism for "Discovering Peer Reflexive Candidates" ICE ID-19)
3390  *
3391  * @param agent context pointer
3392  * @param stream which stream (of the agent)
3393  * @param component which component (of the stream)
3394  * @param p the connectivity check pair for which we got a response
3395  * @param socketptr socket used to send the reply
3396  * @param mapped_sockaddr mapped address in the response
3397  *
3398  * @return pointer to a candidate pair, found in conncheck list or newly created
3399  */
priv_process_response_check_for_reflexive(NiceAgent * agent,NiceStream * stream,NiceComponent * component,CandidateCheckPair * p,NiceSocket * sockptr,struct sockaddr * mapped_sockaddr,NiceCandidate * local_candidate,NiceCandidate * remote_candidate)3400 static CandidateCheckPair *priv_process_response_check_for_reflexive(NiceAgent *agent, NiceStream *stream, NiceComponent *component, CandidateCheckPair *p, NiceSocket *sockptr, struct sockaddr *mapped_sockaddr, NiceCandidate *local_candidate, NiceCandidate *remote_candidate)
3401 {
3402   CandidateCheckPair *new_pair = NULL;
3403   NiceAddress mapped;
3404   GSList *i;
3405   NiceCandidate *local_cand = NULL;
3406 
3407   nice_address_set_from_sockaddr (&mapped, mapped_sockaddr);
3408 
3409   for (i = component->local_candidates; i; i = i->next) {
3410     NiceCandidate *cand = i->data;
3411 
3412     if (nice_address_equal (&mapped, &cand->addr) &&
3413         local_candidate_and_socket_compatible (agent, cand, sockptr)) {
3414       local_cand = cand;
3415       break;
3416     }
3417   }
3418 
3419   /* The mapped address allows to look for a previously discovered
3420    * peer reflexive local candidate, and its related pair. This
3421    * new_pair will be marked 'Valid', while the pair 'p' of the
3422    * initial stun request will be marked 'Succeeded'
3423    *
3424    * In the case of a tcp-act/tcp-pass pair 'p', where the local
3425    * candidate is of type tcp-act, and its port number is zero, a
3426    * conncheck on this pair *always* leads to the creation of a
3427    * discovered peer-reflexive tcp-act local candidate.
3428    */
3429   for (i = stream->conncheck_list; i; i = i->next) {
3430     CandidateCheckPair *pair = i->data;
3431     if (local_cand == pair->local && remote_candidate == pair->remote) {
3432       new_pair = pair;
3433       break;
3434     }
3435   }
3436 
3437   if (new_pair) {
3438     /* note: when new_pair is distinct from p, it means new_pair is a
3439      * previously discovered peer-reflexive candidate pair, so we don't
3440      * set the valid flag on p in this case, because the valid flag is
3441      * already set on the discovered pair.
3442      */
3443     if (new_pair == p)
3444       p->valid = TRUE;
3445     SET_PAIR_STATE (agent, p, NICE_CHECK_SUCCEEDED);
3446     priv_remove_pair_from_triggered_check_queue (agent, p);
3447     priv_free_all_stun_transactions (p, component);
3448     nice_component_add_valid_candidate (agent, component, remote_candidate);
3449   }
3450   else {
3451     if (local_cand == NULL && !agent->force_relay) {
3452       /* step: find a new local candidate, see RFC 5245 7.1.3.2.1.
3453        * "Discovering Peer Reflexive Candidates"
3454        *
3455        * The priority equal to the value of the PRIORITY attribute
3456        * in the Binding request is taken from the "parent" pair p
3457        */
3458       local_cand = discovery_add_peer_reflexive_candidate (agent,
3459                                                            stream->id,
3460                                                            component->id,
3461                                                            p->stun_priority,
3462                                                           &mapped,
3463                                                            sockptr,
3464                                                            local_candidate,
3465                                                            remote_candidate);
3466       nice_debug ("Agent %p : added a new peer-reflexive local candidate %p "
3467           "with transport %s", agent, local_cand,
3468           nice_candidate_transport_to_string (local_cand->transport));
3469     }
3470 
3471     /* step: add a new discovered pair (see RFC 5245 7.1.3.2.2
3472 	       "Constructing a Valid Pair") */
3473     if (local_cand)
3474       new_pair = priv_add_peer_reflexive_pair (agent, stream->id, component,
3475           (NiceCandidateImpl *) local_cand, p);
3476     /* note: this is same as "adding to VALID LIST" in the spec
3477        text */
3478     if (new_pair)
3479       new_pair->valid = TRUE;
3480     /* step: The agent sets the state of the pair that *generated* the check to
3481      * Succeeded, RFC 5245, 7.1.3.2.3, "Updating Pair States"
3482      */
3483     SET_PAIR_STATE (agent, p, NICE_CHECK_SUCCEEDED);
3484     priv_remove_pair_from_triggered_check_queue (agent, p);
3485     priv_free_all_stun_transactions (p, component);
3486   }
3487 
3488   if (new_pair && new_pair->valid)
3489     nice_component_add_valid_candidate (agent, component, remote_candidate);
3490 
3491 
3492   return new_pair;
3493 }
3494 
3495 /*
3496  * Tries to match STUN reply in 'buf' to an existing STUN connectivity
3497  * check transaction. If found, the reply is processed. Implements
3498  * section 7.1.2 "Processing the Response" of ICE spec (ID-19).
3499  *
3500  * @return TRUE if a matching transaction is found
3501  */
priv_map_reply_to_conn_check_request(NiceAgent * agent,NiceStream * stream,NiceComponent * component,NiceSocket * sockptr,const NiceAddress * from,NiceCandidate * local_candidate,NiceCandidate * remote_candidate,StunMessage * resp)3502 static gboolean priv_map_reply_to_conn_check_request (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceSocket *sockptr, const NiceAddress *from, NiceCandidate *local_candidate, NiceCandidate *remote_candidate, StunMessage *resp)
3503 {
3504   union {
3505     struct sockaddr_storage storage;
3506     struct sockaddr addr;
3507   } sockaddr;
3508   socklen_t socklen = sizeof (sockaddr);
3509   GSList *i, *j;
3510   guint k;
3511   StunUsageIceReturn res;
3512   StunTransactionId discovery_id;
3513   StunTransactionId response_id;
3514   stun_message_id (resp, response_id);
3515 
3516   for (i = stream->conncheck_list; i; i = i->next) {
3517     CandidateCheckPair *p = i->data;
3518 
3519     for (j = p->stun_transactions, k = 0; j; j = j->next, k++) {
3520       StunTransaction *stun = j->data;
3521 
3522       stun_message_id (&stun->message, discovery_id);
3523 
3524       if (memcmp (discovery_id, response_id, sizeof(StunTransactionId)))
3525 	continue;
3526 
3527       res = stun_usage_ice_conncheck_process (resp,
3528 	  &sockaddr.storage, &socklen,
3529 	  agent_to_ice_compatibility (agent));
3530       nice_debug ("Agent %p : stun_bind_process/conncheck for %p: "
3531 	  "%s,res=%s,stun#=%d.",
3532 	  agent, p,
3533 	  agent->controlling_mode ? "controlling" : "controlled",
3534 	  priv_ice_return_to_string (res), k);
3535 
3536       if (res == STUN_USAGE_ICE_RETURN_SUCCESS ||
3537 	  res == STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS) {
3538 	/* case: found a matching connectivity check request */
3539 
3540 	CandidateCheckPair *ok_pair = NULL;
3541 
3542 	nice_debug ("Agent %p : pair %p MATCHED.", agent, p);
3543 	priv_remove_stun_transaction (p, stun, component);
3544 
3545 	/* step: verify that response came from the same IP address we
3546 	 *       sent the original request to (see 7.1.2.1. "Failure
3547 	 *       Cases") */
3548 	if (nice_address_equal (from, &p->remote->addr) == FALSE) {
3549 	  candidate_check_pair_fail (stream, agent, p);
3550 	  if (nice_debug_is_enabled ()) {
3551 	    gchar tmpbuf[INET6_ADDRSTRLEN];
3552 	    gchar tmpbuf2[INET6_ADDRSTRLEN];
3553 	    nice_debug ("Agent %p : pair %p FAILED"
3554 		" (mismatch of source address).", agent, p);
3555 	    nice_address_to_string (&p->remote->addr, tmpbuf);
3556 	    nice_address_to_string (from, tmpbuf2);
3557 	    nice_debug ("Agent %p : '%s:%u' != '%s:%u'", agent,
3558 		tmpbuf, nice_address_get_port (&p->remote->addr),
3559 		tmpbuf2, nice_address_get_port (from));
3560 	  }
3561           conn_check_update_check_list_state_for_ready (agent,
3562               stream, component);
3563 	  return TRUE;
3564 	}
3565 
3566         if (remote_candidate == NULL) {
3567           candidate_check_pair_fail (stream, agent, p);
3568           if (nice_debug_is_enabled ()) {
3569             nice_debug ("Agent %p : pair %p FAILED "
3570                 "(got a matching pair without a known remote candidate).", agent, p);
3571           }
3572           conn_check_update_check_list_state_for_ready (agent,
3573               stream, component);
3574           return TRUE;
3575         }
3576 
3577 	/* note: CONNECTED but not yet READY, see docs */
3578 
3579 	/* step: handle the possible case of a peer-reflexive
3580 	 *       candidate where the mapped-address in response does
3581 	 *       not match any local candidate, see 7.1.2.2.1
3582 	 *       "Discovering Peer Reflexive Candidates" ICE ID-19) */
3583 
3584         if (res == STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS) {
3585           nice_debug ("Agent %p : Mapped address not found", agent);
3586           SET_PAIR_STATE (agent, p, NICE_CHECK_SUCCEEDED);
3587           p->valid = TRUE;
3588           nice_component_add_valid_candidate (agent, component, p->remote);
3589         } else
3590           ok_pair = priv_process_response_check_for_reflexive (agent,
3591               stream, component, p, sockptr, &sockaddr.addr,
3592               local_candidate, remote_candidate);
3593 
3594 	/* note: The success of this check might also
3595 	 * cause the state of other checks to change as well
3596          * See sect 7.2.5.3.3 (Updating Candidate Pair States) of
3597          * ICE spec (RFC8445).
3598 	 */
3599 	conn_check_unfreeze_related (agent, p);
3600 
3601 	/* Note: this assignment helps to reduce the numbers of cases
3602 	 * to be tested. If ok_pair and p refer to distinct pairs, it
3603 	 * means that ok_pair is a discovered peer reflexive one,
3604 	 * caused by the check made on pair p.  In that case, the
3605 	 * flags to be tested are on p, but the nominated flag will be
3606 	 * set on ok_pair. When there's no discovered pair, p and
3607 	 * ok_pair refer to the same pair.
3608 	 * To summarize : p is a SUCCEEDED pair, ok_pair is a
3609 	 * DISCOVERED, VALID, and eventually NOMINATED pair.
3610 	 */
3611 	if (!ok_pair)
3612 	  ok_pair = p;
3613 
3614 	/* step: updating nominated flag (ICE 7.1.2.2.4 "Updating the
3615 	   Nominated Flag" (ID-19) */
3616 	if (NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent)) {
3617 	  nice_debug ("Agent %p : Updating nominated flag (%s): "
3618 	      "ok_pair=%p (%d/%d) p=%p (%d/%d) (ucnc/mnora)",
3619 	      agent, p->local->transport == NICE_CANDIDATE_TRANSPORT_UDP ?
3620 		"UDP" : "TCP",
3621 	      ok_pair, ok_pair->use_candidate_on_next_check,
3622 	      ok_pair->mark_nominated_on_response_arrival,
3623 	      p, p->use_candidate_on_next_check,
3624 	      p->mark_nominated_on_response_arrival);
3625 
3626 	  if (agent->controlling_mode) {
3627 	    switch (agent->nomination_mode) {
3628 	      case NICE_NOMINATION_MODE_REGULAR:
3629 		if (p->use_candidate_on_next_check) {
3630 		  nice_debug ("Agent %p : marking pair %p (%s) as nominated "
3631 		      "(regular nomination, controlling, "
3632 		      "use_cand_on_next_check=1).",
3633 		      agent, ok_pair, ok_pair->foundation);
3634 		  ok_pair->nominated = TRUE;
3635 		}
3636 		break;
3637 	      case NICE_NOMINATION_MODE_AGGRESSIVE:
3638 		if (!p->nominated) {
3639 		  nice_debug ("Agent %p : marking pair %p (%s) as nominated "
3640 		      "(aggressive nomination, controlling).",
3641 		      agent, ok_pair, ok_pair->foundation);
3642 		  ok_pair->nominated = TRUE;
3643 		}
3644 		break;
3645 	      default:
3646 		/* Nothing to do */
3647 		break;
3648 	    }
3649 	  } else {
3650 	    if (p->mark_nominated_on_response_arrival) {
3651 	      nice_debug ("Agent %p : marking pair %p (%s) as nominated "
3652 		  "(%s nomination, controlled, mark_on_response=1).",
3653 		  agent, ok_pair, ok_pair->foundation,
3654 		  agent->nomination_mode == NICE_NOMINATION_MODE_AGGRESSIVE ?
3655 		    "aggressive" : "regular");
3656 	      ok_pair->nominated = TRUE;
3657 	    }
3658 	  }
3659 	}
3660 
3661 	if (ok_pair->nominated == TRUE) {
3662           conn_check_update_selected_pair (agent, component, ok_pair);
3663 	  priv_print_conn_check_lists (agent, G_STRFUNC,
3664 	      ", got a nominated pair");
3665 
3666 	  /* Do not step down to CONNECTED if we're already at state READY*/
3667 	  if (component->state != NICE_COMPONENT_STATE_READY)
3668 	    /* step: notify the client of a new component state (must be done
3669 	     *       before the possible check list state update step */
3670 	    agent_signal_component_state_change (agent,
3671 		stream->id, component->id, NICE_COMPONENT_STATE_CONNECTED);
3672 	}
3673 
3674 	/* step: update pair states (ICE 7.1.2.2.3 "Updating pair
3675 	   states" and 8.1.2 "Updating States", ID-19) */
3676 	conn_check_update_check_list_state_for_ready (agent, stream, component);
3677       } else if (res == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT) {
3678         uint64_t tie;
3679         gboolean controlled_mode;
3680 
3681         if (!p->retransmit) {
3682           nice_debug ("Agent %p : Role conflict with pair %p, not restarting",
3683               agent, p);
3684           return TRUE;
3685         }
3686 
3687 	/* case: role conflict error, need to restart with new role */
3688 	nice_debug ("Agent %p : Role conflict with pair %p, restarting",
3689             agent, p);
3690 
3691 	/* note: this res value indicates that the role of the peer
3692 	 * agent has not changed after the tie-breaker comparison, so
3693 	 * this is our role that must change. see ICE sect. 7.1.3.1
3694 	 * "Failure Cases". Our role might already have changed due to
3695 	 * an earlier incoming request, but if not, change role now.
3696 	 *
3697 	 * Sect. 7.1.3.1 is not clear on this point, but we choose to
3698 	 * put the candidate pair in the triggered check list even
3699 	 * when the agent did not switch its role. The reason for this
3700 	 * interpretation is that the reception of the stun reply, even
3701 	 * an error reply, is a good sign that this pair will be
3702 	 * valid, if we retry the check after the role of both peers
3703 	 * has been fixed.
3704 	 */
3705         controlled_mode = (stun_message_find64 (&stun->message,
3706             STUN_ATTRIBUTE_ICE_CONTROLLED, &tie) ==
3707             STUN_MESSAGE_RETURN_SUCCESS);
3708 
3709         priv_check_for_role_conflict (agent, controlled_mode);
3710 	priv_remove_stun_transaction (p, stun, component);
3711         priv_add_pair_to_triggered_check_queue (agent, p);
3712       } else {
3713 	/* case: STUN error, the check STUN context was freed */
3714 	candidate_check_pair_fail (stream, agent, p);
3715         conn_check_update_check_list_state_for_ready (agent, stream, component);
3716       }
3717       return TRUE;
3718     }
3719   }
3720 
3721   return FALSE;
3722 }
3723 
3724 /*
3725  * Tries to match STUN reply in 'buf' to an existing STUN discovery
3726  * transaction. If found, a reply is sent.
3727  *
3728  * @return TRUE if a matching transaction is found
3729  */
priv_map_reply_to_discovery_request(NiceAgent * agent,StunMessage * resp)3730 static gboolean priv_map_reply_to_discovery_request (NiceAgent *agent, StunMessage *resp)
3731 {
3732   union {
3733     struct sockaddr_storage storage;
3734     struct sockaddr addr;
3735   } sockaddr;
3736   socklen_t socklen = sizeof (sockaddr);
3737 
3738   union {
3739     struct sockaddr_storage storage;
3740     struct sockaddr addr;
3741   } alternate;
3742   socklen_t alternatelen = sizeof (sockaddr);
3743 
3744   GSList *i;
3745   StunUsageBindReturn res;
3746   gboolean trans_found = FALSE;
3747   StunTransactionId discovery_id;
3748   StunTransactionId response_id;
3749   stun_message_id (resp, response_id);
3750 
3751   for (i = agent->discovery_list; i && trans_found != TRUE; i = i->next) {
3752     CandidateDiscovery *d = i->data;
3753 
3754     if (d->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE &&
3755         d->stun_message.buffer) {
3756       stun_message_id (&d->stun_message, discovery_id);
3757 
3758       if (memcmp (discovery_id, response_id, sizeof(StunTransactionId)) == 0) {
3759         res = stun_usage_bind_process (resp, &sockaddr.addr,
3760             &socklen, &alternate.addr, &alternatelen);
3761         nice_debug ("Agent %p : stun_bind_process/disc for %p res %d.",
3762             agent, d, (int)res);
3763 
3764         if (res == STUN_USAGE_BIND_RETURN_ALTERNATE_SERVER) {
3765           /* handle alternate server */
3766           NiceAddress niceaddr;
3767           nice_address_set_from_sockaddr (&niceaddr, &alternate.addr);
3768           d->server = niceaddr;
3769 
3770           d->pending = FALSE;
3771           agent->discovery_unsched_items++;
3772         } else if (res == STUN_USAGE_BIND_RETURN_SUCCESS) {
3773           /* case: successful binding discovery, create a new local candidate */
3774 
3775           if (!agent->force_relay) {
3776             NiceAddress niceaddr;
3777 
3778             nice_address_set_from_sockaddr (&niceaddr, &sockaddr.addr);
3779             discovery_add_server_reflexive_candidate (
3780                 agent,
3781                 d->stream_id,
3782                 d->component_id,
3783                 &niceaddr,
3784                 NICE_CANDIDATE_TRANSPORT_UDP,
3785                 d->nicesock,
3786                 FALSE);
3787             if (agent->use_ice_tcp)
3788               discovery_discover_tcp_server_reflexive_candidates (
3789                   agent,
3790                   d->stream_id,
3791                   d->component_id,
3792                   &niceaddr,
3793                   d->nicesock);
3794           }
3795           d->stun_message.buffer = NULL;
3796           d->stun_message.buffer_len = 0;
3797           d->done = TRUE;
3798           trans_found = TRUE;
3799         } else if (res == STUN_USAGE_BIND_RETURN_ERROR) {
3800           /* case: STUN error, the check STUN context was freed */
3801           d->stun_message.buffer = NULL;
3802           d->stun_message.buffer_len = 0;
3803           d->done = TRUE;
3804           trans_found = TRUE;
3805         }
3806       }
3807     }
3808   }
3809 
3810   return trans_found;
3811 }
3812 
3813 static guint
priv_calc_turn_timeout(guint lifetime)3814 priv_calc_turn_timeout (guint lifetime)
3815 {
3816   if (lifetime > 120)
3817     return lifetime - 60;
3818   else
3819     return lifetime / 2;
3820 }
3821 
3822 static void
priv_add_new_turn_refresh(NiceAgent * agent,CandidateDiscovery * cdisco,NiceCandidateImpl * relay_cand,guint lifetime)3823 priv_add_new_turn_refresh (NiceAgent *agent, CandidateDiscovery *cdisco,
3824     NiceCandidateImpl *relay_cand, guint lifetime)
3825 {
3826   CandidateRefresh *cand;
3827 
3828   if (cdisco->turn->type == NICE_RELAY_TYPE_TURN_TLS &&
3829       (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
3830        agent->compatibility == NICE_COMPATIBILITY_OC2007R2))
3831     return;
3832 
3833   cand = g_slice_new0 (CandidateRefresh);
3834   agent->refresh_list = g_slist_append (agent->refresh_list, cand);
3835 
3836   cand->candidate = relay_cand;
3837   cand->nicesock = cdisco->nicesock;
3838   cand->server = cdisco->server;
3839   cand->stream_id = cdisco->stream_id;
3840   cand->component_id = cdisco->component_id;
3841   memcpy (&cand->stun_agent, &cdisco->stun_agent, sizeof(StunAgent));
3842 
3843   /* Use previous stun response for authentication credentials */
3844   if (cdisco->stun_resp_msg.buffer != NULL) {
3845     memcpy(cand->stun_resp_buffer, cdisco->stun_resp_buffer,
3846         sizeof(cand->stun_resp_buffer));
3847     memcpy(&cand->stun_resp_msg, &cdisco->stun_resp_msg, sizeof(StunMessage));
3848     cand->stun_resp_msg.buffer = cand->stun_resp_buffer;
3849     cand->stun_resp_msg.agent = &cand->stun_agent;
3850     cand->stun_resp_msg.key = NULL;
3851   }
3852 
3853   nice_debug ("Agent %p : Adding new refresh candidate %p with timeout %d",
3854       agent, cand, priv_calc_turn_timeout (lifetime));
3855   /* step: also start the refresh timer */
3856   /* refresh should be sent 1 minute before it expires */
3857   agent_timeout_add_seconds_with_context (agent, &cand->timer_source,
3858       "Candidate TURN refresh",
3859       priv_calc_turn_timeout (lifetime),
3860       priv_turn_allocate_refresh_tick_agent_locked, cand);
3861 
3862   nice_debug ("timer source is : %p", cand->timer_source);
3863 
3864   return;
3865 }
3866 
priv_handle_turn_alternate_server(NiceAgent * agent,CandidateDiscovery * disco,NiceAddress server,NiceAddress alternate)3867 static void priv_handle_turn_alternate_server (NiceAgent *agent,
3868     CandidateDiscovery *disco, NiceAddress server, NiceAddress alternate)
3869 {
3870   /* We need to cancel and reset all candidate discovery turn for the same
3871      stream and type if there is an alternate server. Otherwise, we might end up
3872      with two relay components on different servers, creating candidates with
3873      unique foundations that only contain one component.
3874   */
3875   GSList *i;
3876 
3877   for (i = agent->discovery_list; i; i = i->next) {
3878     CandidateDiscovery *d = i->data;
3879 
3880     if (!d->done &&
3881         d->type == disco->type &&
3882         d->stream_id == disco->stream_id &&
3883         d->turn->type == disco->turn->type &&
3884         nice_address_equal (&d->server, &server)) {
3885       gchar ip[INET6_ADDRSTRLEN];
3886       // Cancel the pending request to avoid a race condition with another
3887       // component responding with another altenrate-server
3888       d->stun_message.buffer = NULL;
3889       d->stun_message.buffer_len = 0;
3890 
3891       nice_address_to_string (&server, ip);
3892       nice_debug ("Agent %p : Cancelling and setting alternate server %s for "
3893           "CandidateDiscovery %p on s%d/c%d", agent, ip, d,
3894           d->stream_id, d->component_id);
3895       d->server = alternate;
3896       d->turn->server = alternate;
3897       d->pending = FALSE;
3898       agent->discovery_unsched_items++;
3899 
3900       if (d->turn->type == NICE_RELAY_TYPE_TURN_TCP ||
3901           d->turn->type == NICE_RELAY_TYPE_TURN_TLS) {
3902         NiceStream *stream;
3903         NiceComponent *component;
3904 
3905         if (!agent_find_component (agent, d->stream_id, d->component_id,
3906             &stream, &component)) {
3907           nice_debug ("Could not find stream or component in "
3908               "priv_handle_turn_alternate_server");
3909           continue;
3910         }
3911         d->nicesock = agent_create_tcp_turn_socket (agent, stream, component,
3912             d->nicesock, &d->server, d->turn->type,
3913             nice_socket_is_reliable (d->nicesock));
3914 
3915         nice_component_attach_socket (component, d->nicesock);
3916       }
3917     }
3918   }
3919 }
3920 
3921 /*
3922  * Tries to match STUN reply in 'buf' to an existing STUN discovery
3923  * transaction. If found, a reply is sent.
3924  *
3925  * @return TRUE if a matching transaction is found
3926  */
priv_map_reply_to_relay_request(NiceAgent * agent,StunMessage * resp)3927 static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *resp)
3928 {
3929   union {
3930     struct sockaddr_storage storage;
3931     struct sockaddr addr;
3932   } sockaddr;
3933   socklen_t socklen = sizeof (sockaddr);
3934 
3935   union {
3936     struct sockaddr_storage storage;
3937     struct sockaddr addr;
3938   } alternate;
3939   socklen_t alternatelen = sizeof (alternate);
3940 
3941   union {
3942     struct sockaddr_storage storage;
3943     struct sockaddr addr;
3944   } relayaddr;
3945   socklen_t relayaddrlen = sizeof (relayaddr);
3946 
3947   uint32_t lifetime;
3948   uint32_t bandwidth;
3949   GSList *i;
3950   StunUsageTurnReturn res;
3951   gboolean trans_found = FALSE;
3952   StunTransactionId discovery_id;
3953   StunTransactionId response_id;
3954   stun_message_id (resp, response_id);
3955 
3956   for (i = agent->discovery_list; i && trans_found != TRUE; i = i->next) {
3957     CandidateDiscovery *d = i->data;
3958 
3959     if (d->type == NICE_CANDIDATE_TYPE_RELAYED &&
3960         d->stun_message.buffer) {
3961       stun_message_id (&d->stun_message, discovery_id);
3962 
3963       if (memcmp (discovery_id, response_id, sizeof(StunTransactionId)) == 0) {
3964         res = stun_usage_turn_process (resp,
3965             &relayaddr.storage, &relayaddrlen,
3966             &sockaddr.storage, &socklen,
3967             &alternate.storage, &alternatelen,
3968             &bandwidth, &lifetime, agent_to_turn_compatibility (agent));
3969         nice_debug ("Agent %p : stun_turn_process/disc for %p res %d.",
3970             agent, d, (int)res);
3971 
3972         if (res == STUN_USAGE_TURN_RETURN_ALTERNATE_SERVER) {
3973           NiceAddress addr;
3974 
3975           /* handle alternate server */
3976           nice_address_set_from_sockaddr (&addr, &alternate.addr);
3977           priv_handle_turn_alternate_server (agent, d, d->server, addr);
3978           trans_found = TRUE;
3979         } else if (res == STUN_USAGE_TURN_RETURN_RELAY_SUCCESS ||
3980                    res == STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS) {
3981           /* case: successful allocate, create a new local candidate */
3982           NiceAddress niceaddr;
3983           NiceCandidateImpl *relay_cand;
3984 
3985           nice_address_set_from_sockaddr (&niceaddr, &relayaddr.addr);
3986 
3987           if (res == STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS) {
3988             NiceAddress mappedniceaddr;
3989 
3990             /* We also received our mapped address */
3991             nice_address_set_from_sockaddr (&mappedniceaddr, &sockaddr.addr);
3992 
3993             /* TCP or TLS TURNS means the server-reflexive address was
3994              * on a TCP connection, which cannot be used for server-reflexive
3995              * discovery of candidates.
3996              */
3997             if (d->turn->type == NICE_RELAY_TYPE_TURN_UDP &&
3998                 !agent->force_relay) {
3999               discovery_add_server_reflexive_candidate (
4000                   agent,
4001                   d->stream_id,
4002                   d->component_id,
4003                   &mappedniceaddr,
4004                   NICE_CANDIDATE_TRANSPORT_UDP,
4005                   d->nicesock,
4006                   FALSE);
4007             }
4008             if (agent->use_ice_tcp) {
4009               if ((agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
4010                    agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
4011                   !nice_address_equal_no_port (&niceaddr, &d->turn->server)) {
4012                   nice_debug("TURN port got allocated on an alternate server, "
4013                              "ignoring bogus srflx address");
4014               } else {
4015                 discovery_discover_tcp_server_reflexive_candidates (
4016                     agent,
4017                     d->stream_id,
4018                     d->component_id,
4019                     &mappedniceaddr,
4020                     d->nicesock);
4021               }
4022             }
4023           }
4024 
4025           if (nice_socket_is_reliable (d->nicesock)) {
4026             relay_cand = discovery_add_relay_candidate (
4027                 agent,
4028                 d->stream_id,
4029                 d->component_id,
4030                 &niceaddr,
4031                 NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE,
4032                 d->nicesock,
4033                 d->turn);
4034 
4035             if (relay_cand) {
4036               if (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
4037                   agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
4038                 nice_udp_turn_socket_set_ms_realm(relay_cand->sockptr,
4039                     &d->stun_message);
4040                 nice_udp_turn_socket_set_ms_connection_id(relay_cand->sockptr,
4041                     resp);
4042               }
4043               priv_add_new_turn_refresh (agent, d, relay_cand, lifetime);
4044             }
4045 
4046             relay_cand = discovery_add_relay_candidate (
4047                 agent,
4048                 d->stream_id,
4049                 d->component_id,
4050                 &niceaddr,
4051                 NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE,
4052                 d->nicesock,
4053                 d->turn);
4054           } else {
4055             relay_cand = discovery_add_relay_candidate (
4056                 agent,
4057                 d->stream_id,
4058                 d->component_id,
4059                 &niceaddr,
4060                 NICE_CANDIDATE_TRANSPORT_UDP,
4061                 d->nicesock,
4062                 d->turn);
4063           }
4064 
4065           if (relay_cand) {
4066 	    if (d->stun_resp_msg.buffer)
4067 	      nice_udp_turn_socket_cache_realm_nonce (relay_cand->sockptr,
4068                   &d->stun_resp_msg);
4069             if (agent->compatibility == NICE_COMPATIBILITY_OC2007 ||
4070                 agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
4071               /* These data are needed on TURN socket when sending requests,
4072                * but never reach nice_turn_socket_parse_recv() where it could
4073                * be read directly, as the socket does not exist when allocate
4074                * response arrives to _nice_agent_recv(). We must set them right
4075                * after socket gets created in discovery_add_relay_candidate(),
4076                * so we are doing it here. */
4077               nice_udp_turn_socket_set_ms_realm(relay_cand->sockptr,
4078                   &d->stun_message);
4079               nice_udp_turn_socket_set_ms_connection_id(relay_cand->sockptr,
4080                   resp);
4081             }
4082             priv_add_new_turn_refresh (agent, d, relay_cand, lifetime);
4083 
4084             /* In case a new candidate has been added */
4085             conn_check_schedule_next (agent);
4086           }
4087 
4088           d->stun_message.buffer = NULL;
4089           d->stun_message.buffer_len = 0;
4090           d->done = TRUE;
4091           trans_found = TRUE;
4092         } else if (res == STUN_USAGE_TURN_RETURN_ERROR) {
4093           int code = -1;
4094           uint8_t *sent_realm = NULL;
4095           uint8_t *recv_realm = NULL;
4096           uint16_t sent_realm_len = 0;
4097           uint16_t recv_realm_len = 0;
4098 
4099           sent_realm = (uint8_t *) stun_message_find (&d->stun_message,
4100               STUN_ATTRIBUTE_REALM, &sent_realm_len);
4101           recv_realm = (uint8_t *) stun_message_find (resp,
4102               STUN_ATTRIBUTE_REALM, &recv_realm_len);
4103 
4104           if ((agent->compatibility == NICE_COMPATIBILITY_OC2007  ||
4105               agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
4106               alternatelen != sizeof(alternate)) {
4107             NiceAddress addr;
4108 
4109             nice_address_set_from_sockaddr (&addr, &alternate.addr);
4110 
4111             if (!nice_address_equal (&addr, &d->server)) {
4112               priv_handle_turn_alternate_server (agent, d, d->server, addr);
4113             }
4114           }
4115           /* check for unauthorized error response */
4116           if ((agent->compatibility == NICE_COMPATIBILITY_RFC5245 ||
4117                agent->compatibility == NICE_COMPATIBILITY_OC2007  ||
4118                agent->compatibility == NICE_COMPATIBILITY_OC2007R2) &&
4119               stun_message_get_class (resp) == STUN_ERROR &&
4120               stun_message_find_error (resp, &code) ==
4121               STUN_MESSAGE_RETURN_SUCCESS &&
4122               recv_realm != NULL && recv_realm_len > 0) {
4123 
4124             if (code == STUN_ERROR_STALE_NONCE ||
4125                 (code == STUN_ERROR_UNAUTHORIZED &&
4126                     !(recv_realm_len == sent_realm_len &&
4127                         sent_realm != NULL &&
4128                         memcmp (sent_realm, recv_realm, sent_realm_len) == 0))) {
4129               d->stun_resp_msg = *resp;
4130               memcpy (d->stun_resp_buffer, resp->buffer,
4131                   stun_message_length (resp));
4132               d->stun_resp_msg.buffer = d->stun_resp_buffer;
4133               d->stun_resp_msg.buffer_len = sizeof(d->stun_resp_buffer);
4134               d->pending = FALSE;
4135               agent->discovery_unsched_items++;
4136             } else {
4137               /* case: a real unauthorized error */
4138               d->stun_message.buffer = NULL;
4139               d->stun_message.buffer_len = 0;
4140               d->done = TRUE;
4141             }
4142           } else if (d->pending) {
4143             /* case: STUN error, the check STUN context was freed */
4144             d->stun_message.buffer = NULL;
4145             d->stun_message.buffer_len = 0;
4146             d->done = TRUE;
4147           }
4148           trans_found = TRUE;
4149         }
4150       }
4151     }
4152   }
4153 
4154   return trans_found;
4155 }
4156 
4157 
4158 /*
4159  * Tries to match STUN reply in 'buf' to an existing STUN discovery
4160  * transaction. If found, a reply is sent.
4161  *
4162  * @return TRUE if a matching transaction is found
4163  */
priv_map_reply_to_relay_refresh(NiceAgent * agent,StunMessage * resp)4164 static gboolean priv_map_reply_to_relay_refresh (NiceAgent *agent, StunMessage *resp)
4165 {
4166   uint32_t lifetime;
4167   GSList *i;
4168   StunUsageTurnReturn res;
4169   gboolean trans_found = FALSE;
4170   StunTransactionId refresh_id;
4171   StunTransactionId response_id;
4172   stun_message_id (resp, response_id);
4173 
4174   for (i = agent->refresh_list; i && trans_found != TRUE;) {
4175     CandidateRefresh *cand = i->data;
4176     GSList *next = i->next;
4177 
4178     if (!cand->disposing && cand->stun_message.buffer) {
4179       stun_message_id (&cand->stun_message, refresh_id);
4180 
4181       if (memcmp (refresh_id, response_id, sizeof(StunTransactionId)) == 0) {
4182         res = stun_usage_turn_refresh_process (resp,
4183             &lifetime, agent_to_turn_compatibility (agent));
4184         nice_debug ("Agent %p : stun_turn_refresh_process for %p res %d with lifetime %u.",
4185             agent, cand, (int)res, lifetime);
4186         if (res == STUN_USAGE_TURN_RETURN_RELAY_SUCCESS) {
4187           /* refresh should be sent 1 minute before it expires */
4188           agent_timeout_add_seconds_with_context (agent,
4189               &cand->timer_source,
4190               "Candidate TURN refresh", priv_calc_turn_timeout (lifetime),
4191               priv_turn_allocate_refresh_tick_agent_locked, cand);
4192 
4193           g_source_destroy (cand->tick_source);
4194           g_source_unref (cand->tick_source);
4195           cand->tick_source = NULL;
4196           trans_found = TRUE;
4197         } else if (res == STUN_USAGE_TURN_RETURN_ERROR) {
4198           int code = -1;
4199           uint8_t *sent_realm = NULL;
4200           uint8_t *recv_realm = NULL;
4201           uint16_t sent_realm_len = 0;
4202           uint16_t recv_realm_len = 0;
4203 
4204           sent_realm = (uint8_t *) stun_message_find (&cand->stun_message,
4205               STUN_ATTRIBUTE_REALM, &sent_realm_len);
4206           recv_realm = (uint8_t *) stun_message_find (resp,
4207               STUN_ATTRIBUTE_REALM, &recv_realm_len);
4208 
4209           /* check for unauthorized error response */
4210           if (agent->compatibility == NICE_COMPATIBILITY_RFC5245 &&
4211               stun_message_get_class (resp) == STUN_ERROR &&
4212               stun_message_find_error (resp, &code) ==
4213               STUN_MESSAGE_RETURN_SUCCESS &&
4214               recv_realm != NULL && recv_realm_len > 0) {
4215 
4216             if (code == STUN_ERROR_STALE_NONCE ||
4217                 (code == STUN_ERROR_UNAUTHORIZED &&
4218                     !(recv_realm_len == sent_realm_len &&
4219                         sent_realm != NULL &&
4220                         memcmp (sent_realm, recv_realm, sent_realm_len) == 0))) {
4221               cand->stun_resp_msg = *resp;
4222               memcpy (cand->stun_resp_buffer, resp->buffer,
4223                   stun_message_length (resp));
4224               cand->stun_resp_msg.buffer = cand->stun_resp_buffer;
4225               cand->stun_resp_msg.buffer_len = sizeof(cand->stun_resp_buffer);
4226               priv_turn_allocate_refresh_tick_unlocked (agent, cand);
4227             } else {
4228               /* case: a real unauthorized error */
4229               refresh_free (agent, cand);
4230             }
4231           } else {
4232             /* case: STUN error, the check STUN context was freed */
4233             refresh_free (agent, cand);
4234           }
4235           trans_found = TRUE;
4236         }
4237       }
4238     }
4239     i = next;
4240   }
4241 
4242   return trans_found;
4243 }
4244 
priv_map_reply_to_relay_remove(NiceAgent * agent,StunMessage * resp)4245 static gboolean priv_map_reply_to_relay_remove (NiceAgent *agent,
4246     StunMessage *resp)
4247 {
4248   StunTransactionId response_id;
4249   GSList *i;
4250 
4251   stun_message_id (resp, response_id);
4252 
4253   for (i = agent->refresh_list; i; i = i->next) {
4254     CandidateRefresh *cand = i->data;
4255     StunTransactionId request_id;
4256     StunUsageTurnReturn res;
4257     uint32_t lifetime;
4258 
4259     if (!cand->disposing || !cand->stun_message.buffer) {
4260       continue;
4261     }
4262 
4263     stun_message_id (&cand->stun_message, request_id);
4264 
4265     if (memcmp (request_id, response_id, sizeof(StunTransactionId)) == 0) {
4266       res = stun_usage_turn_refresh_process (resp, &lifetime,
4267           agent_to_turn_compatibility (agent));
4268 
4269       nice_debug ("Agent %p : priv_map_reply_to_relay_remove for %p res %d "
4270           "with lifetime %u.", agent, cand, res, lifetime);
4271 
4272       if (res != STUN_USAGE_TURN_RETURN_INVALID) {
4273         refresh_free (agent, cand);
4274         return TRUE;
4275       }
4276     }
4277   }
4278 
4279   return FALSE;
4280 }
4281 
priv_map_reply_to_keepalive_conncheck(NiceAgent * agent,NiceComponent * component,StunMessage * resp)4282 static gboolean priv_map_reply_to_keepalive_conncheck (NiceAgent *agent,
4283     NiceComponent *component, StunMessage *resp)
4284 {
4285   StunTransactionId conncheck_id;
4286   StunTransactionId response_id;
4287   stun_message_id (resp, response_id);
4288 
4289   if (component->selected_pair.keepalive.stun_message.buffer) {
4290       stun_message_id (&component->selected_pair.keepalive.stun_message,
4291           conncheck_id);
4292       if (memcmp (conncheck_id, response_id, sizeof(StunTransactionId)) == 0) {
4293         nice_debug ("Agent %p : Keepalive for selected pair received.",
4294             agent);
4295         if (component->selected_pair.keepalive.tick_source) {
4296           g_source_destroy (component->selected_pair.keepalive.tick_source);
4297           g_source_unref (component->selected_pair.keepalive.tick_source);
4298           component->selected_pair.keepalive.tick_source = NULL;
4299         }
4300         component->selected_pair.keepalive.stun_message.buffer = NULL;
4301         return TRUE;
4302       }
4303   }
4304 
4305   return FALSE;
4306 }
4307 
4308 
4309 typedef struct {
4310   NiceAgent *agent;
4311   NiceStream *stream;
4312   NiceComponent *component;
4313   uint8_t *password;
4314 } conncheck_validater_data;
4315 
conncheck_stun_validater(StunAgent * agent,StunMessage * message,uint8_t * username,uint16_t username_len,uint8_t ** password,size_t * password_len,void * user_data)4316 static bool conncheck_stun_validater (StunAgent *agent,
4317     StunMessage *message, uint8_t *username, uint16_t username_len,
4318     uint8_t **password, size_t *password_len, void *user_data)
4319 {
4320   conncheck_validater_data *data = (conncheck_validater_data*) user_data;
4321   GSList *i;
4322   gchar *ufrag = NULL;
4323   gsize ufrag_len;
4324 
4325   gboolean msn_msoc_nice_compatibility =
4326       data->agent->compatibility == NICE_COMPATIBILITY_MSN ||
4327       data->agent->compatibility == NICE_COMPATIBILITY_OC2007;
4328 
4329   if (data->agent->compatibility == NICE_COMPATIBILITY_OC2007 &&
4330       stun_message_get_class (message) == STUN_RESPONSE)
4331     i = data->component->remote_candidates;
4332   else
4333     i = data->component->local_candidates;
4334 
4335   for (; i; i = i->next) {
4336     NiceCandidate *cand = i->data;
4337 
4338     ufrag = NULL;
4339     if (cand->username)
4340       ufrag = cand->username;
4341     else
4342       ufrag = data->stream->local_ufrag;
4343     ufrag_len = ufrag? strlen (ufrag) : 0;
4344 
4345     if (ufrag && msn_msoc_nice_compatibility)
4346       ufrag = (gchar *)g_base64_decode (ufrag, &ufrag_len);
4347 
4348     if (ufrag == NULL)
4349       continue;
4350 
4351     stun_debug ("Comparing username/ufrag of len %d and %" G_GSIZE_FORMAT ", equal=%d",
4352         username_len, ufrag_len, username_len >= ufrag_len ?
4353         memcmp (username, ufrag, ufrag_len) : 0);
4354     stun_debug_bytes ("  username: ", username, username_len);
4355     stun_debug_bytes ("  ufrag:    ", ufrag, ufrag_len);
4356     if (ufrag_len > 0 && username_len >= ufrag_len &&
4357         memcmp (username, ufrag, ufrag_len) == 0) {
4358       gchar *pass = NULL;
4359 
4360       if (cand->password)
4361         pass = cand->password;
4362       else if (data->stream && data->stream->local_password[0])
4363         pass = data->stream->local_password;
4364 
4365       if (pass) {
4366         *password = (uint8_t *) pass;
4367         *password_len = strlen (pass);
4368 
4369         if (msn_msoc_nice_compatibility) {
4370           gsize pass_len;
4371 
4372           data->password = g_base64_decode (pass, &pass_len);
4373           *password = data->password;
4374           *password_len = pass_len;
4375         }
4376       }
4377 
4378       if (msn_msoc_nice_compatibility)
4379         g_free (ufrag);
4380 
4381       stun_debug ("Found valid username, returning password: '%s'", *password);
4382       return TRUE;
4383     }
4384 
4385     if (msn_msoc_nice_compatibility)
4386       g_free (ufrag);
4387   }
4388 
4389   return FALSE;
4390 }
4391 
4392 /*
4393  * handle RENOMINATION stun attribute
4394  * @return TRUE if nomination changed. FALSE otherwise
4395  */
conn_check_handle_renomination(NiceAgent * agent,NiceStream * stream,NiceComponent * component,StunMessage * req,NiceCandidate * remote_candidate,NiceCandidate * local_candidate)4396 static gboolean conn_check_handle_renomination (NiceAgent *agent, NiceStream *stream,
4397     NiceComponent *component, StunMessage *req,
4398     NiceCandidate *remote_candidate, NiceCandidate *local_candidate)
4399 {
4400   GSList *lst;
4401   if (!agent->controlling_mode && NICE_AGENT_IS_COMPATIBLE_WITH_RFC5245_OR_OC2007R2 (agent) &&
4402       agent->support_renomination && remote_candidate && local_candidate)
4403   {
4404     uint32_t nom_value = 0;
4405     uint16_t nom_len = 0;
4406     const void *value = stun_message_find (req, STUN_ATTRIBUTE_NOMINATION, &nom_len);
4407     if (nom_len == 0) {
4408       return FALSE;
4409     }
4410     if (nom_len == 4) {
4411       memcpy (&nom_value, value, 4);
4412       nom_value = ntohl (nom_value);
4413     } else {
4414       nice_debug ("Agent %p : received NOMINATION attr with incorrect octet length %u, expected 4 bytes",
4415           agent, nom_len);
4416       return FALSE;
4417     }
4418 
4419     if (nice_debug_is_enabled ()) {
4420       gchar remote_str[INET6_ADDRSTRLEN];
4421       nice_address_to_string(&remote_candidate->addr, remote_str);
4422       nice_debug ("Agent %p : received NOMINATION attr for remote candidate [%s]:%u, value is %u",
4423           agent, remote_str, nice_address_get_port (&remote_candidate->addr), nom_value);
4424     }
4425 
4426     /*
4427      * If another pair is SELECTED, change this pair's priority to be greater than
4428      * selected pair's priority so this pair gets SELECTED!
4429      */
4430     if (component->selected_pair.priority &&
4431         component->selected_pair.remote && component->selected_pair.remote != (NiceCandidateImpl *) remote_candidate &&
4432         component->selected_pair.local && component->selected_pair.local != (NiceCandidateImpl *) local_candidate) {
4433       for (lst = stream->conncheck_list; lst; lst = lst->next) {
4434         CandidateCheckPair *pair = lst->data;
4435         if (pair->local == local_candidate && pair->remote == remote_candidate) {
4436           if (pair->valid) {
4437             pair->priority = component->selected_pair.priority + 1;
4438           }
4439           break;
4440         }
4441       }
4442     }
4443     priv_mark_pair_nominated (agent, stream, component, local_candidate, remote_candidate);
4444     return TRUE;
4445   }
4446   return FALSE;
4447 }
4448 
4449 /*
4450  * Processing an incoming STUN message.
4451  *
4452  * @param agent self pointer
4453  * @param stream stream the packet is related to
4454  * @param component component the packet is related to
4455  * @param nicesock socket from which the packet was received
4456  * @param from address of the sender
4457  * @param buf message contents
4458  * @param buf message length
4459  *
4460  * @pre contents of 'buf' is a STUN message
4461  *
4462  * @return XXX (what FALSE means exactly?)
4463  */
conn_check_handle_inbound_stun(NiceAgent * agent,NiceStream * stream,NiceComponent * component,NiceSocket * nicesock,const NiceAddress * from,gchar * buf,guint len)4464 gboolean conn_check_handle_inbound_stun (NiceAgent *agent, NiceStream *stream,
4465     NiceComponent *component, NiceSocket *nicesock, const NiceAddress *from,
4466     gchar *buf, guint len)
4467 {
4468   union {
4469     struct sockaddr_storage storage;
4470     struct sockaddr addr;
4471   } sockaddr;
4472   uint8_t rbuf[MAX_STUN_DATAGRAM_PAYLOAD];
4473   ssize_t res;
4474   size_t rbuf_len = sizeof (rbuf);
4475   bool control = agent->controlling_mode;
4476   uint8_t uname[NICE_STREAM_MAX_UNAME];
4477   guint uname_len;
4478   uint8_t *username;
4479   uint16_t username_len;
4480   StunMessage req;
4481   StunMessage msg;
4482   StunValidationStatus valid;
4483   conncheck_validater_data validater_data = {agent, stream, component, NULL};
4484   GSList *i, *j;
4485   NiceCandidate *remote_candidate = NULL;
4486   NiceCandidate *remote_candidate2 = NULL;
4487   NiceCandidate *local_candidate = NULL;
4488   gboolean discovery_msg = FALSE;
4489 
4490   nice_address_copy_to_sockaddr (from, &sockaddr.addr);
4491 
4492   /* note: contents of 'buf' already validated, so it is
4493    *       a valid and fully received STUN message */
4494 
4495   if (nice_debug_is_enabled ()) {
4496     gchar tmpbuf[INET6_ADDRSTRLEN];
4497     nice_address_to_string (from, tmpbuf);
4498     nice_debug ("Agent %p: inbound STUN packet for %u/%u (stream/component) from [%s]:%u (%u octets) :",
4499         agent, stream->id, component->id, tmpbuf, nice_address_get_port (from), len);
4500   }
4501 
4502   /* note: ICE  7.2. "STUN Server Procedures" (ID-19) */
4503 
4504   valid = stun_agent_validate (&component->stun_agent, &req,
4505       (uint8_t *) buf, len, conncheck_stun_validater, &validater_data);
4506 
4507   /* Check for discovery candidates stun agents */
4508   if (valid == STUN_VALIDATION_BAD_REQUEST ||
4509       valid == STUN_VALIDATION_UNMATCHED_RESPONSE) {
4510     for (i = agent->discovery_list; i; i = i->next) {
4511       CandidateDiscovery *d = i->data;
4512       if (d->stream_id == stream->id && d->component_id == component->id &&
4513           d->nicesock == nicesock) {
4514         valid = stun_agent_validate (&d->stun_agent, &req,
4515             (uint8_t *) buf, len, conncheck_stun_validater, &validater_data);
4516 
4517         if (valid == STUN_VALIDATION_UNMATCHED_RESPONSE)
4518           continue;
4519 
4520         discovery_msg = TRUE;
4521         break;
4522       }
4523     }
4524   }
4525   /* Check for relay refresh stun agents */
4526   if (valid == STUN_VALIDATION_BAD_REQUEST ||
4527       valid == STUN_VALIDATION_UNMATCHED_RESPONSE) {
4528     for (i = agent->refresh_list; i; i = i->next) {
4529       CandidateRefresh *r = i->data;
4530 
4531       nice_debug_verbose ("Comparing r.sid=%u to sid=%u, r.cid=%u to cid=%u and %p and %p to %p",
4532           r->stream_id, stream->id, r->component_id, component->id, r->nicesock,
4533           r->candidate->sockptr, nicesock);
4534 
4535       if (r->stream_id == stream->id && r->component_id == component->id &&
4536           (r->nicesock == nicesock || r->candidate->sockptr == nicesock)) {
4537         valid = stun_agent_validate (&r->stun_agent, &req,
4538             (uint8_t *) buf, len, conncheck_stun_validater, &validater_data);
4539         nice_debug ("Validating gave %d", valid);
4540         if (valid == STUN_VALIDATION_UNMATCHED_RESPONSE)
4541           continue;
4542         discovery_msg = TRUE;
4543         break;
4544       }
4545     }
4546   }
4547 
4548   g_free (validater_data.password);
4549 
4550   if (valid == STUN_VALIDATION_NOT_STUN ||
4551       valid == STUN_VALIDATION_INCOMPLETE_STUN ||
4552       valid == STUN_VALIDATION_BAD_REQUEST)
4553   {
4554     nice_debug ("Agent %p : Incorrectly multiplexed STUN message ignored.",
4555         agent);
4556     return FALSE;
4557   }
4558 
4559   if (valid == STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE) {
4560     nice_debug ("Agent %p : Unknown mandatory attributes in message.", agent);
4561 
4562     if (agent->compatibility != NICE_COMPATIBILITY_MSN &&
4563         agent->compatibility != NICE_COMPATIBILITY_OC2007) {
4564       rbuf_len = stun_agent_build_unknown_attributes_error (&component->stun_agent,
4565           &msg, rbuf, rbuf_len, &req);
4566       if (rbuf_len != 0)
4567         agent_socket_send (nicesock, from, rbuf_len, (const gchar*)rbuf);
4568     }
4569     return TRUE;
4570   }
4571 
4572   if (valid == STUN_VALIDATION_UNAUTHORIZED) {
4573     nice_debug ("Agent %p : Integrity check failed.", agent);
4574 
4575     if (stun_agent_init_error (&component->stun_agent, &msg, rbuf, rbuf_len,
4576             &req, STUN_ERROR_UNAUTHORIZED)) {
4577       rbuf_len = stun_agent_finish_message (&component->stun_agent, &msg, NULL, 0);
4578       if (rbuf_len > 0 && agent->compatibility != NICE_COMPATIBILITY_MSN &&
4579           agent->compatibility != NICE_COMPATIBILITY_OC2007)
4580         agent_socket_send (nicesock, from, rbuf_len, (const gchar*)rbuf);
4581     }
4582     return TRUE;
4583   }
4584   if (valid == STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST) {
4585     nice_debug ("Agent %p : Integrity check failed - bad request.", agent);
4586     if (stun_agent_init_error (&component->stun_agent, &msg, rbuf, rbuf_len,
4587             &req, STUN_ERROR_BAD_REQUEST)) {
4588       rbuf_len = stun_agent_finish_message (&component->stun_agent, &msg, NULL, 0);
4589       if (rbuf_len > 0 && agent->compatibility != NICE_COMPATIBILITY_MSN &&
4590 	  agent->compatibility != NICE_COMPATIBILITY_OC2007)
4591         agent_socket_send (nicesock, from, rbuf_len, (const gchar*)rbuf);
4592     }
4593     return TRUE;
4594   }
4595 
4596   username = (uint8_t *) stun_message_find (&req, STUN_ATTRIBUTE_USERNAME,
4597 					    &username_len);
4598 
4599   for (i = component->local_candidates; i; i = i->next) {
4600     NiceCandidate *cand = i->data;
4601     NiceAddress *addr;
4602 
4603     if (cand->type == NICE_CANDIDATE_TYPE_RELAYED)
4604       addr = &cand->addr;
4605     else
4606       addr = &cand->base_addr;
4607 
4608     if (nice_address_equal (&nicesock->addr, addr) &&
4609         local_candidate_and_socket_compatible (agent, cand, nicesock)) {
4610       local_candidate = cand;
4611       break;
4612     }
4613   }
4614 
4615   for (i = component->remote_candidates; i; i = i->next) {
4616     NiceCandidate *cand = i->data;
4617     if (nice_address_equal (from, &cand->addr) &&
4618         remote_candidate_and_socket_compatible (agent, local_candidate,
4619         cand, nicesock)) {
4620       remote_candidate = cand;
4621       break;
4622     }
4623   }
4624 
4625   if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE ||
4626       agent->compatibility == NICE_COMPATIBILITY_MSN ||
4627       agent->compatibility == NICE_COMPATIBILITY_OC2007) {
4628     /* We need to find which local candidate was used */
4629     for (i = component->remote_candidates;
4630          i != NULL && remote_candidate2 == NULL; i = i->next) {
4631       for (j = component->local_candidates; j; j = j->next) {
4632         gboolean inbound = TRUE;
4633         NiceCandidate *rcand = i->data;
4634         NiceCandidate *lcand = j->data;
4635 
4636         /* If we receive a response, then the username is local:remote */
4637         if (agent->compatibility != NICE_COMPATIBILITY_MSN) {
4638           if (stun_message_get_class (&req) == STUN_REQUEST ||
4639               stun_message_get_class (&req) == STUN_INDICATION) {
4640             inbound = TRUE;
4641           } else {
4642             inbound = FALSE;
4643           }
4644         }
4645 
4646         uname_len = priv_create_username (agent, stream,
4647             component->id,  rcand, lcand,
4648             uname, sizeof (uname), inbound);
4649 
4650 
4651 
4652         stun_debug ("Comparing usernames of size %d and %d: %d",
4653             username_len, uname_len, username && uname_len == username_len &&
4654             memcmp (username, uname, uname_len) == 0);
4655         stun_debug_bytes ("  First username: ", username,
4656             username ? username_len : 0);
4657         stun_debug_bytes ("  Second uname:   ", uname, uname_len);
4658 
4659         if (username &&
4660             uname_len == username_len &&
4661             memcmp (uname, username, username_len) == 0) {
4662           local_candidate = lcand;
4663           remote_candidate2 = rcand;
4664           break;
4665         }
4666       }
4667     }
4668   }
4669 
4670   if (component->remote_candidates &&
4671       agent->compatibility == NICE_COMPATIBILITY_GOOGLE &&
4672       local_candidate == NULL &&
4673       discovery_msg == FALSE) {
4674     /* if we couldn't match the username and the stun agent has
4675        IGNORE_CREDENTIALS then we have an integrity check failing.
4676        This could happen with the race condition of receiving connchecks
4677        before the remote candidates are added. Just drop the message, and let
4678        the retransmissions make it work. */
4679     nice_debug ("Agent %p : Username check failed.", agent);
4680     return TRUE;
4681   }
4682 
4683   /* This is most likely caused by a second response to a request which
4684    * already has received a valid reply.
4685    */
4686   if (valid == STUN_VALIDATION_UNMATCHED_RESPONSE) {
4687     nice_debug ("Agent %p : Valid STUN response for which we don't have a request, ignoring", agent);
4688     return TRUE;
4689   }
4690 
4691   if (valid != STUN_VALIDATION_SUCCESS) {
4692     nice_debug ("Agent %p : STUN message is unsuccessful %d, ignoring", agent, valid);
4693     return FALSE;
4694   }
4695 
4696   agent->media_after_tick = TRUE;
4697 
4698   if (stun_message_get_class (&req) == STUN_REQUEST) {
4699     if (   agent->compatibility == NICE_COMPATIBILITY_MSN
4700         || agent->compatibility == NICE_COMPATIBILITY_OC2007) {
4701       if (local_candidate && remote_candidate2) {
4702         gsize key_len;
4703 
4704 	if (agent->compatibility == NICE_COMPATIBILITY_MSN) {
4705           username = (uint8_t *) stun_message_find (&req,
4706 	  STUN_ATTRIBUTE_USERNAME, &username_len);
4707 	  uname_len = priv_create_username (agent, stream,
4708               component->id,  remote_candidate2, local_candidate,
4709 	      uname, sizeof (uname), FALSE);
4710 	  memcpy (username, uname, MIN (uname_len, username_len));
4711 
4712 	  req.key = g_base64_decode ((gchar *) remote_candidate2->password,
4713               &key_len);
4714           req.key_len = key_len;
4715 	} else if (agent->compatibility == NICE_COMPATIBILITY_OC2007) {
4716           req.key = g_base64_decode ((gchar *) local_candidate->password,
4717               &key_len);
4718           req.key_len = key_len;
4719 	}
4720       } else {
4721         nice_debug ("Agent %p : received MSN incoming check from unknown remote candidate. "
4722             "Ignoring request", agent);
4723         return TRUE;
4724       }
4725     }
4726 
4727     rbuf_len = sizeof (rbuf);
4728     res = stun_usage_ice_conncheck_create_reply (&component->stun_agent, &req,
4729         &msg, rbuf, &rbuf_len, &sockaddr.storage, sizeof (sockaddr),
4730         &control, agent->tie_breaker,
4731         agent_to_ice_compatibility (agent));
4732 
4733     if (   agent->compatibility == NICE_COMPATIBILITY_MSN
4734         || agent->compatibility == NICE_COMPATIBILITY_OC2007) {
4735       g_free (req.key);
4736     }
4737 
4738     if (res == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT)
4739       priv_check_for_role_conflict (agent, control);
4740 
4741     if (res == STUN_USAGE_ICE_RETURN_SUCCESS ||
4742         res == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT) {
4743       /* case 1: valid incoming request, send a reply/error */
4744       bool use_candidate =
4745           stun_usage_ice_conncheck_use_candidate (&req);
4746       uint32_t priority = stun_usage_ice_conncheck_priority (&req);
4747 
4748       if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE ||
4749           agent->compatibility == NICE_COMPATIBILITY_MSN ||
4750           agent->compatibility == NICE_COMPATIBILITY_OC2007)
4751         use_candidate = TRUE;
4752 
4753       if (stream->initial_binding_request_received != TRUE)
4754         agent_signal_initial_binding_request_received (agent, stream);
4755 
4756       if (remote_candidate == NULL) {
4757 	nice_debug ("Agent %p : No matching remote candidate for incoming "
4758             "check -> peer-reflexive candidate.", agent);
4759 	remote_candidate = discovery_learn_remote_peer_reflexive_candidate (
4760             agent, stream, component, priority, from, nicesock,
4761             local_candidate,
4762             remote_candidate2 ? remote_candidate2 : remote_candidate);
4763         if(remote_candidate && stream->remote_ufrag[0]) {
4764           if (local_candidate &&
4765               local_candidate->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE)
4766             priv_conn_check_add_for_candidate_pair_matched (agent,
4767                 stream->id, component, local_candidate, remote_candidate,
4768                 NICE_CHECK_WAITING);
4769           else
4770             conn_check_add_for_candidate (agent, stream->id, component, remote_candidate);
4771         }
4772       }
4773 
4774       nice_component_add_valid_candidate (agent, component, remote_candidate);
4775 
4776       priv_reply_to_conn_check (agent, stream, component, local_candidate,
4777           remote_candidate, from, nicesock, rbuf_len, &msg, use_candidate);
4778 
4779       if (stream->remote_ufrag[0] == 0) {
4780         /* case: We've got a valid binding request to a local candidate
4781          *       but we do not yet know remote credentials.
4782          *       As per sect 7.2 of ICE (ID-19), we send a reply
4783          *       immediately but postpone all other processing until
4784          *       we get information about the remote candidates */
4785 
4786         /* step: send a reply immediately but postpone other processing */
4787         priv_store_pending_check (agent, component, from, nicesock,
4788             username, username_len, priority, use_candidate);
4789         priv_print_conn_check_lists (agent, G_STRFUNC, ", icheck stored");
4790       }
4791     } else {
4792       nice_debug ("Agent %p : Invalid STUN packet, ignoring... %s",
4793           agent, strerror(errno));
4794       return FALSE;
4795     }
4796   } else {
4797       /* case 2: not a new request, might be a reply...  */
4798       gboolean trans_found = FALSE;
4799 
4800       /* note: ICE sect 7.1.2. "Processing the Response" (ID-19) */
4801 
4802       /* step: let's try to match the response to an existing check context */
4803       if (trans_found != TRUE)
4804         trans_found = priv_map_reply_to_conn_check_request (agent, stream,
4805 	    component, nicesock, from, local_candidate, remote_candidate, &req);
4806 
4807       /* step: let's try to match the response to an existing discovery */
4808       if (trans_found != TRUE)
4809         trans_found = priv_map_reply_to_discovery_request (agent, &req);
4810 
4811       /* step: let's try to match the response to an existing turn allocate */
4812       if (trans_found != TRUE)
4813         trans_found = priv_map_reply_to_relay_request (agent, &req);
4814 
4815       /* step: let's try to match the response to an existing turn refresh */
4816       if (trans_found != TRUE)
4817         trans_found = priv_map_reply_to_relay_refresh (agent, &req);
4818 
4819       if (trans_found != TRUE)
4820         trans_found = priv_map_reply_to_relay_remove (agent, &req);
4821 
4822       /* step: let's try to match the response to an existing keepalive conncheck */
4823       if (trans_found != TRUE)
4824         trans_found = priv_map_reply_to_keepalive_conncheck (agent, component,
4825             &req);
4826 
4827       if (trans_found != TRUE)
4828         nice_debug ("Agent %p : Unable to match to an existing transaction, "
4829             "probably a keepalive.", agent);
4830   }
4831 
4832   /* RENOMINATION attribute support */
4833   conn_check_handle_renomination(agent, stream, component, &req, remote_candidate, local_candidate);
4834 
4835   return TRUE;
4836 }
4837 
4838 /* Remove all pointers to the given @sock from the connection checking process.
4839  * These are entirely NiceCandidates pointed to from various places. */
4840 void
conn_check_prune_socket(NiceAgent * agent,NiceStream * stream,NiceComponent * component,NiceSocket * sock)4841 conn_check_prune_socket (NiceAgent *agent, NiceStream *stream, NiceComponent *component,
4842     NiceSocket *sock)
4843 {
4844   GSList *l;
4845   gboolean pair_failed = FALSE;
4846 
4847   if (component->selected_pair.local &&
4848       component->selected_pair.local->sockptr == sock &&
4849       component->state == NICE_COMPONENT_STATE_READY) {
4850     nice_debug ("Agent %p: Selected pair socket %p has been destroyed, "
4851         "declaring failed", agent, sock);
4852     agent_signal_component_state_change (agent,
4853         stream->id, component->id, NICE_COMPONENT_STATE_FAILED);
4854   }
4855 
4856   /* Prune from the candidate check pairs. */
4857   for (l = stream->conncheck_list; l != NULL;) {
4858     CandidateCheckPair *p = l->data;
4859     GSList *next = l->next;
4860 
4861     if ((p->local != NULL && ((NiceCandidateImpl*) p->local)->sockptr == sock) ||
4862         (p->remote != NULL && ((NiceCandidateImpl*)p->remote)->sockptr == sock) ||
4863         (p->sockptr == sock)) {
4864       nice_debug ("Agent %p : Retransmissions failed, giving up on pair %p",
4865           agent, p);
4866       candidate_check_pair_fail (stream, agent, p);
4867       candidate_check_pair_free (agent, p);
4868       stream->conncheck_list = g_slist_delete_link (stream->conncheck_list, l);
4869       pair_failed = TRUE;
4870     }
4871 
4872     l = next;
4873   }
4874 
4875   /* outside of the previous loop, because it may
4876    * remove pairs from the conncheck list
4877    */
4878   if (pair_failed)
4879     conn_check_update_check_list_state_for_ready (agent, stream, component);
4880 }
4881